feat(issues): retry a processing issue through the individual scanner

POST /api/libraries/:id/issues/:issueId/retry (admin, family-lens gated
via the existing gateIssue) re-runs the work that produced an open issue
— deliberately NOT a library-wide rescan. Two shapes mirror the two
ledger entry kinds:

- item-backed issues rescan their media item through the book-detail
  RescanMediaItem mechanism (self-resolving folders, multi-file
  audiobook routing, write-after-success guards) and then close the
  issue (RetryMediaItemIssue);
- row-less import_failed issues re-import the single file through the
  watcher's standalone processMediaFile path (RetryFailedImport: folders
  resolved RescanMediaItem-style so paths stay library-root-relative),
  whose create-path self-heal plus an explicit path resolve closes the
  issue even when the content was already imported by a prior attempt.

Failures return the REAL underlying error so the UI can show why the
issue still exists; a vanished file is a 409 (ErrRetryFileMissing);
already-resolved issues reject re-retry.

Docs + bruno mirrors regenerated for the new route (the generator's seq
renumbering touches three unrelated bruno files as fallout; openapi
gains the path and the date bump), and the docs schema registry gains
the retry entry so TestDocsMatchRoutes passes.
This commit is contained in:
John O'Keefe committed 2026-10-27 13:22:31 -04:00
1 parent fb117635f8
commit 6f37be59fc
10 files changed
+246 -4

No files matched your search

+3
View File
@@ -147,6 +147,9 @@ var Schemas = map[string]Schema{
"POST /api/libraries/:id/issues/:issueId/:mediaItemId/resolve": {
Response: json.RawMessage(`{"success": false, "message": ""}`),
},
"POST /api/libraries/:id/issues/:issueId/retry": {
Response: json.RawMessage(`{"success": false, "message": ""}`),
},
"DELETE /api/libraries/:id/issues/:issueId": {
Response: json.RawMessage(`{"success": false, "message": ""}`),
},