From a4b09eb0ad631bc60c7938416492654faa0b0c57 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Mon, 13 Jul 2026 17:00:45 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20SHOC-alignment=20Phase=201=20=E2=80=94?= =?UTF-8?q?=20ADRs,=20governance=20files,=20doc=20corrections=20(#220)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ADR 0002 (SHOC merge boundary: separate backend services, shared conventions) and ADR 0003 (adopt SHOC design system + UI/UX layout) - Add CODEOWNERS (internal-dev) and PR template (Summary/Test plan/Jira/ docs-current checklist + contract-table convention) - Fix stale facts in README/CLAUDE.md: MUI v7→v9, RN 0.85→0.86, OpenSearch Serverless/oss-index-creator → Aurora pgvector/ aurora-pgvector-init (ADR 0001), test counts 149→186 (123 xUnit / 26 vitest / 37 pytest), deploy triggers are workflow_dispatch-only, reusable workflow refs float on @main, aws-cdk-lib version claim replaced with Dependabot-maintained note --- .github/CODEOWNERS | 2 + .github/pull_request_template.md | 21 +++++++ CLAUDE.md | 18 ++++-- README.md | 44 +++++++------- docs/adr/0002-shoc-merge-boundary.md | 62 ++++++++++++++++++++ docs/adr/0003-shoc-design-system-adoption.md | 49 ++++++++++++++++ 6 files changed, 167 insertions(+), 29 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/pull_request_template.md create mode 100644 docs/adr/0002-shoc-merge-boundary.md create mode 100644 docs/adr/0003-shoc-design-system-adoption.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..db61049 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Default: all changes require internal-dev review +* @Sea-Haven-Industries/internal-dev diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..1072bdc --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +## Summary + + + +## Test plan + + + +## Jira / tracking + + + +## Checklist + +- [ ] Docs current — README / CLAUDE.md / ADRs / Confluence updated if this changes architecture, endpoints, or behavior +- [ ] If an endpoint shape changed: contract table included below and `shared/api-contracts` updated + + diff --git a/CLAUDE.md b/CLAUDE.md index fa96f5a..5d761bd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,10 +6,10 @@ Proposal management platform for Sea Haven Industries. Dispatchers submit servic ## Architecture -- **api/**: .NET 8 API, EF Core, PostgreSQL, Cognito JWT auth -- **web/**: React 19 + MUI v7 SPA, Vite, CloudFront + S3 -- **mobile/**: React Native 0.85 iOS app, offline-capable, Hermes -- **lambdas/**: Python 3.12 Lambdas (ARM64): pdf-extract, pdf-generate, library-ingest, suggestions, oss-index-creator +- **api/**: .NET 8 API, EF Core, PostgreSQL (Aurora Serverless v2), Cognito JWT auth +- **web/**: React 19 + MUI v9 SPA, Vite, CloudFront + S3 +- **mobile/**: React Native 0.86 iOS app, offline-capable, Hermes +- **lambdas/**: Python 3.12 Lambdas (ARM64): pdf-extract, pdf-generate, library-ingest, suggestions, aurora-pgvector-init - **infra/**: CDK TypeScript (foundation-stack, compute-stack, frontend-stack) - **shared/**: Shared TypeScript API contracts - **scripts/**: Local dev helpers @@ -19,6 +19,12 @@ Proposal management platform for Sea Haven Industries. Dispatchers submit servic External: Cognito JWT via API Gateway (web + mobile client IDs, groups: dispatchers/admins/sysadmins) Internal: Lambdas → .NET Function URL with Secrets Manager API key via custom middleware +## Key Decisions (ADRs in docs/adr/) + +- **ADR 0001**: Bedrock KB vector store is Aurora PostgreSQL + pgvector (replaced OpenSearch Serverless; `oss-index-creator` Lambda replaced by `aurora-pgvector-init`) +- **ADR 0002**: SHOC merge boundary — backends stay separate services permanently (PostgreSQL + Cognito here; SQL Server + ASP.NET Identity in SHOC); consolidation converges on conventions/layers/service patterns, never on platform +- **ADR 0003**: SHOC dev's design system + UI/UX layout is canonical (Montserrat/DM Sans, primary #1c75bc, 244px sidebar, CSS-variable single-token-source consumed by MUI via getCssVar); the old Nunito/#0c4f6f canon and the interim "Sea Haven Ops" Inter/#2563EB theme are superseded + ## Request Flow 1. Dispatcher submits proposal (web/mobile) → InReview (no Draft stage) @@ -29,7 +35,7 @@ Internal: Lambdas → .NET Function URL with Secrets Manager API key via custom ## Infrastructure -AWS us-east-1, RDS PostgreSQL 15, S3, SQS+DLQ, Cognito+Google OAuth, OpenSearch Serverless, Bedrock KB, GitHub Actions OIDC, CloudFront+S3 OAC +AWS us-east-1, Aurora PostgreSQL 15 Serverless v2 (RDS Data API + pgvector), S3, SQS+DLQ, Cognito+Google OAuth, Bedrock KB (Aurora pgvector store — ADR 0001), GitHub Actions OIDC, CloudFront+S3 OAC ## Agent Delegation Rules @@ -58,7 +64,7 @@ AWS us-east-1, RDS PostgreSQL 15, S3, SQS+DLQ, Cognito+Google OAuth, OpenSearch ## Audit Status -AUDIT-REPORT.md completed 2026-05-27. 5 Critical, 36 High, 75+ Medium, 60+ Low findings. Phase 1-5 complete: all Critical/High fixed, 17 Medium fixed, CI runs 108 tests. +AUDIT-REPORT.md completed 2026-05-27. 5 Critical, 36 High, 75+ Medium, 60+ Low findings. Phase 1-5 complete: all Critical/High fixed, 17 Medium fixed, CI runs 186 tests (123 xUnit, 26 vitest, 37 pytest). ### Critical Findings (fix first) diff --git a/README.md b/README.md index 879b0cb..2c4dde6 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ Internal proposal management platform for Sea Haven Industries. Dispatchers subm Monorepo with five primary services: - **.NET 8 API** -- Clean Architecture REST API hosted on Lambda behind API Gateway (JWT-authorized) with Function URL (AWS_IAM) for internal access -- **React 19 Web** -- MUI v7 admin/dispatcher workspace served via CloudFront + S3 +- **React 19 Web** -- MUI v9 admin/dispatcher workspace served via CloudFront + S3 - **React Native Mobile** -- iOS-first field app for dispatchers (offline-capable) -- **Python Lambdas** -- PDF extraction, PDF generation, library ingestion, AI suggestions, AOSS index provisioning +- **Python Lambdas** -- PDF extraction, PDF generation, library ingestion, AI suggestions, Aurora pgvector bootstrap - **CDK Infrastructure** -- Three TypeScript stacks managing all AWS resources ## Repository Structure @@ -23,8 +23,8 @@ Monorepo with five primary services: ``` proposal-system/ ├── api/ .NET 8 Web API (Lambda-hosted, EF Core + PostgreSQL) -├── web/ React 19 + MUI v7 + Vite frontend -├── mobile/ React Native 0.85 iOS app +├── web/ React 19 + MUI v9 + Vite frontend +├── mobile/ React Native 0.86 iOS app ├── lambdas/ Python 3.12 processing functions (arm64) ├── infra/ CDK TypeScript (3 stacks) ├── shared/ TypeScript API contracts (shared between web + mobile) @@ -38,11 +38,11 @@ proposal-system/ | Component | Technologies | |---|---| | API | .NET 8, ASP.NET Core, EF Core + Npgsql, FluentValidation, Cognito JWT, Amazon.Lambda.AspNetCoreServer | -| Web | React 19, TypeScript, MUI v7, Vite, Redux Toolkit, TanStack Query, axios | -| Mobile | React Native CLI 0.85, React 19, React Native Paper, React Navigation, react-native-app-auth (PKCE), amazon-cognito-identity-js (SRP), Keychain, offline draft queue | +| Web | React 19, TypeScript, MUI v9, Vite, Redux Toolkit, TanStack Query, axios | +| Mobile | React Native CLI 0.86, React 19, React Native Paper, React Navigation, react-native-app-auth (PKCE), amazon-cognito-identity-js (SRP), Keychain, offline draft queue | | Lambdas | Python 3.12, arm64, pdfplumber, reportlab, httpx, boto3 | -| Infrastructure | CDK TypeScript (aws-cdk-lib 2.253.1) | -| AI/RAG | Bedrock Knowledge Base (Titan Embeddings v2), OpenSearch Serverless (VPC-only), Claude Sonnet via Bedrock cross-region inference | +| Infrastructure | CDK TypeScript (aws-cdk-lib pinned exact, kept current by Dependabot) | +| AI/RAG | Bedrock Knowledge Base (Titan Embeddings v2), Aurora PostgreSQL + pgvector vector store (see ADR 0001), Claude Sonnet via Bedrock cross-region inference | | Auth | Cognito User Pool + Google OAuth IdP (groups: dispatchers, admins, sysadmins) | ## AWS Resources @@ -51,8 +51,8 @@ All resources are in **us-east-1** (account 328440206208). | CDK Stack | Key Resources | |---|---| -| `proposal-system-foundation` | RDS PostgreSQL 15 (t4g.small), S3 buckets, SQS queue + DLQ, Cognito user pool, Secrets Manager | -| `proposal-system-compute` | API Gateway HTTP API (JWT authorizer + access logging), .NET 8 API Lambda + Function URL (AWS_IAM), Python Lambdas (pdf-extract, pdf-generate, library-ingest, suggestions, oss-index-creator), OpenSearch Serverless collection (VPC endpoint), Bedrock KB | +| `proposal-system-foundation` | Aurora PostgreSQL 15 Serverless v2 (RDS Data API, pgvector), S3 buckets, SQS queue + DLQ, Cognito user pool, Secrets Manager | +| `proposal-system-compute` | API Gateway HTTP API (JWT authorizer + access logging), .NET 8 API Lambda + Function URL (AWS_IAM), Python Lambdas (pdf-extract, pdf-generate, library-ingest, suggestions, aurora-pgvector-init bootstrap), Bedrock KB (Aurora pgvector store) | | `proposal-system-frontend` | CloudFront distribution (S3 OAC) | | Resource Type | Names | @@ -118,17 +118,17 @@ Seven parallel jobs calling org reusable workflows: | Job | Workflow | What it checks | |---|---|---| -| .NET Build & Test | `ci-dotnet.yaml` | Restore, build, test the API solution (104 xUnit tests) | +| .NET Build & Test | `ci-dotnet.yaml` | Restore, build, test the API solution (123 xUnit tests) | | Web Frontend Check | `ci-typescript-cdk.yaml` | TypeScript typecheck for web | -| Web Tests | `ci-typescript-cdk.yaml` | vitest suite (26 tests — auth, interceptors, components) | +| Web Tests | inline job | vitest suite (26 tests — auth, interceptors, components) | | Mobile Typecheck | `ci-typescript-cdk.yaml` | TypeScript typecheck for mobile | | Python Lint | `ci-python-sam.yaml` | ruff check + format on lambdas/ | -| Python Tests | `ci-python-sam.yaml` | pytest suite (19 tests — pdf-generate, suggestions handlers) | +| Python Tests | inline job | pytest suite (37 tests — pdf-generate, suggestions, library-ingest, internal API signing) | | CDK Synth | `ci-typescript-cdk.yaml` | Synthesize CDK stacks (includes .NET publish) | -### Deploy (on push to main) +### Deploy (manual) -Calls `cd-cdk.yaml` reusable workflow: +Auto-deploy on push to main is currently disabled (PR #167) — both deploy workflows run via `workflow_dispatch` from the Actions tab. `deploy.yaml` calls the `cd-cdk.yaml` reusable workflow: 1. Publishes .NET 8 API and Python Lambdas 2. Runs `cdk deploy --all` 3. Executes `scripts/post-deploy.sh` (builds web, syncs to S3, invalidates CloudFront) @@ -139,9 +139,7 @@ Deploy uses OIDC role `githubdeploy-proposal-system`. Concurrency group prevents Workflow: `deploy-mobile.yaml` -- builds and uploads to TestFlight via `cd-mobile-ios.yaml` reusable workflow on `macos-26`. -Triggers: -- **Automatic**: push to `main` with changes in `mobile/**` -- **Manual**: `workflow_dispatch` for on-demand builds +Trigger: **manual only** (`workflow_dispatch`) while the app is pre-V1, to save macOS runner cost. ## Mobile iOS @@ -186,13 +184,13 @@ Failed SQS messages are reported via `batchItemFailures` and retried up to 3 tim ## Testing -149 tests across three stacks, all run in CI on every PR: +186 tests across three stacks, all run in CI on every PR: | Suite | Framework | Count | Coverage | |---|---|---|---| -| .NET API | xUnit | 104 | State machine transitions, authorization attributes, middleware, validators, ProposalNumberGenerator, LineItemService state guards | +| .NET API | xUnit | 123 | State machine transitions, authorization attributes, middleware, validators, ProposalNumberGenerator, LineItemService state guards | | Web | vitest | 26 | ProtectedRoute, RoleGuard, API client interceptor (401 logout, token attachment) | -| Python Lambdas | pytest | 19 | pdf-generate and suggestions handler contracts | +| Python Lambdas | pytest | 37 | pdf-generate, suggestions, library-ingest handler contracts, internal API signing | ```bash cd api && dotnet test # .NET tests @@ -207,7 +205,7 @@ Hardening applied across all layers (see AUDIT-REPORT.md for full details): - **Auth:** Cognito JWT validation with audience check, startup fails if auth not configured, DevMode gated to `IsDevelopment()` - **API:** FluentValidation on all DTOs, generic error responses (no stack traces or config leaks), structured audit logging with before/after diffs - **Function URL:** AWS_IAM auth + internal API key (two-layer defense) -- **Infrastructure:** S3 `enforceSSL` + `BLOCK_ALL`, SQS managed encryption, OpenSearch VPC-only, Cognito optional TOTP MFA, API Gateway access logging +- **Infrastructure:** S3 `enforceSSL` + `BLOCK_ALL`, SQS managed encryption, Aurora in private subnets, Cognito optional TOTP MFA, API Gateway access logging - **Lambdas:** Prompt injection sanitization, PDF size limits, numeric validation on AI suggestions, S3 key sanitization, idempotent SQS processing -- **CI/CD:** OIDC (no long-lived credentials), SHA-pinned workflow refs, `--require-approval broadening` on local deploys +- **CI/CD:** OIDC (no long-lived credentials), org reusable workflows (`@main`), `--require-approval broadening` on local deploys - **Web:** sessionStorage for tokens (not localStorage), error boundaries, role guards on all admin routes, 401 interceptor clears auth state diff --git a/docs/adr/0002-shoc-merge-boundary.md b/docs/adr/0002-shoc-merge-boundary.md new file mode 100644 index 0000000..c603636 --- /dev/null +++ b/docs/adr/0002-shoc-merge-boundary.md @@ -0,0 +1,62 @@ +# ADR 0002 — SHOC merge boundary: separate backend services, shared conventions + +- **Status:** Accepted (2026-07-13) +- **Decision owner:** Adam Moussa +- **Scope:** `proposal-system` ↔ SHOC (`shoc-backend` / `shoc-frontend-new`) consolidation strategy + +## Context + +proposal-system was built as a standalone service deliberately mirroring SHOC's +architecture for a clean future merge. As of 2026-07-13 the two projects diverge on +platform fundamentals: + +| Axis | proposal-system | SHOC | +|---|---|---| +| Database | Aurora PostgreSQL (pgvector) via EF Core/Npgsql | SQL Server via EF Core | +| Identity | Cognito (hosted UI, groups, web + mobile clients) | ASP.NET Identity + custom JWT issuance | +| API layout | 4-project Clean Architecture (Api/Application/Infrastructure/Domain) | Single API project, services injecting DbContext | +| Error contract | RFC 7807 ProblemDetails, string enums | Typed-exception codes per controller, numeric enums | +| Hosting | Lambda behind API Gateway (CDK) | Elastic Beanstalk (external-dev account) | + +A full platform alignment (engine migration, auth migration, rehosting) would cost +weeks, carry data-migration risk, and deliver no user value. + +## Decision + +**The backends remain separate services permanently. Consolidation converges on +conventions, layers, and service patterns — never on platform.** + +Concretely: + +1. **No database engine migration** in either direction. PostgreSQL stays here; + SQL Server stays in SHOC. +2. **No identity migration now.** Cognito stays here. At consolidation time, identity + converges on Cognito (or a federation layer in front of both) — not on + ASP.NET Identity, which would regress to self-managed credentials and reintroduce + the remediated WEB-C1 token-theft class (SHOC currently stores JWTs in + localStorage). +3. **Conventions converge** (tracked by the 2026-07 SHOC-alignment plan): + - Frontend: SHOC's design system + UI/UX layout (ADR 0003), domain layering + (`src/domain//{api,schemas,mappers,types,use-cases}`), TanStack Query, + zod, react-hook-form. + - API contracts: shared TypeScript contracts package + zod schemas; ProblemDetails + with machine-readable business `code` extensions (SHOC's error-code vocabulary, + proposal-system's envelope). + - Mutation semantics: optimistic concurrency with SHOC's 409-plus-currentState + response shape; staged audit-trail entries persisted at one SaveChanges boundary. + - Process: org reusable CI callers, CODEOWNERS, PR template, conventional commits. +4. **Layering stays Clean Architecture here.** SHOC's flatter service style is not + adopted; if SHOC restructures at consolidation, this repo's 4-project layout is the + reference shape. + +## Consequences + +- The eventual "merge" is a monorepo consolidation of independently deployable + services sharing a frontend architecture and wire conventions — not a single + backend. +- A merged frontend can treat both APIs identically for errors (ProblemDetails + + `code`) and conflicts (409 + currentState) once alignment phases 3/6 land. +- Anything requiring one database across both domains (cross-domain reporting, + shared entities) must go through APIs, not shared tables. +- SHOC's localStorage JWT + CORS `*` are flagged to the SHOC team as findings; they + are not constraints on this repo. diff --git a/docs/adr/0003-shoc-design-system-adoption.md b/docs/adr/0003-shoc-design-system-adoption.md new file mode 100644 index 0000000..741dade --- /dev/null +++ b/docs/adr/0003-shoc-design-system-adoption.md @@ -0,0 +1,49 @@ +# ADR 0003 — Adopt the SHOC design system and UI/UX layout + +- **Status:** Accepted (2026-07-13) +- **Decision owner:** Adam Moussa +- **Scope:** `web/` theming, layout shell, and all future proposal-system UI work + +## Context + +Three design-token sets existed across Sea Haven web apps as of 2026-07-13: + +1. **Old canon** — Nunito, primary `#0c4f6f`, 220px sidebar, `#f4f6f7` background + (what SHOC's stale `docs/DESIGN_SYSTEM.md` still describes). +2. **SHOC dev's new system** (shoc-frontend-new PR #17) — Montserrat (display) / + DM Sans (body) / JetBrains Mono, primary `#1c75bc`, navy `#262262`, page background + `#f9fafb`, 244px sidebar (76px collapsed), 64px gradient topbar + (`#1b1f52 → #1c4f8f → #1c75bc`), defined in a single CSS-variable token file + (`src/styles/theme.css`) consumed by both MUI (`getCssVar` → `createTheme`) and + Tailwind v4. +3. **proposal-system's "Sea Haven Ops" theme** — Inter, accent `#2563EB`, + navy-900 AppBar, 216px drawer (`web/src/theme.ts`). + +## Decision + +**SHOC dev's new design system and UI/UX layout (set 2) is the canonical Sea Haven +standard.** proposal-system adopts it fully: + +- **Tokens:** mirror shoc-frontend-new dev's `theme.css` values and structure + (fonts, palette, radii, spacing, shadows). +- **Mechanism:** single CSS-variable token file is the one source of truth; + `web/src/theme.ts` becomes a thin `getCssVar` → MUI `createTheme` adapter matching + SHOC's `mui-theme.ts`. Token changes are values-only edits, never theme rewrites. +- **Layout shell:** SHOC's admin shell dimensions and treatment — 244px/76px-collapse + sidebar, 64px gradient topbar, avatar initials. +- **Component library:** MUI only. Tailwind (SHOC runs a MUI + Tailwind v4 hybrid off + the same CSS variables) is **not** adopted here pre-consolidation; the shared + CSS-variable source keeps that door open. + +The reference is shoc-frontend-new's **`dev` branch** at adoption time; subsequent +SHOC token changes should be ported as values-only updates. + +## Consequences + +- The "Sea Haven Ops" theme (Inter/#2563EB) is retired; alignment plan Phase 2 + implements the port. +- Visual verification for Phase 2 compares proposal-system screens side-by-side with + SHOC dev screens, not with the old canon. +- The superseded Nunito/`#0c4f6f` tokens must not be reintroduced anywhere. +- At monorepo consolidation, both frontends already share token structure, so a + single `theme.css` can serve both.