- MSAL.js (PKCE) browser-side auth against Azure Entra ID - Bearer token interceptor on all API calls - Backend JWT validation middleware (python-jose + JWKS) - All API routes protected; /api/health stays public - vite base set to /gsb/, BrowserRouter basename=/gsb - docker-compose: remove frontend service, lock backend to 127.0.0.1:8002, remove dev volumes - backend: 2 workers, no --reload Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
104 lines
5.3 KiB
Markdown
104 lines
5.3 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## Overview
|
||
|
||
GMAL Scope Builder is a Dockerized AI-powered scoping tool that matches client deliverables (from uploaded Word/Excel documents) against a standardized GMAL asset database, then builds team ratecards and FTE models. The AI layer uses Claude Opus 4.6 for both document parsing and asset matching.
|
||
|
||
## Development Commands
|
||
|
||
### Docker (primary workflow)
|
||
```bash
|
||
docker compose build # Build all images
|
||
docker compose up -d # Start all services (bg)
|
||
docker compose logs backend --tail 50 # Backend logs
|
||
docker compose logs frontend --tail 20 # Frontend logs
|
||
docker compose down # Stop all services
|
||
```
|
||
|
||
### Services run on
|
||
- Frontend: http://localhost:3010
|
||
- Backend API: http://localhost:8001
|
||
- PostgreSQL: localhost:5433
|
||
|
||
### One-time setup
|
||
```bash
|
||
cp .env.example .env # Add ANTHROPIC_API_KEY
|
||
# Place GMAL Excel file in data/ directory
|
||
curl -X POST http://localhost:8001/api/gmal/ingest # Populate GMAL catalog
|
||
```
|
||
|
||
### Frontend (without Docker)
|
||
```bash
|
||
cd frontend && npm install
|
||
npm run dev # Vite dev server with HMR
|
||
npm run build # TypeScript compile + production bundle
|
||
```
|
||
|
||
### Backend (without Docker)
|
||
```bash
|
||
cd backend && pip install -r requirements.txt
|
||
uvicorn app.main:app --reload --port 8000
|
||
```
|
||
|
||
### Database operations
|
||
```bash
|
||
# Backup
|
||
docker compose exec db pg_dump -U scope_user -d scope_builder > backups/dump.sql
|
||
|
||
# Restore
|
||
docker compose exec -T db psql -U scope_user -d scope_builder < backups/dump.sql
|
||
```
|
||
|
||
## Architecture
|
||
|
||
### Stack
|
||
- **Frontend**: React 18 + TypeScript + Vite + React Router + Axios
|
||
- **Backend**: FastAPI + SQLAlchemy (async) + asyncpg + Uvicorn
|
||
- **Database**: PostgreSQL 16
|
||
- **AI**: Claude Opus 4.6 via Anthropic SDK (tool_use for structured output)
|
||
- **Document parsing**: openpyxl, python-docx
|
||
|
||
### Backend structure (`backend/app/`)
|
||
- **`main.py`**: FastAPI app, CORS config, router registration, AI usage/debug endpoints
|
||
- **`models/`**: SQLAlchemy ORM — `gmal.py` (catalog: GmalAsset, Role, GmalHours, ServiceLine) and `project.py` (workflow: Project, ClientAsset, Match, RatecardLine)
|
||
- **`services/`**: Core business logic — see flow below
|
||
- **`api/`**: Route handlers for `gmal`, `ingest`, `projects`, `matching`, `ratecard`
|
||
- **`schemas/`**: Pydantic request/response models
|
||
- **`utils/claude_client.py`**: Wraps Anthropic SDK with per-project + global token/cost tracking and a 50-call debug log
|
||
|
||
### Frontend structure (`frontend/src/`)
|
||
- **`App.tsx`**: Router, navigation bar, live AI cost tracker, expandable debug panel
|
||
- **`pages/`**: Dashboard, NewProject, ProjectView (main workflow), GmalBrowser, GmalEditor, Help
|
||
- **`api/client.ts`**: Axios instance pointing to backend
|
||
- **`types/index.ts`**: Shared TS interfaces + `MODEL_TYPE_LABELS` / `CONFIDENCE_COLORS` constants
|
||
|
||
### Core data flow
|
||
|
||
1. **Ingestion** — Excel file → `excel_parser.py` → `GmalAsset` + `Role` + `GmalHours` (per model type) in PostgreSQL
|
||
|
||
2. **Project creation** — User selects one of 5 **model types** (Current, AI-Enhanced, Offshore+, Local, Factory); this key drives which `GmalHours` rows are used throughout
|
||
|
||
3. **Document parsing** — Uploaded `.docx`/`.xlsx` → `doc_parser.py` extracts raw text → Claude with `extract_assets` tool returns structured `ClientAsset` list (name, description, volume, complexity hint)
|
||
|
||
4. **AI matching** — Each `ClientAsset` → `ai_matching.py` → Claude with `submit_matches` tool → ranked GMAL matches with confidence (`exact`/`close`/`multiple`/`none`), score 0–1, reasoning, caveats. Processed in batches of 10 with cancellation support.
|
||
|
||
5. **Ratecard building** — User selects a match per asset → `ratecard_builder.py` looks up `GmalHours[gmal_asset, model_type]`, multiplies by `ClientAsset.volume` → `RatecardLine` rows (one per role per asset)
|
||
|
||
6. **Team shape** — `team_shape.py` aggregates hours per role → FTE = total / 1800; efficiency slider (0–90%) is applied to **delivery roles only** (programme roles are not reduced)
|
||
|
||
7. **Export** — `export_excel.py` produces multi-tab workbook (ratecard, asset detail, team shape, efficiency); `export_pdf.py` produces caveats report
|
||
|
||
### Project status lifecycle
|
||
`draft` → `parsing` → `matching` → `review` → `building` → `finalized`
|
||
|
||
### AI cost tracking
|
||
Every Claude call records input/output tokens and USD cost (`$3/M` input, `$15/M` output) via `claude_client.py`. Costs are stored on the `Project` model and surfaced globally via `GET /ai/usage`. The frontend polls this and shows a live cost tracker + expandable debug panel.
|
||
|
||
## Key design decisions
|
||
- **All Claude calls use `tool_use`** for structured output — no fragile JSON parsing from free-text responses
|
||
- **`model_type` is set at project creation** and cannot change — it filters all `GmalHours` lookups
|
||
- **Programme roles are exempt from efficiency reduction** in team shape calculations (they don't scale with AI productivity)
|
||
- **Matching is async/batched** — supports cancellation mid-job; poll `/api/projects/{id}/status` for progress
|
||
- **The GMAL catalog (390 assets)** is ingested from a single Excel file in `data/`; re-run `/api/gmal/ingest` to reload after updating the file
|