# 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 (`empresaId` por > 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 en `SPEC.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`/`role` que 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_id` o 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. - Antes de `update`/`delete`/`get by id` de 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 `localStorage` es manipulable. ### 1.3 Secretos - Contraseñas: `bcrypt` (cost ≥ 12). Nunca en logs ni respuestas. - `.env` fuera de git. El arranque del backend debe **abortar en producción** si `JWT_SECRET` o 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áusulas `IN (...)` 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'`. - La SPA de producción recibe CSP desde `frontend/public/serve.json` (el servidor `serve` copia ese archivo al build); el backend usa Helmet en `/api`. En Vite dev no se aplica el header del servidor `serve`, para permitir el módulo de recarga de React. El logo de empresa solo admite PNG/JPG/WEBP comprobados por firma y se entrega con `nosniff`. ### 1.6 Frontend / caché - El JWT en `localStorage` es 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 de `progress_pct`, cálculo de estado de vencimiento 🟢/🟡/🔴) y `frontend/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.js` con `api.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`/`activities` como plantilla). - **Un archivo, una responsabilidad.** Si un `service` crece 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 de `data`. - El cálculo de `progress_pct` (actividad y proyecto) vive en **un solo lugar** (`activities/service.js` y `projects/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-id` verifican 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).