1d22adc42e
Backend (Express + MariaDB) y frontend (React + Vite, identidad Fluent/Windows) con el nucleo funcional: seguridad, organizacion, proyectos, actividades, subtareas, dependencias, dashboard, calendario, gantt, comentarios, adjuntos, notificaciones in-app y catalogos. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6.0 KiB
6.0 KiB
Seguridad y Calidad — project.linkedcorp.net
Copia ajustada de la plantilla del grupo (
project-md-templates/SEGURIDAD-Y-CALIDAD.md). Léela antes de escribir código de una nueva funcionalidad y úsala como checklist antes de mergear.Diferencia con la plantilla original: la plantilla asume multi-empresa (
empresaIdpor tenant). Este proyecto es de una sola empresa (single-company), así que el "aislamiento" que aplica aquí no es entre empresas sino entre usuarios y su alcance por rol: qué proyectos/ actividades puede ver o tocar cada rol (ver tabla de roles enSPEC.md).Regla de oro: la seguridad primero; luego, cero duplicación; luego, facilidad de revisión y de extender.
1. Seguridad (NO negociable)
1.1 Alcance por rol (equivalente al aislamiento multi-tenant)
- NUNCA confíes en un
userId/roleque venga en el body/query. El usuario y su rol salen SIEMPRE del token (req.currentUser), nunca del body. - Reglas de alcance por rol (ver
SPEC.md):- Colaborador: solo puede ver/actualizar actividades y subtareas donde es
responsible_user_id, y comentar en los proyectos donde es miembro. - Coordinador/Líder: solo puede crear/editar proyectos donde es
owner_user_ido miembro (project_members), y las actividades de esos proyectos. - Jefe de TI y Administrador: sin restricción de alcance.
- Consultor: solo lectura en todo, ningún endpoint de escritura le responde 2xx.
- Colaborador: solo puede ver/actualizar actividades y subtareas donde es
- Antes de
update/delete/get by idde un recurso, verificar que el usuario tiene alcance sobre ese recurso (por rol + pertenencia al proyecto) y responder 404 si no corresponde (no 403, para no revelar existencia a quien no debería ni saber que existe). - Los IDs relacionados que llegan en el body (
projectId,activityId,dependsOnActivityId, etc.) deben validarse: que existan y que el usuario tenga alcance sobre ellos antes de usarlos.
1.2 Autenticación y autorización
- Toda ruta no pública pasa por middleware de auth (
backend/src/middleware/auth.js). - Revalida en CADA request que la cuenta siga activa (
users.is_active). Un JWT válido por firma NO basta: desactivar un usuario debe cortarle el acceso al instante, no cuando expire el token. - La autorización del frontend es solo UX (ocultar botones/menús); el backend re-verifica rol y
alcance en cada endpoint. El usuario en
localStoragees manipulable.
1.3 Secretos
- Contraseñas:
bcrypt(cost ≥ 12). Nunca en logs ni respuestas. .envfuera de git. El arranque del backend debe abortar en producción siJWT_SECRETo las credenciales de BD son valores por defecto/vacíos.- No exponer rutas absolutas del filesystem del servidor en respuestas de API.
1.4 Entrada y datos
- SQL siempre parametrizado (placeholders
?). Nunca concatenar entrada del usuario. Las cláusulasIN (...)dinámicas se arman con placeholders, no con el valor. - Nombres de columna/orden dinámicos SOLO desde una whitelist del servidor, jamás desde el query string tal cual.
- Uploads (
attachments): validar tamaño y MIME por whitelist. El nombre/ruta del archivo lo genera el servidor (evita path traversal); nunca usar el nombre que manda el cliente como ruta. - Fechas: validar coherencia (
due_date >= start_date, etc.) en el servicio, no solo en el frontend.
1.5 Errores, logs y límites
- Los 5xx ocultan el detalle al cliente en producción.
- Rate limiting en
POST /api/auth/login. - Sirviendo la SPA: CSP (helmet) —
script-src 'self'(sin inline),style-src 'self' 'unsafe-inline',img-src 'self' data: blob:,object-src 'none'.
1.6 Frontend / caché
- El JWT en
localStoragees un trade-off aceptado; mantener CSP y sanitización. - Si en el futuro se agrega caché offline, purgarla en logout y en
401.
2. Cero duplicación (procesos, flujos y funciones)
- Un helper vive en un solo lugar. Antes de escribir una función, buscar si ya existe.
- Helpers compartidos en
backend/src/utils/(fechas, cálculo deprogress_pct, cálculo de estado de vencimiento 🟢/🟡/🔴) yfrontend/src/services/lib(formateadores,fmtDate,roleLabel). - El patrón CRUD repetido (listar/buscar/crear/editar/borrar) se abstrae en un hook reutilizable en
el frontend (
useAsync/useCrud); loading/try-catch/ContentDialog de error, en un solo lugar. - Una sola capa de API en el frontend (
src/services/api.jsconapi.get/post/put/delete).
3. Orden, revisión y facilidad de extender
- Arquitectura backend por módulo: routes → controller → service → repository → db. Un módulo
nuevo replica esa forma (ver
projects/activitiescomo plantilla). - Un archivo, una responsabilidad. Si un
servicecrece mucho o mezcla temas, partirlo. - Sin código muerto.
- Convención única de respuestas:
{ success, data, error }en todos los endpoints; listados con{ items, total }dentro dedata. - El cálculo de
progress_pct(actividad y proyecto) vive en un solo lugar (activities/service.jsyprojects/service.js), nunca duplicado en el frontend como fuente de verdad — el frontend solo muestra el valor que devuelve la API.
4. Checklist antes de mergear / desplegar
Seguridad
- ¿El usuario/rol sale del token, no del body?
- ¿
update/delete/get-by-idverifican alcance por rol (404 si no corresponde)? - ¿La ruta tiene el middleware de auth/rol correcto? ¿Se revalida
is_active? - ¿SQL parametrizado (incl.
IN)? ¿MIME/tamaño validados en adjuntos? - ¿Secretos fuera de respuestas/logs? ¿5xx sin datos internos?
Calidad
- ¿Reutilicé helpers existentes en vez de duplicar?
- ¿Borré el código muerto que este cambio deja atrás?
- ¿El archivo/módulo sigue el patrón y no se volvió inmanejable?
Verificación
- Build/backend arrancan sin errores; smoke test del flujo tocado en dev.
- Migraciones idempotentes; respaldo antes de aplicarlas en producción (cuando exista deploy).