gora.
GoraGen — AI video generavimo platforma

Tech stekas

FastAPI + Postgres 16 + ChromaDB + R2, keturios aplikacijos už vieno Caddy, izoliuotas workers-konteineris, Plan-100 control plane.

~6 min skaityti · 1102 žodžių

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:

  1. SQL-migracijų paleidimas (61 failas, idempotentinės, ordered, pg_advisory_lock(42) skirtas multi-replica safety).
  2. Legacy vast_instance.json singleton-konfigūracijos migracija į vast_instances lentelę.
  3. Auth-lentelių inicializacija, admino seed iš ENV, __system__ sentinel-vartotojo seed (FK į users(id) sisteminiuose įrašuose).
  4. reconcile_interrupted_on_startup() — pakartotinai į eilę įdedami job'ai, likę running būsenoje po netvarkingo shutdown'o.
  5. In-flight WS-sesijų restore iš DB, pakibusios pažymimos kaip interrupted.
  6. Voice-sample'ų generavimas per pirmą boot'ą (jei dar nebuvo).
  7. scheduler_loop paleidimas (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'ina provision_attempts. Leader-elected per provision_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:

  1. Cookie JWT — primary, browser flow. access_token + refresh_token ant .goragen.com. Argon2 slaptažodžiams.
  2. Bearer gk_live_* — SDK / CI. Argon2-hash'inti raktai api_keys.key_hash. Falls through get_current_user po 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). Skaito Idempotency-Key, daro idempotency_keys lookup 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'ina crypto.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_buffer ring-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'iai ssh_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, bucket goragen-prod, CDN ant cdn.goragen.com).
  • Sentry — error tracking (no-op kai SENTRY_DSN tušč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).