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>
110 lines
6.0 KiB
Markdown
110 lines
6.0 KiB
Markdown
# 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'`.
|
|
|
|
### 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).
|