---
name: "Oliver Sales Ops Platform"
client: Oliver Internal
status: active
tech: [React, FastAPI, PostgreSQL, Claude API, Docker, TypeScript, SQLAlchemy]
local_path: /Users/ai_leed/Documents/Projects/Oliver/oliver-sales-ops-platform
deploy: deploy.sh (auto port selection + Apache proxy)
url: https://optical-dev.oliver.solutions/oliver-sales-ops-platform/
server: optical-dev
tags:
  - project
created: 2026-04-28
port: 8003
db: PostgreSQL 16
---

## Overview

The OLIVER Sales Ops Platform is an end-to-end RFP-to-mobilization pipeline that automates the commercial proposal process. An account team uploads a client brief, and the platform walks it through a 17-stage state machine, with Claude AI agents driving key decision points: intake, diagnosis, qualification, Q&A pack generation, asset normalization, GMAL matching, ratecard building, team shaping, pitch deck generation, and post-win delivery planning. It produces defensible, fully-costed proposals backed by AI synthesis and human approvals. This is Phase 1 of the GMAL Scope Builder v2, deployed on optical-dev and used internally by Oliver's commercial and sales operations teams.

## Tech Stack

- **Frontend:** React 18 + TypeScript, Vite (HMR dev), TailwindCSS, Lucide React icons
- **Backend:** FastAPI (Python 3.11+), async SQLAlchemy ORM, Alembic migrations
- **Database:** PostgreSQL 16 (Alpine), async driver via `asyncpg`
- **Infrastructure:** Docker Compose, Apache 2.x reverse proxy (optical-dev), volume-based file uploads
- **AI/ML:** Anthropic Claude (claude-opus-4-5 / claude-4.7), nine distinct agent services
- **Key libraries:** Pydantic v2 (settings validation), Mailgun (approval notifications), Redis (future Celery queue)

## Architecture

**Component map:**
- Browser (MSAL SSO or dev auth bypass) → Apache reverse proxy (optical-dev) → FastAPI backend on port 8003 → PostgreSQL 16 + Redis 7 → Anthropic Claude API + Mailgun

**State machine:** Every Opportunity has 17 `stage_states` rows. Stage 1 starts `in_progress`; stages 2–17 start `not_started`. Stage advancement requires `/stages/{n}/complete`; stages 3 and 14 additionally gate on `Approval` rows being marked `approved`. Agent runs (intake, diagnosis, etc.) are independent of stage state — users iterate freely. Destructive re-runs cascade invalidate downstream stages.

**Data model:** 
- `Opportunity` (root entity) → `StageState` (1 per stage) → `Approval` (gated stages) 
- Client assets normalized into `ClientAsset` rows 
- `Match` rows (Stage 7) link opportunities to GMAL capabilities 
- `RatecardLine` (Stage 8) and `TeamShape` (Stage 11) compute delivery cost/resource plan
- Artifacts (pitch markdown, implementation plan) stored as JSON on stage record or exported as files

**Local dev adds Vite HMR frontend on port 3011** (activated with `COMPOSE_PROFILES=dev`). Production serves pre-built static SPA from Apache.

```
┌─ Browser (React SPA) ─────────────────────┐
│  localhost:3011 (dev) or Apache (prod)    │
└────────────────┬──────────────────────────┘
                 │ /api/
                 ▼
        ┌─ FastAPI Backend ─────┐
        │ localhost:8003        │
        │ async SQLAlchemy      │
        └────────┬──────────────┘
                 │
    ┌────────────┼────────────┐
    ▼            ▼            ▼
PostgreSQL    Redis       Anthropic
  (5435)      (6380)      Claude API
```

## Dev Commands

```bash
# Clone & setup
git clone git@bitbucket.org:zlalani/oliver-sales-ops-platform.git
cd oliver-sales-ops-platform
cp .env.example .env
# Edit .env: set ANTHROPIC_API_KEY, DEV_AUTH_BYPASS=true

# Start full dev stack (Vite HMR + backend)
COMPOSE_PROFILES=dev docker compose up -d

# Or backend only (no frontend container)
docker compose up -d

# Verify backend health
curl http://localhost:8003/api/health

# View logs
docker compose logs -f backend

# Restart a service
docker compose restart backend

# Run tests (in isolated venv)
python3 -m venv /tmp/osop_test_venv
/tmp/osop_test_venv/bin/pip install -r backend/requirements-dev.txt psycopg2-binary
cd backend && /tmp/osop_test_venv/bin/pytest tests/ -v

# Connect to DB
docker compose exec db psql -U osop_user -d oliver_sales_ops

# Manual migration
docker compose exec backend alembic upgrade head
```

## Deployment

- **Server:** optical-dev (internal Oliver dev server)
- **Deploy:** `deploy.sh` (auto-selects free ports, renders Apache conf from template, persists to `.env`)
- **URL:** `https://optical-dev.oliver.solutions/oliver-sales-ops-platform/`
- **Port:** 8003 (backend); Apache proxies `/oliver-sales-ops-platform/api/` → `127.0.0.1:8003`
- **Service:** None (Docker Compose managed directly; no systemd wrapper)
- **Local path:** `/Users/ai_leed/Documents/Projects/Oliver/oliver-sales-ops-platform`

**First-time server setup (optical-dev):**
1. Clone repo to `/opt/oliver-sales-ops-platform/`
2. Copy `.env.example` → `.env`, set `ANTHROPIC_API_KEY` and `APP_PUBLIC_URL`
3. Run `deploy.sh` — auto-selects ports (5435, 6380, 8003), builds images, starts containers, renders Apache conf
4. Manually add include to Apache vhost: `Include /opt/oliver-sales-ops-platform/deploy/apache-osop.conf`
5. `sudo apachectl configtest && sudo systemctl reload apache2`

**Static SPA path:** `/var/www/html/oliver-sales-ops-platform/` (built during deploy, served by Apache)

## Environment Variables

- `ANTHROPIC_API_KEY` — Claude API key (required, no default)
- `DEV_AUTH_BYPASS` — Set `true` to skip Azure SSO; uses dev identity below (default: `true` in `.env.example`)
- `DEV_AUTH_EMAIL` — Dev bypass user email (default: `dev@localhost`)
- `DEV_AUTH_NAME` — Dev bypass display name (default: `Dev User`)
- `DEV_AUTH_ROLE` — Dev bypass role: `admin` | `editor` | `viewer` (default: `editor`)
- `OSOP_DB_PORT` — Postgres host port (auto-selected, default 5435, range 5435–5535)
- `OSOP_REDIS_PORT` — Redis host port (auto-selected, default 6380, range 6380–6480)
- `OSOP_BACKEND_PORT` — FastAPI host port (auto-selected, default 8003, range 8003–8099)
- `OSOP_FRONTEND_PORT` — Vite dev server port (default 3011, dev profile only)
- `APP_PUBLIC_URL` — Public app URL (e.g., `https://optical-dev.oliver.solutions`, used in emails)
- `MAILGUN_API_KEY` — Mailgun key for approval notifications (required for Stage 3/14 emails)
- `MAILGUN_DOMAIN` — Mailgun domain

## API / Endpoints

Key FastAPI endpoints (all under `/api/`):

- `GET /health` — Backend + DB health check
- `GET /users/me` — Current authenticated user
- `POST /opportunities` — Create new opportunity
- `GET /opportunities/{id}` — Fetch opportunity + all stages
- `GET /stages/{stage_id}` — Get stage detail + state
- `POST /stages/{stage_id}/run-agent` — Execute agent for a stage (intake, diagnosis, etc.)
- `POST /stages/{stage_id}/complete` — Mark stage complete (checks approval gates)
- `POST /approvals` — Create approval request for Stage 3 or 14
- `PATCH /approvals/{approval_id}` — Approve/reject
- `POST /opportunities/{id}/export-qa-pack` — Export Stage 4 Q&A as Excel/Word

Full spec: `docs/project/api_spec.md`

## Known Issues

- **Stage 7 (GMAL Matching):** Runs as FastAPI background task in Phase 1; no dedicated Celery worker deployed yet
- **Stage 17 (Salesforce/SharePoint):** Deferred to Phase 2; stub only
- **SSO:** Azure MSAL integration exists; fallback dev-auth-bypass for local development
- **File uploads:** Stored in Docker volume `/app/data/uploads/opp_<id>/`; no cloud bucket integration yet

## Documentation

Full architecture, requirements, database schema, and ADRs are in `docs/project/` and `docs/reference/`:
- `docs/project/architecture.md` — System design, state machine, security
- `docs/project/requirements.md` — Functional workflows per stage
- `docs/project/database_schema.md` — Table definitions + indexes
- `docs/project/infrastructure.md` — Ports, volumes, environment
- `docs/project/runbook.md` — Local setup, testing, deployment
- `docs/reference/README.md` — Architectural decision records

## Git

- **Remote:** `git@bitbucket.org:zlalani/oliver-sales-ops-platform.git`
- **Branch:** `main` (deployed to optical-dev)
- **Last commits:** User menu UX fixes, SSO allowlist, avatar + sign-out button, port auto-selection, Apache template deploy

## Sessions
### 2026-05-11 – Add ameliagreene@oliver.agency to allowed users list
**Asked:** Add ameliagreene@oliver.agency to allowed users list and update server
**Done:** User added to allowlist and deployment completed on server

### 2026-05-05 – Add two users to the allowlist
**Asked:** Add two users to the allowlist and update the server.
**Done:** Added users to allowlist via git pull and backend restart with sudo permissions.

### 2026-05-05 – Add two email addresses to the
**Asked:** Add two email addresses to the allowed users list and update the server.
**Done:** Added nicky.vissers@brandtech.plus and rudi.reagon@brandtech.plus to the allowed users list and pushed changes to server.

### 2026-04-29 – Add SPA redirect URI to Azure
**Asked:** Add SPA redirect URI to Azure and configure allowed users for the application.
**Done:** Added redirect URI to Azure, provided list of authorized users, and removed non-existent user; changes pushed and ready for deployment.

### 2026-04-29 – How should authorized user emails be
**Asked:** How should authorized user emails be formatted and added to the system?
**Done:** Added UserMenu component to navbar and configured 7 authorized users with admin roles for 2 of them.

### 2026-04-29 – Remove zlalani@oliver.agency from the authorized users
**Asked:** Remove zlalani@oliver.agency from the authorized users list and confirm Azure SPA redirect URI addition.
**Done:** Updated authorized users list by removing zlalani@oliver.agency and confirmed 7 valid user emails for Azure configuration.

### 2026-04-29 – Configure Azure redirect URI and allowed
**Asked:** Configure Azure redirect URI and allowed users for MSAL authentication.
**Done:** Added SPA redirect URI to Azure, compiled list of 9 authorized users with admin roles assigned, and removed invalid user account.

### 2026-04-29 – Configure Azure AD authentication environment variables
**Asked:** Configure Azure AD authentication environment variables with actual tenant and client IDs.
**Done:** Identified that backend `.env` file contains placeholder values instead of real Azure AD credentials causing authentication failures.

### 2026-04-29 – Confirm Azure AD redirect URI addition
**Asked:** Confirm Azure AD redirect URI addition and provide allowed user emails format.
**Done:** Added SPA redirect URI to Azure, received user email list with admin roles assigned, and removed non-existent user from allowlist.

### 2026-04-29 – How should the allowed user emails
**Asked:** How should the allowed user emails be formatted for Azure configuration?
**Done:** Configured Azure redirect URI and provided 8 approved user emails, removing zlalani@oliver.agency due to non-existence; identified DEV_AUTH_BYPASS blocking SSO enforcement.

### 2026-04-29 – Add SPA redirect URI to Azure
**Asked:** Add SPA redirect URI to Azure and configure authorized user emails for the application.
**Done:** Added redirect URI to Azure, provided list of authorized users, and resolved Git permission issues by running deployment commands with sudo.

### 2026-04-29 – Add SPA redirect URI to Azure
**Asked:** Add SPA redirect URI to Azure and configure authorized user emails for the Oliver Sales Ops platform.
**Done:** Added redirect URI to Azure, compiled authorized user list (8 users), removed non-existent user zlalani@oliver.agency, and resolved git directory permission issues.

### 2026-04-29 – Configure Azure redirect URI and set
**Asked:** Configure Azure redirect URI and set up allowed users for the Oliver Sales Ops Platform.
**Done:** Added SPA redirect URI to Azure, updated authorized users list (removed zlalani@oliver.agency), and pushed changes with deployment instructions provided.

### 2026-04-29 – How should the allowed users list
**Asked:** How should the allowed users list be formatted for Azure SPA redirect configuration?
**Done:** Configured allowed users list with 7 authorized emails and removed invalid zlalani@oliver.agency user, then deployed changes.

### 2026-04-29 – What email format is needed for
**Asked:** What email format is needed for authorized users and should zlalani@oliver.agency be removed from the allowlist?
**Done:** Verified SSO configuration and confirmed that the allowlist will be updated on next deployment via docker-compose restart.

### 2026-04-29 – Configure allowed users list with proper
**Asked:** Configure allowed users list with proper YAML formatting for the Oliver Sales Ops Platform.
**Done:** Updated allowed_users.yaml with 9 users (3 admins, 6 editors), removed non-existent zlalani user, and fixed YAML indentation.

### 2026-04-29 – Configure Azure AD redirect URI and
**Asked:** Configure Azure AD redirect URI and set up allowed user email list for authentication.
**Done:** Added SPA redirect URI to Azure, received 8 authorized user emails, and confirmed email normalization rules (lowercase, stripped, apostrophe preserved).

### 2026-04-29 – How should allowed user emails be
**Asked:** How should allowed user emails be formatted for the configuration?
**Done:** Documented the YAML format for allowed users with role definitions (viewer, editor, admin) in config/allowed_users.yaml.

### 2026-04-28 – How should SSO access control be
**Asked:** How should SSO access control be implemented — separate Azure environment or backend allowlist via allowed_users.yaml?
**Done:** Configured SSO with backend-based user allowlist validation; pushed initial commit and set redirect URI to https://optical-dev.oliver.solutions/oliver-sales-ops-platform/

### 2026-04-28 – How should SSO user restriction be
**Asked:** How should SSO user restriction be implemented — separate Azure environment or backend alloweduser.yaml file with email checks?
**Done:** Confirmed redirect URI is correctly configured in MSAL; instructed to add https://optical-dev.oliver.solutions/oliver-sales-ops-platform/ to Azure AD app registration as SPA redirect URI.

### 2026-04-28 – How should SSO user access control
**Asked:** How should SSO user access control be implemented — separate Azure environment or backend allowlist with allowed emails?
**Done:** Implemented backend-based SSO access control with allowlist verification, redirect URL configured to https://optical-dev.oliver.solutions/oliver-sales-ops-platform/

### 2026-04-28 – How should SSO user access restrictions
**Asked:** How should SSO user access restrictions be implemented — separate Azure environment or backend allowlist validation?
**Done:** Confirmed backend allowlist approach is viable; reviewed AuthProvider.tsx and updated docstring in _upsert_app_user for clarity.


## Change Log
| Date | Requested | Changed | Files |
|------|-----------|---------|-------|
| 2026-05-11 | User allowlist update | Added ameliagreene@oliver.agency, deployed to server | allowlist.config, server.env |
| 2026-05-05 | Allowlist update | Added nicky.vissers@brandtech.plus and rudi.reagon@brandtech.plus to allowlist, restarted backend | allowlist config, backend service |
| 2026-05-05 | Allowed users list | Add nicky.vissers@brandtech.plus, rudi.reagon@brandtech.plus | allowedUsers.ts, config.server.ts |
| 2026-04-29 | Azure configuration | Added SPA redirect URI, configured allowed users list, removed zlalani@oliver.agency | Azure app registration, user configuration file |
| 2026-04-29 | User authentication setup | Added UserMenu component, configured authorized users list (removed zlalani@oliver.agency) | UserMenu.tsx, auth config |
| 2026-04-29 | Azure SPA setup | Removed zlalani@oliver.agency, confirmed redirect URI and user list | Azure config file |
| 2026-04-29 | Azure MSAL config | Redirect URI added to https://optical-dev.oliver.solutions/oliver-sales-ops-platform/, authorized users list updated (removed zlalani@oliver.agency), Client ID and tenant ID verified | Azure app registration, frontend MSAL configuration |
| 2026-04-29 | Azure AD setup | AZURE_TENANT_ID, AZURE_CLIENT_ID values replaced with real credentials | .env |
| 2026-04-29 | Azure AD configuration | Redirect URI added, user allowlist updated (removed zlalani@oliver.agency) | .env, docker-compose.yml |
| 2026-04-29 | Azure SSO setup | Added redirect URI and user allowlist, disabled DEV_AUTH_BYPASS flags | .env |
| 2026-04-29 | Azure redirect URI configuration | Added SPA redirect URI https://optical-dev.oliver.solutions/oliver-sales-ops-platform/, configured authorized users (removed zlalani@oliver.agency) | Azure configuration, deployment scripts |
| 2026-04-29 | Azure configuration | SPA redirect URI added to https://optical-dev.oliver.solutions/oliver-sales-ops-platform/, authorized users configured (8 emails), zlalani@oliver.agency removed | Azure app registration, git config |
| 2026-04-29 | Azure config | SPA redirect URI added, authorized users configured, zlalani@oliver.agency removed | .env, deploy configuration files |
| 2026-04-29 | Azure SSO allowlist config | Added 7 authorized users, removed zlalani@oliver.agency, verified DEV_AUTH_BYPASS setting | allowed_users.yaml, docker-compose.yml, auth.py, deploy.sh |
| 2026-04-29 | Azure SPA redirect URI, SSO allowlist setup, remove zlalani@oliver.agency | Added redirect URI to Azure, verified docker volume mount for config, confirmed DEV_AUTH_BYPASS logic | docker-compose.yml, auth.py, allowed_users.yaml |
| 2026-04-29 | Allowed users config | Add 9 users with roles, remove zlalani@oliver.agency, fix YAML indentation | config/allowed_users.yaml |
| 2026-04-29 | Azure AD auth setup | Added redirect URI to https://optical-dev.oliver.solutions/oliver-sales-ops-platform/, configured email allowlist with 8 users, normalized via preferred_username claim | Azure AD config, authentication service |
| 2026-04-29 | User configuration format | Added YAML schema documentation with role definitions and case-insensitive email handling | config/allowed_users.yaml, backend/app/models/user.py |
| 2026-04-28 | SSO user allowlist | Added allowed_users.yaml validation, configured redirect URI, set DEV_AUTH_BYPASS flags | config/allowed_users.yaml, .env, deploy/deploy.sh |
| 2026-04-28 | SSO configuration with user allowlist | redirectUri verification, Azure AD SPA redirect URI registration | MSAL config, app registration 9079054c-9620-4757-a256-23413042f1ef |
| 2026-04-28 | SSO access control | Created allowlist service, added auth middleware with email verification, configured redirect URL | config/allowed_users.yaml, backend/app/services/allowlist.py, backend/app/middleware/auth.py |
| 2026-04-28 | SSO user restrictions | AuthProvider logic review, _upsert_app_user docstring update | AuthProvider.tsx, _upsert_app_user |

## Related