El desarrollo de Taskito se guio por principios SOLID y una arquitectura por capas (routers → servicios → repositorios/ORM → esquemas), priorizando seguridad, mantenibilidad y pruebas desde el inicio. Se optó por un enfoque iterativo: primero un “esqueleto” funcional end-to-end, luego endurecimiento de seguridad y validaciones, y finalmente observabilidad y experiencia de usuario.
En el frontend se usó Next.js (App Router) para (mayoritariamente client-side para velocidad de desarrollo) y una SPA fluida, con TailwindCSS para estilos utilitarios y shadcn/ui para componentes accesibles y consistentes. La gestión de estado global se resolvió con Redux Toolkit, y se alinearon las validaciones con el backend para evitar discrepancias (errores claros en formularios y reglas compartidas). Nginx actúa como reverse proxy y punto de terminación TLS, sirviendo estáticos y enrutando a la API.
El backend se implementó con FastAPI por su tipado, rendimiento y documentación automática. Pydantic define esquemas de entrada/salida y garantiza validación robusta. SQLAlchemy se emplea como ORM, aprovechando el binding de parámetros para mitigar inyecciones SQL y mantener una capa de persistencia limpia y testeable. La autenticación se basa en JWT con expiración configurable y control de permisos (roles), y se añadieron middlewares y políticas de seguridad (CORS, CSP estricta para reducir superficie de XSS y carga de recursos no confiables, y SSL en el proxy). Para protección en formularios se utilizó el patrón de doble envío (double submit) de CSRF en las interacciones que lo requieren. Redis apoya almacenamiento del rate limiting; SlowAPI impone límites diferenciados para endpoints de autenticación y generales.
Las pruebas: Pytest para unitarias y de servicios (incluyendo rutas críticas de error y seguridad), mientras que Cypress cubre flujos end-to-end y componentes del frontend (autenticación, CRUD de tareas, filtros y paginación). Se priorizó la trazabilidad de errores mediante respuestas HTTP consistentes y mensajes de validación comprensibles. En integración local, Docker Compose orquesta todos los contenedores (frontend, api, db, redis, nginx y observabilidad), garantizando reproducibilidad y un entorno cercano a producción.
En observabilidad, Grafana + Loki + Promtail permiten centralizar logs y paneles básicos para salud del sistema. La API expone healthchecks y métricas esenciales, y el proxy facilita diagnóstico con access logs. Finalmente, se mantuvo coherencia entre frontend y backend: mismas reglas de validación, manejo de errores uniforme y tipado estricto, lo que redujo defectos y aceleró la iteración.
Herramientas y tecnologías clave:
- Frontend: Next.js, TailwindCSS, shadcn/ui, Redux Toolkit, Cypress.
- Backend: FastAPI, SQLAlchemy, Pydantic, Pytest, SlowAPI (rate limiting).
- Infra/observabilidad: Docker Compose, Nginx (SSL), Redis, Grafana, Loki, Promtail.
- Seguridad: JWT, CSRF (double submit), CSP estricta, CORS, SQL parametrizado, TLS.
Esta guía explica cómo instalar y ejecutar todo el proyecto Taskito en tu entorno local usando Docker Compose. Incluye frontend (Next.js), backend (FastAPI), base de datos (PostgreSQL), Redis, Nginx (con SSL autofirmado), Grafana y Loki/Promtail para logs.
- Frontend: Next.js (puerto interno 5173) servido tras Nginx.
- Backend: FastAPI (puerto interno 8000) tras Nginx con prefijo
/api. - DB: PostgreSQL 14 (volumen persistente).
- Cache/Queue: Redis 7 (volumen persistente).
- Observabilidad: Grafana + Loki + Promtail.
- Reverse proxy: Nginx (HTTP 80 / HTTPS 443) con certificado autofirmado.
Rutas rápidas:
- Frontend: https://localhost/
- API: https://localhost/api
- Healthcheck: https://localhost/api/health
- Grafana: http://localhost:3000/d/taskito-logs/taskito-logs?orgId=1&from=now-1h&to=now&timezone=browser (user:
admin, pass:admin)
- Docker Desktop (con WSL2 habilitado)
- Git
- Puertos libres: 80, 443, 5173, 8000, 3000, 3100, 5432, 6379
- Nota SSL: el certificado es autofirmado (desarrollo). El navegador mostrará advertencia la primera vez: acepta la excepción para continuar.
Opcional (solo si quieres correr sin Docker):
- Python 3.11
- Node.js 18+ y npm 9+
git clone https://github.com/ReylanLugo/taskito.git
cd taskitoDocker Compose utiliza este archivo para configurar api, postgres y frontend.
Crea ./.env.local con el contenido:
# Database configurationPOSTGRES_USER=postgresPOSTGRES_PASSWORD=dev_passwordPOSTGRES_DB=taskitoPOSTGRES_PORT=5432# Redis configurationREDIS_HOST=redisREDIS_PORT=6379# API configurationAPI_PORT=8000# Additional app settingsDEBUG=TrueSECRET_KEY=taskito_dev_secret_key# Authentication settingsALGORITHM=HS256ACCESS_TOKEN_EXPIRE_MINUTES=30REFRESH_TOKEN_SECRET="anything"REFRESH_TOKEN_EXPIRE_MINUTES=3600RATE_LIMIT_ENABLED=TrueRATE_LIMIT_REQUESTS=100RATE_LIMIT_WINDOW="minutes"RATE_LIMIT_AUTH_REQUESTS=100RATE_LIMIT_AUTH_WINDOW="minutes"CORS_ALLOW_ORIGINS=["http://localhost:3000", "http://localhost:5173", "https://localhost"]## FrontendAUTH_SECRET="sF7of/9pD2Hsq7MeCgI2x1qyAxABTpPxCPEKCM1VnYQ="AUTH_TRUST_HOST=trueNEXTAUTH_URL=http://localhost:3000NEXTAUTH_SECRET="sF7of/9pD2Hsq7MeCgI2x1qyAxABTpPxCPEKCM1VnYQ="NEXT_PUBLIC_BACKEND_URL=http://api:8000NEXT_PUBLIC_API_URL=http://localhost:3000Notas:
- El backend (
backend/app/config.py) ya define CORS parahttp(s)://localhosty:3000. - El
docker-compose.ymlexporta al frontend:NEXT_PUBLIC_API_URL=https://localhost/apiyNODE_TLS_REJECT_UNAUTHORIZED=0(permite SSL autofirmado en dev).
(Pydantic necesita tener instalado rust y su compilador) Desde la raíz del proyecto:
docker compose up -d --build
Si algo sale mal para un hard reset y limpieza de todos los contenedores:
docker compose down -v --rmi all --remove-orphans; docker compose build --no-cache; docker compose up -dServicios que se levantarán (según docker-compose.yml):
nginx: reverse proxy, puertos 80/443.api: FastAPI en 8000 (volumen./backend:/app). Ejecutastartup.sh(espera DB, aplica migraciones, inicia Uvicorn).postgres: 14 (volumen persistentepostgres-data).redis: 7 (volumen persistenteredis-data).lokiypromtail: recolección de logs.grafana: dashboards (puerto interno 3000), accesible por Nginx en/grafana.frontend: Next.js (puerto interno 5173), accesible por Nginx en/.
- Ver contenedores:
docker compose ps- Revisar logs (Grafana):
(user: `admin`, pass: `admin`)
http://localhost:3000/d/taskito-logs/taskito-logs?orgId=1&from=now-1h&to=now&timezone=browser
- Probar en el navegador:
- Frontend: https://localhost/
- API root: https://localhost/api/docs (Login primero en https://localhost para obtener la cookie) (Debido a las politicas CSP con cada actualizacion se debe actualizar el hash en el middleware para permitir la insertacion de js en el dom por parte de swagger)
Si el navegador advierte por certificado, acepta la excepción (SSL autofirmado de desarrollo).
docker compose exec api alembic revision --autogenerate -m "Initial migration"docker compose exec api alembic upgrade headcd backend
winget install -e --id Python.Python.3.11 (3.11.9)
py -3.11-m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
pytest --cov=app --cov-report=term-missing --cov-report=htmlcd frontend
npm install
npx cypress run --component- Nginx: 80 y 443
- API: 8000 (interno), accesible vía Nginx en
https://localhost/api - API Docs: 8000 (interno), accesible vía Nginx en
https://localhost/api/docs - Frontend: 5173 (interno), accesible vía Nginx en
https://localhost/ - Grafana: 3000 (interno), accesible vía Nginx en
https://localhost/grafana/ - Loki: 3100 (interno)
- Postgres: 5432 (mapeado)
- Redis: 6379 (mapeado)
- SSL autofirmado: el navegador mostrará advertencia; acepta la excepción para
https://localhost. - Conflicto de puertos: libera el puerto o ajusta mapeos en
docker-compose.yml. .env.localfaltante o variables incorrectas: elapino conectará a Postgres/Redis. En Docker, usapostgresyrediscomo hosts.- Fin de línea en
startup.sh(Windows): si ves/bin/bash^M, convierte a LF y reconstruye. - Migraciones: si el modelo cambió, crea migración autogenerada y aplica
alembic upgrade head.
docker compose down # Parar
docker compose down -v # Parar y borrar volúmenes (pierdes datos de Postgres/Redis)- Backend: FastAPI + SQLAlchemy + Alembic + Redis + SlowAPI (rate limiting) + middlewares de seguridad, CORS, CSP y CSRF.
- Frontend: Next.js + Redux Toolkit + Cypress.
- Observabilidad: Grafana + Loki + Promtail.
┌──────────────────────────┐
│ Usuario │
│ Navegador(NextJs/Redux)│
└───────────┬──────────────┘
│ HTTP(S)
│
┌──────────────────────────┐ ┌──────────▼───────────┐
│ Contenedor: nginx │ │ Contenedor: frontend │
│ Reverse Proxy / Static │ │ (App Router) │
│ - TLS/terminación (HTTPS)│ │ - Sirve UI │
│ - Rutas /gzip /caché │ │ - Habla con API │
└──────────┬───────────────┘ └──────────┬────────────┘
│ HTTP(S)
│
▼
┌───────────────────────────────────────────────────────────────┐
│ Contenedor: api (FastAPI) │
│ App: Taskito │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Routers: │ │
│ │ - /auth (login, register, perfil, roles) │ │
│ │ - /tasks (CRUD, filtros, stats, comentarios) │ │
│ │ - /users (CRUD propositos admin) │ │
│ │ - /ws (websocket) │ │
│ │ - /health, / │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Servicios (SOLID): │ │
│ │ - UserService (hash, JWT, roles, activación) │ │
│ │ - TaskService (CRUD, filtros, paginación, orden) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Schemas (Pydantic): User*, Task*, Filters, Token* │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Middleware/Seguridad: │ │
│ │ - Rate limiting (slowapi: auth vs general) │ │
│ │ - JWT auth │ │
│ │ - Validaciones coherentes front/back │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │ │
│ │SQLAlchemy │Rate limit store │
└──────┼───────────────┬────────────────┼───────────────┬───────┘
│ │ │
▼ │ ▼
┌──────────────────┐ │ ┌──────────────────────┐
│ Contenedor: db │ │ │ Contenedor: redis │
│ PostgreSQL │ │ │ (opcional) │
│ - Datos de users │ │ │ - Store para limiter │
│ y tasks │ │ └──────────────────────┘
└──────────────────┘ │ │
│ (logs, métricas opcionales)
▼
┌──────────────────────────────┐
│ Contenedor: monitoring/logs │
│ (Loki/Grafana) │
└──────────────────────────────┘
Estado actual:
- Backend (FastAPI) con autenticación JWT, validaciones sólidas y rate limiting (auth vs general).
- Base de datos PostgreSQL y Redis disponibles en Compose.
- Frontend funcionando detrás de Nginx con HTTPS en desarrollo, integración con API y documentación de Swagger protegida por políticas CSP.
- Observabilidad básica con Loki + Grafana.
Próximos pasos propuestos:
- Notificaciones de tareas próximas a vencerse (background jobs)
- Objetivo: alertar a usuarios cuando una tarea esté por vencer (por ejemplo, 24h/1h antes) y cuando se venza.
- Tecnologías: Celery (workers) + Redis (broker y opcionalmente backend de resultados) + Celery Beat (scheduler).
- Acciones:
- Añadir servicios al
docker-compose.yml:celery-workerycelery-beatque apunten al mismo código del backend y compartan.env. - Definir tareas en
backend/app/tasks/notifications.py(ej.:send_due_soon_notifications,send_overdue_notifications). - Programar jobs en Celery Beat (crontab o interval) para revisar tareas con
due_datecercano y emitir notificaciones (email, WebSocket, o push interno). - Exponer configuración (ventanas de aviso, plantillas de mensaje) en
config.pyy variables de entorno. - Registrar métricas y logs de ejecución para auditoría (ej.: cuántas notificaciones enviadas, errores, reintentos).
- Añadir servicios al
- SSR con Next.js y ajuste de Nginx
- Objetivo: migrar el frontend a SSR con Next.js (App Router), mejorando SEO, performance inicial y rutas dinámicas.
- Acciones:
- Migrar el frontend a Next.js (si no está completo) y unificar entorno en puerto 3000.
- Actualizar
frontend/Dockerfilepara producción SSR (build + start) y development según necesidad. - Refactorizar
nginxpara:- Proxyear
/al SSR de Next.js (puerto 3000),/apial backend (puerto 8000) y/wssi aplica. - Habilitar HTTP/2, gzip/brotli, cache estático agresivo para
_next/staticy headers de seguridad. - Mantener compatibilidad con CSP (actualizar hashes si se inyecta JS en Swagger/NextAuth).
- Proxyear
Checklist sugerido:
- Añadir
celery[redis]alrequirements.txty crear móduloapp/celery.pycon la instancia. - Crear
celery-workerycelery-beatendocker-compose.ymlcon healthchecks. - Implementar tareas de notificación y pruebas de integración (fixtures con Redis y DB).
- Añadir endpoints/flags para activar/desactivar notificaciones por usuario.
- Migrar frontend a Next.js SSR y ajustar variables (
NEXTAUTH_URL,NEXT_PUBLIC_*). - Refactor de
nginx.confpara enrutar SSR/estático/API/WS con compresión y caché adecuados. - Actualizar documentación (README) y diagramas.