Architecture
Architecture
Rokks runs as a Docker Compose stack of ~16 services. All internal communication is over HTTPS with a mesh CA. No service exposes a host port except frontend (3000/3443).
Service map
| Service | Docker name | Role |
|---|---|---|
| Frontend | frontend | nginx serving SPA + Edge proxy for all API traffic |
| Registry | registry | SQLite-backed bootstrap anchor — secrets, service discovery, config |
| Auth | auth | OAuth exchange — issues JWTs for user sessions |
| Doc Gateway | doc-gateway | Firestore + GCS proxy — all document/blob reads and writes |
| SQL Gateway | sql-gateway | TimescaleDB / PostgreSQL proxy — all SQL queries |
| Worker | worker | SQLite job engine — ETL, sync, index, alert, AI generation jobs |
| Edge | edge | Internal API router — authenticates browser traffic, forwards to worker/gateways |
| AI Gateway | ai | LLM proxy — Gemini cloud or local LM Studio |
| Data Transform | data-transform | SSE-streaming ETL backend for file processing |
| Dispatcher | dispatcher | Cron scheduler — reads schedules, acquires locks, submits jobs to Worker |
| Sentinel | sentinel | Alert evaluator — evaluates alert rules, submits notification jobs |
| Healthcheck | healthcheck | Liveness aggregator — probes all services and surfaces results |
| Monitor | monitor | Metrics aggregator — collects per-service operation logs |
| App Connect | appconnect | Airtable connector — discovery, schema, incremental sync |
| Web API | webapi | Web API connector — HTTP/WebSocket extraction |
| MonIO | monio | Optional MongoDB-backed document backend (alternative to Firestore) |
Communication topology
Browser └── Edge (nginx, port 3000/3443) ├── /auth/* → Auth ├── /api/* → Edge service (proxy) │ ├── /api/doc/* → Doc Gateway │ ├── /api/sql/* → SQL Gateway │ ├── /api/ai/* → AI Gateway │ ├── /api/jobs/* → Worker │ ├── /api/audit/* → Worker │ └── /api/transform/* → Data Transform └── / → SPA (static files)All backend-to-backend calls (within Docker) use INTERNAL_SERVICE_SECRET for authentication and go directly between containers — they do not hop through Edge.
Data flow
External data source (CSV, API, Airtable) └── Data Fabric (File Area / Web API / App Connect) └── Worker job (ETL / WEBAPI_SYNC / AIRTABLE_SYNC) ├── Extract → raw rows in memory ├── Transform → runTransformation() (shared/transform.js) └── Load → SQL Gateway → TimescaleDB └── Dashboard widgets query via SQL GatewayThe same runTransformation function runs in both browser preview and backend execution — no divergence is possible.
Physical / logical layer duality
Every table has two names:
- Physical name:
t_<32-hex>— immutable, used in all DDL and SQL - Logical name: human-readable snake_case, exposed as a PostgreSQL view (
CREATE OR REPLACE VIEW)
Column names follow the same pattern: f_<hex8> (physical) with a human label stored in table_metadata.columnMap.
Renames are pure metadata updates — zero DDL, zero data movement.