🎯 Qué construyes: una API REST de gestión de tareas colaborativa, completa y de calidad profesional. Y después, la reconstruyes en otro lenguaje.
Prerrequisitos: capítulos 0-11. Duración: 2 semanas la primera versión, 3-5 días cada versión adicional.
🧠 Por qué repetir el mismo proyecto. Cuando construyes lo mismo en Laravel, FastAPI y Go, dejas de aprender frameworks y empiezas a aprender ingeniería. Ves que la inyección de dependencias, los middlewares, la validación y los repositorios son el mismo concepto con tres sintaxis. Los frameworks caducan; esos conceptos, no. Es el ejercicio que más rápido te convierte en alguien que puede aprender cualquier stack en dos semanas.
El dominio
Un gestor de tareas con espacios de trabajo compartidos. Suena simple; tiene toda la complejidad que necesitas.
erDiagram
USUARIOS ||--o{ MIEMBROS : "pertenece a"
ESPACIOS ||--o{ MIEMBROS : "tiene"
ESPACIOS ||--o{ PROYECTOS : contiene
PROYECTOS ||--o{ TAREAS : contiene
USUARIOS ||--o{ TAREAS : "asignado a"
TAREAS ||--o{ COMENTARIOS : tiene
TAREAS }o--o{ ETIQUETAS : "etiquetada con"Requisitos funcionales
Autenticación y usuarios
POST /auth/registro·POST /auth/login·POST /auth/refresh·POST /auth/logout- Contraseñas con hash y sal (bcrypt/argon2). Nunca en claro, nunca reversible.
- Recuperación de contraseña por email con token de un solo uso y caducidad de 30 min.
GET /yodevuelve el perfil del usuario autenticado.
Espacios de trabajo y permisos
- CRUD de espacios. Quien lo crea es
propietario. - Invitar miembros por email con rol:
propietario,editor,lector. - Autorización por recurso: un
lectorno puede crear tareas; un miembro de otro espacio no puede ver nada de este.
Proyectos y tareas
- CRUD de proyectos dentro de un espacio.
- CRUD de tareas: título, descripción, estado (
pendiente/en_curso/hecha), prioridad, fecha límite, responsable. - Listado con filtros combinables: estado, responsable, etiqueta, rango de fechas, texto libre.
- Paginación y ordenación configurable.
- Reordenar tareas dentro de un proyecto (posición manual).
Comentarios y etiquetas
- Comentarios en tareas, editables solo por su autor.
- Etiquetas por espacio, asignables a varias tareas (N:M).
Actividad
- Registro de actividad por tarea: quién cambió qué y cuándo.
GET /tareas/{id}/actividad
Requisitos no funcionales (los que definen la nota)
| # | Requisito | Cómo se comprueba |
|---|---|---|
| NF1 | Cero SQL concatenado. Consultas parametrizadas siempre | Revisión de código |
| NF2 | Autorización comprobada en cada endpoint, no solo autenticación | Test: usuario A no accede a datos de B |
| NF3 | Validación de entrada en el borde, con errores de campo | POST con datos inválidos → 422 detallado |
| NF4 | Sin N+1. Listar 50 tareas con responsable y etiquetas = pocas consultas | Log de consultas o EXPLAIN |
| NF5 | Índices justificados en el README | Documentación |
| NF6 | Rate limiting en login y registro | Test: 6º intento → 429 |
| NF7 | Errores con formato uniforme y sin filtrar internals | Provocar un 500 y mirar el cuerpo |
| NF8 | Logs estructurados con id de correlación por petición | Inspección de logs |
| NF9 | Cobertura de tests ≥70% en la capa de dominio | Informe de cobertura |
| NF10 | OpenAPI generado y accesible en /docs | Abrir la URL |
| NF11 | Migraciones versionadas, aplicables desde cero | make db-reset funciona |
| NF12 | Arranca con docker compose up sin pasos manuales | Probarlo en limpio |
⚠️ NF2 es el que casi todo el mundo suspende. Es fácil comprobar "¿estás logueado?" y olvidar "¿este recurso es tuyo?". El test obligatorio: crea dos usuarios en espacios distintos y comprueba que el usuario A recibe 404 (no 403) al pedir una tarea de B. 404, porque un 403 confirma que el recurso existe, lo que ya es información filtrada.
Fases
Fase 1 — Rebanada vertical (días 1-3) Un solo caso de uso completo: registrar usuario → login → crear tarea → listarla. Con test de integración. Aquí decides la estructura del proyecto entero.
Fase 2 — El dominio (días 4-7) Espacios, miembros, roles, proyectos, tareas completas, comentarios, etiquetas. Migraciones y datos de prueba (seeds).
Fase 3 — Autorización de verdad (días 8-9) Middleware/guard de permisos por rol y por pertenencia. Tests que intenten saltárselo.
Fase 4 — Calidad (días 10-12) Suite de tests, arreglar los N+1 que encuentres, índices, rate limiting, logs, OpenAPI.
Fase 5 — Empaquetado (días 13-14) Dockerfile multi-etapa, docker-compose.yml, Makefile, README con ADRs, despliegue.
Fase 6 — La segunda versión (semanas 3-4) Reconstruye lo mismo en otro lenguaje del libro. No mires el primer código hasta terminar cada módulo. Al acabar, escribe una comparativa honesta: qué fue más fácil, qué más difícil y por qué.
Rutas sugeridas por perfil
| Si vienes de… | Primera versión | Segunda | Tercera (opcional) |
|---|---|---|---|
| Nada / PHP | Laravel (cap. 3) | FastAPI (cap. 5) | Go (cap. 8) |
| Python | FastAPI (cap. 5) | NestJS (cap. 6) | Go (cap. 8) |
| JavaScript | NestJS (cap. 6) | Elysia (cap. 7) | Laravel (cap. 3) |
| Quiero rendimiento | Go (cap. 8) | Rust + Axum (ap. I) | FastAPI (cap. 5) |
| Objetivo empresa grande | Spring Boot (ap. J) | NestJS (cap. 6) | — |
Criterios de aceptación
□ docker compose up y la API responde, con la BD migrada y con datos de prueba
□ GET /docs muestra el OpenAPI completo
□ Un usuario NO puede leer, modificar ni borrar recursos de otro espacio (test que lo prueba)
□ Un lector recibe 403 al intentar crear una tarea
□ POST /auth/login 6 veces seguidas → 429 con Retry-After
□ POST con body inválido → 422 con los errores por campo
□ GET /proyectos/1/tareas?estado=pendiente&pagina=2&por_pagina=20 funciona y pagina bien
□ Listar 50 tareas con responsable y etiquetas NO dispara 50+ consultas
□ Las contraseñas en la BD son hashes (míralo con psql)
□ Un 500 provocado NO devuelve el stack trace al cliente, pero SÍ queda en los logs
□ make test pasa en limpio
□ El README explica al menos 3 decisiones con su porquéCasos límite que debes cubrir
Son los que separan un CRUD de tutorial de una API real:
- Registro con un email ya existente → 409, y el mensaje no debe revelar si el email existe en contextos donde eso sea información sensible.
- Borrar un espacio con 500 tareas dentro → ¿cascada, borrado lógico o prohibido? Decídelo y documéntalo.
- El último propietario intenta salir del espacio → prohibido: un espacio sin propietario es un recurso huérfano.
- Dos usuarios editan la misma tarea a la vez → última escritura gana, o control de versión optimista. Toma una decisión consciente.
- Una fecha límite en el pasado → ¿se permite? (Sí: se registran tareas ya vencidas.)
- Título con 10.000 caracteres, emojis, comillas y saltos de línea → debe funcionar o rechazarse limpiamente, nunca romperse.
- Token caducado a mitad de una sesión larga → 401 con un código que el frontend distinga de "credenciales incorrectas".
- Petición sin
Content-Type: application/json→ 415, no un 500.
Extensiones
- Tiempo real (cap. 21): las tareas se actualizan en la pantalla de todos los miembros vía SSE o WebSocket.
- Adjuntos (caso 5 del cap. 26): subida directa a S3 con URL prefirmada.
- Búsqueda de texto completo:
tsvectorde PostgreSQL primero; solo si se queda corto, un buscador dedicado (apéndice T). - Caché (apéndice B): Redis para el listado de tareas, con invalidación al escribir. Mide antes y después: si no mejora, quítalo — y documenta por qué.
- Exportación: a CSV y a iCal, asíncrona con cola si el volumen lo justifica.
- Webhooks salientes: notificar a una URL externa al completar una tarea, con reintentos, firma HMAC y dead letter queue.
Siguiente: 03-plataforma-de-cursos.md