Tech stekas
FastAPI + Postgres 16 + ChromaDB + R2, keturios aplikacijos už vieno Caddy, izoliuotas workers-konteineris, Plan-100 control plane.
TL;DR
Backend — vienintelis FastAPI-app'as. Workers — atskiras singleton-konteineris su aštuoniais loop'ais. Frontend — trys aplikacijos (landing ant Astro, dash ant React 19 + TanStack Router, admin ant React 19) už vieno Caddy su TLS, CSP ir WS-timeout'ais 1h ilgiems pipeline'ams. Postgres 16 + ChromaDB + Cloudflare R2 — pagrindinė saugykla. 61 migracija, Plan-100 control plane su koordinatoriumi/runner'iu/reconciler'iu.
Stack'as ir architektūra
Topologija
Caddy (TLS + per-host CSP + WS timeouts 1h, flush_interval -1)
↓
├── landing.goragen.com → Astro static
├── app.goragen.com → React 19 SPA (dash)
├── admin.goragen.com → React 19 SPA (admin)
└── api.goragen.com → FastAPI + WS endpoints
↓
↓ workers (replicas:1, stop_grace 120s)
↓ ├── coordinator_loop
↓ ├── runner_loop
↓ ├── reconciler_loop
↓ ├── auto_provisioner_loop
↓ ├── daily_cleanup_loop
↓ ├── distribution_worker
↓ ├── voice/lip_sync workers
↓ └── heartbeat_loop
↓
├── Postgres 16 (psycopg v3)
├── ChromaDB (vectors)
└── External:
Vast.ai (GPU rental)
Kling Direct API
Anthropic Claude
Google Gemini
Cloudflare R2
Sentry
API (FastAPI)
api/main.py — entry-point'as. Startup-seka:
- SQL-migracijų paleidimas (61 failas, idempotentinės, ordered,
pg_advisory_lock(42)skirtas multi-replica safety). - Legacy
vast_instance.jsonsingleton-konfigūracijos migracija įvast_instanceslentelę. - Auth-lentelių inicializacija, admino seed iš ENV,
__system__sentinel-vartotojo seed (FK įusers(id)sisteminiuose įrašuose). reconcile_interrupted_on_startup()— pakartotinai į eilę įdedami job'ai, likęrunningbūsenoje po netvarkingo shutdown'o.- In-flight WS-sesijų restore iš DB, pakibusios pažymimos kaip
interrupted. - Voice-sample'ų generavimas per pirmą boot'ą (jei dar nebuvo).
scheduler_looppaleidimas (likę loop'ai — workers-konteineryje).
Shutdown metu: app.state.bg_tasks cancel, WS close-code 1012 («Service Restart») broadcast aktyvioms sesijoms. Dash-klientas mato 1012 ir iš karto bando reconnect — be timeout-wait.
Workers konteineris
Atskiras sidecar, replicas: 1 (singleton). Tai kritiška — kai kurie loop'ai laiko būseną atmintyje (lease tracking, in-progress provisions), kurios negalima dalintis be sudėtingos koordinacijos.
Talpina:
- coordinator_loop — admission control. Skaito
instance_requests, taiko parallel-limits + velocity-guard, INSERT'inaprovision_attempts. Leader-elected perprovision_leader. - runner_loop — execution. Patraukia claimed attempts, kviečia
scripts/vast_provision.ensure_instance(...), taiko terminal reducer (success → ready, failed → terminated ir t. t.). - reconciler_loop — recovery. Skenuoja penkių tipų šaltinių stale leases, force-terminate'ina įstrigusius
cancelling, atlaisvina destroyed instances. - auto_provisioner_loop — minutinis tick'as, rule-based spawn/destroy. Šiuo metu emituoja per control plane į
source_kind='auto_pool'. - daily_cleanup_loop — 24h retention sweep:
job_queue, decisions, lora_workspaces, idempotency keys, domain events >180d, disk usage check. - distribution_worker — 30s tick'as, scheduled posts → social platforms.
- voice_clone_worker / lip_sync_worker — voice job mock'ai (būsimam pilnam inference).
- heartbeat_loop — kas 30 sekundžių rašo
system_settings.workers_last_heartbeat.
SIGTERM → 120s graceful. Koordinatorius, runner'is, reconciler'is observe'ina heartbeat_task.done(), kad leadership loss nebūtų tylus.
Duomenų bazė
PostgreSQL 16, prieiga per api/db.py:get_connection — psycopg v3 wrapper'is su SQLite-style API. Tai reikalinga, nes legacy runtime SQL buvo rašyta po SQLite (row[0], row["col"], ? placeholder'iai); api/db_dialect.translate_runtime_sql perrašo placeholder'ius + datetime('now') kiekvieno execute metu.
Tai kompromisas: vietoj 100k+ SQL eilučių perrašymo — runtime-transliatorius. Phase 11→12 cutover (2026-05-12) pašalino dual-driver.
Migracijos
61 SQL-failas api/migrations/:
- 001–027 — Phase 0–7 foundation: auth, workspaces, plans, personas, storyboards, gallery, distribution, voice, API keys, webhooks.
- 028–029 — Phase 8.1: job_queue, instance LoRA cache.
- 030–032 — Phase 8.2: vast_instances, provisioning_rules, provisioner_decisions.
- 033 — Phase 8.3: lora_training_jobs.
- 034–037 — Phase 9: domain_events, idempotency_keys, user_daily_spend, cost-protection knobs.
- 040–044 — Phase 11→12: Postgres-cutover artefaktai.
- 047–054 — Phase 14 slim_provisioning: model_registry_v2, node_packages, presets, bootstrap meta, Telegram bot storage.
- 055–061 — Plan-100 Stage 1–6: shadow tables, atomic reuse claim, cutover flags, observability thresholds.
Kiekviena migracija — idempotentinė, _migrations tracker-lentelė, pg_advisory_lock(42) serializuoja multi-replica startup'us.
ChromaDB
knowledge/db/chroma/ — vektorinis indeksas prompt'ų receptams ir Civitai-duomenims. 2 458 ComfyUI node-schemos užkešuotos node_info_cache.py. 40 reference workflows (WAN 2.1, HunyuanVideo, LTX 2.3) yra knowledge/db/workflow_examples/.
knowledge/workflow_builder.py — programinis ComfyUI-grafų surinkimas; patch_workflow_with_lora įterpia LoRA-loader'ius į base-workflow.
Autentifikacija
Du režimai:
- Cookie JWT — primary, browser flow.
access_token+refresh_tokenant.goragen.com. Argon2 slaptažodžiams. - Bearer
gk_live_*— SDK / CI. Argon2-hash'inti raktaiapi_keys.key_hash. Falls throughget_current_userpo cookie-kelio.
require_admin, require_plan(...) — depends-dekoratoriai autorizacijai.
Middleware
- rate_limit.py — slowapi keyed pagal JWT user → API key prefix → IP.
- idempotency.py — Phase 9 C5
@idempotent(ttl_hours=24). SkaitoIdempotency-Key, daroidempotency_keyslookup PRIEŠ handler'io vykdymą. Hit → replay cached JSONResponse; hash mismatch (tas pats raktas, kitas body) → 409; missing header → 400. Pritaikyta 5 mutating endpoint'ams. Dash-klientas auto-inject'inacrypto.randomUUID()šiems keliams ir pakartotinai naudoja key per 401/429/5xx retry'us. - maintenance_middleware — globalus 503, kai
system_settings.maintenance_mode == 'true'(admin/auth/health passthrough). - CORS — pinned į
["GET","POST","PATCH","DELETE","OPTIONS"]. - _record_unhandled — unhandled exceptions feedina į
error_bufferring-buffer'į admin dashboard'ui.
Frontend
apps/dash — vartotojo kabinetas
React 19 + TypeScript + Vite 6 + Tailwind 4. Routing — TanStack Router (file-based, flat).
State split'as:
- TanStack Query — server cache, refetch, mutations.
- Zustand — cross-component session signals (live cost ticker).
lib/_http.ts— HTTP klientas, tvarko 401/refresh, 429 retry, 5xx exponential backoff, offline detection.
WebSocket reconnect — backoff [1s, 2s, 5s, 10s, 30s] failuose src/lib/ws.ts.
Routes (high-level): /, /library, /library/$slug, /generate, /storyboard, /gallery, /voice, /lora, /distribution, /compliance, /settings/* (7 sub-routes).
Onboarding-tour'as tingiai užkraunamas per Driver.js.
apps/admin — admin SPA
React 19. Sidebar shell'as AdminShell.tsx su keyboard shortcuts.
Routes: /dashboard, /users, /personas, /presets, /workflows, /instances, /tasks (4 sub-tabs), /lora, /system (6 sub-tabs įskaitant control-plane), /compliance, /settings.
apps/landing — marketingas
Astro static. Be SPA-runtime. Bendrauja tik su /auth/register, /auth/login, /auth/forgot-password.
Caddy
Vienas TLS-terminator'is. Per-host CSP. Reverse-proxy į keturis servisus. Kritinis nustatymas ilgiems pipeline'ams:
read_timeout 1h
write_timeout 1h
flush_interval -1
LoRA-treniravimas užtrunka 45-90 minučių, storyboard — 10-15 minučių. Be šių timeout'ų WS-sesija nukristų kas 30-60 sekundžių.
External
- Vast.ai — rented GPU pool. Provisioning per
scripts/vast_provision.py. SSH ControlMaster + retry helper'iaissh_utils.py. - Kling Direct API — endpoint'ai T2V, I2V, omni, extend, lip-sync, effects. JWT (HS256)
KlingClient. - Anthropic Claude — orkestracija (model selection, prompt engineering, captions).
- Google Gemini 2.5 Pro — output evaluation (4 kriterijai, verdict).
- Cloudflare R2 — kanoninė saugykla (
STORAGE_BACKEND=s3, bucketgoragen-prod, CDN antcdn.goragen.com). - Sentry — error tracking (no-op kai
SENTRY_DSNtuščias).
Ką perrašyčiau
— Workers vienetinė replika. Šiuo metu singleton iš būtinybės (in-memory state). Galima išskaidyti į per-loop konteinerius su atsakomybės atskyrimu — kiekvienas loop'as atskiras procesas su persistent state Postgres'e. Bet tai didelis darbas ir dabar tai ne blokeris.
— Workflow šablonai kaip kodas. Šiuo metu reference workflows — JSON-failai. Galima padaryti DSL grafų konstravimui iš primityvų (camera move + model + lora + sampler), kuris kompiliuojasi į JSON.
— Self-hosted Kling alternative. Kling — uždaras API. Kai open-source alternative pasivys (WAN 3.x / Hunyuan v2), galima persijungti per model_selector be pakeitimų aukščiau.
Platforma yra prode goragen.com. 61 migracija — tai šeši mėnesiai aktyvaus vystymo su reguliariu deploy'u be downtime'o (Phase 11→12 cutover'is buvo kritiškas, praėjo chunked).