Curso Fitz de 0 a experto — Plan¶
Estado: M1-M8 completos (cerrados al 2026-06-03). M7 (Interop
Python) se sumó tras Fase 12.5 al detectar que el plan original no lo
cubría como módulo dedicado — el ex-M7 (Producción y deployment) se
renumeró a M8 y se le agregó un cap nuevo (M8.C5) sobre deploy real
de apps con interop. El contenido vive en
docs/curso/.
Actualización 2026-06-03 (al cerrar M7+M8): cinco ajustes sobre el plan original (trazado en v0.9.x):
- M6 cambia capstone: ORM nativo Fitz (cap 31 de la guía) como camino default; SQLAlchemy via
fitz py-typesqueda como cap opcional para users con modelos Python existentes. La Fase 10 (cerrada en v0.10.x) volvió a SQLAlchemy un nice-to-have, no la opción principal.- M7 espera Fase 12 (ya CERRADO): el módulo de deployment esperaba que
fitz dockerfile/fitz compose/fitz deploy(Fase 12) estuvieran implementados. Fase 12 ENTERA CERRADA al 2026-06-03 (v0.12.5), el módulo se escribió y después se renumeró a M8 (ver punto 5).- Tabla nueva "Mapping curso → guide.md" (ver más abajo). El curso NO duplica el contenido de la guía — la cita como referencia técnica. Cada cap del curso linkea al cap correspondiente de la guía para "el detalle exhaustivo".
- M7 NUEVO — Interop Python (3 caps, 2026-06-03): el plan original tenía la interop Python como UN cap opcional (C32b) dentro de M6. Al cierre del curso, decidimos darle módulo dedicado porque la Fase 8 entera (8.1-8.b-8.c) cerró con features densas (marshaling, async bridge,
--bundle-python,--bundle-pip) que justifican espacio propio. M7 nuevo cubre: C1 Setup venv + first imports, C2 numpy + pandas para data analysis real, C3 SQLAlchemy interop + matriz de decisión honesta vs ORM nativo.- M7 anterior renumerado a M8 + cap nuevo C5: el módulo de producción y deployment ahora es M8. Cap M8.C5 NUEVO ("Deploy real de apps con interop Python") cubre
--bundle-python+--bundle-pip+ Dockerfile bundleado — específicamente para apps salidas de M7 que necesitan distribución sin Python en destino. Total final del curso: 8 módulos / 41 capítulos.
Qué es¶
Serie de tutoriales en español que enseñan Fitz desde la instalación hasta un proyecto productivo, usando VSCode como editor obligatorio (para que la extensión y el LSP sean parte visible del aprendizaje).
Se diferencia de docs/guide.md:
guide.md |
curso | |
|---|---|---|
| Estilo | referencia feature-por-feature | narrativo, proyecto que crece |
| Audiencia | gente que ya empezó | desde cero absoluto |
| Código | ejemplos aislados | un solo proyecto incremental |
| Pre-reqs | sabés programar | sabés programar pero no Fitz |
Posicionamiento y por qué importa¶
La guide.md cubre el lenguaje feature por feature, sirve como
referencia y como introducción a quien ya está mirando Fitz con
intención técnica. Lo que falta es la puerta de entrada
pedagógica para alguien que cae al sitio, lee "HTTP nativo +
async + auth + WebSockets" y necesita verlo construirse paso a
paso desde un print("hola") hasta un servicio real con DB.
El curso ocupa ese espacio. También es marketing implícito de la extensión VSCode — exigir VSCode obliga a mostrar el LSP en funcionamiento desde el capítulo 3.
Decisiones tomadas (confirmadas 2026-05-23)¶
- Idioma: español, consistente con
guide.md. - Ubicación:
docs/curso/(paralelo aguide.md). Cada módulo es una sub-carpeta con sus capítulos en.md. - Screenshots: descripciones ASCII para la mayoría; solo
screenshots reales para hitos visuales (M1 instalación
completa, M4 Scalar UI en
/docs, M6 hot reload corriendo). - M7 incluido como parte mandatoria (no opcional). Curso total = 7 módulos, 36 capítulos.
- Smoke automatizado: el código de cada capítulo vive en
examples/curso/cXX-tema/y entra al smokeGUIDE_EXAMPLES_COMPILEpara que no se rompa silencioso. Es costo de CI conocido (~30 ejemplos extra) a cambio de garantía de no-drift.
Convención de carpetas (lo que el curso enseña a construir)¶
mi-proyecto/
├── fitz.toml
├── fitz.lock
├── src/
│ ├── main.fitz # entry point (bin)
│ ├── lib.fitz # opcional, módulo raíz exportable
│ ├── models/ # type definitions (User, Order, ...)
│ ├── services/ # lógica de negocio
│ ├── handlers/ # @get/@post/@ws — HTTP/WS endpoints
│ ├── middleware/ # @middleware reusables
│ └── db/ # acceso a datos (interop Python en M6)
├── tests/ # @test fns con `fitz test`
├── .env # cargado con load_env() (M7)
└── README.md
"Namespaces" en Fitz = módulos (from src.models.user import
User). El curso lo trata como tal y enseña cuándo separar.
Regla heurística que el curso enseña: un archivo por concepto
cohesivo, agrupar por capa (models / services / handlers
/ db) antes que por feature, hasta que el proyecto crezca
lo suficiente para justificar el cambio.
Módulos y capítulos¶
M1 — Setup y primer programa (5 capítulos)¶
Requisito explícito: VSCode + extensión Fitz instalada.
| Cap | Título | Objetivo | En VSCode se ve | Entregable |
|---|---|---|---|---|
| C1 | Instalación | Bajar binario fitz, instalar .vsix, validar fitz --version |
Extension activada, status bar muestra "Fitz LSP" | Terminal con fitz funcionando |
| C2 | fitz new |
Crear hola-fitz con fitz new hola-fitz, abrir en VSCode |
Estructura fitz.toml + src/main.fitz, syntax highlighting |
Proyecto skeleton |
| C3 | Hola mundo + LSP | Editar main.fitz, hover sobre print, autocomplete, tipear error y borrarlo |
Hover tooltip con tipos, autocomplete pop-up, subrayado rojo | print("Hola, Fitz") corriendo |
| C4 | CLI esencial | fitz run / check / fitz fmt / fitz lint — qué hace cada uno |
Comandos desde terminal integrada | Familiaridad con el ciclo edit-run |
| C5 | REPL | fitz repl, comandos :type, :help, :load, history |
REPL en terminal integrada | Experimentar interactivamente |
M2 — Tipos y funciones (7 capítulos, single-file todavía)¶
| Cap | Título | Cubre |
|---|---|---|
| C6 | Variables y primitivos | let, Int/Float/Str/Bool/Null, reasignación, anotaciones opcionales |
| C7 | Strings e interpolación | "hola, {name}", métodos upper/lower/len, operadores |
| C8 | Funciones | fn, params/return tipados, expresión => vs bloque, scope |
| C9 | Control flow | if/while/for in 0..10/loop/match |
| C10 | Tipos custom | type User { id: Int, name: Str, email: Str? = null }, defaults, nullables, igualdad |
| C11 | Errores con Result | Result<T>, Ok/Err, operador ?, match exhaustivo |
| C12 | Higher-order | xs.map(fn(x) => x * 2), filter, find, FnExpr inline |
Entregable del módulo: calculadora CLI single-file con
tipos custom + validaciones via Result.
M3 — Módulos y organización (5 capítulos) ★ namespaces y buenas prácticas¶
| Cap | Título | Objetivo |
|---|---|---|
| C13 | import vs from import |
Cuándo usar cada uno, aliases con as, path relativo desde el archivo |
| C14 | Multi-archivo: separar models/ |
Refactor de la calculadora — sacar type a src/models/operacion.fitz. Mostrar go-to-definition cruzando archivos |
| C15 | [lib] y [bin] en fitz.toml |
Convertir una parte en biblioteca, otra en binario. Cuándo conviene |
| C16 | Path deps reusables | fitz add validador --path ../validador-fitz — extraer un módulo a un crate aparte y reusarlo |
| C17 | Tests con @test |
tests/unit_models.fitz, assert_eq, fitz test, filtros |
Entregable: calculadora reorganizada en src/models/ +
src/services/ + tests/, con un validador-fitz como path
dep separado, todo lintado y formateado.
M4 — HTTP first-class (5 capítulos)¶
| Cap | Título | Cubre |
|---|---|---|
| C18 | Primer @get |
Handler simple, @server(3000), curl, ver /docs Scalar en navegador |
| C19 | Path params + body | @get("/users/{id}") + @post("/users") con User body deserializado, Result<User> → 200/500 |
| C20 | Organización HTTP | Mover handlers a src/handlers/users.fitz. Convención: un archivo por recurso |
| C21 | OpenAPI + headers | @header(name="Authorization", into="token"), @server(api_version="1.2.0"), fitz openapi |
| C22 | Middleware + CORS | @middleware(log_request) apilado, cors(...) permisivo vs production, gate-only pattern |
Entregable: API REST de usuarios con 5 endpoints, OpenAPI
auto en /docs, middleware de logging, CORS configurado.
M5 — Async, auth, real-time (4 capítulos)¶
| Cap | Título | Cubre |
|---|---|---|
| C23 | Async nativo | async fn, .await, sleep, handlers async, paralelismo HTTP real |
| C24 | Auth nativa | @auth_provider con JWT + hash.password/verify (Argon2), @authenticated/@admin, 401/403 en OpenAPI auto |
| C25 | WebSockets tipados | @ws("/chat") @authenticated + WsConn<Message> + broadcast + heartbeat, AsyncAPI en /asyncapi.json |
| C26 | Jobs sin Celery | @cron("0 */5 * * * *") + @background + spawn(track_metric) |
Entregable: chat WebSocket con login (JWT), broadcast, job cron de limpieza, todo en el mismo binario.
M6 — Capstone: Postgres + ORM nativo Fitz (6 capítulos)¶
Cambio respecto al plan original: este módulo usaba SQLAlchemy via
fitz py-typescomo capstone. Con la Fase 10 cerrada (ORM nativo Fitz, driver Postgres puro, sin libpq), el camino default ahora es el ORM nativo. SQLAlchemy queda como cap opcional al final del módulo para users con modelos Python existentes.
| Cap | Título | Cubre |
|---|---|---|
| C27 | Setup Postgres | docker-compose.yml para Postgres local, db.connect(env("DATABASE_URL")?), primer query con db.query |
| C28 | Modelos con @table |
type User { ... } @table("users") @primary id: Int + @column/@belongs_to/@has_many, generación automática del schema |
| C29 | Migraciones | fitz db diff para ver el SQL DDL que falta, fitz db migrate para aplicarlo, fitz db status para ver el estado |
| C30 | CRUD end-to-end | Handlers Fitz con User.where(fn(u) => ...).all(db)?, User.insert(db, user), eager loading con .preload("posts") |
| C31 | DX en producción | fitz dev (hot reload) + fitz test (integración contra DB de test) + fitz lint + GitHub Actions con Postgres service container |
| C32 | fitz build + Docker |
Compilar a binario, Dockerfile multi-stage (boilerplate api-orm-full como referencia), deploy local con docker compose up |
Cap opcional al final del módulo (no obligatorio para el entregable):
| Cap | Título | Cubre |
|---|---|---|
| C32b | Si ya tenés modelos Python | fitz py-types para auto-generar types Fitz desde modelos SQLAlchemy, interop con feature python habilitada |
Entregable: app CRUD de blog con auth JWT (de M5), Postgres
real, migraciones automáticas, hot reload en dev, binario
standalone para prod, Dockerizado. Sin pip, sin SQLAlchemy, sin
ORM externo — todo nativo del lenguaje.
M7 — Producción y deployment (4 capítulos) — ⏸ PENDIENTE FASE 12¶
Estado: este módulo está suspendido hasta que cierre Fase 12 (deployment ciudadano primera clase). Los caps de abajo asumen que
fitz dockerfile/fitz compose/fitz deployestán implementados y producen artefactos canónicos. Escribirlo antes de que existan implicaría que el lector aprenda flow manual que después cambia — peor pedagógicamente.Mientras tanto, M1-M6 se releasea como "curso completo backend". Los users que llegan al final de M6 ya tienen una app dockerizable con el boilerplate
api-orm-fullcomo referencia (cap 32 del módulo M6).
| Cap | Título | Cubre |
|---|---|---|
| C33 | Estructura final | Walkthrough de la convención completa con justificación de cada carpeta — modelos vs services vs handlers vs db |
| C34 | Variables de entorno | env("DATABASE_URL")? + load_env(".env")?, conventions para dev/staging/prod |
| C35 | fitz dockerfile + fitz compose |
Generación automática del Dockerfile + docker-compose con la DB detectada del @table (Fase 12.1+12.2) |
| C36 | CI + deploy + más allá | fitz check/test/lint en GitHub Actions + fitz deploy (Fase 12.x), roadmap personal del lector |
Entregable: app de M6 con .env para configuración, CI verde
en GitHub, fitz dockerfile + fitz deploy corriendo end-to-end.
Mapping curso → guide.md¶
El curso NO duplica el contenido de la guía. Cada capítulo cita
la sección correspondiente de guide.md como "detalle
exhaustivo". El curso aporta:
- Narrativa: un proyecto que crece capítulo a capítulo.
- Setup ergonómico: VSCode + LSP visible desde C3.
- Organización de carpetas:
src/models/+services/+handlers/+db/+tests/— convención que la guía no cubre. - Decisiones del autor: cuándo elegir qué.
Mapping completo al estado actual de la guía (post-v0.11.1):
| Cap curso | Cubre | Base en guide.md |
|---|---|---|
| C1 Instalación | Setup fitz + VSCode + .vsix |
(nuevo — no está en guía) |
C2 fitz new |
Crear proyecto skeleton | §16b Package manager |
| C3 Hola + LSP | Editar + hover + autocomplete | §2 + §22 (editores) |
| C4 CLI esencial | run/check/fmt/lint en terminal | §23 fmt + §24 test + §25 dev + §27 lint |
| C5 REPL | fitz repl + :type + :load |
§26 REPL |
| C6-C12 Tipos+fns | Vars/Strings/Fns/Control/Type/Result/HOF | §3-15 |
| C13-C16 Módulos+pkg | import + multi-archivo + [lib] + path deps + tests |
§16 + §16b + §24 |
| C17 Tests | @test/assert_eq/fitz test/filtros |
§24 |
| C18-C22 HTTP | @get/path params/body/OpenAPI/middleware/CORS |
§17 + §18 docs + middleware |
| C23 Async | async fn/.await/sleep |
§19 |
| C24 Auth | @auth_provider/@authenticated/JWT/Argon2 |
§28 |
| C25 WS | @ws/WsConn<T>/broadcast/AsyncAPI |
§29 |
| C26 Cron | @cron/@background/spawn |
§30 |
| C27-C32 ORM nativo capstone | Postgres + @table + migraciones + CRUD + Docker |
§31 Postgres + ORM + DB y ORM exhaustivo |
| M7.C1-C3 Interop Python (nuevo) | Setup venv + from python import + numpy/pandas + SQLAlchemy async |
§21 entero (15 sub-secciones) |
| M8.C1 Distribución avanzada | Binarios standalone + cross-compile + --bundle-python |
§20 fitz build + §21.11 |
| M8.C2 Observability | logs + spans + métricas + OTLP | §33 Observability |
| M8.C3 Secrets management | secret() + config() + Secret<T> |
§32 env + §35 Deployment |
| M8.C4 Deploy con Docker | fitz docker init/build + healthz + K8s + 12-factor |
§35 Deployment ciudadano |
| M8.C5 Deploy con interop Python (nuevo) | --bundle-python + --bundle-pip + Dockerfile bundleado |
§21.11 + §21.12 |
Regla operativa del curso: cada cap arranca diciendo qué features nuevas introduce y, al final, linkea a las secciones exhaustivas de la guía. El lector que quiera profundizar tiene camino claro; el lector que sigue lineal no se desvía.
Template del capítulo¶
Cada capítulo en docs/curso/mX/cXX-tema.md sigue esta
estructura:
# CXX — Título corto
**Pre-requisitos**: CYY (...), CZZ (...)
**Objetivo**: una sola oración con qué tiene que saber/hacer
el lector al terminar.
**Por qué importa**: una sola oración con el "por qué" para
que el lector entienda el motivo, no solo el cómo.
## Paso 1 — ...
## Paso 2 — ...
## Paso 3 — ...
(En cada paso: comando, código, qué se ve en VSCode si aplica)
## Código antes / después
(Diff o bloques `antes:` / `después:` cuando hay refactor)
## Validación
(Cómo confirmar que funciona — `fitz run`, `curl`, output esperado)
## Entregable commiteable
`examples/curso/cXX-tema/` — ejecutable con `fitz run` (o `fitz
build` si aplica). Entra al smoke `GUIDE_EXAMPLES_COMPILE`.
## Lo que viene en CXX+1
(Bridge de una oración al próximo capítulo)
Cuándo arrancar¶
Sin fecha. Es iniciativa paralela a las fases del lenguaje — no bloquea ni es bloqueada por Fase 10 / 11 / 12.
Cuando arranquemos, el orden propuesto es:
- Crear
docs/curso/con unindex.mdque liste los módulos - Escribir M1 entero (5 caps) y validar smoke
- Releasear M1 públicamente (post en blog, anuncio, etc.) para ver si tracciona antes de invertir en M2-M7
- Iterar el resto según feedback
Cada módulo es una unidad releasable independiente. M1-M3 funcionan como "tutorial corto"; M1-M4 como "tutorial HTTP"; M1-M6 como "curso completo backend"; M7 es polish para los que quieren llegar a producción.
Riesgos identificados¶
- Drift: cada cambio del lenguaje puede romper código del
curso. Mitigación: smoke automatizado +
feedback_post_changes_smoke_examples_boilerplates. - Mantenimiento de screenshots: si los hacemos, envejecen. Mitigación: descripciones ASCII por default, screenshots solo para los 3 hitos visuales.
- Audiencia diluida: el curso compite con
guide.mdpor attention budget. Mitigación: cross-link explícito al inicio de ambos ("¿buscás referencia? → guide. ¿buscás aprender desde cero? → curso"). - Tiempo de escritura: 36 capítulos es mucho. Mitigación: releasear por módulo, no esperar al curso entero.
Tiers pre-M5 (acordado 2026-06-01)¶
M5 del curso cubre Async (C23) + Auth (C24) + WebSockets (C25) +
Jobs (C26). Los caps C24/C25/C26 tienen deudas residuales
documentadas en docs/roadmap.md → "Fase 9.w iteración 2" que se
diferían a "post-Fase 10". Fase 10 cerró en v0.10.x, así que el
disparador real ahora es el avance del curso.
Decisión: ciertas deudas se cierran ANTES de arrancar a escribir M5, para no enseñar funcionalidad con gaps obvios (ej: el cap C26 sin persistencia tendría que decir "ojo, si reinicia el server perdés los jobs" — justo lo que Fitz vende contra Celery).
T1 — bloquean M5 (cerrar antes de arrancar a escribir)¶
Estado: CERRADO entero (2026-06-02, v0.11.2) — bloque
9.w.3.iter2 cubrió los tres items en un release dedicado.
Detalle técnico en docs/roadmap.md → "9.w.3.iter2" y en el
CHANGELOG. El cap 30 de la guía documenta el flow nuevo.
| # | Item | Cap impactado | Estado |
|---|---|---|---|
| 1 | Persistencia de jobs sobre DB nativa | C26 Jobs | ✅ CERRADO v0.11.2 — store=db crea fitz_cron_jobs + fitz_cron_runs con CREATE TABLE IF NOT EXISTS al boot, persiste cada attempt |
| 2 | Retry con backoff exponencial para @cron (+ tz/retry también en @background) |
C26 Jobs | ✅ CERRADO v0.11.2 — retry={max, backoff: "exponential"\|"linear"\|"constant", initial_secs, max_secs} capeado |
| 3 | Cron timezone configurable (@cron(..., tz="America/Argentina/Buenos_Aires")) |
C26 Jobs | ✅ CERRADO v0.11.2 — IANA via chrono-tz, default UTC |
Bonus cerrado en el mismo bloque (no estaba en T1 original):
catch_up=true|false — al boot, si hubo missed runs entre
last_run_at y now, ejecuta UN run inmediato (no N, evita
spam). Default false.
T2 — evaluar antes de M5 (cierran caso de uso del cap si entran)¶
| # | Item | Cap impactado | Decisión |
|---|---|---|---|
| 4 | Rooms/channels en WebSockets | C25 WS | Depende del ejemplo del cap. Si el chat tiene salas (típico), entra T1. Si es chat global plano, baja a T3 |
| 5 | Reconnect con state replay | C25 WS | Acopla con persistencia de T1.1. Si entra T1.1 con storage genérico, agrego mientras estoy ahí |
| 6 | RBAC con roles custom (más allá de @admin) |
C24 Auth | El cap puede vivir con @admin único, pero un curso real va a querer enseñar @requires("editor") o similar |
| 7 | Token refresh/revocación server-side | C24 Auth | Acopla con T1.1 (la blacklist necesita storage). Si está la persistencia, este es chico |
T3 — post-M5 (mencionar como deuda visible en el cap, no bloquean)¶
- Coordinación multi-instancia (locks distribuidos) — el curso enseña single-instance, está bien
spawncon coordinación múltiple (Promise.all style) — helper de stdlib eventualmente- Sessions cookie-based — alternativa a JWT, fuera de alcance del curso
- JWT asimétricos (RS256/ES256) — advanced security
- Backpressure explícito en WS
- Heterogéneos en
jwt.encode/decode(Map)
Orden de ejecución acordado¶
Mini-fases discretas, una por release, en este orden:
- 9.w.3.iter2 ✅ CERRADO 2026-06-02 (v0.11.2) — Persistencia + retry + timezone + catch_up de jobs (T1.1 + T1.2 + T1.3 + bonus catch_up cerrados juntos).
- 9.w.1.iter2 — RBAC custom + token refresh (T2.6 + T2.7 — comparten la noción de "roles persistidos" si entra refresh).
- 9.w.2.iter2 — Rooms + reconnect state replay (T2.4 + T2.5 — solo si el ejemplo del C25 los exige; si no, baja a T3).
- Arrancar M5 del curso.
C23 (Async) no tiene deudas relevantes — sale directo cuando llegue su turno.
Cuando alguno de los tiers cierre, marcarlo en esta tabla como
CERRADO con fecha + versión, y actualizar paralelamente en
docs/roadmap.md → "Fase 9.w iteración 2".