5.3 KiB
Task 3 report: store many immutable sources in one batch
Next.js 16 documentation read
Before editing route/component code, read the version-matched docs required by
the plan from node_modules/next/dist/docs/:
01-app/01-getting-started/15-route-handlers.md(Request/FormData and Route Handler contract)01-app/02-guides/upgrading/version-16.md(Next 16 runtime and async request API guidance)
RED/GREEN evidence
RED baseline: npx vitest run src/app/api/delivery-notes/upload/route.test.ts
failed against the old one-batch-per-file implementation when the new
dn_batch_sources contract was exercised (the old test/mocking contract had
no source collection and multi-file behavior expected separate batches).
GREEN: npx vitest run src/app/api/delivery-notes/upload/route.test.ts
passed: 1 file, 5 tests.
Type verification: npm run typecheck passed (tsc --noEmit).
Diff hygiene: git diff --check passed.
Implementation
- Changed
src/app/api/delivery-notes/upload/route.tsto create one batch per request and immutabledn_batch_sourcesrows per accepted file. - Added per-source capture/session/time/GPS metadata parsing, SHA-256 source deduplication, capture-session idempotency, 20 MB/file and 50-file limits, and mixed-validity per-file outcomes.
- Retained the legacy single-file response fields and added multi-file
batch_id,source_count,status,results, and summary data. - Updated
src/components/upload-delivery-note-button.tsxto report files in one processing batch and show per-file duplicate/error details. - Replaced route tests with focused coverage for one-batch/three-source creation, repeated capture sessions, duplicate hashes, mixed valid/invalid files, metadata, and the legacy response.
Self-review and concerns
- Only the three scoped Task 3 implementation/test files were changed; report evidence is stored alongside the SDD and Clock/photo-app files were untouched.
- Invalid files are represented in a 201 multi-file response so valid sources
are not lost; a single invalid file retains the legacy 400 validation payload
(including
max_bytes,got, andallowedwhere applicable). dn_batches.fileandfile_hashare populated from the first source for legacy readers while the canonical originals are stored indn_batch_sources.- The route persists
dn_batches.source_countafter source writes and deletes a newly-created batch when no source can be persisted.
Commit
6e298990e407e3f71085ece4f432259f87c6403d fix(dn): harden bulk upload idempotency
Fix round 2 implementation:
00e82e51a51a17eb4545d2b74bfbf44bc80570b0 fix(dn): close bulk upload consistency gaps
Fix round 1 evidence
- Preflighted source hashes before batch creation. Single-duplicate and
all-duplicate multi-file requests create no new
dn_batchesrow. - Replaced capture-session interpolation with PocketBase SDK binding via
pb.filter("capture_session_id = {:captureSession}", { captureSession }); the suite covers quotes, backslashes, and control-like newlines. - Restored single-file 400 validation payloads for empty, oversized, and unsupported files; retained mixed multi-file partial success behavior.
- Persisted
dn_batches.source_countwith the successful source count and deleted the newly-created batch if all source writes fail. - Expanded the focused route suite to 11 tests, retaining one-batch/source, metadata, duplicate, mixed-validity, and legacy response coverage.
Exact fix-round verification:
npx vitest run src/app/api/delivery-notes/upload/route.test.ts — passed, 1
file, 11 tests.
npm run typecheck — passed (tsc --noEmit).
git diff --check — passed.
Fix round 3 implementation commit:
05c9b6b8f084ac71e9cc462d521b1c48539855db fix(dn): contain bulk batch lifecycle
Fix round 3 evidence
- New batches are created as
status: "needs_attention"andstage: "preparing", so a surviving batch is never processable whilesource_countpersistence is unresolved. Only the successful final update setssource_count,status: "inbox", andstage: "queued". - If that final update fails, deletion is attempted. If deletion also fails, the response/log report both failures and the surviving batch remains in its initial non-processable state.
- In-request hash grouping now reports deferred copies as duplicates only when the primary source write succeeds; if it fails, all grouped copies report the same visible source-write error.
Exact fix-round 3 verification:
npx vitest run src/app/api/delivery-notes/upload/route.test.ts — passed, 1
file, 15 tests.
npm run typecheck — passed (tsc --noEmit).
git diff --check — passed.
Fix round 2 evidence
- Oversized single-file validation now returns the exact legacy payload with
error,filename,max_bytes, andgot. - Equal hashes within one request are deduplicated in memory; only one source is written and later duplicate outcomes point at the new batch.
- A
dn_batches.source_countupdate failure deletes the newly-created batch and returns HTTP 500 with a visible error. If deletion also fails, the response and log include both the update and cleanup failures.
Exact fix-round 2 verification:
npx vitest run src/app/api/delivery-notes/upload/route.test.ts — passed, 1
file, 14 tests.
npm run typecheck — passed (tsc --noEmit).
git diff --check — passed.