# KEYVORA Architecture

## Overview

KEYVORA is a multi-tenant SaaS for creating, configuring, and hosting Discord bots. Users authenticate via Discord OAuth2, manage workspaces, and deploy bot instances that run in isolated containers orchestrated by internal workers.

```
Browser → NGINX (TLS, host routing)
            ├─ keyvora.eu        → Landing (static / Vite)
            ├─ cp.keyvora.eu     → Control Panel SPA
            ├─ api.keyvora.eu    → Fastify (/v1, /ws)
            ├─ cdn.keyvora.eu    → Static assets
            └─ docs.keyvora.eu   → Docs

Fastify ↔ PostgreSQL (source of truth)
       ↔ Redis (sessions cache, rate limits, Pub/Sub, BullMQ)
       ↔ Workers (reconcile desired vs actual bot state)
       ↔ Bot runtimes (non-root containers, no Docker socket exposure)
```

## Design principles

1. **Desired vs actual state** — PostgreSQL stores desired bot status; workers report actual state and reconcile.
2. **Never expose secrets** — Bot tokens encrypted at rest; APIs return redacted metadata only.
3. **Server-side authorization** — Workspace RBAC and platform admin roles checked on every mutating endpoint.
4. **No eval in flows** — Visual flows compile to a constrained JSON DSL executed by `flow-engine`.
5. **Private data plane** — Postgres, Redis, MinIO, and worker ports are never public.

## Apps

| App | Responsibility |
|-----|----------------|
| `apps/api` | Auth, REST `/v1`, WebSocket `/ws`, OpenAPI |
| `apps/landing` | Marketing, pricing, Discord login entry |
| `apps/control-panel` | Dashboard, bots, builder, hosting UI |
| `apps/worker` | BullMQ jobs, reconciliation, deployments |
| `apps/bot-runtime` | discord.js process inside constrained container |

## Packages

| Package | Role |
|---------|------|
| `@keyvora/database` | Prisma schema, migrations, client |
| `@keyvora/shared` | Types, Zod schemas, error codes, plan entitlements |
| `@keyvora/config` | Env loading & validation |
| `@keyvora/discord` | OAuth helpers, REST wrappers |
| `@keyvora/flow-engine` | DSL validate/execute (Phase 4) |
| `@keyvora/ui` | Shared Vue components |

## Auth flow (Phase 1)

1. Client hits `GET /v1/auth/discord` → server creates `state` + PKCE `code_verifier`, stores in Redis, redirects to Discord.
2. Discord callback → verify state, exchange code with `code_verifier`, upsert user + oauth account, create session.
3. Session id in HttpOnly Secure SameSite cookie; CSRF token for mutating cookie-auth requests.
4. `GET /v1/me` returns profile + workspaces.

## Realtime (planned)

Authenticated WebSocket at `api.keyvora.eu/ws` with topic ACLs. Redis Pub/Sub fans out bot status, logs, notifications.

## Hosting model (planned)

Orchestrator never exposes Docker socket to tenants. Workers hold credentials and run idempotent start/stop jobs with distributed locks.

## Current server notes

- Existing NGINX site at `/etc/nginx/sites-available/keyvora` (not enabled as of Phase 1 scaffolding).
- TLS cert covers apex, www, api, cp, cdn, docs.
- Port `3100` is occupied by another project (`raw-ac`); KEYVORA API defaults to **3200**.
- PostgreSQL and Redis listen on localhost only — preferred for production data plane.
