Architecture Review

Thalx Planned vs Implemented

Full codebase review — backend, frontend, skills system, and infrastructure. Confronting integration contracts v1 against what was actually built.

2026-03-13 | rev. completa + 5/5 discrepancias resueltas + frontend merge completado

9
Decisiones cambiadas
9
Features agregados
5/5
Discrepancias resueltas
4
Migrations pendientes
~37m
E2E Pipeline Time
11
Pipeline Steps

Pipeline actual

11 pasos, 3 formatos en paralelo, skills versionados

1 Ingest
2 Transcribe
3 Analyze
4a Scripts ×3
4b Anim Specs ×3
5 TTS
6 Footage
7 Render
8 Upload
9 Publish

Resumen ejecutivo

La arquitectura implementada diverge significativamente del contrato de integracion v1, pero en la direccion correcta. Los cambios clave (Remotion sobre Creatomate, faster-whisper local, Supabase Storage sobre R2) son decisiones de control y costo bien fundamentadas. Se agregaron capacidades no previstas como el skills system con auto-eval y animation specs parametrizadas. Los problemas criticos son: dos frontends coexistentes sin canonical definido, contratos de API desalineados, y 4 migrations sin aplicar que impiden persistencia de cache y brand packs.

Decisiones estrategicas que evolucionaron

9 componentes cambiaron vs el contrato de integracion v1

Componente Planeado (v1) Implementado Razon Veredicto
Render Creatomate API Remotion SSR (React, local) Control total, mood/energy parametrizado, $0 por render Mejor
Transcripcion Whisper API (cloud) faster-whisper small (local CPU) Sin quota limits, OOM fix medium→small Mejor
YouTube DL Supadata API ($9/mo) yt-dlp + IPRoyal proxy Control real-time, fallback sin proxy Mejor
Storage Cloudflare R2 Supabase Storage Integrado con DB, presign simplificado Mejor
Analisis LLM Claude haiku Claude Sonnet Mejor calidad structured output Mejor
Scripts 1 fase, 6 outputs paralelos 2 fases (content + production), 3 outputs Narrativa ≠ visual, arquitectura limpia Mejor
LLM SDK PydanticAI Claude Agent SDK (Max) Sin API key, subscription Trade-off
Outputs 6 tipos (blog, newsletter, summary, videos, post_x) SOLO 3 videos Foco en reels, no text outputs Scope cut
Queue arq + Upstash Redis arq + Railway Redis Upstash 500K limit exceeded Fix hoy

Features agregados fuera del plan

9 capacidades que no estaban en el contrato v1

Feature Estado Impacto
Skills system (prompts YAML versionados) Produccion Prompts como codigo, versionables, evaluables
Eval framework (12 validators + 23 tests) Produccion Quality gate automatico por skill
Auto-eval cron diario + self-improvement Produccion Skills mejoran solos, notificacion Slack
Brand pack (JSONB persistente) Codigo OK, migration pendiente Identidad visual cross-video
Animation spec (mood, energy, transitions) Produccion Render parametrizado, no hardcoded
3-layer cost control (TTS) Produccion Previene runaway bills ElevenLabs
Footage cache + rate limiting Codigo OK, migration pendiente Pexels 200 req/hr respetado
AI video gen stub Stub Interface lista para Sora/Kling/Runway
Content Advisor (agent Miles) Produccion Recomienda contenido → reels Thalx

Discrepancias detectadas

5 problemas identificados — todos resueltos ✓

#1 — Dos frontends coexisten Resuelto

src/ es el frontend canonical. Todas las features de frontend/ fueron portadas: wizard, drag-drop, video player, pipeline steps, output format cards, register page.

Fix: frontend/ queda como legacy reference, puede eliminarse.

#2 — API contract mismatch Resuelto

Unificado en BFF pattern:

Frontend POST /api/process (SvelteKit BFF)
BFF Supabase insert + FastAPI dispatch
Tipo CreateJobPayload con campo outputs: OutputFormat[]
#3 — Campo names inconsistentes Resuelto
Frontend envia outputs (no outputs_requested) — alineado con backend ✓
source_type mapping en BFF: contentTypesource_type
result_urls como JSON dict ✓ — alineado frontend-backend
#4 — ENV var mismatch Resuelto

.env.example actualizado: solo vars que src/ necesita (PUBLIC_SUPABASE_*, SUPABASE_SERVICE_KEY, BACKEND_URL). Refs a R2 y PUBLIC_API_URL removidas.

#5 — Presign endpoint diverge Resuelto
src/ usa /api/upload/presign (SvelteKit BFF → Supabase Storage) ✓
No depende del backend para presign — todo server-side en SvelteKit ✓
frontend/ llamaba directo al backend (deprecated) ✓

Migrations pendientes

4 migrations sin aplicar en Supabase Dashboard

# Que agrega Impacto si no se aplica Prioridad
006 published_videos table publish.py usa fallback graceful, pero no persiste publicaciones Alta
007 status constraint 'publishing' Sin efecto real (text field, no enum) Baja
008 Storage buckets: tts-cache, footage-cache, outputs TTS cache y footage cache no persisten entre jobs Critica
009 brand_pack JSONB + footage_source en jobs Brand pack no se guarda en DB, footage_source ignorado Alta

Accion requerida: Aplicar las 4 migrations en Supabase Dashboard (SQL Editor). El codigo ya maneja fallbacks, pero sin las migrations el cache se pierde en cada job (costo TTS duplicado) y los brand packs no persisten.

Performance — Primer E2E Job

Video: "Claude Code Skills Just Got Even Better" (16:14) — 2026-03-12

YouTube DL
1m
OK
Whisper small
10m
CPU-bound
Analysis
33s
OK
Scripts ×3
2m
Parallel
Render TikTok
19s
OK
Render Reel
38s
OK
Render YouTube
22m
MUY LENTO
Upload
<10s
OK
~37m
Total E2E
86%
Whisper + YT Render
Sin TTS
ElevenLabs exceeded
Solid BG
No Pexels key

Cuellos de botella identificados

1. Render YouTube (22 min) — El formato 16:9 con 8-12 scenes genera un video de ~26MB. Remotion SSR reconstruye el bundle en cada render. Solucion: bundle caching + concurrent scene rendering.

2. Whisper small (10 min) — CPU-bound en VPS 8GB. Model medium causaba OOM. Solucion: GPU instance o Whisper API para videos largos.

3. Sin TTS ni footage real — ElevenLabs quota exceeded + Pexels sin API key. Los videos salen mudos con fondo solido. Solucion: renovar ElevenLabs + configurar PEXELS_API_KEY.

Arquitectura actual

Sistema completo tal como esta implementado

Frontend — Vercel
SvelteKit 5
Tailwind 4 + SSR
🔒
Auth
Supabase email/pw
📤
BFF Routes
/api/process, /api/jobs
🔃
SSE Stream
Real-time progress
↓ POST /api/jobs/{id}/dispatch    ↓ GET /api/jobs/{id}/stream
Backend — Railway
FastAPI
REST + SSE + Auth
📋
Jobs API
CRUD + dispatch
🆘
arq Queue
Redis enqueue
↓ arq dequeue → process_job()
Worker Pipeline — Railway
📥
Ingest
yt-dlp + proxy
🎙
Transcribe
faster-whisper
🧠
Analyze
Claude Sonnet
📝
Scripts ×3
Skills v1 + parallel
🎨
Anim Spec
mood/energy/trans
🔈
TTS
ElevenLabs 3-layer
🎥
Footage
Pexels + AI stub
🎬
Render
Remotion SSR
🚀
Publish
YT / IG / TT
↓ Supabase updates cada step    ↓ Storage upload
Data Layer
🗃
PostgreSQL
jobs, tts_usage, cache
💾
Storage
job-files, outputs
🔩
Redis
Railway (arq queue)
Quality Layer
📚
Skills v1
5 prompts YAML+MD
Validators
12 checks / skill
🕐
Auto-eval
Cron diario + Slack

Recomendaciones priorizadas

13 items organizados por prioridad — 3 completados ✓

P0 Hacer funcionar (bloqueante)
01 Aplicar migrations 006-009 en Supabase Dashboard
02 Configurar env vars en Vercel (BACKEND_URL, SUPABASE_SERVICE_KEY)
03 Resolver cual frontend es el canonical — src/ es canonical ✓
04 Alinear API contracts — BFF + CreateJobPayload tipado ✓
P1 Calidad de output
05 ElevenLabs quota — renovar para TTS real en videos
06 PEXELS_API_KEY — configurar para footage real (no solid color)
07 Optimizar render YouTube (22 min → target <5 min con bundle caching)
P2 Robustez
08 Unificar .env.example — actualizado solo con vars de src/ ✓
09 Deploy backend como systemd service (actualmente Railway)
10 Health monitoring proactivo (Railway + Vercel)
P3 Evolucion
11 UI para crear/seleccionar brand packs
12 Conectar AI video gen (Sora/Kling/Runway)
13 Blog con contenido real (MDX / CMS headless)