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