Repository navigation
Description
Problem
src/routes/collection.ts owns the collection-link operation: ownership checks, already-linked checks, catalogue lookup, duplicate detection, and the SQL update. These rules are coupled to Express and the read/check/write sequence is not one transaction. Collection and CARES routes also distinguish business refusals by matching error-message text, so changing wording can change HTTP behavior.
Proposed change
- Add a collection operation accepting entry id, acting member id, and target Species id. Inside a queued transaction, read current ownership/link state, check current duplicates, and update the row. Reads participating in that decision must use the transaction connection rather than the global read-only connection.
- Continue using the catalogue's interface to resolve Species; do not copy its table SQL into the route or collection module. Reject stale/missing Species without leaving a partially linked entry.
- Define typed collection refusal codes such as missing, forbidden, already-linked, and duplicate; map them to the existing route response contract. Extend the same approach to the touched CARES operations without forcing both domains into a universal error hierarchy.
- Keep HTTP parsing, status/HTMX headers, and rendering in adapters. Reuse the existing message partial for touched responses rather than constructing repeated HTML strings with interpolated error text.
- Review add/re-add/link writers together for the current-entry duplicate invariant. Queuing only link while another competing writer bypasses the queue does not establish atomicity. If a new unique index is needed, first audit existing duplicates and propose an explicit data-preserving migration; do not silently delete them.
Acceptance criteria and tests
- The linking rules are callable/testable without Express and the route contains no direct link SQL.
- Missing entry/Species, non-owner, already-linked entry, duplicate current entry, and success have explicit tests and stable refusal codes.
- Concurrent attempts cannot create two current entries for the same member/Species through the affected writers.
- Failure leaves names, link, notes, photos, and CARES registration unchanged. Success preserves existing linking semantics.
- Real route tests assert status/HTMX response behavior and escaped error output.
- Existing collection and CARES visibility/registration tests, typecheck, and lint pass.
Related and boundaries
Coordinate with #468, which already owns the collection PATCH regression test and double-read cleanup; this ticket primarily owns linking and shared refusal handling. Preserve the #454/#465 rule: ordinary note edits do not unlink a Species and a CARES registration belongs to the member/Species, not the collection entry. Upload compensation is a separate ticket. No generic repository framework is needed.
Review baseline
Source review at 78e0f1b2ff157e289c237d533f1406302d95118e. Repository typechecking and the focused specialty-award/level-progress tests passed during the review; these are not reproductions of the new failure scenarios above. Full database and E2E suites were not run.
Related proposals from this review
- Share image variant uploads and compensate partial storage/persistence failures #538: Share image variant uploads and compensate partial storage/persistence failures
Activity