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

41 KiB
Raw Blame History

pdf_options stylesheet body_class css
format margin headerTemplate footerTemplate displayHeaderFooter
A4 25mm 20mm <div style="font-size:8px;color:#999;width:100%;text-align:right;margin-right:20mm;">Oliver DeckForge — System Administration Guide</div> <div style="font-size:8px;color:#999;width:100%;text-align:center;"><span class="pageNumber"></span> / <span class="totalPages"></span></div> true
https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown.min.css
markdown-body 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
  2. Installation & Deployment
  3. Environment Variables Reference
  4. Authentication Configuration
  5. Role-Based Access Control
  6. Admin Panel Operations
  7. Template Pipeline
  8. AI Provider Configuration
  9. Database Administration
  10. Background Jobs & Workers
  11. Nginx & Networking
  12. Storage & File Management
  13. Monitoring & Logging
  14. Backup & Recovery
  15. Security Hardening
  16. Scaling & Performance
  17. Troubleshooting
  18. API Reference

1. Architecture Overview

1.1 System Architecture

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

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

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

# 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:

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

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

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

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:
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
  1. 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

Security Warning: Development mode should never be used in production. Always configure Azure AD or another SSO provider for production deployments.

4.4 JWT Configuration

Parameter Value
Algorithm HS256
Expiry 24 hours
Storage session_token HTTP cookie
Payload sub (user UUID), email, role, exp, iat

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.


5. Role-Based Access Control

5.1 Role Hierarchy

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

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

You cannot change your own role. This prevents accidental lockout.

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

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

After deleting layouts, the system automatically re-registers the template by recreating PresentationLayoutCodeModel records for the remaining layouts.

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)

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

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

# 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

Always review auto-generated migrations before applying. SQLAlchemy may miss rename operations (interpreting them as drop + create) or produce incorrect defaults.

9.4 Direct Database Access

# 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

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

# 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

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:

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

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

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:

# 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

# 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

# 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

# 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

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

Before deploying to production, complete every item:

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:

origins = [
    "https://your-domain.com",
    "https://app.your-domain.com",
]

15.3 API Key Encryption

Enable at-rest encryption for stored API keys:

# 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

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

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

# 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

# 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

Oliver DeckForge | System Administration Guide

Version 1.0 | © 2026 All Rights Reserved