---
name: "Oliver DeckForge"
client: Oliver Internal / Multi-tenant
status: active
server: optical-dev
tech: [Next.js 14, FastAPI, PostgreSQL, Redis, SQLModel, Anthropic/OpenAI/Google APIs, Puppeteer]
local_path: /Users/ai_leed/Documents/Projects/Oliver/ppt-tool
deploy: make dev (local) | Apache2 reverse proxy (prod)
url: https://optical-dev.oliver.solutions/ppt-tool/
tags: [oliver, presentation, ai, nextjs, multi-tenant, rbac]
created: 2026-04-14
port: 80/443
db: PostgreSQL 16
---

## Overview

**ppt-tool** is an AI-powered enterprise presentation generator that transforms user-provided topics, URLs, or documents into complete branded PPTX/PDF slide decks. It serves Oliver Internal and multi-tenant Oliver Agency clients with features including Azure AD SSO, RBAC, client isolation, review workflows, and custom master deck template support. The system combines LLM-driven content generation with enterprise-grade security, image generation, and export capabilities.

## Tech Stack

- **Frontend:** Next.js 14 (App Router), React, Redux Toolkit, Shadcn UI, TypeScript
- **Backend:** FastAPI, SQLModel (ORM), Alembic (migrations), arq (async queue), Python 3.11
- **Database:** PostgreSQL 16
- **Infrastructure:** Docker Compose, Apache2 reverse proxy, nginx (dev only)
- **AI/ML:** Anthropic Claude, OpenAI GPT, Google Gemini, multi-provider image generation
- **Key libraries:** python-pptx, PyMuPDF, Puppeteer (PDF export), MSAL (Azure AD), aiohttp

## Architecture

**ppt-tool** follows a three-tier microservices architecture:

```
┌─────────────────────────────────────────────┐
│   Apache2 Reverse Proxy (Production)        │
│   /ppt-tool/* → web:3000 | /api/* → api:8000
└────────────────┬────────────────────────────┘
         ┌───────┴───────┐
    ┌────┴─────┐   ┌─────┴────┐
    │ Next.js   │   │ FastAPI  │
    │ (web:3000)│   │ (api:8000)
    └────┬─────┘   └────┬─────┘
         │              │
         │         ┌────┴──────┐
         │    ┌────┴──┐  ┌─────┴──────┐
         └────│ PostgreSQL  │  Redis 7     │
              │ (5432)      │  (6379)      │
              └─────────────┴──────────────┘
```

**Component breakdown:**

| Component | Role |
|-----------|------|
| **web (Next.js 14)** | React SPA with Redux state, Shadcn UI components, PDF export via Puppeteer API route |
| **api (FastAPI)** | REST API (routers in `backend/api/v1/`), auth (JWT + Azure AD), RBAC, SSE streaming for job progress |
| **worker (arq)** | Background async job processor running on Redis queue — handles long-running LLM calls and content generation |
| **postgres** | Primary database: users, clients, presentations, templates, OAuth tokens, generated metadata |
| **redis** | Job queue for arq + pub/sub for real-time progress streaming |

**Core data flow (presentation generation pipeline):**

1. **Input** → Frontend posts topic/URL/files to `/api/v1/ppt/presentation/create`
2. **Summarization** → LLM condenses raw content into structured sections
3. **Outline generation** → LLM generates per-slide outlines (title + bullets) via streaming
4. **Layout selection** → LLM/rules map each outline to a slide layout template
5. **Slide content generation** → Concurrent batches of 10 slides — LLM fills layout fields with content
6. **Image generation** → Optional AI images inserted per slide
7. **Export** → python-pptx creates PPTX; Puppeteer converts to PDF
8. **Storage** → Files saved to `app_data/exports/`; references stored in database

**Backend layers:**

| Layer | Path | Purpose |
|-------|------|---------|
| Routers | `backend/api/v1/` | FastAPI route definitions, request validation |
| Services | `backend/services/` | Business logic: auth, image gen, brand enforcement, PPTX creation |
| Workers | `backend/workers/` | arq task definitions for background jobs |
| Models (SQL) | `backend/models/sql/` | SQLModel ORM table definitions |
| Models (Pydantic) | `backend/models/` | Request/response schemas |
| Utils | `backend/utils/` | LLM wrappers, export helpers, asset management |

**Key services:**

- `AuthService` → Azure AD MSAL + dev-bypass JWT creation
- `ImageGenerationService` → Multi-provider image gen (Anthropic, OpenAI, Google)
- `BrandEnforcementService` → Per-client brand context injection for LLM prompts
- `PptxPresentationCreator` → python-pptx slide generation and layout enforcement

## Dev Commands

```bash
# Clone and setup (first time)
cd /Users/ai_leed/Documents/Projects/Oliver/ppt-tool
cp .env.example .env
# Edit .env: set ANTHROPIC_API_KEY, JWT_SECRET_KEY, DEV_AUTH_PASSWORD

# Start all services (Docker, recommended)
make dev

# Run database migrations (first time)
make migrate

# Seed initial data (first time)
make seed

# Open app
open http://localhost

# View logs
make logs

# Stop services
make down

# Backend tests
make test

# E2E tests (Cypress)
make test-e2e

# Shell into API container
make shell-api

# Connect to database
make shell-db

# Fast code-only update (skips rebuild)
./update.sh

# Database operations
make shell-api
alembic upgrade head              # Run migrations
alembic revision --autogenerate -m "message"  # Create migration
alembic downgrade -1              # Rollback
```

**Without Docker:**

```bash
# Backend
cd backend
python3.11 -m venv venv
source venv/bin/activate
pip install -e .
export DATABASE_URL="postgresql+asyncpg://deckforge:deckforge@localhost:5432/deckforge"
export REDIS_URL="redis://localhost:6379/0"
export JWT_SECRET_KEY="..."
uvicorn api.main:app --reload --port 8000

# Frontend (separate terminal)
cd frontend
npm install
npm run dev  # Proxies /api/v1/* to http://localhost:8000
```

## Deployment

- **Server:** optical-dev.oliver.solutions
- **Deploy:** Apache2 reverse proxy (`apache/deckforge.conf`); Docker services managed via systemd or manual `docker compose` on host
- **URL:** `https://optical-dev.oliver.solutions/ppt-tool/`
- **Port:** 80 (HTTP) / 443 (HTTPS, via Apache); internal services: api:8000, web:3000, postgres:5432, redis:6379
- **Service:** Manual deployment; use `./update.sh` for fast code-only pushes or rebuild full stack with `docker compose up`
- **Local path:** /Users/ai_leed/Documents/Projects/Oliver/ppt-tool

**Apache proxy rules:**

| Rule | Target |
|------|--------|
| `/ppt-tool/api/v1/` | http://127.0.0.1:API_PORT/api/v1/ (basePath stripped) |
| `/ppt-tool/` | http://127.0.0.1:WEB_PORT/ppt-tool/ (basePath intact) |
| `/ppt-tool/app_data/`, `/ppt-tool/static/` | FastAPI static serve |

**Key Apache settings:** SSE enabled (no-gzip, proxy-sendchunked), 100 MB upload limit, security headers (X-Content-Type-Options, X-Frame-Options, etc.).

## Environment Variables

| Variable | Description |
|----------|-------------|
| `POSTGRES_PASSWORD` | PostgreSQL password (default: `deckforge`) |
| `DATABASE_URL` | Full asyncpg connection URL; auto-derived if not set |
| `DB_POOL_SIZE` | Connection pool size (default: 20) |
| `REDIS_URL` | Redis connection URL (default: `redis://localhost:6379/0`) |
| `JWT_SECRET_KEY` | **Required** — Random 256-bit string for JWT signing |
| `DEV_AUTH_PASSWORD` | **Required** — Bypass auth password for dev login (any email) |
| `ANTHROPIC_API_KEY` | Anthropic Claude API key |
| `OPENAI_API_KEY` | OpenAI API key for GPT models |
| `GOOGLE_API_KEY` | Google Gemini API key |
| `AZURE_AD_CLIENT_ID` | Azure AD app registration client ID |
| `AZURE_AD_TENANT_ID` | Azure AD tenant ID |
| `PUPPETEER_EXECUTABLE_PATH` | Path to Chromium/Chrome for PDF export |

## API / Endpoints

**Key endpoints (base: `/api/v1/`):**

| Method | Endpoint | Purpose |
|--------|----------|---------|
| POST | `/auth/login` | Dev/Azure AD login — returns JWT |
| POST | `/ppt/presentation/create` | Create presentation from topic/URL/files |
| GET | `/ppt/presentation/{id}` | Fetch presentation metadata + progress |
| GET | `/ppt/presentation/{id}/stream` | SSE stream for real-time generation progress |
| POST | `/ppt/presentation/{id}/regenerate-slide` | Regenerate single slide content |
| GET | `/ppt/presentation/{id}/export/{format}` | Download PPTX or PDF |
| POST | `/clients/{client_id}/master-decks` | Upload custom

## Sessions
### 2026-05-12 – Check repo updates, pull them, and
**Asked:** Check repo updates, pull them, and investigate why the server returns 503.
**Done:** Checked latest commit (e63f790 from March 23, 2026 fixing MSAL config) and identified it was from a team member's work on Docker build args.

### 2026-05-12 – Check repo updates and investigate 503
**Asked:** Check repo updates and investigate 503 server error.
**Done:** Identified that all Docker containers were stopped after server reboot on April 30 with no systemd service for auto-restart; latest commit is e63f790 with intact data.

### 2026-05-12 – Check repository updates and investigate 503
**Asked:** Check repository updates and investigate 503 server errors | Pulled latest code and diagnosed container failures causing service unavailability | docker-compose.yml, Apache config logs
**Done:** Repository sync and server debugging | Code updated, identified stopped Docker containers as 503 cause | Container logs, server status files

### 2026-04-14 – Project catalogued
**Done:** Added to Obsidian second brain.

---
## Change Log
| Date | Requested | Changed | Files |
|------|-----------|---------|-------|
| 2026-05-12 | Repo maintenance | Git pull, MSAL config verification, 503 error investigation | docker-compose.yml, .env, config files |
| 2026-05-12 | Repo updates, Docker restart | Pull latest code, restart docker compose containers, add systemd service for auto-start | docker-compose.yml, systemd config |
| 2026-05-12 | Repo update & 503 diagnosis | Pull latest changes, restart containers, check Apache/Docker status | docker-compose.yml, Apache logs, container configs |
| 2026-04-14 | Initial setup | Note created | — |

## Related
- [[presenton/Presenton]]