Saltar a contenido

Construyendo TaskHub

Proyecto integrador post-curso. Una app real, production-ready, Dockerizada desde el día 1, que demuestra todo el stack único de Fitz trabajando junto en un solo binario.

TaskHub es un Trello colaborativo en vivo: usuarios con roles (admin / owner / member) gestionan projects con tasks y comments, las actualizaciones se broadcastean por WebSocket a todos los conectados al mismo board, un cron job nocturno limpia tasks completadas hace más de N días, un endpoint de IA sugiere prioridad usando un LLM via interop Python, y todo corre con Prometheus + Jaeger en producción. El binario Fitz pesa ~30 MB.

flowchart TB
    subgraph Cliente
        FE[Frontend vanilla JS]
    end
    subgraph Compose
        FE -- "/api/* + /ws/*" --> NX[nginx]
        NX --> APP["binario Fitz \n auth + ORM + WS + cron + interop"]
        APP --> PG[(Postgres 16)]
        APP -- traces OTLP --> JG[Jaeger]
        APP -- /metrics --> PR[Prometheus]
        APP -- spawn --> PY[Python interop \n LLM priorización]
    end

¿Por qué este proyecto existe?

El curso Fitz de 0 a experto cubre cada feature aisladamente a lo largo de 42 capítulos. El capstone del módulo M6 ("Notas con tiempo real") ya integra una parte importante del stack: auth + ORM + WS + cron + Docker compose.

Pero hay piezas que el curso entero no integra todas juntas:

Feature Cubierto en el curso aislado Integrado en M6.C7 capstone Integrado en TaskHub
Auth con JWT + Argon2id M5.C2
ORM nativo Postgres M6.C1-C5
Workflow fitz db diff/migrate/rollback M6.C6 ❌ (usa CREATE TABLE IF NOT EXISTS) ✅ end-to-end con cambios reales de schema
RBAC custom con @requires("role") M5.C2 (mención) ❌ (solo @authenticated) ✅ 3 roles: admin / owner / member
WebSocket tipado M5.C3
Cron + @background + persistencia M5.C4 ⚠ (cron memoria) ✅ con store=db
Interop Python en producción M7 ✅ priorización IA con LLM
Observability completa (OTel + Prometheus + Jaeger) M8.C2 ❌ (logs básicos) ✅ desde día 1 en compose
fitz docker init/build M8.C4 ⚠ (Dockerfile a mano) ✅ generado por el subcomando
healthz + readyz + SIGTERM drain M8.C4
Frontend integrado (vanilla JS) ✅ con nginx como proxy a /api/* + /ws/*
Docker compose con 5 services real ⚠ (2: app + db) ✅ (5: app + db + prometheus + jaeger + nginx)

TaskHub no es otro tutorial — es una app real que podrías deployar en producción mañana. Sirve para tres audiencias:

  • Quien terminó el curso: ver cómo el stack se integra en una app más ambiciosa que el capstone de M6.
  • Quien ya conoce Fitz: salta directo a "muestrame un proyecto serio end-to-end" sin pasar por 42 caps pedagógicos.
  • Quien evalúa Fitz para producción: ver el peso real de un deploy completo (~30 MB binario + 5 services en compose).

¿Qué hace TaskHub?

App de gestión colaborativa de tareas, estilo Trello/Asana chico. Dominio mínimo pero suficiente para demostrar el stack:

Modelo de datos (ORM nativo):

  • User: id, email, password_hash, role (admin/owner/member), created_at.
  • Project: id, name, description, owner_id (FK → User).
  • Task: id, project_id (FK), title, description, status (todo/doing/done), priority (1-5), assignee_id (FK → User?), due_date, ai_suggested_priority (cache), created_at.
  • Comment: id, task_id (FK), user_id (FK), body, created_at.

Funcionalidades end-to-end:

  • Register + login con JWT + Argon2id (M5.C2 del curso).
  • CRUD de projects + tasks + comments con relations (M6.C2-C4).
  • RBAC con 3 roles: admin ve todo, owner gestiona sus projects, member solo ve projects donde está asignado a alguna task.
  • WebSocket en vivo por project: cuando alguien cambia status de una task, todos los conectados al mismo /ws/projects/{id} reciben el evento (M5.C3 + extensión).
  • Cron job nocturno: limpia tasks done con más de 90 días
  • envía emails recordatorios de tasks todo con due_date próxima (M5.C4 + persistencia).
  • Endpoint IA: POST /api/tasks/{id}/suggest-priority invoca un LLM via interop Python (OpenAI/Anthropic compatible o heurística local), devuelve Result<Int> (1-5), cachea el resultado en la columna ai_suggested_priority (M7.C1-C3).
  • Frontend vanilla JS: index login → lista de projects → vista de un project con board kanban (drag & drop de tasks entre columnas) → tasks con comments. Sin frameworks (mismo patrón que boilerplates/api-orm-full-fullstack).
  • Producción: /healthz + /readyz + SIGTERM drain de 30s + spans OTel hacia Jaeger + métricas hacia Prometheus + tabla de monitoring custom (M8.C2-C4).

Lo que NO hace TaskHub (para mantener el scope manejable):

  • Multi-tenant con organizations. (Cada user ve sus propios projects vía el RBAC.)
  • File uploads / attachments.
  • OAuth con providers externos (Google/GitHub).
  • Notificaciones push o email transaccional real (mockeamos el envío de email en el cron, sin Mailgun/SES).
  • Mobile app o PWA.

Si querés alguna de esas features, son extensiones naturales post-TaskHub.


Roadmap de capítulos

Cap Título Cubre
C1 Setup Docker-first: los 5 services del compose docker compose up -d levanta app vacía + Postgres + Prometheus + Jaeger + nginx. Tour de qué hace cada uno. Validación con healthchecks.
C2 Schema + workflow fitz db end-to-end Declarás @table type para User/Project/Task/Comment + workflow real: fitz db new initialdiff > file.sqlmigrate. Cambio de schema posterior + rollback. fitz db check en CI con GitHub Actions.
C3 Auth con RBAC custom: 3 roles apilables Register + login con JWT + Argon2id. @auth_provider + @authenticated + @requires("admin"\|"owner"\|"member") apilable (semántica OR). Endpoints protegidos + bootstrap del primer admin + tests por cada rol con curl.
C4 CRUD + relations + WebSocket en vivo @has_many + @belongs_to + companion fields. CRUD de projects + tasks con .preload("tasks") para eager loading + scope por ownership. @authenticated @ws("/ws/projects/{id}") con WsConn<TaskEvent> + broadcast simétrico + limitación honesta del MVP (HTTP handlers no triggerean broadcasts).
C5 Cron + background jobs con persistencia 2 @cron("...", tz=..., retry=..., store=db_result) + @background async fn + spawn(...) desde handler + endpoint admin GET /api/jobs lee fitz_cron_runs. Tablas auto-creadas. Sin Celery, sin Redis — compose sigue con 5 services.
C6 Interop Python: priorización IA con LLM from python import priority + endpoint POST /api/tasks/{id}/suggest-priority. Módulo Python con OpenAI gpt-4o-mini opcional + fallback heurística por keywords. match Result<Int> para fallback de emergencia. Cache en ai_suggested_priority. Diferenciador único: binario nativo Rust + ecosistema Python sin penalty IPC.
C7 Observability + frontend + deploy production (final) @server(prometheus=true) para /metrics + OTel spans → Jaeger. @healthz/@readyz con check real de DB + SIGTERM drain auto. Frontend vanilla JS (~500 LoC) con login + projects list + board kanban drag&drop + WS live updates. Dockerfile final con fitz build --bundle-python --bundle-pip openai → image ~50 MB distroless.
Post-C7 TaskHub publicado como boilerplates/taskhub/ El estado final del C7 publicado al lado de los 9 boilerplates existentes (este es el 10mo y más completo). Clone + docker compose up -d --build + bootstrap admin = TaskHub corriendo en ~30s. Sin pasar por los 7 caps. Cierra el proyecto entero.

Cada cap tiene su entregable commiteable en examples/taskhub/cX-tema/. La app crece capítulo a capítulo — al terminar tenés un proyecto que podés extender. Después del C7, el estado final se publica como boilerplate descargable en boilerplates/taskhub/ con un README dedicado — para que cualquiera que quiera probar TaskHub sin leer los 7 caps lo pueda clonar y arrancar en ~30 segundos.


Pre-requisitos

Conocimiento:

  • Curso de 0 a experto cerrado (M1-M8) o experiencia equivalente con Fitz. TaskHub asume que ya:
  • Sabés escribir handlers HTTP con @get/@post/... (M4).
  • Conocés async fn + .await + @auth_provider + @ws + @cron (M5).
  • Manejás el ORM con @table + relations + .where(closure) (M6).
  • Probaste interop Python con from python import (M7).
  • Sabés qué hace fitz docker init/build, observability básica + Secret<T> (M8).

Si te faltan piezas, hacé los caps puntuales del curso primero — TaskHub no los re-explica desde cero.

Software local:

  • Fitz instalado (fitz --version debería responder).
  • Docker Desktop (Windows/Mac) o Docker Engine + Docker Compose v2 (Linux).
  • psql opcional (para inspeccionar la DB a mano).
  • curl o httpie para probar endpoints.
  • wscat para probar WebSockets (npm i -g wscat).
  • Editor con extensión Fitz instalada (VSCode).

Cuentas externas (opcionales — solo para C6 con LLM real):

  • API key de OpenAI o Anthropic. Si no, el cap C6 cae a fallback heurístico (priority basada en keywords del título).

Cómo seguir TaskHub

  • Lineal (recomendado primera vez): C1 → C2 → ... → C7. Cada cap arranca del estado del cap anterior + suma una capa.
  • Saltado: cada cap tiene un README en examples/taskhub/cN/ con git checkout del estado inicial. Saltás al cap que te interesa.
  • Para evaluar Fitz para producción: leé este index + el cap C7 (deploy production) directo. Te da el peso real del binario, la imagen Docker, métricas, tracing.

Comparativa final (TaskHub vs stack típico)

Stack Deploy Boot Memory idle Image Deps en el binario
Fitz (TaskHub) 1 binario standalone 50-100ms 20-40 MB ~150 MB compose total auth + ORM + WS + cron + axum + serde + jwt + argon2 + tokio multi-thread
Python+FastAPI+SQLAlchemy+Celery+Redis pip install ×20+ + workers + redis + db 3-5s 120-180 MB ~600 MB compose requirements.txt
Node+Express+TypeORM+bull+Redis npm install ×100+ + workers + redis + db 1-3s 80-120 MB ~500 MB compose package.json
Spring Boot + Hibernate + Quartz jar + db 10-30s 250-400 MB ~400 MB compose pom.xml

Diferenciador estructural: TaskHub no tiene Celery porque los cron jobs viven en el binario, no tiene Redis porque no hace falta broker, no tiene workers separados porque tokio multi-thread los reemplaza, y no tiene serializadores externos porque el ORM + auth + WS están integrados al lenguaje.


Próximo paso

Cap 1 — Setup Docker-first: los 5 services del compose →

Empezamos arrancando los 5 services del compose con un binario Fitz vacío que responde 200 OK en /healthz. Validamos cada service health-checkeado antes de tocar una línea de lógica de negocio.