All documentation

Book 2

Architecture Handbook

OPSQAI is a self-hosted, multi-tenant knowledge and workflow platform delivered as a small set of container images. This book explains what runs where, how data moves, and how the components stay isolated.

1. Deployment topology

                +-------------------+
  Users  --->   |  Reverse proxy    |   TLS
                |  (Caddy/Traefik)  |
                +---------+---------+
                          |
                +---------v---------+       +---------------+
                |   opsqai-web      | <---> |   postgres    |  pgvector
                |   (SSR + API)     |       +---------------+
                +---------+---------+
                          |                 +---------------+
                          +---------------> |   redis       |  queue
                          |                 +---------------+
                +---------v---------+       +---------------+
                |   opsqai-worker   | <---> |   minio / S3  |  documents + backups
                |   (jobs, RAG)     |       +---------------+
                +-------------------+

2. Containers

  • opsqai-web — TanStack Start (React 19 + Vite 7) SSR, server functions for all app APIs.
  • opsqai-worker — Node runtime pulling jobs from Redis: document ingestion, embeddings, backups, license refresh.
  • postgres:16 + pgvector — primary store, RLS on every tenant table.
  • redis:7 — BullMQ queues and short-lived caches.
  • minio — default S3 backend; swappable for external S3 or Azure Blob at install time.

3. Data flow — a document question

  1. User uploads a PDF via the Portal → opsqai-web writes bytes to S3 and a row to documents.
  2. opsqai-web enqueues an ingest job.
  3. opsqai-worker pulls the job, extracts text, chunks it, requests embeddings from the configured AI provider, writes document_chunks with embedding vector(N) at the install's pinned embedding dimension.
  4. User asks a question → opsqai-web embeds the query, runs ORDER BY embedding <-> :q LIMIT 8 under the tenant's RLS policy, and passes the top chunks as context to the AI provider.
  5. The answer streams back to the user with inline citations pointing to the source chunks.

4. License system

Licenses are Ed25519-signed JSON tokens issued by the Management Center. Every OPSQAI boot verifies the signature offline against a pinned public key; the worker refreshes entitlements every 24h against mc.opsqai.de. A grace window keeps the instance running for 14 days if the MC is unreachable.

Modules, seat counts and expiry live in the token; nothing about the customer's data leaves the install.

5. Security model

  • Every app query runs as the authenticated user; RLS is the enforcement boundary.
  • Server functions requiring auth use the requireAuth middleware; admin server functions verify roles via a security-definer has_role() before touching the admin client.
  • Roles live in public.user_roles — never on profiles.
  • Object storage uses per-tenant path prefixes plus signed URLs; direct bucket access is blocked at the proxy.

6. AI adapter

The AI layer is behind a single interface: chat(messages, opts), embed(texts), stream(messages, opts). Adapters ship for Lovable AI Gateway, Azure OpenAI, OpenAI-compatible, and Ollama. Switching provider is a config change, not a code change.

7. Updates & maintenance

Each release is a signed compose bundle plus SQL migrations. Migrations run behind a Postgres advisory lock so multi-replica upgrades are safe. Schema changes are always backward-compatible for one minor version to allow rolling upgrades.