feat: backfill file hashes for existing documents (#56) #59

Merged
marcel merged 4 commits from feature/56-backfill-file-hashes into main 2026-03-24 22:09:37 +01:00
Owner

Summary

Adds a one-shot admin action that computes SHA-256 hashes for all documents that were uploaded before the #55 migration. Without this, those documents would always show the "outdated annotations" notice and their annotations would be hidden.

  • FileService.downloadFileBytes() — downloads raw bytes from S3 for hash computation
  • AnnotationService.backfillAnnotationFileHashForDocument() — sets the document hash on any annotation that still has fileHash = NULL
  • DocumentService.backfillFileHashes() — iterates all (fileHash IS NULL, filePath IS NOT NULL) documents, downloads, hashes, saves, then propagates the hash to annotations; skips gracefully on S3 errors
  • POST /api/admin/backfill-file-hashes — new endpoint in AdminController, protected by ADMIN permission, returns { count } like the existing backfill-versions endpoint
  • Admin System tab — second card "Datei-Hashes berechnen" with loading state and success message
  • i18n: four new keys in de/en/es

Test plan

  • 173 backend unit tests pass (./mvnw test)
  • svelte-check introduces no new type errors
  • E2E: admin triggers file hash backfill and sees success message — navigates to System tab, clicks button, success counter appears
  • After running backfill: annotations on old documents reappear, no outdated-notice shown

Depends on #55 (branched from feature/55-file-hash-annotations).
Closes #56

## Summary Adds a one-shot admin action that computes SHA-256 hashes for all documents that were uploaded before the #55 migration. Without this, those documents would always show the "outdated annotations" notice and their annotations would be hidden. - **`FileService.downloadFileBytes()`** — downloads raw bytes from S3 for hash computation - **`AnnotationService.backfillAnnotationFileHashForDocument()`** — sets the document hash on any annotation that still has `fileHash = NULL` - **`DocumentService.backfillFileHashes()`** — iterates all `(fileHash IS NULL, filePath IS NOT NULL)` documents, downloads, hashes, saves, then propagates the hash to annotations; skips gracefully on S3 errors - **`POST /api/admin/backfill-file-hashes`** — new endpoint in `AdminController`, protected by `ADMIN` permission, returns `{ count }` like the existing `backfill-versions` endpoint - **Admin System tab** — second card "Datei-Hashes berechnen" with loading state and success message - **i18n**: four new keys in de/en/es ## Test plan - [ ] 173 backend unit tests pass (`./mvnw test`) - [ ] `svelte-check` introduces no new type errors - [ ] E2E: `admin triggers file hash backfill and sees success message` — navigates to System tab, clicks button, success counter appears - [ ] After running backfill: annotations on old documents reappear, no outdated-notice shown Depends on #55 (branched from `feature/55-file-hash-annotations`). Closes #56
marcel changed target branch from feature/55-file-hash-annotations to main 2026-03-24 22:09:19 +01:00
marcel added 4 commits 2026-03-24 22:09:19 +01:00
- DocumentRepository: findByFileHashIsNullAndFilePathIsNotNull()
- AnnotationRepository: findByDocumentIdAndFileHashIsNull()
- FileService: downloadFileBytes() downloads raw bytes from S3 for hashing
- AnnotationService: backfillAnnotationFileHashForDocument() sets hash on null-hash annotations
- DocumentService: backfillFileHashes() iterates documents with null hash,
  downloads bytes, computes SHA-256, saves doc, then propagates hash to annotations
- AdminController: POST /api/admin/backfill-file-hashes delegates to DocumentService

Closes #56

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
feat(frontend): add backfill file hashes card to admin System tab
Some checks failed
CI / Unit & Component Tests (push) Successful in 2m28s
CI / Backend Unit Tests (push) Successful in 2m17s
CI / E2E Tests (push) Failing after 24m34s
CI / Unit & Component Tests (pull_request) Successful in 2m16s
CI / Backend Unit Tests (pull_request) Successful in 2m7s
CI / E2E Tests (pull_request) Failing after 22m53s
00195dc8db
- System tab gains a second card with a 'Datei-Hashes berechnen' button
  that calls POST /api/admin/backfill-file-hashes and shows the updated count
- i18n: admin_system_backfill_hashes_* keys added in de/en/es
- E2E: test verifies the button triggers the backfill and shows the success message

Closes #56

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Status badges (UPLOADED, PLACEHOLDER, etc.) provided no real value
to users and have been removed from the document list and document
detail header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
test(e2e): update reader annotation test to match post-#61 behaviour
Some checks failed
CI / Unit & Component Tests (pull_request) Successful in 2m22s
CI / Backend Unit Tests (pull_request) Successful in 2m23s
CI / Backend Unit Tests (push) Successful in 2m16s
CI / Unit & Component Tests (push) Successful in 2m29s
CI / E2E Tests (pull_request) Successful in 23m27s
CI / E2E Tests (push) Failing after 16m19s
63013cc86a
The old test waited for the PDF canvas (30 s timeout) before checking
for a disabled Annotieren button — a brittle dependency that caused
consistent failure because the reader's file fetch never completed in
CI. Since issue #61 will remove the disabled button entirely for users
without ANNOTATE_ALL, rewrite the test to assert the button is absent,
which is correct both in the interim and after #61.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
marcel merged commit 63013cc86a into main 2026-03-24 22:09:37 +01:00
marcel deleted branch feature/56-backfill-file-hashes 2026-03-24 22:09:38 +01:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#59