mirror of
https://github.com/Sea-Haven-Industries/proposal-system.git
synced 2026-09-30 08:53:15 +00:00
Apple review requires a test account login path that doesn't depend on Google OAuth. Add amazon-cognito-identity-js for direct SRP auth with a native email/password form on the login screen. Fill in the empty Cognito client ID and pool ID, fix the Cognito domain prefix, and align CDK callback URLs with the app's actual URL scheme. Enable push-triggered mobile deploys, add CDK outputs for client IDs, fix stale README references, and add mobile/README.md.
160 lines
6 KiB
Markdown
160 lines
6 KiB
Markdown
# Proposal System
|
|
|
|
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 Overview
|
|
|
|
Monorepo with five primary services:
|
|
|
|
- **.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, AOSS index provisioning
|
|
- **CDK Infrastructure** -- Three TypeScript stacks managing all AWS resources
|
|
|
|
## Repository Structure
|
|
|
|
```
|
|
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
|
|
├── 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.85, 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, 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 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, oss-index-creator), OpenSearch Serverless collection, 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+
|
|
- Python 3.12
|
|
- PostgreSQL 16 (via docker-compose or native)
|
|
|
|
### 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
|
|
```
|
|
|
|
## CI/CD
|
|
|
|
### 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
|
|
|
|
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
|
|
|
|
## 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) |
|
|
|
|
## 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. 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 approved proposal to KB for future matching
|