Add comprehensive README for the proposal-system monorepo

This commit is contained in:
Adam Moussa 2026-05-18 15:19:27 -04:00
parent 2a07db1234
commit cd088b67f4

167
README.md
View file

@ -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 | Monorepo with five primary services:
|---|---|
| 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 |
## AWS Resources - **.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
- **Stack prefix:** `proposal-system-*` - **React Native Mobile** -- iOS-first field app for dispatchers (offline-capable)
- **Account:** 328440206208 - **Python Lambdas** -- PDF extraction, PDF generation, library ingestion, AI suggestions
- **Region:** us-east-1 - **CDK Infrastructure** -- Three TypeScript stacks managing all AWS resources
| 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 |
## Repository Structure ## Repository Structure
``` ```
proposal-system/ proposal-system/
├── infra/ # CDK app (TypeScript) - 3 stacks ├── api/ .NET 8 Web API (Lambda-hosted, EF Core + PostgreSQL)
├── api/ # .NET 8 Web API (Lambda-hosted) ├── web/ React 19 + MUI v7 + Vite frontend
├── web/ # React 19 + MUI frontend ├── mobile/ React Native 0.79 iOS app
├── mobile/ # React Native app (iOS) ├── lambdas/ Python 3.12 processing functions (arm64)
├── lambdas/ # Python 3.12 processing functions ├── infra/ CDK TypeScript (3 stacks)
├── shared/ # Shared TypeScript types/contracts ├── shared/ TypeScript API contracts (shared between web + mobile)
└── .github/ # CI/CD workflows ├── 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 ## Local Development
### Prerequisites ### Prerequisites
- .NET 8 SDK - .NET 8 SDK
- Node.js 24 - Node.js 24+
- Python 3.12 - 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 ```bash
cd api cd api
dotnet restore dotnet restore
dotnet run --project src/ProposalSystem.Api 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 ### Web Frontend
```bash ```bash
cd web cd web
npm install npm install
npm run dev 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 ### Infrastructure
```bash ```bash
cd infra cd infra
npm install npm install
npx cdk synth npx cdk synth
npx cdk deploy --all
``` ```
## CI/CD ## CI/CD
- **CI:** Runs on pull requests to `main` (dotnet build/test, tsc, ruff, cdk synth) ### CI (on pull request to main)
- **Deploy:** Runs on push to `main` (cdk deploy, frontend S3 sync, CloudFront invalidation)
- **OIDC Role:** `githubdeploy-proposal-system` 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 ## Data Flow
1. Dispatcher submits proposal request (web or mobile) 1. Dispatcher submits proposal request (web or mobile)
2. API creates proposal record, publishes SQS message 2. API creates proposal record, publishes SQS message
3. If vendor PDF attached: `pdf-extract` Lambda parses and structures data 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 4. Suggestions Lambda queries Bedrock KB for similar proposals, generates line items via Claude
5. Admin reviews/edits line items in workspace 5. Admin reviews/edits line items in pricing workspace
6. On approval: `pdf-generate` Lambda creates branded PDF 6. On approval: `pdf-generate` Lambda creates branded PDF
7. On send: `library-ingest` Lambda adds to KB for future matching 7. On send: `library-ingest` Lambda adds approved proposal to KB for future matching
8. Slack notifications at key status transitions