Skip to main content

Architecture overview

ContentsVision is a two-tier web application with an asynchronous AI processing pipeline. This page is the map: the stack, the repo layout, the runtime topology, and how requests and jobs flow. The following pages drill into each layer.

Tech stack

LayerTechnology
FrontendNext.js 14 (App Router), React 18, TypeScript, Tailwind CSS, Framer Motion, TanStack Query and Virtual
BackendPython 3.11, FastAPI, SQLAlchemy 2 (async), Pydantic v2
DatabaseSQLite via aiosqlite (async)
MediaFFmpeg (via ffmpeg-python), Pillow, OpenCV (headless)
AIOpenRouter (Claude vision and analysis), Deepgram Nova-2 (transcription)
AuthAdjustSquare SSO, JSON Web Tokens (python-jose, HS256)
AnalyticsPostHog (product analytics + session replay), optional, off by default
Exportspandas + openpyxl (Excel), hand-rolled CSV
DeploymentDocker Compose, nginx, Cloudflare Tunnel

Repository layout

contentsvision/
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI app, router registration, CORS, /health
│ │ ├── api/routes/ # HTTP endpoints (auth, claims, rooms, upload, jobs, inventory, settings, activity, billing)
│ │ ├── core/ # config, database, security (JWT), auth_deps, actor, observability
│ │ ├── models/ # SQLAlchemy ORM models (claim, room, job, inventory, team, user, activity)
│ │ ├── schemas/ # Pydantic request/response shapes
│ │ └── services/ # pipeline, video_processor, audio_processor, claude_analyzer,
│ │ # numbering, auto_approve, prompt_settings, billing, activity, adjust_square
│ ├── tests/ # pytest suite (offline, in-memory DB)
│ └── requirements.txt
├── frontend/
│ └── src/
│ ├── app/ # Next.js App Router pages
│ ├── components/ # React components
│ ├── lib/ # api client, auth, settings contexts, helpers
│ └── types/ # TypeScript interfaces
├── docs/ # this handbook (Docusaurus)
├── nginx/nginx.conf
├── docker-compose.yml # local
└── docker-compose.prod.yml # production (nginx + Cloudflare Tunnel)

Runtime topology

In production, four containers run behind a Cloudflare Tunnel. No ports are exposed to the public internet; all ingress arrives through the tunnel into nginx.

The same logical split exists in local development, just without nginx or the tunnel: the Next dev server proxies /api to the uvicorn backend. See local development.

Backend layering

The backend follows a conventional layered shape. Requests flow down; the pipeline runs to the side as a background task.

LayerResponsibilityKey files
RoutesHTTP surface, validation, auth, response shapingapp/api/routes/*
AuthValidate JWT, resolve current user and team, build the Actorcore/auth_deps.py, core/actor.py, core/security.py
ServicesBusiness logic: the pipeline, billing, numbering, auto-approve, Adjust Square clientapp/services/*
ModelsSQLAlchemy ORM tablesapp/models/*
SchemasPydantic request/response contractsapp/schemas/*
CoreConfig, database engine, observabilitycore/config.py, core/database.py, core/observability.py

Two request paths: synchronous API vs background pipeline

ContentsVision has two distinct execution paths, and understanding the split explains most of the design.

Synchronous API calls

Standard REST. The route reads or writes the database and returns immediately. Most endpoints (claims, rooms, inventory edits, settings) work this way.

Background pipeline jobs

Uploading media returns right away, but the heavy AI work runs as a FastAPI background task against its own database session. The frontend then watches progress over Server-Sent Events.

This is why a long video does not block the HTTP request, and why the Adjust Square submission also hands its slow photo uploads to a background task (see Adjust Square).

Where to go next