diff --git a/README.md b/README.md index 65bde41..d8e9827 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,167 @@ -# Proposal Management System +# Proposal System -AI-powered proposal generation and management system for Sea Haven Industries. Enables dispatchers to submit proposal requests, uses Bedrock RAG to auto-generate draft line items from historical data, and provides admins with a pricing/approval workspace with professional PDF output. +Internal proposal management platform for Sea Haven Industries. Dispatchers submit proposal requests, AI generates draft line items from historical data via Bedrock RAG, admins review and approve in a pricing workspace, and the system produces branded PDFs for delivery. -## Architecture +## Architecture Overview -| Layer | Technology | -|---|---| -| Backend API | .NET 8 / ASP.NET Core on Lambda (`Amazon.Lambda.AspNetCoreServer`) | -| Database | RDS PostgreSQL 15 + EF Core | -| Frontend Web | React 19 + MUI v7 + TypeScript | -| Mobile | React Native (iOS-first) | -| IaC | CDK (TypeScript) - 3 stacks | -| AI/RAG | Bedrock Knowledge Base + Claude (Bedrock Runtime) | -| PDF Processing | Python 3.12 Lambdas | -| Auth | Cognito User Pool + Google OAuth | -| Storage | S3 (PDFs, attachments, library) | -| Notifications | Slack Bot API | +Monorepo with five primary services: -## AWS Resources - -- **Stack prefix:** `proposal-system-*` -- **Account:** 328440206208 -- **Region:** us-east-1 - -| Resource | Name | -|---|---| -| Lambda (.NET 8) | `proposal-system-api` | -| API Gateway HTTP API | `proposal-system-gateway` | -| RDS PostgreSQL | `proposal-system-db` | -| S3 Buckets | `proposal-system-uploads`, `proposal-system-generated`, `proposal-system-library` | -| Bedrock Knowledge Base | `proposal-system-kb` | -| Lambda (Python) | `proposal-system-pdf-extract`, `proposal-system-pdf-generate`, `proposal-system-library-ingest` | -| Cognito User Pool | `proposal-system-auth` | -| CloudFront | `proposal-system-web` | -| SQS Queue | `proposal-system-jobs` + DLQ | +- **.NET 8 API** -- Clean Architecture REST API hosted on Lambda behind API Gateway +- **React 19 Web** -- MUI v7 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 +- **CDK Infrastructure** -- Three TypeScript stacks managing all AWS resources ## Repository Structure ``` proposal-system/ -├── infra/ # CDK app (TypeScript) - 3 stacks -├── api/ # .NET 8 Web API (Lambda-hosted) -├── web/ # React 19 + MUI frontend -├── mobile/ # React Native app (iOS) -├── lambdas/ # Python 3.12 processing functions -├── shared/ # Shared TypeScript types/contracts -└── .github/ # CI/CD workflows +├── api/ .NET 8 Web API (Lambda-hosted, EF Core + PostgreSQL) +├── web/ React 19 + MUI v7 + Vite frontend +├── mobile/ React Native 0.79 iOS app +├── lambdas/ Python 3.12 processing functions (arm64) +├── infra/ CDK TypeScript (3 stacks) +├── shared/ TypeScript API contracts (shared between web + mobile) +├── scripts/ Post-deploy and utility scripts +├── .github/ CI/CD workflows +└── docker-compose.yml ``` +## Tech Stack + +| 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.79, React 19, React Native Paper, React Navigation, react-native-app-auth (PKCE), 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, Claude via Bedrock Runtime | +| Auth | Cognito User Pool + Google OAuth IdP (groups: dispatchers, admins, sysadmins) | + +## AWS Resources + +All resources are in **us-east-1** (account 328440206208). CDK stacks are defined but not yet deployed to AWS. + +| 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, .NET 8 API Lambda, Python Lambdas (pdf-extract, pdf-generate, library-ingest, suggestions), Bedrock KB | +| `proposal-system-frontend` | CloudFront distribution (S3 OAC) | + +| Resource Type | Names | +|---|---| +| S3 Buckets | `proposal-system-uploads`, `proposal-system-generated`, `proposal-system-library`, `seahaven-ios-certificates` | +| SQS | `proposal-system-jobs` + `proposal-system-jobs-dlq` (message body filtering by jobType) | +| Secrets | `proposal-system/db-credentials`, `proposal-system/internal-api-key` | + ## Local Development ### Prerequisites - .NET 8 SDK -- Node.js 24 +- Node.js 24+ - Python 3.12 -- AWS CDK CLI (`npm install -g aws-cdk@2.253.1`) +- PostgreSQL 16 (via docker-compose or native) -### Backend API +### Database + +```bash +docker compose up -d # starts PostgreSQL on port 5432 +# database: proposalsystem, password: localdev +``` + +### API ```bash cd api dotnet restore dotnet run --project src/ProposalSystem.Api +# runs on http://localhost:5000 ``` +In development mode (`DevMode=true` in appsettings.Development.json): +- JWT auth uses a local symmetric HMAC key (no Cognito required) +- S3 service returns fake presigned URLs +- SQS publisher logs messages without sending + ### Web Frontend ```bash cd web npm install npm run dev +# runs on http://localhost:5173, proxies /api to localhost:5000 ``` +When `VITE_COGNITO_CLIENT_ID` is not set, the login screen shows role-selector buttons for local development. + ### Infrastructure ```bash cd infra npm install npx cdk synth -npx cdk deploy --all ``` ## CI/CD -- **CI:** Runs on pull requests to `main` (dotnet build/test, tsc, ruff, cdk synth) -- **Deploy:** Runs on push to `main` (cdk deploy, frontend S3 sync, CloudFront invalidation) -- **OIDC Role:** `githubdeploy-proposal-system` +### CI (on pull request to main) + +Five parallel jobs calling org reusable workflows: + +| Job | Workflow | What it checks | +|---|---|---| +| .NET Build & Test | `ci-dotnet.yaml` | Restore, build, test the API solution | +| Web Frontend Check | `ci-typescript-cdk.yaml` | TypeScript typecheck for web | +| Mobile Typecheck | `ci-typescript-cdk.yaml` | TypeScript typecheck for mobile | +| Python Lint | `ci-python-sam.yaml` | ruff check + format on lambdas/ | +| CDK Synth | `ci-typescript-cdk.yaml` | Synthesize CDK stacks (includes .NET publish) | + +### Deploy (on push to main) + +Calls `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) + +Deploy uses OIDC role `githubdeploy-proposal-system`. Concurrency group prevents parallel deploys. + +### Mobile Deploy (currently disabled) + +Workflow: `deploy-mobile.yaml` -- triggered by `workflow_dispatch` only (manual). + +To activate for release, change the trigger to push on main with path filter `mobile/**`. + +## Mobile iOS + +The iOS app uses **Fastlane** with **match** for code signing. Certificates and profiles are stored in the `seahaven-ios-certificates` S3 bucket (versioning enabled, public access blocked). + +Build and upload to TestFlight is handled by the `cd-mobile-ios.yaml` reusable workflow. Required secrets: + +| Secret | Purpose | +|---|---| +| `AWS_DEPLOY_ROLE_ARN` | OIDC role for match S3 access | +| `MATCH_PASSWORD` | Decryption passphrase for signing assets | +| `ASC_KEY_ID` | App Store Connect API key ID | +| `ASC_ISSUER_ID` | App Store Connect issuer | +| `ASC_KEY_CONTENT` | App Store Connect API key (base64) | + +To activate automatic deploys, update `deploy-mobile.yaml` trigger from `workflow_dispatch` to: + +```yaml +on: + push: + branches: [main] + paths: ["mobile/**"] +``` ## Data Flow 1. Dispatcher submits proposal request (web or mobile) 2. API creates proposal record, publishes SQS message 3. If vendor PDF attached: `pdf-extract` Lambda parses and structures data -4. Suggestion engine queries Bedrock KB for similar proposals, generates line items via Claude -5. Admin reviews/edits line items in workspace +4. Suggestions Lambda queries Bedrock KB for similar proposals, generates line items via Claude +5. Admin reviews/edits line items in pricing workspace 6. On approval: `pdf-generate` Lambda creates branded PDF -7. On send: `library-ingest` Lambda adds to KB for future matching -8. Slack notifications at key status transitions +7. On send: `library-ingest` Lambda adds approved proposal to KB for future matching