Repository navigation
docs: add TRD for order handler boundary enforcement - #659
Merged
Merged
Conversation
Audits libs/ui/src/app/order and presentation/handlers/order for repositories and raw params leaking into handler props, and lays out a 4-phase plan to move that logic into the owning usecases. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARwg5gU5WfUmWAPx8xq8XY
|
The latest updates on your projects. Learn more about Vercel for GitHub. 3 Skipped Deployments
|
D4 previously always seeded PaymentCancelUsecase with a placeholder reference/method and relied on SYNC_PARAMS to correct it. OrderStatus's loader already knows the payment on the common path, so seed from it there; MenuList/Cart still need the placeholder since the cart is deliberately never SSR-seeded (D5 of the composition/SSR TRD). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARwg5gU5WfUmWAPx8xq8XY
mnindrazaka
added a commit
that referenced
this pull request
Sep 30, 2026
* docs: add TRD for order handler boundary enforcement (#659) * docs: add TRD for order handler/usecase boundary Audits libs/ui/src/app/order and presentation/handlers/order for repositories and raw params leaking into handler props, and lays out a 4-phase plan to move that logic into the owning usecases. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARwg5gU5WfUmWAPx8xq8XY * docs: seed paymentCancelUsecase from known payment where available D4 previously always seeded PaymentCancelUsecase with a placeholder reference/method and relied on SYNC_PARAMS to correct it. OrderStatus's loader already knows the payment on the common path, so seed from it there; MenuList/Cart still need the placeholder since the cart is deliberately never SSR-seeded (D5 of the composition/SSR TRD). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARwg5gU5WfUmWAPx8xq8XY --------- Co-authored-by: Claude <noreply@anthropic.com> * refactor(order): move table-binding side effects into TableResolveUsecase (#660) Phase 1 of docs/trd-order-handler-usecase-boundary.md (D1, D3). MenuListHandler and CartHandler no longer receive cartRepository/sessionRepository/tableCode props: TableResolveUsecase now takes optional sessionRepository/cartRepository dependencies and owns setTableCode/updateTable as part of its own onStateChange, with the cart-bind de-dupe moved from a handler useRef to an instance field. Handlers read tableResolveUsecase.params.code instead of a duplicated tableCode prop. Claude-Session: https://claude.ai/code/session_01YWhceHti3NXs7xRt5uw5o3 Co-authored-by: Claude <noreply@anthropic.com> * refactor(order): move tableCode/cashierLocation into order status/history usecases (#661) Implements P2 of docs/trd-order-handler-usecase-boundary.md. OrderHistoryUsecase and OrderStatusUsecase now take an optional SessionRepository dependency and read tableCode once in getInitialState(), the same idiom CartUsecase already uses for cartQueryRepository. OrderStatusUsecase also takes cashierLocation as a Params field carried through Context, the same shape CheckoutUsecase already uses for customerName. OrderHistoryHandler and OrderStatusHandler no longer receive sessionRepository/cashierLocation as props; both are read off the usecase's own state instead. Claude-Session: https://claude.ai/code/session_01Gj1cLXBEeLrUTrhhJ1QeJB Co-authored-by: Claude <noreply@anthropic.com> * refactor(order): move checkout feature flags into CheckoutUsecase params (#662) Per docs/trd-order-handler-usecase-boundary.md phase 3 (D5): enabled, enabledMethods, and cashierLocation are checkout-flow config values that belong on CheckoutUsecase.params, the same way customerName already does, instead of being threaded past CartHandler as bare props read from process.env in the composition root. CartHandler now reads these off checkout.state instead of receiving them as separate props. Claude-Session: https://claude.ai/code/session_01Ete6mVquK6t44UQsxf8xjG Co-authored-by: Claude <noreply@anthropic.com> * refactor(order): construct paymentCancelUsecase in composition roots, not handlers (#663) Removes the last repository (paymentRepository) from every order handler's prop list. MenuListHandler, CartHandler, and OrderStatusHandler each reconstructed a PaymentCancelUsecase inline via useState + a conditional setState whenever their own pendingPayment/payment changed; that ~20-line block is now a single new usePaymentCancelSyncedTo hook that re-syncs a usecase built once by the composition root via a dispatched SYNC_PARAMS action, matching how PaymentCancelUsecase already supported this. Also documents the rule in docs/handlers.md so this doesn't regress the next time an order screen is touched. Implements Phase 4 of docs/trd-order-handler-usecase-boundary.md. Claude-Session: https://claude.ai/code/session_01RFonbEaS6P4NfMBuhJWK2p Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add a technical requirements document establishing that order app handlers accept only usecases and documented exceptions, never repositories or duplicated usecase state.
Summary
This TRD (
docs/trd-order-handler-usecase-boundary.md) audits the current state oflibs/ui/src/presentation/handlers/order/andlibs/ui/src/app/order/composition roots, identifies 16 non-usecase props across 4 handlers (8 of which are repositories), and proposes a phased 4-PR refactor to enforce the boundary already established indocs/trd-order-app-composition-and-ssr.md§3.1 and exemplified by POS handlers.Key findings
cartRepository,paymentRepository,sessionRepository,tableCode,preparingCountpaymentRepository,sessionRepository,enabled,enabledMethods,cashierLocation,tableCode,preparingCountpaymentRepository,sessionRepository,cashierLocationsessionRepositoryRoot causes: side effects that belong in usecases are written inline in handlers (
useEffectcalling repositories), usecases are reconstructed reactively in handlers instead of once in composition roots, and config/feature-flag values are passed as bare props instead of through usecaseParams.Proposed solution
Four phased PRs, each independently revertable:
TableResolveUsecaseabsorbs session/cart table-binding side effects; handlers readtableResolveUsecase.params.codeinstead of a duplicatetableCodepropOrderHistoryUsecase/OrderStatusUsecaseabsorbsessionRepositoryfor synchronoustableCoderead ingetInitialState()(matchingCartUsecase's existing pattern);OrderStatusUsecaseabsorbscashierLocationCheckoutUsecaseabsorbsenabled,enabledMethods,cashierLocationasParams(matching howcustomerName/customerWhatsappNumberalready work)usePaymentCancelSyncedTohook re-syncsPaymentCancelUsecasevia dispatchedSYNC_PARAMSaction; composition roots construct it once; handlers never seepaymentRepositoryEnd state: zero repositories in any handler's prop list;
preparingCountis the one documented exception (D6) — a read-only SSR-seeded integer with no state machine.Design decisions
TableResolveUsecasetakes optional{ sessionRepository?, cartRepository? }dependencies and owns both side effects, with de-dupe logic moving fromboundTableCodeRefto an instance fieldOrderHistoryUsecase/OrderStatusUsecasereadtableCodesynchronously ingetInitialState()via optionalsessionRepositorydependency — same patternCartUsecasealready uses forcartQueryRepository.getSelectedItemId()tableCodestops being a handler prop; handlers readtableResolveUsecase.params.codeinsteadpaymentCancelUsecaseonce; new hook re-syncs it viaSYNC_PARAMSaction, replacing three duplicated ~20-lineuseState/conditional-setStateblocksCheckoutUsecase.ParamsandOrderStatusUsecase.Paramsgain feature-flag/config fields;CheckoutState.Contextcarries them through unchangedpreparingCountremains a plain prop — it is SSR-seeded, read-only, has no state machine, and wrapping it in a usecase would add abstraction beyond what the task requiresRollback
Every phase is
https://claude.ai/code/session_01ARwg5gU5WfUmWAPx8xq8XY