feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
// @proposal-system/api-contracts — single source of truth for API wire types.
|
|
|
|
|
// Fix: WEB-M5 — web and mobile both import these; shapes mirror the .NET DTOs
|
|
|
|
|
// in api/src/ProposalSystem.Application/DTOs/ (JsonStringEnumConverter → string
|
|
|
|
|
// enums, Guid → string, DateTime → ISO string, decimal → number).
|
|
|
|
|
// Runtime validation schemas live in ./schemas (separate entrypoint so
|
|
|
|
|
// consumers that only need types never pull zod).
|
|
|
|
|
|
|
|
|
|
// ── Enums (string over the wire) ──────────────────────────────────────────
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
export type ProposalStatus = 'Draft' | 'InReview' | 'Approved' | 'Sent' | 'Revised';
|
2026-05-27 18:04:47 -04:00
|
|
|
export type ServiceCategory = 'HVAC' | 'Plumbing' | 'Electrical' | 'General' | 'Renovation' | 'Other';
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
export type Priority = 'Standard' | 'Urgent' | 'Emergency';
|
|
|
|
|
export type LineItemSource = 'AI' | 'Vendor' | 'Manual' | 'Historical';
|
|
|
|
|
export type PricingMode = 'UnitPrice' | 'TotalPrice' | 'Both';
|
|
|
|
|
export type UserRole = 'Dispatcher' | 'Admin' | 'SysAdmin';
|
|
|
|
|
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
// ── Shared envelopes ──────────────────────────────────────────────────────
|
|
|
|
|
export interface PagedResponse<T> {
|
|
|
|
|
items: T[];
|
|
|
|
|
totalCount: number;
|
|
|
|
|
page: number;
|
|
|
|
|
pageSize: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Proposals (ProposalDtos.cs) ───────────────────────────────────────────
|
|
|
|
|
export interface ProposalListItem {
|
|
|
|
|
id: string;
|
|
|
|
|
proposalNumber: string;
|
|
|
|
|
customerName: string;
|
|
|
|
|
workOrderNumber: string;
|
|
|
|
|
serviceCategory: ServiceCategory;
|
|
|
|
|
priority: Priority;
|
|
|
|
|
status: ProposalStatus;
|
|
|
|
|
totalBidAmount: number;
|
|
|
|
|
submittedAt: string;
|
|
|
|
|
submittedByName: string | null;
|
|
|
|
|
assignedAdminName: string | null;
|
2026-07-14 01:18:30 -04:00
|
|
|
/** Opaque optimistic-concurrency token (base64); echo back untouched. */
|
|
|
|
|
rowVersion: string;
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProposalDetail {
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
id: string;
|
|
|
|
|
proposalNumber: string;
|
|
|
|
|
workOrderNumber: string;
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
poNumber: string | null;
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
customerName: string;
|
|
|
|
|
customerAddress: string;
|
|
|
|
|
scopeOfWork: string;
|
|
|
|
|
refinedScope: string | null;
|
|
|
|
|
serviceCategory: ServiceCategory;
|
|
|
|
|
priority: Priority;
|
|
|
|
|
status: ProposalStatus;
|
|
|
|
|
totalBidAmount: number;
|
|
|
|
|
vendorTotalCost: number | null;
|
|
|
|
|
notes: string;
|
|
|
|
|
submittedById: string;
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
submittedByName: string | null;
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
submittedAt: string;
|
|
|
|
|
assignedAdminId: string | null;
|
|
|
|
|
approvedById: string | null;
|
|
|
|
|
approvedAt: string | null;
|
|
|
|
|
sentAt: string | null;
|
|
|
|
|
currentRevision: number;
|
|
|
|
|
parentProposalId: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
2026-07-14 01:18:30 -04:00
|
|
|
/** Opaque optimistic-concurrency token (base64); echo back untouched. */
|
|
|
|
|
rowVersion: string;
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
}
|
|
|
|
|
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
export interface CreateProposalRequest {
|
|
|
|
|
workOrderNumber: string;
|
|
|
|
|
poNumber?: string;
|
|
|
|
|
customerName: string;
|
|
|
|
|
customerAddress: string;
|
|
|
|
|
scopeOfWork: string;
|
|
|
|
|
serviceCategory: ServiceCategory;
|
|
|
|
|
priority: Priority;
|
|
|
|
|
notes?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateProposalRequest {
|
|
|
|
|
refinedScope?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
poNumber?: string;
|
|
|
|
|
workOrderNumber?: string;
|
|
|
|
|
assignedAdminId?: string;
|
2026-07-14 01:18:30 -04:00
|
|
|
/** Expected proposal rowVersion — REQUIRED by the server (422 ProposalVersionRequired when missing). */
|
|
|
|
|
proposalVersion?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Body for the state-transition endpoints (approve, return-to-review, send,
|
|
|
|
|
* revise): the expected proposal rowVersion. The server rejects a missing
|
|
|
|
|
* token with 422 {code:"ProposalVersionRequired"} and a malformed one with
|
|
|
|
|
* 422 {code:"InvalidRowVersion"}. */
|
|
|
|
|
export interface ProposalVersionRequest {
|
|
|
|
|
proposalVersion?: string;
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProposalFilters {
|
|
|
|
|
search?: string;
|
|
|
|
|
page?: number;
|
|
|
|
|
pageSize?: number;
|
|
|
|
|
status?: string;
|
|
|
|
|
serviceCategory?: string;
|
|
|
|
|
priority?: string;
|
|
|
|
|
fromDate?: string;
|
|
|
|
|
toDate?: string;
|
|
|
|
|
mine?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProposalStats {
|
|
|
|
|
totalCount: number;
|
|
|
|
|
inReviewCount: number;
|
|
|
|
|
approvedCount: number;
|
|
|
|
|
sentCount: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Line items (LineItemDtos.cs) ──────────────────────────────────────────
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
export interface LineItem {
|
|
|
|
|
id: string;
|
|
|
|
|
proposalId: string;
|
|
|
|
|
description: string;
|
|
|
|
|
quantity: number;
|
|
|
|
|
unit: string;
|
|
|
|
|
unitPrice: number | null;
|
|
|
|
|
totalPrice: number;
|
|
|
|
|
pricingMode: PricingMode;
|
|
|
|
|
sortOrder: number;
|
|
|
|
|
source: LineItemSource;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
2026-07-14 01:18:30 -04:00
|
|
|
/** Opaque optimistic-concurrency token (base64); echo back untouched. */
|
|
|
|
|
rowVersion: string;
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
}
|
|
|
|
|
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
export interface CreateLineItemRequest {
|
|
|
|
|
description: string;
|
|
|
|
|
quantity: number;
|
|
|
|
|
unit: string;
|
|
|
|
|
unitPrice: number | null;
|
|
|
|
|
totalPrice: number;
|
|
|
|
|
pricingMode: PricingMode;
|
|
|
|
|
sortOrder: number;
|
|
|
|
|
source: LineItemSource;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateLineItemEntry {
|
|
|
|
|
id: string | null;
|
|
|
|
|
description: string;
|
|
|
|
|
quantity: number;
|
|
|
|
|
unit: string;
|
|
|
|
|
unitPrice: number | null;
|
|
|
|
|
totalPrice: number;
|
|
|
|
|
pricingMode: PricingMode;
|
|
|
|
|
sortOrder: number;
|
|
|
|
|
source: LineItemSource;
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
}
|
|
|
|
|
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
export interface BulkUpdateLineItemsRequest {
|
|
|
|
|
lineItems: UpdateLineItemEntry[];
|
2026-07-14 01:18:30 -04:00
|
|
|
/** Expected proposal rowVersion — the bulk replace is guarded by the PROPOSAL token. */
|
|
|
|
|
proposalVersion?: string;
|
Initial scaffold: monorepo structure, CDK stacks, CI/CD, domain model
Phase 0 of proposal-system: complete project setup including:
- CDK infrastructure (3 stacks: foundation, compute, frontend)
- .NET 8 solution with Clean Architecture (Domain, Application, Infrastructure, Api)
- EF Core data model (PostgreSQL) with all entities
- Python Lambda placeholders (pdf-extract, pdf-generate, library-ingest)
- React 19 web frontend scaffold (Vite + MUI)
- React Native mobile placeholder
- Shared TypeScript API contracts
- GitHub Actions CI/CD (ci.yaml + deploy.yaml)
- OIDC deploy role (githubdeploy-proposal-system)
- Dependabot configuration
- Cognito User Pool with Google OAuth, PKCE clients, groups
2026-05-16 18:40:46 -04:00
|
|
|
}
|
2026-06-18 12:40:55 -04:00
|
|
|
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
// ── Customers (CustomerDtos.cs) ───────────────────────────────────────────
|
2026-06-18 12:40:55 -04:00
|
|
|
export interface Customer {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
addresses: string[];
|
|
|
|
|
contactEmail: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
export interface CustomerListParams {
|
|
|
|
|
page?: number;
|
|
|
|
|
pageSize?: number;
|
|
|
|
|
search?: string;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-18 12:40:55 -04:00
|
|
|
export interface CreateCustomerRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
addresses?: string[];
|
|
|
|
|
contactEmail?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateCustomerRequest {
|
|
|
|
|
name?: string;
|
|
|
|
|
addresses?: string[];
|
|
|
|
|
contactEmail?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
// ── Pricing library (PricingLibraryDtos.cs) ───────────────────────────────
|
2026-06-18 12:49:47 -04:00
|
|
|
export interface PricingLibraryItem {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
description: string | null;
|
|
|
|
|
serviceCategory: ServiceCategory;
|
|
|
|
|
unit: string | null;
|
|
|
|
|
unitPrice: number | null;
|
|
|
|
|
keywords: string | null;
|
|
|
|
|
source: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
export interface PricingLibraryListParams {
|
|
|
|
|
page?: number;
|
|
|
|
|
pageSize?: number;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-18 12:49:47 -04:00
|
|
|
export interface CreatePricingLibraryItemRequest {
|
|
|
|
|
title: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
serviceCategory: ServiceCategory;
|
|
|
|
|
unit?: string;
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
unitPrice?: number | null;
|
2026-06-18 12:49:47 -04:00
|
|
|
keywords?: string;
|
|
|
|
|
source?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdatePricingLibraryItemRequest {
|
|
|
|
|
title?: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
serviceCategory?: ServiceCategory;
|
|
|
|
|
unit?: string;
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
unitPrice?: number | null;
|
2026-06-18 12:49:47 -04:00
|
|
|
keywords?: string;
|
|
|
|
|
}
|
feat(contracts): shared api-contracts adoption, zod schemas, ProblemDetails codes (#222)
* feat(web): adopt SHOC design system and shell layout (ADR 0003)
Port shoc-frontend-new dev's design system with its CSS-variable
single-token-source mechanism:
- src/styles/theme.css: SHOC token file ported verbatim (Montserrat/
DM Sans/JetBrains Mono, primary #1c75bc, navy #262262, full radius/
shadow/sidebar/header token layers); fonts self-hosted via @fontsource
- src/lib/theme/{css-vars,mui-theme}.ts: getCssVar -> createTheme
adapter mirroring SHOC's mui-theme.ts (palette, typography, shadows
tuple, component overrides; MUI v9 slot renames expressed as class
selectors); theme.ts is now a re-export
- Shell: SHOC composition (sidebar column + sticky gradient topbar +
scrolling main); sidebar 244px/76px collapse with brand header row,
grouped nav, SHOC active treatment (white card + 3px accent bar);
topbar 100-degree gradient, surface hamburger, gradient avatar pill
- Brand: SeahavenMark + BrandLockup ported (Tailwind re-expressed as
sx; wordmark subtitle localized to PROPOSAL SYSTEM)
- Login: SHOC auth-card treatment (centered 384px card on #f9fafb)
- Old "Sea Haven Ops" Inter/#2563EB theme and Nunito remnants removed;
remaining hardcoded hexes replaced with tokens; lucide-react for
shell/nav icons per SHOC convention
Verify: tsc clean, 26/26 vitest, vite build OK; Playwright screenshots
pixel-sampled against the extracted SHOC spec (all hard values exact,
no blocking deviations).
* feat(contracts): adopt shared api-contracts in web, add zod schemas and ProblemDetails codes
Closes WEB-M5 (web hand-duplicated wire types, standing drift risk):
- shared/api-contracts: rewritten as the authoritative superset of the
.NET DTOs (ProposalListItem/ProposalDetail with poNumber and
submittedByName, line item requests, customers, pricing library,
dashboard, audit, sites, auth, presigned upload, ApiProblem); stale
Proposal/UpdateLineItemsRequest shapes removed
- shared/api-contracts/src/schemas.ts: zod runtime schemas coupled to
every wire type via `satisfies z.ZodType<T>` (schema/type drift is now
a compile error); separate entrypoint so type-only consumers (mobile)
never pull zod
- web: imports @proposal-system/api-contracts (file: dep + tsconfig
paths + vite preserveSymlinks); all 7 lib/api modules re-export shared
types so page imports stay stable; enum unions tightened
(PricingLibraryPage form state now ServiceCategory-typed)
- fix(web): customer create/update sent a singular `address` field the
API silently dropped (contract is addresses: string[], CustomerDtos.cs)
- addresses now round-trip, extra addresses preserved on edit
- api: ProblemDetails responses carry a machine-readable top-level
`code` (SHOC error-code vocabulary): ValidationFailed,
InvalidStateTransition, NotFound, Unauthorized, InternalError; new
BusinessRuleException(code, message) maps to 422 with its code;
GlobalExceptionHandlerTests cover the full mapping (wire contract)
Cross-checked .NET DTOs vs TS types vs zod schemas with the
orchestrator scanner (Gemini): core domains consistent; internal-only
DTOs (FileDtos vendor/lambda surface, SimilarProposalDtos, UserDtos
admin surface) intentionally uncovered.
Verify: dotnet 166/166, web tsc + vitest 26/26 + build, mobile tsc,
shared tsc all green.
* fix(web): install shared api-contracts deps via postinstall
Web Frontend Check failed on PR #222: tsc compiles
shared/api-contracts/src/schemas.ts through the tsconfig path alias,
and module resolution for its zod import walks up from shared/, never
reaching web/node_modules. CI only ran npm ci in web/, so the shared
package's deps were absent. A postinstall hook installs them wherever
web's deps are installed (CI typecheck, web-test, deploy bundling).
Passed locally only because a stray repo-root node_modules/zod
satisfied the lookup.
2026-07-13 19:28:33 -04:00
|
|
|
|
|
|
|
|
// ── Admin (DashboardDtos.cs, AuditDtos.cs) ────────────────────────────────
|
|
|
|
|
export interface DashboardStats {
|
|
|
|
|
pendingCount: number;
|
|
|
|
|
approvedThisWeek: number;
|
|
|
|
|
avgTurnaroundHours: number;
|
|
|
|
|
totalProposals: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AuditEntry {
|
|
|
|
|
id: string;
|
|
|
|
|
proposalId: string | null;
|
|
|
|
|
userId: string;
|
|
|
|
|
userName: string | null;
|
|
|
|
|
action: string;
|
|
|
|
|
details: string | null;
|
|
|
|
|
timestamp: string;
|
|
|
|
|
ipAddress: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Sites (SiteDtos.cs) ───────────────────────────────────────────────────
|
|
|
|
|
export interface Site {
|
|
|
|
|
siteCode: string;
|
|
|
|
|
fullAddress: string | null;
|
|
|
|
|
address: string | null;
|
|
|
|
|
city: string | null;
|
|
|
|
|
state: string | null;
|
|
|
|
|
zip: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Auth / users (UserDtos.cs, AuthController) ────────────────────────────
|
|
|
|
|
export interface AuthUser {
|
|
|
|
|
id: string;
|
|
|
|
|
email: string;
|
|
|
|
|
displayName: string;
|
|
|
|
|
role: UserRole;
|
|
|
|
|
token: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UserProfile {
|
|
|
|
|
id: string;
|
|
|
|
|
email: string;
|
|
|
|
|
displayName: string;
|
|
|
|
|
role: UserRole;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Files / PDFs (FileDtos.cs) ────────────────────────────────────────────
|
|
|
|
|
export interface PdfVersion {
|
|
|
|
|
revision: number;
|
|
|
|
|
generatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PresignedUpload {
|
|
|
|
|
uploadUrl: string;
|
|
|
|
|
s3Key: string;
|
|
|
|
|
expiresAt: string;
|
|
|
|
|
vendorProposalId: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Errors (GlobalExceptionHandler.cs) ────────────────────────────────────
|
|
|
|
|
// RFC 7807 ProblemDetails + machine-readable business code (SHOC error-code
|
|
|
|
|
// vocabulary convention). Branch on `code`, never on title/detail text.
|
|
|
|
|
export type ApiProblemCode =
|
|
|
|
|
| 'ValidationFailed'
|
|
|
|
|
| 'InvalidStateTransition'
|
|
|
|
|
| 'NotFound'
|
|
|
|
|
| 'Unauthorized'
|
|
|
|
|
| 'InternalError'
|
|
|
|
|
| (string & {}); // business codes are open-ended (e.g. future CancelNotAllowed)
|
|
|
|
|
|
|
|
|
|
export interface ApiProblem {
|
|
|
|
|
status: number;
|
|
|
|
|
title: string;
|
|
|
|
|
detail: string;
|
|
|
|
|
code: ApiProblemCode;
|
|
|
|
|
}
|
2026-07-14 01:18:30 -04:00
|
|
|
|
|
|
|
|
// Optimistic-concurrency conflict envelope (SHOC ADR 0004 — NOT ProblemDetails):
|
|
|
|
|
// guarded writes that lose a race return 409 with the reloaded currentState so
|
|
|
|
|
// clients can refresh immediately. The unguarded-race safety net returns
|
|
|
|
|
// 409 { status: "Conflict", message, code: 409 } instead — same `message`
|
|
|
|
|
// field, no currentState.
|
|
|
|
|
export interface ConcurrencyConflict<T> {
|
|
|
|
|
message: string;
|
|
|
|
|
currentState: T | null;
|
|
|
|
|
}
|