proposal-system/web/src/domain
Adam Moussa e6e2c60c2f
feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites)
Additive-only: pages still use lib/api/* and constants/queryKeys.ts until
the page-migration agents run. Each domain ships api.ts (HTTP moved from
lib/api), types.ts (contract re-exports + view types), schemas.ts (contract
schema re-exports + form schemas with toRequest mappers), and use-cases.ts
(TanStack Query v5 hooks + hierarchical query keys, mirroring current page
invalidations and toast-on-error behavior).

Adds an explicit vite/vitest alias for the
@proposal-system/api-contracts/schemas subpath (package has no exports map)
plus a schema/mapper smoke test suite.
2026-07-13 17:58:19 -04:00
..
__tests__ feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites) 2026-07-13 17:58:19 -04:00
admin feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites) 2026-07-13 17:58:19 -04:00
customers feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites) 2026-07-13 17:58:19 -04:00
lineItems feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites) 2026-07-13 17:58:19 -04:00
pricingLibrary feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites) 2026-07-13 17:58:19 -04:00
proposals feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites) 2026-07-13 17:58:19 -04:00
sites feat(web): scaffold domain module layer (proposals, lineItems, customers, pricingLibrary, admin, sites) 2026-07-13 17:58:19 -04:00
README.md feat(web): domain-layer conventions doc + react-hook-form deps (Phase 4 prep) 2026-07-13 17:47:05 -04:00

Frontend domain layer — conventions

SHOC-alignment Phase 4 (mirrors shoc-frontend-new dev's src/domain/<entity>/ layering). Every agent/contributor working in this tree builds to THIS spec.

Structure

src/domain/<entity>/
├── api.ts        # HTTP calls only: axios via lib/api/client, path constants, no hooks
├── types.ts      # re-exports from @proposal-system/api-contracts + view-only types
├── schemas.ts    # re-exports from @proposal-system/api-contracts/schemas + form schemas
└── use-cases.ts  # TanStack Query hooks + this domain's query keys (the ONLY public surface)

Domains: proposals, lineItems, customers, pricingLibrary, admin, sites. (auth arrives with the separate auth-storage PR — do NOT create it here.)

Rules

  1. Pages import ONLY from domain/<x>/use-cases (and types) — never from lib/api/*, never apiClient directly, never useQuery/useMutation inline in a page. Pages are thin callers.
  2. Query keys live in the domain: each use-cases.ts exports export const <entity>Keys = { all: ['<entity>'] as const, detail: (id: string) => ['<entity>', id] as const, ... } (TanStack hierarchical-key convention). src/constants/queryKeys.ts is deleted at integration — do not add imports of it.
  3. Invalidation uses the domain key objects across domains where needed (e.g. approving a proposal invalidates proposalsKeys.all).
  4. Forms: react-hook-form + zodResolver (from @hookform/resolvers/zod). Form schemas live in the domain's schemas.ts, derived from the shared contract schemas (@proposal-system/api-contracts/schemas) via .pick/.extend/.omit — never hand-written duplicates. Form field state maps to the request type at submit (a toCreateRequest(formValues) mapper in schemas.ts when non-trivial).
  5. lib/api/client.ts stays — the single axios instance (interceptors, 401 handling). Domain api.ts files import it. The old lib/api/<domain>.ts modules are deleted once no page imports them (integration step) — lib/api/auth.ts stays until the auth PR.
  6. Mutations: toast on error stays in the hook (matching current UX), success invalidation in the hook; page-specific side effects (navigate, dialog close) via the mutation's callbacks at the call site.
  7. No new state managers, no context — server state = TanStack Query, existing Redux auth/ui slices untouched (auth refactor is a separate PR).
  8. Styling: tokens only (var(--...), theme) — no hardcoded hexes.
  9. Verify before returning/committing: npx tsc --noEmit, npm test -- --run, npm run build — all green, no skipped tests, no @ts-ignore.