Context
Deck CRUD is implemented but PATCH /decks/{id} is missing. Currently the
only ways to mutate a deck are: hit POST /decks to create a new one (no
in-place edits) or DELETE /decks/{id} (soft delete). Real users will need
to edit deck names, swap cards in/out of the pool, and add/remove loadouts
without recreating the entire deck.
Why deferred
Partial updates need a thoughtful field-level merge protocol — a "PUT with
all fields" replaces too much (you lose any client/server fields the client
did not know about), while a naive "merge whatever you sent" creates
ambiguity around how to clear optional fields, replace lists, etc.
RFC 7396 (JSON Merge Patch) and RFC 6902 (JSON Patch) are both options;
neither is one-line wiring.
Decisions to make
- Patch format: JSON Merge Patch (simpler, less expressive) vs JSON
Patch (full granularity, more verbose) vs a custom shape per resource.
- List-shaped fields: how do clients add/remove individual pool entries
vs replace the whole pool? The natural merge of a list is full
replacement, but for big pools that becomes expensive.
- Loadouts as nested resources: do we treat each loadout as
individually addressable (e.g. PATCH /decks/{id}/loadouts/{loadoutId})
or merge them as a list under the deck?
- Concurrent updates: do we need optimistic concurrency (e.g.
If-Match with an etag/version) before two clients can race?
Scope
- Pick a patch format
- Add
PATCH /decks/{id} handler
- DB layer:
update_deck plus child-table reconciliation, in a transaction
- Update
updated_at on every successful patch
- Auth: owner-only (consistent with DELETE)
- Add integration tests in
tests/api_decks.rs
- Regenerate
openapi.json
Pointers
- Existing handlers:
src/api/decks.rs::create_deck and delete_deck
- DB layer:
src/db/deck.rs (no UPDATE queries today)
- Schema:
migrations/20260502120000_decks.sql
Context
Deck CRUD is implemented but
PATCH /decks/{id}is missing. Currently theonly ways to mutate a deck are: hit
POST /decksto create a new one (noin-place edits) or
DELETE /decks/{id}(soft delete). Real users will needto edit deck names, swap cards in/out of the pool, and add/remove loadouts
without recreating the entire deck.
Why deferred
Partial updates need a thoughtful field-level merge protocol — a "PUT with
all fields" replaces too much (you lose any client/server fields the client
did not know about), while a naive "merge whatever you sent" creates
ambiguity around how to clear optional fields, replace lists, etc.
RFC 7396 (JSON Merge Patch) and RFC 6902 (JSON Patch) are both options;
neither is one-line wiring.
Decisions to make
Patch (full granularity, more verbose) vs a custom shape per resource.
vs replace the whole pool? The natural merge of a list is full
replacement, but for big pools that becomes expensive.
individually addressable (e.g.
PATCH /decks/{id}/loadouts/{loadoutId})or merge them as a list under the deck?
If-Matchwith an etag/version) before two clients can race?Scope
PATCH /decks/{id}handlerupdate_deckplus child-table reconciliation, in a transactionupdated_aton every successful patchtests/api_decks.rsopenapi.jsonPointers
src/api/decks.rs::create_deckanddelete_decksrc/db/deck.rs(no UPDATE queries today)migrations/20260502120000_decks.sql