End-to-end runnable skeleton for the OLIVER Sales Operations Platform — the V2 of the Scope Builder, broadened to a complete RFP-to-mobilization pipeline (intake → qualification → Q&A → match → ratecard → delivery model → efficiency → team shape → caveats → approval gates → pitch → post-win planning → downstream handoff). Backend (FastAPI + async SQLAlchemy + Alembic): - Models: app_users (with workflow_roles for approver routing), GMAL catalog ported from V1 (gmal_assets / roles / gmal_hours / service lines / role-level mappings), and the new state machine (opportunities, stage_states, stage_artifacts, approvals). - Initial Alembic migration creates 11 tables and 5 enum types using the postgresql.ENUM(create_type=False) pattern so the types aren't double-created when referenced from multiple columns. - Claude client defaults to claude-opus-4-7 with cost tracking + debug log; Azure SSO middleware ported as-is from V1. - Public /api/health round-trips a SELECT 1 to verify the DB is reachable. Frontend (React 18 + Vite + TanStack Query + MSAL + Mermaid): - Home page renders the canonical 17-stage flowchart (Mermaid) plus an enumerated stage card grid with the two approval gates highlighted. - React Router uses /osop basename to mirror the V1 /gsb/ deploy pattern; axios client targets /osop/api with MSAL token interceptor. Compose: - name: oliver-sales-ops-platform (so the project doesn't collide with the deploy-folder default per shared-server policy in CLAUDE.md). - Ports 5435 / 6380 / 8003 / 3011 to coexist with V1 on the same host. - Source mounts on backend (app/, alembic/, alembic.ini) and frontend (src/, configs) so dev iteration doesn't require rebuilds. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
2 KiB
YAML
73 lines
2 KiB
YAML
name: oliver-sales-ops-platform
|
|
|
|
services:
|
|
db:
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_DB: oliver_sales_ops
|
|
POSTGRES_USER: osop_user
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-osop_pass_2026}
|
|
volumes:
|
|
- osop_pgdata:/var/lib/postgresql/data
|
|
ports:
|
|
- "127.0.0.1:5435:5432"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U osop_user -d oliver_sales_ops"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 5
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
restart: unless-stopped
|
|
ports:
|
|
- "127.0.0.1:6380:6379"
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 5
|
|
|
|
backend:
|
|
build: ./backend
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
environment:
|
|
DATABASE_URL: postgresql+asyncpg://osop_user:${POSTGRES_PASSWORD:-osop_pass_2026}@db:5432/oliver_sales_ops
|
|
DATABASE_URL_SYNC: postgresql://osop_user:${POSTGRES_PASSWORD:-osop_pass_2026}@db:5432/oliver_sales_ops
|
|
REDIS_URL: redis://redis:6379/0
|
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
AZURE_TENANT_ID: ${AZURE_TENANT_ID}
|
|
AZURE_CLIENT_ID: ${AZURE_CLIENT_ID}
|
|
DEV_AUTH_BYPASS: ${DEV_AUTH_BYPASS:-}
|
|
ports:
|
|
- "127.0.0.1:8003:8000"
|
|
volumes:
|
|
- ${DATA_DIR:-./data}:/app/data
|
|
- ./backend/app:/app/app
|
|
- ./backend/alembic:/app/alembic
|
|
- ./backend/alembic.ini:/app/alembic.ini
|
|
|
|
frontend:
|
|
build: ./frontend
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- backend
|
|
environment:
|
|
VITE_DEV_AUTH_BYPASS: ${VITE_DEV_AUTH_BYPASS:-}
|
|
ports:
|
|
- "127.0.0.1:3011:3000"
|
|
volumes:
|
|
- ./frontend/src:/app/src
|
|
- ./frontend/index.html:/app/index.html
|
|
- ./frontend/vite.config.ts:/app/vite.config.ts
|
|
- ./frontend/tsconfig.json:/app/tsconfig.json
|
|
- ./frontend/tsconfig.node.json:/app/tsconfig.node.json
|
|
|
|
volumes:
|
|
osop_pgdata:
|