Skip to content

🎯 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.

mermaid
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 /yo devuelve 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 lector no 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) ​

#RequisitoCómo se comprueba
NF1Cero SQL concatenado. Consultas parametrizadas siempreRevisión de código
NF2Autorización comprobada en cada endpoint, no solo autenticaciónTest: usuario A no accede a datos de B
NF3Validación de entrada en el borde, con errores de campoPOST con datos inválidos → 422 detallado
NF4Sin N+1. Listar 50 tareas con responsable y etiquetas = pocas consultasLog de consultas o EXPLAIN
NF5Índices justificados en el READMEDocumentación
NF6Rate limiting en login y registroTest: 6º intento → 429
NF7Errores con formato uniforme y sin filtrar internalsProvocar un 500 y mirar el cuerpo
NF8Logs estructurados con id de correlación por peticiónInspección de logs
NF9Cobertura de tests ≥70% en la capa de dominioInforme de cobertura
NF10OpenAPI generado y accesible en /docsAbrir la URL
NF11Migraciones versionadas, aplicables desde ceromake db-reset funciona
NF12Arranca con docker compose up sin pasos manualesProbarlo 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ónSegundaTercera (opcional)
Nada / PHPLaravel (cap. 3)FastAPI (cap. 5)Go (cap. 8)
PythonFastAPI (cap. 5)NestJS (cap. 6)Go (cap. 8)
JavaScriptNestJS (cap. 6)Elysia (cap. 7)Laravel (cap. 3)
Quiero rendimientoGo (cap. 8)Rust + Axum (ap. I)FastAPI (cap. 5)
Objetivo empresa grandeSpring 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:

  1. 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.
  2. Borrar un espacio con 500 tareas dentro → ¿cascada, borrado lógico o prohibido? Decídelo y documéntalo.
  3. El último propietario intenta salir del espacio → prohibido: un espacio sin propietario es un recurso huérfano.
  4. Dos usuarios editan la misma tarea a la vez → última escritura gana, o control de versión optimista. Toma una decisión consciente.
  5. Una fecha límite en el pasado → ¿se permite? (Sí: se registran tareas ya vencidas.)
  6. Título con 10.000 caracteres, emojis, comillas y saltos de línea → debe funcionar o rechazarse limpiamente, nunca romperse.
  7. Token caducado a mitad de una sesión larga → 401 con un código que el frontend distinga de "credenciales incorrectas".
  8. Petición sin Content-Type: application/json → 415, no un 500.

Extensiones ​

  1. Tiempo real (cap. 21): las tareas se actualizan en la pantalla de todos los miembros vía SSE o WebSocket.
  2. Adjuntos (caso 5 del cap. 26): subida directa a S3 con URL prefirmada.
  3. Búsqueda de texto completo: tsvector de PostgreSQL primero; solo si se queda corto, un buscador dedicado (apéndice T).
  4. 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é.
  5. Exportación: a CSV y a iCal, asíncrona con cola si el volumen lo justifica.
  6. 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