9.2 KiB
| name | client | status | server | tech | local_path | deploy | url | tags | created | port | db | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Activation Calendar Helper | Oliver Agency | active | optical-web-1 |
|
/Users/ai_leed/Documents/Projects/Oliver/ac-helper | sudo ./deploy.sh | https://ai-sandbox.oliver.solutions/ac-helper/ |
|
2026-04-14 | 8100 | PostgreSQL 16 |
Overview
AC Helper is a web-based internal tool for Oliver Agency staff to manage marketing deliverables (activation calendars). It combines an AI-powered natural language command interface for creating and updating deliverables with a brief extractor pipeline that automatically parses uploaded marketing documents (PDF, PPTX, DOCX, XLSX) and converts them into structured rows. The app is live in production on optical-web-1 and serves as the primary interface for activation calendar management.
Tech Stack
- Frontend: React 19 + TypeScript + Vite, Handsontable grid component, Tailwind CSS 4, Zustand state management
- Backend: Python 3.11, Quart (async Flask), Hypercorn ASGI server
- Database: PostgreSQL 16 with asyncpg connection pool; JSONB columns for structured data
- Infrastructure: Docker Compose (2 containers: app + postgres); Apache reverse proxy with TLS termination
- AI/ML: Google Gemini (flash model) for natural language commands; parallel LLM analysis (OpenAI GPT-4.1, Google Gemini, Anthropic Claude) for brief extraction
- Auth: Azure AD MSAL (PKCE flow); JWT validation with PyJWT; dev mode bypass support
- Real-time: WebSocket (Quart native) for job progress streaming
- Key libraries: axios, react-query, TypeScript, pydantic, asyncpg, aiohttp, PyJWT
Architecture
AC Helper follows a client-server architecture with a single Apache reverse proxy fronting all traffic:
┌─────────────────────────────────────────────────────────────────┐
│ Browser (React SPA) │
│ - CommandBar (AI natural language input) │
│ - Handsontable grid (deliverable editing) │
│ - Brief upload interface │
│ - Admin panels │
└────────────────────┬────────────────────────────────────────────┘
│ HTTPS
▼
┌─────────────────────────┐
│ Apache (optical-web-1) │
│ - TLS terminator │
│ - Reverse proxy │
└──┬──────────────────┬───┘
│ │
┌──────▼─────────┐ ┌───▼──────────┐
│ Static files │ │ API/WS proxy │
│ /var/www/html/ │ │ :8100→:8000 │
│ ac-helper/ │ └───┬──────────┘
└────────────────┘ │
▼
┌────────────────────────────┐
│ Docker: ac-tool (Quart) │
│ - REST API blueprints │
│ - WebSocket handler │
│ - Background job workers │
│ - asyncpg pool │
└────────────┬───────────────┘
│
▼
┌────────────────────────────┐
│ Docker: ac-tool-db │
│ PostgreSQL 16 (named vol) │
└────────────────────────────┘
Key components:
- Frontend: Vite SPA with Zustand state store; Handsontable for grid UI; Quart WebSocket listener for real-time job progress
- Backend: Blueprints split by domain (auth, sheets, jobs, ai, export, dropdowns, admin, clients); sheets manager handles CRUD with JSONB persistence; job manager queues and executes background tasks; AI command processor validates against dropdown constraints then calls Gemini
- Database: PostgreSQL with sheets stored as JSONB; clients, users, exports as relational tables
- Job system: In-memory queue with asyncio locks for concurrency control; background workers process brief extraction, exports, etc.; results broadcast via WebSocket
Dev Commands
Option A — Backend only (fastest for API work):
cd /Users/ai_leed/Documents/Projects/Oliver/ac-helper
git clone git@bitbucket.org:zlalani/ac-helper.git
cp .env.example .env
# Edit .env: set DEV_MODE=true, GEMINI_API_KEY, POSTGRES_PASSWORD
# Start a separate PostgreSQL container:
docker run -d --name ac-pg \
-e POSTGRES_DB=achelper \
-e POSTGRES_USER=achelper \
-e POSTGRES_PASSWORD=achelper \
-p 5432:5432 postgres:16-alpine
# Terminal 1: Backend
cd backend
pip install -r requirements.txt
python run_server.py
# Listens on http://localhost:8000
# Terminal 2: Frontend dev server
cd frontend
npm install
npm run dev
# Listens on http://localhost:5173; proxies /api to localhost:8000
Option B — Full Docker Compose (preferred for realistic testing):
cd /Users/ai_leed/Documents/Projects/Oliver/ac-helper
cp .env.example .env
# Edit .env: GEMINI_API_KEY, SESSION_SECRET, POSTGRES_PASSWORD (at minimum)
docker compose up --build
# Access http://localhost:8100
Build frontend only:
cd frontend && npm run build
# Output: dist/ (served by Apache in prod)
Run tests:
cd backend && pytest
Deployment
- Server: optical-web-1 (ai-sandbox.oliver.solutions)
- Deploy:
sudo ./deploy.sh(run from project root as root) - URL: https://ai-sandbox.oliver.solutions/ac-helper/
- Port: 8100 (internal Docker port; Apache proxies from 443)
- Service: Docker Compose (no systemd service; containers use
restart: unless-stopped) - Local path: /Users/ai_leed/Documents/Projects/Oliver/ac-helper
Deploy process (automated by deploy.sh):
- Validates
.envexists and required keys are set - Checks Docker, docker compose, and git are installed
git pull --ff-only(no merges)docker compose build --pull(rebuilds both containers)- Extracts frontend dist to
/var/www/html/ac-helper/and fixes ownership docker compose down && docker compose up -d(blue-green restart)- Waits for PostgreSQL healthcheck and app
/healthendpoint - Rollback:
git revert <commit>+./deploy.sh(or manualdocker compose down && git checkout <previous> && docker compose up)
Environment Variables
| Variable | Purpose | Dev default | Production | Required |
|---|---|---|---|---|
DEV_MODE |
Bypass Azure AD auth; allow all endpoints | true |
false |
Yes |
DATABASE_URL |
PostgreSQL connection string | postgresql://achelper:achelper@localhost:5432/achelper |
Built from POSTGRES_PASSWORD |
Yes |
POSTGRES_PASSWORD |
DB password | achelper_secret |
Set in .env (secret) |
Yes |
SESSION_SECRET |
JWT signing key | change-me-in-production |
Long random string (50+ chars) | Yes |
GEMINI_API_KEY |
Google Gemini API key (AI commands) | (empty) | Set in .env |
Yes |
GEMINI_MODEL |
Gemini model identifier | gemini-3-flash-preview |
gemini-3-flash-preview |
No |
OPENAI_API_KEY |
OpenAI API key (brief extractor) | (empty) | Set in .env |
Optional |
OPENAI_MODEL |
OpenAI model identifier | gpt-4.1 |
gpt-4.1 |
No |
ANTHROPIC_API_KEY |
Anthropic Claude API key (brief extractor) | (empty) | Set in .env |
Optional |
ANTHROPIC_MODEL_SONNET |
Claude model identifier | claude-sonnet-4-5-20250929 |
claude-sonnet-4-5-20250929 |
No |
AZURE_TENANT_ID |
Azure AD tenant | (from .env.example) | e519c2e6-bc6d-4fdf-8d9c-923c2f002385 |
Yes (prod) |
AZURE_CLIENT_ID |
Azure AD app registration | (from .env.example) | 9079054c-9620-4757-a256-23413042f1ef |
Yes (prod) |
AZURE_REDIRECT_URI |
OAuth callback URL | http://localhost:5173/ |
https://ai-sandbox.oliver.solutions/ac-helper/ |
Yes (prod) |
ADMIN_EMAILS |
Comma-separated admin emails | (empty) | daveporter@oliver.agency,vadymsamoilenko@oliver.agency |
No |
ADMIN_EMAIL |
Primary admin email | (empty) | daveporter@oliver.agency |
No |
EMERGENCY_TOKEN |
Bypass SSO token (for outages) | (empty) | Set in .env; leave blank to disable |
Optional |
MAX_CONCURRENT_JOBS |
Max parallel job queue size | 5 |
5 |
No |
MAX_UPLOAD_SIZE_MB |
Sessions
2026-04-14 – Project catalogued
Done: Added to Obsidian second brain.
Change Log
| Date | Requested | Changed | Files |
|---|---|---|---|
| 2026-04-14 | Initial setup | Note created | — |