feat: persistent photo job queue, worker, history with rollback

- Replace in-memory photoAiJobs Map with DB-backed photo_jobs table
- Background photo worker (worker.js) with retry, backoff, stale reset
  - Handles both AI (Real-ESRGAN) and server-side (sharp) enhancement
  - Controlled via photo_worker_enabled setting
- Photo job history in enhance modal with before/after thumbnails + rollback
- Worker dashboard: photo jobs section with status counts, recent table,
  compare slider for before/after, rollback from worker UI
- New endpoints: /api/photo-jobs/status|wake|enabled|requeue-failed,
  /api/entries/:id/photo/jobs (history), .../rollback
- swapEntryPhotoFiles logs every mutation to photo_jobs table
This commit is contained in:
dev
2026-09-17 17:36:56 +03:00
parent 27a2238082
commit 1145be02f3
8 changed files with 876 additions and 55 deletions
+12
View File
@@ -27,6 +27,7 @@
.enhance-sliders { flex: 0 0 240px; display: flex; flex-direction: column; gap: 14px; }
.enhance-sliders .settings-field input[type=range] { width: 100%; }
.enhance-foot { justify-content: flex-end; gap: 8px; margin-top: 14px; }
.photo-thumb { width: 56px; height: 56px; object-fit: cover; border-radius: 6px; border: 1px solid var(--border); display: block; }
@media (max-width: 800px) {
.enhance-body { flex-direction: column; }
.enhance-sliders { flex: 1 1 auto; display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
@@ -215,6 +216,7 @@
</div>
</div>
<div class="card-foot enhance-foot">
<button type="button" class="btn-primary ghost" id="enhanceHistoryBtn" title="История изменений фотографии">🕘 История</button>
<button type="button" class="btn-primary ghost" id="enhanceRestoreBtn" style="display:none" title="Вернуть исходную фотографию">↩ Вернуть оригинал</button>
<button type="button" class="btn-primary ghost" id="enhanceAiBtn" style="display:none" title="ИИ-восстановление (Real-ESRGAN)">🤖 ИИ</button>
<button type="button" class="btn-primary ghost" id="enhanceAutoBtn" title="Подобрать настройки автоматически">✨ Авто</button>
@@ -224,6 +226,16 @@
</div>
</div>
<div class="modal-overlay" id="photoHistoryModal">
<div class="edit-modal enhance-modal">
<h3 id="photoHistoryTitle">История изменений фотографии</h3>
<div id="photoHistoryList" style="display:flex;flex-direction:column;gap:12px;max-height:60vh;overflow:auto"></div>
<div class="card-foot enhance-foot">
<button type="button" class="btn-primary ghost" id="photoHistoryCloseBtn">Закрыть</button>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script src="vendor/lucide.min.js"></script>
<script src="admin.js"></script>