Release: shopping lists (spec 001) #30

Merged
araemer merged 23 commits from stage into main 2026-10-03 18:00:46 +00:00
Owner

Merges the current state of stage into main.

Included

  • Shopping lists (spec 001) (#21): tables and entities, repositories, handlers, application service, mappers and REST resources, with tests, Bruno requests, ADRs and the implementation plan.
  • GET /user/list-shareable: the users a list can be shared with.
  • Error envelope: every error is sent as { error, code } from one middleware.
  • npm run migration runs against the compiled data source.
  • CI (#26): builds against the platform commit pinned in contract.ref.
  • Docs (#22 and others): push every commit and use WIP draft PRs; purpose suffixes in class and module names; architecture doc for the shopping list domain.

Not included

  • #23 (race-free optimistic locking, issue #20) is still open against stage.
  • #25 (spec 002, shopping list overview previews) is still a WIP draft against stage.

Deployment

This release contains new migrations (shopping list tables). Merging does not deploy; production deploys are triggered by a v* tag on main.

🤖 Generated with Claude Code

Merges the current state of `stage` into `main`. ## Included - **Shopping lists (spec 001)** (#21): tables and entities, repositories, handlers, application service, mappers and REST resources, with tests, Bruno requests, ADRs and the implementation plan. - `GET /user/list-shareable`: the users a list can be shared with. - **Error envelope**: every error is sent as `{ error, code }` from one middleware. - `npm run migration` runs against the compiled data source. - **CI** (#26): builds against the platform commit pinned in `contract.ref`. - **Docs** (#22 and others): push every commit and use WIP draft PRs; purpose suffixes in class and module names; architecture doc for the shopping list domain. ## Not included - #23 (race-free optimistic locking, issue #20) is still open against `stage`. - #25 (spec 002, shopping list overview previews) is still a WIP draft against `stage`. ## Deployment This release contains new migrations (shopping list tables). Merging does not deploy; production deploys are triggered by a `v*` tag on `main`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
docs(adr) Add shopping list and error serialization ADRs for spec 001
All checks were successful
/ test (pull_request) Successful in 1m2s
f1274a1bb1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(git) Push every commit and use WIP: draft PRs
All checks were successful
/ test (pull_request) Successful in 1m1s
9866c9f0bb
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(adr) Extend the shopping list lock to share writes and concurrent moves (spec 001)
All checks were successful
/ test (pull_request) Successful in 1m2s
15c857a374
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(plan) Add shopping list implementation plan (spec 001)
All checks were successful
/ test (pull_request) Successful in 1m2s
58b761de1b
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HttpError carries a required ErrorCode with a generic default per status;
errorLoggerMiddleware is the only writer of error bodies. Direct writes in
the auth/authorization middleware, AuthRestResource, ImageRestResource and
the unknown-route fallback become thrown/forwarded HttpErrors. Uuid.parse
throws ValidationError; UserHandler uses USER_NOT_FOUND. The unregistered
errorHandler.ts is deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Returns every user except the caller as CompactUserDto (no email, no
role) for share recipient pickers. Registered before GET /user/:userId.
Adds the one-way CompactUserMapper and the shared avatarUrlFor helper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Migrations and entities for shopping_list, shopping_list_share,
shopping_list_item, shopping_list_item_reason and shopping_list_default.
Item rows keep a sort_order and ticked state outside the content
version; reasons and defaults are plain tables without AbstractEntity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
EntityManager-bound repositories (no AbstractRepository) with a
transaction runner for list row locks; item rows are written only via
targeted UPDATEs that pin or conditionally bump version. Adds the German
plural name matcher, ShoppingListAccessPolicy, ShoppingListHandler
(lists, shares, default) and ShoppingListItemHandler (items).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ShoppingListApplicationService validates request shapes (400 before any
handler call) and maps to contract DTOs; one-way share/item/compact
mappers; three routers mounted under /shopping-list, /shopping-list-item
and /shopping-list-share. Bruno files follow in a separate commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewed-on: #22
Three new resource folders plus UserRestResource/listShareable.bru.
Folder seq values are renumbered alphabetically, which also fixes the
duplicate seq 8 on Passkey/Rating.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs(architecture) Document the shopping list domain and error envelope
All checks were successful
/ test (pull_request) Successful in 1m9s
da0778c2e7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
refactor(shoppingList) Share list loading and locking between both handlers
All checks were successful
/ test (pull_request) Successful in 1m17s
a97844241d
loadList, loadListWithPermission and lockListOrNotFound move from private
copies in ShoppingListHandler and ShoppingListItemHandler into one
ShoppingListLoading module, together with the shared 404 message.
ShoppingListAccessPolicy stays pure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
refactor(shoppingList) Rename helpers to purpose-suffixed names
All checks were successful
/ test (pull_request) Successful in 1m8s
0dd5f3d9b7
ShoppingListAccessPolicy -> ShoppingListPermissionHelper,
ShoppingListLoading -> shoppingListHandlerUtils,
ShoppingItemNameMatcher -> shoppingItemNameUtils,
ShoppingListTransactionRunner -> ShoppingListTransactionHelper.
The approved plan keeps its original names and gains a rename note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
refactor(shoppingList) Address review feedback on names, comments and tests
All checks were successful
/ test (pull_request) Successful in 1m8s
7c298c7480
- Repository/transaction names: listRepository, itemRepository,
  transactionHelper; transaction callbacks take one named
  transactionRepositories parameter; em -> entityManager; no 1-2 letter
  lambda parameters (s, r).
- computeReorder: openItems/requestedItemIds/requestedOpenItemIds/
  remainingOpenItemIds, with "open = not ticked" spelled out.
- Renames: trimToNull -> trimOrNull, avatarUrlFor -> avatarUrlByKey,
  CompactUserColumns/fromColumns -> CompactUserFields/fromFields (JSDoc
  explains why it is not a projection).
- Comments: lockLists says locks end with the transaction; getList says
  resolve() answers 403; item mapper explains omitted optional fields;
  W1-W10 plan labels removed from the item repository.
- Tests use HttpStatusCode instead of literal status numbers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ts-node-commonjs runner could not load the ESM sources, and the data
source's migrations glob (<dir>/migrations/*.js) only matches in build/.
The script now builds first and runs typeorm against build/data-source.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
refactor(shoppingList) Address implementation review findings
All checks were successful
/ test (pull_request) Successful in 1m8s
8c8a68ce4e
- JSDoc: @param/@returns on all ShoppingListApplicationService methods;
  createNewEntity and doMergeDtoIntoEntity documented.
- Explicit return types on the sendFile and transaction callbacks and on
  the service-test mocks.
- Overview SQL uses table-name constants and takes the owner permission
  from ShoppingListEffectivePermission.OWNER as a query parameter.
- TARGET_LIST_NOT_FOUND constant replaces a duplicated message.
- Tests: ShoppingListTransactionHelper unit test; leftover `repos`
  renamed; ResponseStub fields documented.
- Plan rename note also lists the field renames from PR review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reviewed-on: #21
chore(ci) Build against the platform commit pinned in contract.ref
All checks were successful
/ test (pull_request) Successful in 1m13s
9dcc5d1e34
CI cloned recipe-platform at the head of main. Platform main already carries
the contract for spec 002, which this repo does not implement yet, so builds
no longer compiled. All three workflows now check out the commit named in
contract.ref before installing the contract, and fail if the file is missing
or empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge pull request 'chore(ci) Build against the platform commit pinned in contract.ref' (#26) from contract-pin into stage
All checks were successful
/ build (push) Successful in 1m52s
/ test (pull_request) Successful in 1m15s
8b2ddc950a
Reviewed-on: #26
araemer changed title from stage to Release: shopping lists (spec 001) 2026-10-03 17:40:39 +00:00
chore(ci) Check the contract pin in the PR pipeline
All checks were successful
/ test (pull_request) Successful in 1m18s
/ contract_pin (pull_request) Successful in 11s
506ed14d4e
Adds a separate job contract_pin to pr_check.yaml. It passes only when the
commit in contract.ref is on recipe-platform main and is not older than the
pin on the PR's base branch. Build and tests keep their own job and status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merge pull request 'chore(ci) Check the contract pin in the PR pipeline' (#29) from contract-pin-check into stage
All checks were successful
/ build (push) Successful in 1m48s
/ test (pull_request) Successful in 1m17s
/ contract_pin (pull_request) Successful in 4s
2f69ac10d8
Reviewed-on: #29
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
araemer/recipe-backend!30
No description provided.