Commit graph

2 commits

Author SHA1 Message Date
d6404edefc
feat(contracts+web): thread concurrency tokens and 409 conflict handling through the domain layer
Phase 6b of the SHOC-alignment plan — client side of the optimistic-concurrency
wire contract shipped in 6a.

shared/api-contracts (additive):
- rowVersion: string on ProposalListItem, ProposalDetail, and LineItem
- proposalVersion?: string on UpdateProposalRequest and
  BulkUpdateLineItemsRequest; new ProposalVersionRequest
- ConcurrencyConflict<T> { message, currentState } — the SHOC ADR 0004
  409 envelope (guarded path; the unguarded fallback carries no state)
- matching zod schemas, all kept under the satisfies z.ZodType<T> coupling

web:
- lib/api/errors.ts: ConflictError carrying the server's reloaded
  currentState; client.ts interceptor throws it on 409 (WEB-M2 401
  handling untouched)
- guarded mutations read the token from the cached proposal detail at
  mutate time; the save flow chains rotated tokens (PUT response token
  into the bulk replace) and ends with a detail refetch so
  approve-after-save never sends a stale version
- 409 recovery in the admin use-cases: write currentState into the
  detail cache, invalidateProposalViews() (stale-queue invariant holds
  on the failure path too), and toast the conflict instead of the
  generic failure message
- e2e smoke mock payloads carry rowVersion; vitest coverage for the
  interceptor ConflictError paths, token threading/rotation, and 409
  cache recovery

Verified: shared typecheck, web tsc/vitest (69)/build/prettier/Playwright
smoke, mobile tsc (create-only, no changes needed).
2026-07-13 21:01:46 -04:00
191f710752
ci(web): Phase 5 — prettier check + Playwright smoke via org frontend workflow
Converts the web CI job from ci-typescript-cdk.yaml (typecheck only) to
ci-typescript-frontend.yaml: format:check, build (tsc -b included),
vitest, and a Playwright chromium smoke. Folds the standalone Web Tests
job into it (aggregator needs updated). Pure CI — no AWS secrets.

The smoke (e2e/smoke.spec.ts) drives dev-login → dashboard shell →
proposal list, plus the unauthenticated bounce, against a fully mocked
API (pathname-anchored route interception — a '**/api/**' glob would
swallow vite's /src/lib/api/* module URLs). Config mirrors SHOC's
playwright.config.ts (port 4173, chromium, dev-server webServer).

Prettier: singleQuote + printWidth 100 to match the existing codebase
style; lint intentionally not added (no ESLint config yet — run-lint
false, out of Phase 5 scope). rollback = revert this workflow file.
2026-07-13 20:14:41 -04:00