ppt-tool/docs/02-System-Administration-Guide.md
Vadym Samoilenko 8cbe01dfa6 Add project documentation: User Manual and System Administration Guide
PDF documents with Mermaid diagrams, styled with purple theme.
Includes build script for regenerating PDFs from Markdown sources.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:06:28 +00:00

1333 lines
41 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
pdf_options:
format: A4
margin: 25mm 20mm
headerTemplate: '<div style="font-size:8px;color:#999;width:100%;text-align:right;margin-right:20mm;">Oliver DeckForge &mdash; System Administration Guide</div>'
footerTemplate: '<div style="font-size:8px;color:#999;width:100%;text-align:center;"><span class="pageNumber"></span> / <span class="totalPages"></span></div>'
displayHeaderFooter: true
stylesheet:
- https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown.min.css
body_class: markdown-body
css: |-
body { font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; }
.markdown-body { max-width: 100%; }
h1 { color: #5146E5; border-bottom: 3px solid #5146E5; padding-bottom: 8px; }
h2 { color: #3b3494; border-bottom: 1px solid #E9E8F8; padding-bottom: 6px; margin-top: 2em; }
h3 { color: #4a4a4a; }
h4 { color: #555; }
table { width: 100%; }
th { background: #5146E5; color: white; }
td, th { padding: 8px 12px; }
code { background: #f0eff8; color: #5146E5; padding: 2px 6px; border-radius: 4px; }
pre code { background: #1e1e2e; color: #cdd6f4; display: block; padding: 16px; border-radius: 8px; }
blockquote { border-left: 4px solid #5146E5; background: #f8f7ff; padding: 12px 16px; margin: 16px 0; }
.tip { border-left: 4px solid #22c55e; background: #f0fdf4; padding: 12px 16px; margin: 16px 0; border-radius: 0 8px 8px 0; }
.warning { border-left: 4px solid #f59e0b; background: #fffbeb; padding: 12px 16px; margin: 16px 0; border-radius: 0 8px 8px 0; }
.danger { border-left: 4px solid #ef4444; background: #fef2f2; padding: 12px 16px; margin: 16px 0; border-radius: 0 8px 8px 0; }
img { max-width: 100%; max-height: 280px; object-fit: contain; display: block; margin: 16px auto; }
---
# Oliver DeckForge — System Administration Guide
**Version 1.0** | Complete Setup, Configuration & Operations Reference
---
## Table of Contents
1. [Architecture Overview](#1-architecture-overview)
2. [Installation & Deployment](#2-installation--deployment)
3. [Environment Variables Reference](#3-environment-variables-reference)
4. [Authentication Configuration](#4-authentication-configuration)
5. [Role-Based Access Control](#5-role-based-access-control)
6. [Admin Panel Operations](#6-admin-panel-operations)
7. [Template Pipeline](#7-template-pipeline)
8. [AI Provider Configuration](#8-ai-provider-configuration)
9. [Database Administration](#9-database-administration)
10. [Background Jobs & Workers](#10-background-jobs--workers)
11. [Nginx & Networking](#11-nginx--networking)
12. [Storage & File Management](#12-storage--file-management)
13. [Monitoring & Logging](#13-monitoring--logging)
14. [Backup & Recovery](#14-backup--recovery)
15. [Security Hardening](#15-security-hardening)
16. [Scaling & Performance](#16-scaling--performance)
17. [Troubleshooting](#17-troubleshooting)
18. [API Reference](#18-api-reference)
---
## 1. Architecture Overview
### 1.1 System Architecture
```mermaid
graph LR
Browser([Browser]) --> NG[nginx :80]
NG --> NX[Next.js :3000]
NG --> FA[FastAPI :8000]
FA --> PG[(PostgreSQL)]
FA --> RD[(Redis)]
FA --> VOL[/app_data/]
ARQ[ARQ Worker] --> PG
ARQ --> RD
ARQ --> VOL
FA --> AI{AI APIs}
ARQ --> AI
```
### 1.2 Service Overview
| Service | Technology | Port | Purpose |
|---------|-----------|------|---------|
| **nginx** | nginx:alpine | 80 | Reverse proxy, static file serving, SSL termination |
| **web** | Next.js 14 | 3000 | Frontend SPA, Puppeteer-based export |
| **api** | FastAPI + SQLModel | 8000 | REST API, authentication, RBAC |
| **worker** | ARQ (Python) | — | Background AI generation, parsing, retention |
| **postgres** | PostgreSQL 16 | 5432 | Primary relational database |
| **redis** | Redis 7 | 6379 | Job queue, caching |
### 1.3 Request Flow
```mermaid
sequenceDiagram
participant B as Browser
participant N as nginx
participant W as Next.js
participant A as FastAPI
participant M as Middleware
participant DB as PostgreSQL
B->>N: HTTP Request
alt /api/v1/*
N->>A: Proxy to backend
A->>M: Auth + RBAC check
M->>DB: Validate session
DB-->>M: User context
M-->>A: request.state.user
A-->>N: JSON response
else /* (all other)
N->>W: Proxy to frontend
W-->>N: HTML/JS/CSS
end
N-->>B: Response
```
### 1.4 Data Flow: Presentation Generation
```mermaid
flowchart LR
A[Submit] --> B[Decompose] --> C[Outline] --> D[Template]
D --> E[Job Queue] --> F[Worker]
F --> G[AI Content] --> H[Images] --> I[Save DB]
I --> J[SSE Notify] --> K[Editor]
```
---
## 2. Installation & Deployment
### 2.1 Prerequisites
| Requirement | Minimum | Recommended |
|-------------|---------|-------------|
| Docker | 20.10+ | 24.0+ |
| Docker Compose | v2.0+ | v2.20+ |
| RAM | 4 GB | 8 GB+ |
| Disk | 10 GB | 50 GB+ (for generated assets) |
| CPU | 2 cores | 4+ cores |
### 2.2 Quick Start
```bash
# 1. Clone repository
git clone <repository-url>
cd ppt-tool
# 2. Configure environment
cp .env.example .env
# Edit .env — set ANTHROPIC_API_KEY at minimum
# 3. Build and start
make dev
# 4. Run migrations
make migrate
# 5. Seed default data
make seed
```
The application is available at:
- **http://localhost** — Full application (via nginx)
- **http://localhost:3000** — Frontend directly
- **http://localhost:8000** — API directly
- **http://localhost/docs** — Swagger API documentation
### 2.3 Makefile Commands
| Command | Description |
|---------|-------------|
| `make dev` | Build and start all services with logs |
| `make build` | Build Docker images only |
| `make up` | Start services in background (detached) |
| `make down` | Stop and remove all containers |
| `make migrate` | Run Alembic database migrations |
| `make seed` | Seed default admin user and team |
| `make test` | Run backend pytest suite |
| `make test-e2e` | Run Cypress E2E tests |
| `make test-all` | Run all tests |
| `make logs` | Follow all container logs |
| `make shell-api` | Open bash shell in API container |
| `make shell-db` | Open psql shell in PostgreSQL |
### 2.4 Local Development (Without Docker)
#### Backend
```bash
cd backend
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
export DATABASE_URL="postgresql+asyncpg://deckforge:deckforge@localhost:5432/deckforge"
export REDIS_URL="redis://localhost:6379/0"
export APP_DATA_DIRECTORY="./data"
export ANTHROPIC_API_KEY="sk-ant-..."
# Start API
uvicorn api.main:app --reload --port 8000
# Start worker (separate terminal)
python -m arq workers.main.WorkerSettings
```
#### Frontend
```bash
cd frontend
npm install
npm run dev
```
The Next.js dev server proxies `/api/v1/` requests to `http://localhost:8000` via rewrites in `next.config.mjs`.
### 2.5 Docker Image Details
**Backend Dockerfile** (multi-stage):
- **Builder stage**: `python:3.11-slim-bookworm` + `uv` package manager
- **Runtime stage**: Includes LibreOffice (PDF conversion), Chromium (browser automation), fontconfig, ONNX models
- Exposes port 8000
**Frontend Dockerfile**:
- **Base**: `node:20-alpine`
- Includes Chromium for server-side Puppeteer PDF/PPTX export
- Environment: `PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser`
- Exposes port 3000
---
## 3. Environment Variables Reference
### 3.1 Database & Infrastructure
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `POSTGRES_PASSWORD` | No | `deckforge` | PostgreSQL password |
| `DATABASE_URL` | Auto | Set by docker-compose | Full async connection string |
| `REDIS_URL` | No | `redis://redis:6379/0` | Redis connection string |
| `APP_DATA_DIRECTORY` | No | `/app_data` | Path for images, exports, uploads |
| `TEMP_DIRECTORY` | No | `/tmp/deckforge` | Temporary file storage |
### 3.2 Authentication
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `JWT_SECRET_KEY` | **Yes** | `change-me-...` | Secret for JWT signing (256-bit+) |
| `AZURE_AD_TENANT_ID` | No | — | Azure AD tenant ID (blank = dev mode) |
| `AZURE_AD_CLIENT_ID` | No | — | Azure AD app client ID |
| `AZURE_AD_CLIENT_SECRET` | No | — | Azure AD app secret |
| `AZURE_AD_REDIRECT_URI` | No | `http://localhost/api/v1/auth/callback` | OAuth callback URL |
| `DEV_AUTH_PASSWORD` | No | `devpass123` | Dev bypass login password |
### 3.3 AI Providers
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `LLM` | No | `anthropic` | Primary LLM provider |
| `ANTHROPIC_API_KEY` | **Yes*** | — | Claude API key |
| `ANTHROPIC_MODEL` | No | `claude-sonnet-4-6` | Claude model ID |
| `OPENAI_API_KEY` | No | — | OpenAI API key |
| `OPENAI_MODEL` | No | — | OpenAI model ID |
| `GOOGLE_API_KEY` | No | — | Google Gemini API key |
| `GOOGLE_MODEL` | No | — | Google model ID |
| `OLLAMA_URL` | No | — | Ollama server URL |
| `OLLAMA_MODEL` | No | — | Ollama model name |
| `IMAGE_PROVIDER` | No | `nanobanana_pro` | Image generation provider |
| `DISABLE_IMAGE_GENERATION` | No | — | Set to disable image gen |
*Required if using Anthropic (default provider)
### 3.4 Application Settings
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `CAN_CHANGE_KEYS` | No | `false` | Allow runtime API key changes |
| `DISABLE_ANONYMOUS_TRACKING` | No | `true` | Disable analytics tracking |
| `SETTINGS_ENCRYPTION_KEY` | No | — | Fernet key for encrypting stored API keys |
| `EXTENDED_REASONING` | No | — | Enable LLM extended thinking |
| `TOOL_CALLS` | No | — | Enable LLM tool use |
| `WEB_GROUNDING` | No | — | Enable web search in generation |
| `NEXT_INTERNAL_URL` | No | `http://web:3000` | Backend → frontend URL (Docker) |
### 3.5 Supported AI Providers
**LLM Providers:**
| Provider | Value | Models |
|----------|-------|--------|
| Anthropic | `anthropic` | claude-opus-4-6, claude-sonnet-4-6, claude-sonnet-4-5, claude-haiku-4-5 |
| OpenAI | `openai` | gpt-4.1, gpt-4.1-mini, gpt-4o, o3, o4-mini |
| Google | `google` | gemini-2.5-flash, gemini-2.5-pro, gemini-2.0-flash |
| Ollama | `ollama` | Any locally installed model |
| Custom | `custom` | Any OpenAI-compatible endpoint |
**Image Providers:**
| Provider | Value | Requirements |
|----------|-------|-------------|
| NanoBanana Pro | `nanobanana_pro` | Google API key |
| Gemini Flash | `gemini_flash` | Google API key |
| DALL-E 3 | `dall-e-3` | OpenAI API key |
| GPT Image 1.5 | `gpt-image-1.5` | OpenAI API key |
| Pexels | `pexels` | Pexels API key |
| Pixabay | `pixabay` | Pixabay API key |
| ComfyUI | `comfyui` | Local ComfyUI instance |
---
## 4. Authentication Configuration
### 4.1 Authentication Flow
```mermaid
flowchart LR
A[Login Page] --> B{Azure AD?}
B -->|Yes| C[SSO] --> D[Callback] --> E{User exists?}
B -->|No| F[Dev Login] --> E
E -->|Yes| G[Update login]
E -->|No| H[Create user]
G --> I[JWT Cookie]
H --> I
```
### 4.2 Azure AD Setup (Production)
1. **Register an application** in Azure Portal > Azure AD > App Registrations
2. Set the **Redirect URI** to: `https://your-domain.com/api/v1/auth/callback`
3. Create a **client secret** under Certificates & Secrets
4. Configure environment variables:
```env
AZURE_AD_TENANT_ID=your-tenant-id
AZURE_AD_CLIENT_ID=your-client-id
AZURE_AD_CLIENT_SECRET=your-client-secret
AZURE_AD_REDIRECT_URI=https://your-domain.com/api/v1/auth/callback
```
5. Grant API permissions: `User.Read` (delegated)
### 4.3 Development Mode
When `AZURE_AD_TENANT_ID` is empty or not set, the system enables development authentication:
- Login form with email + password fields
- Password validated against `DEV_AUTH_PASSWORD` environment variable
- Users are auto-created on first login
- Default role: `user`
<div class="danger">
**Security Warning:** Development mode should never be used in production. Always configure Azure AD or another SSO provider for production deployments.
</div>
### 4.4 JWT Configuration
| Parameter | Value |
|-----------|-------|
| Algorithm | HS256 |
| Expiry | 24 hours |
| Storage | `session_token` HTTP cookie |
| Payload | `sub` (user UUID), `email`, `role`, `exp`, `iat` |
<div class="warning">
**Critical:** Change `JWT_SECRET_KEY` from the default value in production. Use a cryptographically random 256-bit key. All active sessions are invalidated when this key changes.
</div>
---
## 5. Role-Based Access Control
### 5.1 Role Hierarchy
```mermaid
graph LR
SA[Super Admin] --> CA[Client Admin] --> U[User]
SA -.->|Full access| ALL[All Clients]
CA -.->|Scoped| CLIENT[Assigned Clients]
U -.->|Basic| OWN[Own Data]
```
### 5.2 Permission Matrix
| Feature | Super Admin | Client Admin | User |
|---------|:-----------:|:------------:|:----:|
| **Presentations** | All | Client-scoped | Own only |
| **Admin Panel** | Full | Limited | None |
| **User Management** | CRUD all | View team members | — |
| **Client Management** | CRUD all | View/edit assigned | — |
| **Team Management** | All teams | Assigned client teams | — |
| **Master Decks** | All | Client-scoped | — |
| **Storage** | All clients | Client-scoped | — |
| **Analytics** | Global + per-client | Client-scoped | — |
| **Audit Logs** | All | Client-scoped | — |
| **System Settings** | Full access | — | — |
| **Brand Config** | All clients | Client-scoped | — |
### 5.3 Multi-Tenant Data Isolation
```mermaid
flowchart LR
A[Request] --> B[Auth] --> C[RBAC] --> D{Role}
D -->|super_admin| E[No filter]
D -->|client_admin| F[Team lookup → client_ids]
D -->|user| G[Own data + team clients]
```
The `_resolve_client_filter()` pattern is used throughout:
- **Super Admin with no client_id param** → Returns `None` (no filter, see all)
- **Super Admin with client_id param** → Filters to specific client
- **Client Admin** → Auto-scoped to accessible clients via `TeamMembershipModel`
- **User** → Scoped to own data within accessible clients
### 5.4 Admin Panel Navigation
The sidebar dynamically shows menu items based on role:
| Menu Item | Super Admin | Client Admin |
|-----------|:-----------:|:------------:|
| Users | Yes | — |
| Clients | Yes | Yes |
| Storage | Yes | Yes |
| Audit Log | Yes | Yes |
| Analytics | Yes | Yes |
| Settings | Yes | — |
---
## 6. Admin Panel Operations
### 6.1 User Management
**Path:** Admin > Users (Super Admin only)
#### Listing Users
- Table with columns: Name, Email, Role, Status, Last Login
- Filterable by active status and role
#### Changing User Roles
1. Find the user in the list
2. Click the role dropdown
3. Select new role: `super_admin`, `client_admin`, or `user`
<div class="warning">
You cannot change your own role. This prevents accidental lockout.
</div>
#### Deactivating Users
1. Click **Deactivate** on the user row
2. Confirm the action
3. User's `is_active` is set to false — they can no longer log in
4. Their presentations remain in the system
#### Transferring Ownership
Before deactivating a user (e.g., for GDPR compliance):
1. Use the transfer ownership endpoint to move all presentations to another user
2. Then deactivate the original user
### 6.2 Client Management
**Path:** Admin > Clients
#### Creating a Client
1. Click **"+ New Client"**
2. Enter the client name
3. A URL-safe slug is auto-generated
4. A default team is auto-created for the client
#### Client Settings
Each client has configurable:
| Setting | Description |
|---------|-------------|
| **Name** | Display name |
| **Slug** | URL-safe identifier (unique) |
| **Review Policy** | `self_approve` or `require_reviewer` |
| **Retention Days** | Auto-delete presentations after N days (optional) |
### 6.3 Team Management
**Path:** Admin > Clients > [Client] > Teams
Teams group users within a client:
- Each client has a **default team** (cannot be deleted)
- Users can belong to multiple teams
- Team membership determines client access for non-admin users
#### Adding Team Members
1. Navigate to the client's team page
2. Click **"+ Add Member"**
3. Search and select a user from the dropdown
4. The user now has access to this client's data
### 6.4 Brand Configuration
**Path:** Admin > Clients > [Client] > Brand Config
Configure branding per client:
| Setting | Description |
|---------|-------------|
| **Primary Colors** | Color picker, add/remove multiple colors |
| **Secondary Colors** | Color picker, add/remove multiple colors |
| **Fonts** | Heading, Body, and Accent font names |
| **Logos** | Upload multiple logo images |
| **Voice Rules** | Text guidelines for AI tone and style |
| **Voice Examples** | Good/bad example pairs for AI training |
| **Brand Guideline** | Upload a PDF/DOCX brand guide |
Brand configuration is injected into AI prompts during presentation generation to ensure brand consistency.
### 6.5 Storage Management
**Path:** Admin > Storage
#### Summary Dashboard
Four cards show:
- **Presentations** count
- **Export Files** count
- **Master Decks** count
- **Total Size** (formatted)
#### Client Selector (Super Admin)
Dropdown to filter by specific client or view all clients combined.
#### Presentation Table
- Columns: Title, Status, Created, Files, Size
- Checkboxes for bulk selection
- Per-row actions: Download PPTX, Delete
#### Bulk Operations
- Select multiple presentations via checkboxes
- Click **"Delete Selected"** for bulk soft-delete
#### Purge Files (Super Admin Only)
- Amber banner shows count of soft-deleted presentations
- **"Purge Files"** permanently removes files from disk
- Returns statistics: files purged, bytes freed
### 6.6 Analytics Dashboard
**Path:** Admin > Analytics
#### Overview Metrics
- Total Presentations (all-time)
- This Month / This Week (30/7-day counts)
- Active Users (distinct users, last 30 days)
- Approval Rate (% approved or in_review)
#### Usage Metrics
- **Presentations per Day** — 14-day bar chart
- **Top 10 Users** — ranked by presentation count
#### Quality Metrics
- **Status Distribution** — draft/in_review/approved breakdown
- **Presentations with Comments** — count
#### Performance Metrics
- **Average Generation Time** — job completion duration
- **Total Jobs** — all-time count
- **Error Rate** — % failed jobs
#### AI Usage (if tracking enabled)
- Total AI Calls, Input/Output Tokens
- Usage by Provider (bar chart)
- Usage by Model (top 10)
- Daily Usage Trend
### 6.7 Audit Logs
**Path:** Admin > Audit Log
All mutating API requests are logged automatically.
#### Query Filters
- **Action** — text search (e.g., "admin_delete")
- **User ID** — filter by specific user
- **Resource Type** — e.g., "presentation", "storage"
- **Client ID** — scope to a client
- **Date Range** — from/to date pickers
#### Export
- Click **"Export Audit Log"**
- Choose format: CSV or JSON
- Downloads up to 10,000 entries
#### Logged Actions
| Action | Trigger |
|--------|---------|
| `admin_delete` | Single presentation soft-delete |
| `admin_bulk_delete` | Bulk presentation delete |
| `admin_purge` | Hard-delete purged files |
| Role changes, team membership updates, etc. | Various admin operations |
---
## 7. Template Pipeline
### 7.1 Master Deck → Template Flow
```mermaid
flowchart LR
A[Upload PPTX] --> B[Enqueue Job]
B --> C{Parse Mode}
C -->|layouts| D[slideLayouts XML]
C -->|slides| E[slides XML]
D --> F[PDF → Screenshots]
E --> F
F --> G[LLM Vision: Screenshot+XML → TSX]
G --> H[Store Layouts] --> I[Register Template]
```
### 7.2 Upload & Parse
1. Navigate to **Admin > Clients > [Client] > Master Decks**
2. Click **"Upload PPTX"** and select a `.pptx` file
3. The deck enters **"pending"** status, then **"processing"**
4. Auto-polling every 5 seconds shows current status
5. On completion, status changes to **"completed"** and layouts appear
### 7.3 Parse Modes
| Mode | Source | Best For |
|------|--------|----------|
| **slides** (default) | Actual slides (`ppt/slides/`) | Decks with unique slide designs; 1:1 screenshot match |
| **layouts** | Slide layouts (`ppt/slideLayouts/`) | Decks with reusable layout templates; may produce more layouts |
### 7.4 Layout Management
After parsing, manage layouts in the expanded deck view:
**Filtering & Search:**
- Text search by layout name
- Type filter dropdown (auto-detected from layout types)
- Code filter: All / Has Code / Missing Code
**Individual Actions:**
- **Edit** — modify name, type, or React TSX code
- **Delete** — remove with confirmation dialog
**Bulk Actions:**
- Toggle **Select Mode** to show checkboxes
- **Select All** / **Deselect All**
- **Delete Selected** — bulk remove
<div class="tip">
After deleting layouts, the system automatically re-registers the template by recreating `PresentationLayoutCodeModel` records for the remaining layouts.
</div>
### 7.5 Reparsing
If layouts need to be regenerated (e.g., after an LLM model upgrade):
1. Click the reparse dropdown on the deck card
2. Choose **"Reparse (slides)"** or **"Reparse (layouts)"**
3. All existing layouts are replaced with freshly parsed versions
---
## 8. AI Provider Configuration
### 8.1 Settings Page
**Path:** Admin > Settings (Super Admin only)
```mermaid
flowchart LR
A[Select LLM Provider] --> B[Fetch Available Models]
B --> C[Select Model]
C --> D[Enter API Key]
D --> E[Test Connection]
E -->|OK| F[Save Settings]
E -->|Fail| G[Check Key / Network]
```
### 8.2 Configuring LLM Provider
1. Open **Admin > Settings**
2. Select the **LLM Provider** from the dropdown
3. The **Model** dropdown auto-populates with available models
4. Enter the **API Key** if not already set (shown as "Set" badge if configured)
5. Click **"Test"** to verify connectivity
6. Click **"Save Changes"**
### 8.3 Configuring Image Provider
1. Select the **Image Provider** from the dropdown
2. Ensure the required API key is set (e.g., Google API key for NanoBanana Pro)
3. Save changes
### 8.4 Connection Testing
The **"Test"** button performs a lightweight API call to validate the key:
| Result | Display |
|--------|---------|
| Success | Green check + latency in ms |
| Failure | Red X + error message |
### 8.5 Settings Persistence
Settings are persisted to the database via `KeyValueSqlModel`:
- Survive container restarts
- API keys optionally encrypted at rest (if `SETTINGS_ENCRYPTION_KEY` is set)
- Environment variables serve as defaults — database values override them
---
## 9. Database Administration
### 9.1 Schema Overview
```mermaid
erDiagram
UserModel ||--o{ TeamMembershipModel : "belongs to"
TeamModel ||--o{ TeamMembershipModel : "has"
ClientModel ||--o{ TeamModel : "owns"
ClientModel ||--o{ BrandConfigModel : "has"
ClientModel ||--o{ MasterDeckModel : "has"
UserModel ||--o{ PresentationModel : "creates"
ClientModel ||--o{ PresentationModel : "scopes"
PresentationModel ||--o{ SlideModel : "contains"
PresentationModel ||--o{ JobModel : "tracks"
UserModel ||--o{ AuditLogModel : "generates"
UserModel ||--o{ AIUsageModel : "tracks"
MasterDeckModel ||--o{ TemplateModel : "registers as"
TemplateModel ||--o{ PresentationLayoutCodeModel : "has layouts"
```
### 9.2 Core Tables
| Table | Purpose | Key Fields |
|-------|---------|------------|
| `usermodel` | User accounts | id, email, role, azure_oid, is_active |
| `clientmodel` | Tenant organizations | id, name, slug, retention_days, review_policy |
| `teammodel` | Team groupings | id, name, client_id, is_default |
| `teammembershipmodel` | User↔Team links | user_id, team_id, assigned_by |
| `presentationmodel` | Presentations | id, title, owner_id, client_id, status, content |
| `slidemodel` | Individual slides | id, presentation, index, content, layout |
| `jobmodel` | Background jobs | id, job_type, status, progress, error_message |
| `masterdeck` | Master PPTX decks | id, client_id, layouts (JSON), parse_status |
| `templatemodel` | Registered templates | id, name, description |
| `presentationlayoutcodemodel` | Layout TSX code | presentation, layout_name, layout_code |
| `brandconfigmodel` | Brand settings | client_id, colors, fonts, logos, voice_rules |
| `auditlogmodel` | Audit trail | user_id, action, resource_type, ip_address |
| `aiusagemodel` | AI usage metrics | provider, model, tokens, duration_ms |
| `keyvaluesqlmodel` | KV settings store | key, value (JSON) |
| `imageasset` | Generated images | id, path, is_uploaded |
### 9.3 Alembic Migrations
```bash
# View migration history
docker compose exec api alembic history
# Apply all pending migrations
make migrate
# or: docker compose exec api alembic upgrade head
# Generate new migration after model changes
docker compose exec api alembic revision --autogenerate -m "description"
# Rollback last migration
docker compose exec api alembic downgrade -1
# View current revision
docker compose exec api alembic current
```
<div class="warning">
Always review auto-generated migrations before applying. SQLAlchemy may miss rename operations (interpreting them as drop + create) or produce incorrect defaults.
</div>
### 9.4 Direct Database Access
```bash
# Interactive psql
make shell-db
# Common queries
SELECT COUNT(*) FROM usermodel;
SELECT COUNT(*) FROM presentationmodel WHERE deleted_at IS NULL;
SELECT status, COUNT(*) FROM jobmodel GROUP BY status;
SELECT provider, SUM(total_tokens) FROM aiusagemodel GROUP BY provider;
```
---
## 10. Background Jobs & Workers
### 10.1 ARQ Worker Configuration
```mermaid
flowchart LR
RD[(Redis)] --> W[ARQ Worker]
W --> A[generate_presentation]
W --> B[parse_master_deck]
W --> C[Cron: cleanup 2AM / purge Mon 3AM]
```
| Setting | Value | Description |
|---------|-------|-------------|
| `max_jobs` | 5 | Maximum concurrent background jobs |
| `job_timeout` | 1800s (30 min) | Per-job timeout |
| `max_tries` | 3 | Retry attempts on failure |
| `health_check_interval` | 30s | Health check frequency |
### 10.2 Job Types
#### Presentation Generation (`generate_presentation_task`)
1. Load request from PresentationModel
2. Fetch brand context (colors, fonts, voice rules)
3. Generate outlines via LLM
4. Generate per-slide structure and content
5. Run image generation for each slide
6. Save results to database
7. Update JobModel progress (0100%)
#### Master Deck Parsing (`parse_master_deck_task`)
1. Extract XML layouts/slides from PPTX
2. Convert PPTX to PDF via LibreOffice
3. Split PDF into per-page screenshots
4. Send each screenshot + XML to LLM vision
5. Store generated React TSX code
6. Register as template
#### Retention Cleanup (Cron — Daily)
- Soft-deletes presentations exceeding client's `retention_days`
- Runs at 2:00 AM UTC
#### Retention Purge (Cron — Weekly)
- Permanently deletes files for presentations soft-deleted 30+ days ago
- Runs Monday 3:00 AM UTC
### 10.3 Monitoring Jobs
```bash
# View worker logs
docker compose logs -f worker
# Check job status in database
make shell-db
# Then: SELECT id, job_type, status, progress, error_message FROM jobmodel ORDER BY created_at DESC LIMIT 20;
```
### 10.4 Common Job Issues
| Issue | Cause | Solution |
|-------|-------|----------|
| Job stuck at 0% | Worker crashed or no workers running | Restart worker: `docker compose restart worker` |
| Job times out | LLM response too slow | Increase `job_timeout` in WorkerSettings |
| Job fails repeatedly | Invalid API key or model | Check Settings page, test connection |
| Queue backed up | Too many concurrent requests | Scale workers horizontally |
---
## 11. Nginx & Networking
### 11.1 Routing Rules
```mermaid
flowchart LR
A[Request :80] --> B{Path}
B -->|/api/v1/*| C[FastAPI :8000]
B -->|/app_data/*| D[Static files]
B -->|/static/*| D
B -->|/* catch-all| E[Next.js :3000]
```
### 11.2 Key Configuration
| Setting | Value | Purpose |
|---------|-------|---------|
| `client_max_body_size` | 100M | Allow large PPTX uploads |
| `proxy_read_timeout` | 30m | Long-running LLM operations |
| `proxy_connect_timeout` | 30m | Connection establishment |
| `proxy_buffering` | off | SSE streaming support |
| `chunked_transfer_encoding` | off | SSE streaming support |
### 11.3 SSL/TLS (Production)
The default `nginx.conf` serves HTTP only. For production, add SSL:
```nginx
server {
listen 443 ssl http2;
ssl_certificate /etc/ssl/certs/your-cert.pem;
ssl_certificate_key /etc/ssl/private/your-key.pem;
# ... existing location blocks ...
}
server {
listen 80;
return 301 https://$host$request_uri;
}
```
### 11.4 Inter-Service Communication
```mermaid
flowchart LR
API["api :8000"] -->|DATABASE_URL| PG["postgres :5432"]
API -->|REDIS_URL| RD["redis :6379"]
API -->|NEXT_INTERNAL_URL| WEB["web :3000"]
WORKER["worker"] -->|DATABASE_URL| PG
WORKER -->|REDIS_URL| RD
WEB -->|API_INTERNAL_URL| API
NG["nginx :80"] --> API
NG --> WEB
```
All services communicate via Docker Compose's internal network. No ports need to be exposed to the host except:
- **80** (nginx) — user access
- **5432** (postgres) — optional, for direct DB access
- **6379** (redis) — optional, for debugging
---
## 12. Storage & File Management
### 12.1 Directory Structure
```
/app_data/
├── images/ # AI-generated images (UUID-named PNG files)
├── exports/ # Generated PPTX/PDF export files
├── uploads/ # User-uploaded documents (DOCX, PDF, TXT)
├── fonts/ # Custom font files
└── master_decks/ # Master deck PPTX files and screenshots
└── {deck_id}/
├── original.pptx
├── screenshots/
│ ├── page_1.png
│ ├── page_2.png
│ └── ...
└── pdf/
└── deck.pdf
```
### 12.2 File Serving
| Context | Serving Method |
|---------|---------------|
| **Docker (production)** | nginx serves `/app_data/` directly from volume |
| **Local development** | FastAPI `StaticFiles` mount on `/app_data` |
| **Frontend access** | Next.js rewrites `/app_data/*` to backend |
### 12.3 Retention Policy
```mermaid
flowchart LR
A[Presentation Created] -->|retention_days exceeded| B[Soft Delete<br/>deleted_at = now]
B -->|30 days later| C[Hard Purge<br/>Files removed from disk]
```
- **Retention days** configured per client in `ClientModel.retention_days`
- **Soft delete** runs daily at 2:00 AM UTC (sets `deleted_at` timestamp)
- **Hard purge** runs weekly Monday at 3:00 AM UTC (removes files for items soft-deleted 30+ days ago)
- **Manual purge** available via Admin > Storage > "Purge Files" button
### 12.4 Disk Space Monitoring
Monitor the `app_data` volume:
```bash
# Check volume usage
docker compose exec api du -sh /app_data/*
# Check available disk space
docker compose exec api df -h /app_data
```
---
## 13. Monitoring & Logging
### 13.1 Log Access
```bash
# All services
make logs
# Specific service
docker compose logs -f api
docker compose logs -f worker
docker compose logs -f postgres
docker compose logs -f web
# Last N lines
docker compose logs --tail=100 api
```
### 13.2 Audit Trail
The `AuditMiddleware` automatically logs all mutating API requests:
| Field | Content |
|-------|---------|
| `user_id` | Authenticated user's UUID |
| `action` | Operation name (e.g., "admin_delete") |
| `resource_type` | Entity type (e.g., "presentation") |
| `resource_id` | Entity UUID |
| `client_id` | Tenant context |
| `details` | JSON with request/response metadata |
| `ip_address` | Client IP address |
| `created_at` | Timestamp (indexed for fast queries) |
Audit logging is fire-and-forget (non-blocking) via `asyncio.create_task()`.
### 13.3 AI Usage Tracking
The `AIUsageModel` tracks all LLM API calls:
| Metric | Description |
|--------|-------------|
| Provider | anthropic, openai, google, ollama |
| Model | Specific model ID |
| Call Type | outline, content, vision, etc. |
| Input Tokens | Tokens sent to the model |
| Output Tokens | Tokens received |
| Duration (ms) | Call latency |
| Error Details | Error message if failed |
View aggregated metrics at **Admin > Analytics > AI Usage**.
### 13.4 Health Checks
| Service | Method | Interval | Timeout |
|---------|--------|----------|---------|
| PostgreSQL | `pg_isready` | 5s | 5s, 5 retries |
| Redis | `redis-cli ping` | 5s | 5s, 5 retries |
| API | Lifespan startup | At boot | — |
| Worker | ARQ health check | 30s | — |
---
## 14. Backup & Recovery
### 14.1 Backup Components
| Component | Location | Strategy |
|-----------|----------|----------|
| Database | `postgres_data` volume | `pg_dump` to file |
| Redis | `redis_data` volume | Optional (transient queue data) |
| Files | `app_data` volume | File-level backup or snapshot |
| Settings | Database (KeyValueSqlModel) | Included in pg_dump |
| Migrations | `backend/migrations/` | In git repository |
### 14.2 Database Backup
```bash
# Full database dump
docker compose exec postgres pg_dump -U deckforge deckforge > backup_$(date +%Y%m%d).sql
# Compressed backup
docker compose exec postgres pg_dump -U deckforge deckforge | gzip > backup_$(date +%Y%m%d).sql.gz
# Restore from backup
docker compose exec -T postgres psql -U deckforge deckforge < backup.sql
```
### 14.3 File Backup
```bash
# Backup app_data volume
docker run --rm -v ppt-tool_app_data:/data -v $(pwd):/backup alpine \
tar czf /backup/app_data_$(date +%Y%m%d).tar.gz -C /data .
# Restore app_data
docker run --rm -v ppt-tool_app_data:/data -v $(pwd):/backup alpine \
tar xzf /backup/app_data_YYYYMMDD.tar.gz -C /data
```
### 14.4 Disaster Recovery
```mermaid
flowchart LR
A[Deploy Stack] --> B[Restore DB] --> C[alembic upgrade] --> D[Restore app_data] --> E[Start Services] --> F[Verify]
```
1. Deploy fresh Docker Compose stack
2. Start PostgreSQL and Redis first
3. Restore database from latest `pg_dump`
4. Run `alembic upgrade head` to ensure schema is current
5. Restore `app_data` volume from backup
6. Start remaining services
7. Verify data integrity via Admin Panel
---
## 15. Security Hardening
### 15.1 Production Checklist
<div class="danger">
Before deploying to production, complete every item:
</div>
| Item | Action | Priority |
|------|--------|----------|
| JWT Secret | Change `JWT_SECRET_KEY` to a random 256-bit key | Critical |
| Dev Auth | Set `AZURE_AD_TENANT_ID` to disable dev bypass | Critical |
| CORS | Restrict `allow_origins` from `*` to your domain | High |
| SSL/TLS | Configure nginx with SSL certificates | High |
| Database Password | Use a strong `POSTGRES_PASSWORD` | High |
| API Keys | Set `SETTINGS_ENCRYPTION_KEY` for at-rest encryption | High |
| Port Exposure | Remove host port mappings for postgres/redis | Medium |
| Secrets | Move `.env` to Docker secrets or vault | Medium |
| Rate Limiting | Add nginx rate limiting rules | Medium |
| Monitoring | Set up external monitoring and alerting | Medium |
### 15.2 CORS Configuration
The default CORS configuration allows all origins. For production, modify `backend/api/main.py`:
```python
origins = [
"https://your-domain.com",
"https://app.your-domain.com",
]
```
### 15.3 API Key Encryption
Enable at-rest encryption for stored API keys:
```bash
# Generate a Fernet key
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# Add to .env
SETTINGS_ENCRYPTION_KEY=your-generated-fernet-key
```
### 15.4 Middleware Execution Order
```mermaid
flowchart LR
A[Request] --> B[1.CORS] --> C[2.Auth] --> D[3.Audit] --> E[4.UserConfig] --> F[Handler]
```
Middlewares are added in reverse order in FastAPI (last added = first executed).
---
## 16. Scaling & Performance
### 16.1 Horizontal Scaling
```mermaid
flowchart LR
LB[Load Balancer] --> API[API x N]
API --> PG[(Managed PostgreSQL)]
API --> RD[(Managed Redis)]
W[Workers x N] --> PG
W --> RD
API --> S3[S3 / CDN]
W --> S3
```
| Component | Scaling Strategy |
|-----------|-----------------|
| **API** | Run multiple replicas behind load balancer |
| **Worker** | Run multiple instances (ARQ handles job locking) |
| **PostgreSQL** | Use managed service (RDS, Cloud SQL) with read replicas |
| **Redis** | Use managed service (ElastiCache) with clustering |
| **Files** | Replace local volume with S3 + CDN |
| **nginx** | Replace with cloud load balancer (ALB, Cloud Load Balancing) |
### 16.2 Vertical Scaling
| Setting | Location | Effect |
|---------|----------|--------|
| `max_jobs` | `WorkerSettings` | More concurrent background jobs |
| `job_timeout` | `WorkerSettings` | Allow longer-running LLM operations |
| `worker_connections` | `nginx.conf` | More concurrent connections |
| `client_max_body_size` | `nginx.conf` | Larger file uploads |
### 16.3 Performance Optimization
- **Database indexes** already exist on:
- `auditlogmodel.created_at`
- `teammembershipmodel(user_id, team_id)` (unique)
- `usermodel.email` (unique)
- `clientmodel.slug` (unique)
- **Async operations**: All database queries use `asyncpg` (async PostgreSQL driver)
- **Sync LLM calls**: Wrapped in `asyncio.to_thread()` to avoid blocking the event loop
- **SSE streaming**: Server-Sent Events for real-time progress (no polling overhead)
- **Fire-and-forget audit**: Audit logs don't block request processing
---
## 17. Troubleshooting
### 17.1 Common Issues
| Issue | Cause | Solution |
|-------|-------|----------|
| API won't start | PostgreSQL not ready | Wait for health check (1525s) |
| Worker jobs not processing | Redis down or worker crashed | `docker compose restart worker` |
| Auth failures after restart | JWT_SECRET_KEY changed | All users must re-login |
| File uploads fail | Disk full or wrong permissions | Check `du -sh /app_data/*` and permissions |
| PPTX export 500 | Puppeteer / Chromium issue | Restart web service, check memory |
| Slide edit timeout | LLM response too slow | Check provider status, increase timeouts |
| Master deck stuck "processing" | Worker died during parse | Restart worker, reparse the deck |
| Images not showing | Static files not served | Check FastAPI mounts and nginx config |
| SSE not working | Proxy buffering enabled | Ensure nginx `proxy_buffering off` |
### 17.2 Diagnostic Commands
```bash
# Service health
docker compose ps
# Container resource usage
docker stats
# API application logs
docker compose logs --tail=50 api
# Worker job processing logs
docker compose logs --tail=50 worker
# Database connection check
docker compose exec postgres pg_isready -U deckforge
# Redis connectivity
docker compose exec redis redis-cli ping
# Database query — check failed jobs
docker compose exec postgres psql -U deckforge -c \
"SELECT id, job_type, status, error_message FROM jobmodel WHERE status='failed' ORDER BY created_at DESC LIMIT 10;"
# Disk usage
docker compose exec api du -sh /app_data/*
```
### 17.3 Resetting the System
```bash
# Full reset (WARNING: destroys all data)
docker compose down -v
docker compose up --build -d
make migrate
make seed
```
---
## 18. API Reference
### 18.1 Authentication Endpoints
| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/v1/auth/login` | Redirect to Azure AD login |
| GET | `/api/v1/auth/callback` | OAuth callback handler |
| POST | `/api/v1/auth/dev-login` | Dev mode authentication |
| GET | `/api/v1/auth/dev-status` | Check if dev mode is enabled |
| POST | `/api/v1/auth/logout` | Clear session |
| GET | `/api/v1/auth/me` | Current user info |
### 18.2 Admin Endpoints
| Method | Path | Access |
|--------|------|--------|
| GET/PUT/DELETE | `/api/v1/admin/users/*` | Super Admin |
| POST/GET/PUT/DELETE | `/api/v1/admin/clients/*` | Admin |
| POST/GET/DELETE | `/api/v1/admin/teams/*` | Admin |
| GET/PUT | `/api/v1/admin/settings` | Super Admin |
| GET/POST | `/api/v1/admin/settings/models` | Super Admin |
| POST | `/api/v1/admin/settings/test-connection` | Super Admin |
| GET/DELETE/POST | `/api/v1/admin/storage/*` | Admin |
| GET | `/api/v1/admin/analytics/*` | Admin |
| GET | `/api/v1/admin/audit-log` | Admin |
| GET/PUT/POST/DELETE | `/api/v1/admin/master-decks/*` | Admin |
| GET/PUT/POST/DELETE | `/api/v1/admin/brand-config/*` | Admin |
### 18.3 Presentation Endpoints
| Method | Path | Description |
|--------|------|-------------|
| POST | `/api/v1/ppt/presentation/create` | Create new presentation |
| GET | `/api/v1/ppt/presentation/all` | List presentations |
| GET | `/api/v1/ppt/presentation/{id}` | Get presentation detail |
| PUT | `/api/v1/ppt/presentation/{id}` | Update presentation |
| DELETE | `/api/v1/ppt/presentation/{id}` | Delete presentation |
| POST | `/api/v1/ppt/presentation/decompose` | Decompose content |
| POST | `/api/v1/ppt/presentation/prepare` | Prepare for generation |
| GET | `/api/v1/ppt/presentation/{id}/review` | Get review status |
| PUT | `/api/v1/ppt/presentation/{id}/status` | Change review status |
| POST | `/api/v1/ppt/presentation/{id}/comment` | Add review comment |
| POST | `/api/v1/ppt/jobs/generate` | Start generation job |
| GET | `/api/v1/ppt/jobs/{id}/status` | Job status (SSE) |
| POST | `/api/v1/ppt/export/pptx` | Export as PPTX |
| POST | `/api/v1/ppt/export/pdf` | Export as PDF |
---
<div style="text-align: center; margin-top: 60px; color: #999;">
**Oliver DeckForge** | System Administration Guide
Version 1.0 | &copy; 2026 All Rights Reserved
</div>