Architecture

Two stacks, one set of rules.

Both products are self-hosted Docker Compose stacks: an nginx front door, a FastAPI service, PostgreSQL for every record and Redis for everything that may be lost. Only the proxy is published. Every AI call goes through one server-side gateway.

Shared principles

Decisions both products make the same way.

  • One origin

    The compiled React app and the API are served from the same origin behind nginx, so session cookies stay same-site and no cross-origin access is needed.

  • PostgreSQL holds the truth

    Every business record lives in PostgreSQL, and Alembic owns the schema: the application never creates tables behind its back. Redis holds sessions, rate-limit counters, caches and queues only.

  • Protected by construction

    Every router except sign-in is mounted behind a session check, so a new route cannot be added unauthenticated. Tests walk the whole route table to prove it.

  • Blocking work off the event loop

    Route handlers are synchronous and run in a thread pool; long jobs in cognita dev run in a separate Celery worker with progress streamed back.

  • Secrets as files

    Keys are mounted as Docker secrets, never baked into images. cognita dev refuses to start in production with a missing secret or an unsafe setting.

  • Evidence by design

    Exports carry hashes, uploads are typed by their content and stored under generated names, and downloads go through an authenticated route only.

cognita dev

Four internal networks, one way in, one way out.

nginx is the only container with a published port. The API, worker and scheduler share an internal data network with PostgreSQL and Redis. Only the worker can reach the internet, through a proxy that allows the model providers' API hosts and nothing else.

cognita dev deployment The browser reaches nginx on port 443. nginx forwards API calls to the FastAPI api service. The api, the scheduler and the Celery worker share an internal data network with PostgreSQL 16, Redis 7 and the files volume. Only the worker reaches model providers, through the squid egress proxy. vLLM and ClamAV are optional services. Browser Users on your network proxy · nginx TLS 1.2+ · CSP nonce security headers · SPA egress · squid the worker's only way out Model providers Anthropic · Google outside your network api · FastAPI sessions · RBAC · audit 4 uvicorn workers scheduler · beat chain check 02:00 UTC provider status, retries worker · Celery AI jobs · exports scans · evidence packs vLLM · optional on-prem model on GPU for Restricted data data network · internal PostgreSQL 16 every business record WAL archived hourly Redis 7 sessions · rate limits job queue · no records files volume generated names SHA-256 per file ClamAV · optional scans every upload before download 443 only app network · /api egress network allowlist: provider hosts
Every container runs as non-root with a read-only root filesystem, all capabilities dropped and no-new-privileges. Losing Redis logs everyone out but loses no data.

A request, step by step

  1. nginx terminates TLS, adds the security headers and a per-response CSP nonce, and forwards /api, unbuffered for progress streams.
  2. Middleware records metrics, adds a request ID, checks the CSRF header and origin, and applies rate limits.
  3. The protected router checks the session cookie against Redis; a Redis failure is a 503, never a pass.
  4. The endpoint checks its named permission, then whether the project is in the caller's scope.
  5. The service writes to PostgreSQL with the audit event in the same transaction. If the audit write fails, the change rolls back.

What runs in the background

  • AI generation, reviews and rewrites, with progress over server-sent events
  • Word, PDF and PowerPoint exports, rendered in the worker and stored with their hash
  • Upload scanning and retries every 30 minutes when ClamAV is enabled
  • Evidence pack builds with a verifiable manifest
  • Audit chain verification every night at 02:00 UTC
  • Provider status checks every 5 minutes, shown in the admin console
cognita grc

A compact stack that degrades instead of failing.

In production, nginx serves the compiled app and proxies /api to FastAPI on the same origin. The API, PostgreSQL and Redis stay on the internal network. If Redis goes down, sessions survive and rate limiting falls back to in-process counting.

cognita grc deployment The browser reaches the nginx frontend, which serves the compiled app and proxies API calls to the FastAPI backend. The backend uses PostgreSQL 15, Redis 7 and an uploads volume on the internal network. AI requests pass through the AI service, which checks the kill switch, then call Google Gemini or an optional on-premises vLLM model. Browser Users on your network frontend · nginx compiled app proxies /api, same origin Google Gemini API cloud model outside your network backend · FastAPI RBAC · audit · reports 4 uvicorn workers AI service kill switch checked first model allowlist vLLM · optional on-prem model on GPU prompts stay on-prem internal network PostgreSQL 15 every record schema by Alembic Redis 7 revocation · rate limits cache · 2 s timeouts uploads volume generated names SHA-256 on upload /api → backend:8000
SCA reviews run Google OSV-Scanner inside the backend image, which looks up package names and versions at osv.dev. Nightly database snapshots are taken by a host task, outside the containers.
AI gateway

Every model call takes the same path, and can be stopped at one point.

In cognita dev, provider SDKs may be imported only inside one module, and CI fails the build if anything else tries. The API process never calls a model; the worker does.

  1. Checked. The job endpoint verifies the model key against the allowlist, the caller's role, the project's data classification, the emergency stop and the budgets. A refusal is audited and no provider is called.
  2. Queued. The job goes to the Celery worker; the browser follows its progress over server-sent events and can cancel it.
  3. Called. The gateway calls Claude or Gemini through the egress proxy, or vLLM on the internal network, with reference files passed as delimited data and no tools.
  4. Validated. Output is checked against the task's schema and retried once before failing with a clear message.
  5. Recorded. Model, prompt version, input hashes, tokens, cost and latency are stored with the job and in the audit log.
  6. Proposed. The result lands as a new draft version labelled AI-generated, and stays labelled until a person edits it.

cognita grc applies the same idea in one service: every AI request checks the database-held switch first (cached for 60 seconds, failing closed), then calls Gemini or the on-premises vLLM model and validates the JSON it gets back.

Documents and files

Outputs people already use, made safely.

Exports

Word, PDF, PowerPoint, Excel

cognita dev renders Word with python-docx and converts it to PDF with LibreOffice, builds decks with python-pptx, and stamps every page with the version hash. cognita grc builds PDFs with ReportLab and jsPDF, Excel with openpyxl and Word with python-docx.

Uploads

Typed by content, not by name

File types are detected from their leading bytes, archives are read entry by entry with size, ratio and count limits, and files are stored under generated names outside any web-served path.

Spreadsheets

No formula injection

Every exported cell passes one escaping function, so text starting with =, +, - or @ can never run as a formula when someone opens the file.

Deployment

One host, Docker Compose, your network.

Each product ships as a Compose file. Bring a Linux host with Docker, point DNS at it, add a certificate, and start the stack.

cognita devcognita grc
Servicesproxy, api, worker, scheduler, egress, PostgreSQL 16, Redis 7frontend (nginx), backend, PostgreSQL 15, Redis 7
Optional profilesClamAV upload scanning, vLLM on a GPU host, backup servicevLLM on a GPU host
Published ports443 and 80 on the proxy onlyThe nginx port only
First startmake up generates secrets and a certificate; make admin creates the first administratordocker compose -f docker-compose.prod.yml up -d --build, then create the first administrator
Production guard railsENV=production refuses missing secrets, a non-HTTPS origin or test switchesSecure cookies and HSTS switched on together once served over HTTPS
BackupsEncrypted database and file backups, hourly WAL archiving, restore drill in CINightly pg_dump snapshots with a verified manifest; export and import between environments
MigrationsAlembic, with grants for the application role in every migrationAlembic, applied once at start in production
Technology

The same stack, pinned to exact versions.

Layercognita devcognita grc
LanguagePython 3.12, TypeScript 5.9Python 3.11, TypeScript 5.9
APIFastAPI 0.141, Pydantic 2.13, gunicorn + uvicornFastAPI 0.141, Pydantic 2.9, uvicorn
DataSQLAlchemy 2.0, Alembic 1.13, PostgreSQL 16, Redis 7SQLAlchemy 2.0, Alembic 1.13, PostgreSQL 15, Redis 7
Background workCelery 5.4 worker and beatFastAPI background tasks, host scheduler for backups
Security librariesargon2-cffi, PyJWT, slowapi, structlogbcrypt, PyJWT, cryptography, slowapi
AIanthropic, google-genai, OpenAI-compatible client for vLLMgoogle-generativeai, OpenAI-compatible client for vLLM
Documentspython-docx, python-pptx, openpyxl, LibreOffice, GraphvizReportLab, python-docx, openpyxl, pypdf, jsPDF
FrontendReact 19, Vite 7, MUI 7, React Router 7, TanStack Query, TipTap, React FlowReact 19, Vite 7, MUI 7 and MUI X DataGrid, React Router 7, Mermaid
Testspytest against PostgreSQL, Vitest, Playwright, axepytest with SQLite and an in-process Redis
Architecture review

Walk your security architects through it.

We can run a technical session on the network layout, the AI gateway and the evidence model with your architecture and security teams.