feat: version 3.0.0 -- Correcciones de auditoria de seguridad, accesibilidad y redundancia
Permisos (superadmin, viewer, busqueda, tareas recurrentes), bootstrap atomico, revocacion de JWT por version de sesion (028), control optimista de edicion (029), logo sin SVG + CSP, ingesta endurecida, correos escapados, borradores, paginacion de proyectos, accesibilidad de dialogos/controles e i18n. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
|
||||
- Tipo: Bearer JWT (`Authorization: Bearer <token>`), emitido por `/api/auth/login`.
|
||||
- El backend revalida `is_active` del usuario en cada request (no solo la firma del JWT).
|
||||
- El JWT incluye `sv` (versión de sesión). Cambiar o restablecer la clave revoca los JWT
|
||||
anteriores; se responde `401` y el usuario vuelve a iniciar sesión.
|
||||
|
||||
## Formato de respuesta
|
||||
|
||||
@@ -20,6 +22,14 @@
|
||||
}
|
||||
```
|
||||
|
||||
## Edición concurrente
|
||||
|
||||
Los `PUT` de proyectos, comentarios, actividades, tareas, departamentos, usuarios, los cuatro
|
||||
catálogos, notas, tareas recurrentes, equipos y SMTP exigen `editVersion` (entero positivo)
|
||||
obtenido de la lectura correspondiente como `edit_version`. El `PUT /api/company` exige el mismo
|
||||
campo en multipart. La API responde `428` si falta o es inválido y `409` si otro guardado cambió
|
||||
el registro. En empresa y SMTP la respuesta `GET` incluye `edit_version`.
|
||||
|
||||
## Endpoints principales
|
||||
|
||||
### Auth
|
||||
@@ -45,16 +55,19 @@
|
||||
|
||||
### Usuarios (`/api/users`) — lectura para cualquier autenticado; escritura solo Administrador/Superadministrador
|
||||
- `GET /api/users` · `POST /api/users` · `PUT /api/users/:id` · `PATCH /api/users/:id/active`
|
||||
- `POST /api/users/:id/approve` — `{ roleId?, departmentId? }`, solo sobre usuarios `pending_approval`
|
||||
- `POST /api/users/:id/approve` — `{ roleId?, departmentId?, editVersion }`, solo sobre usuarios `pending_approval`; también rechaza cambios concurrentes con `409`.
|
||||
- `POST /api/users/:id/reject` — borra al usuario `pending_approval` (se audita el email antes)
|
||||
|
||||
### Departamentos (`/api/departments`)
|
||||
- `GET /api/departments` (árbol) · `POST /api/departments` · `PUT /api/departments/:id` · `DELETE /api/departments/:id`
|
||||
|
||||
### Proyectos (`/api/projects`)
|
||||
- `GET /api/projects` (filtros: estado, responsable, prioridad; `trash=true` = papelera, solo
|
||||
superadmin) · `POST /api/projects`
|
||||
- `GET /api/projects/:id` · `PUT /api/projects/:id`
|
||||
- `GET /api/projects` (filtros: `statusId`, `priorityId`, `ownerUserId`, `dueSoon=true`,
|
||||
`progress=hide|only`, `q`, `trash=true` solo superadmin; `page` desde 1 y `pageSize` 1–100,
|
||||
predeterminado 20) → `{ items, total, page, pageSize }` · `POST /api/projects`.
|
||||
- `GET /api/projects/options` → `{ id, code, name }[]` accesibles al usuario para selectores.
|
||||
- `GET /api/projects/:id` · `PUT /api/projects/:id` — para editar, enviar `editVersion` obtenido
|
||||
de `GET`; `428` sin versión, `409` si otra edición la cambió.
|
||||
- `DELETE /api/projects/:id` — eliminación lógica (`deleted_at`/`deleted_by`), mismo permiso que
|
||||
editar el proyecto. `POST /api/projects/:id/restore` y `DELETE /api/projects/:id/permanent`
|
||||
(borrado físico, irreversible, arrastra actividades/comentarios/adjuntos) — ambos solo
|
||||
@@ -107,21 +120,24 @@
|
||||
(`last_reminder_sent_at`, se limpia al completar el ciclo).
|
||||
|
||||
### Comentarios (`/api/comments`)
|
||||
|
||||
- `PUT /api/comments/:id` — `{ message, editVersion }`; `428` sin versión y `409` si cambió.
|
||||
- `GET /api/comments?entityType=project&entityId=1` · `POST /api/comments`
|
||||
|
||||
### Adjuntos (`/api/attachments`)
|
||||
- `GET /api/attachments?entityType=activity&entityId=1` · `POST /api/attachments` (multipart)
|
||||
- `GET /api/attachments?entityType=activity&entityId=1` · `POST /api/attachments?entityType=activity&entityId=1`
|
||||
(multipart; entidad y permiso se validan antes de recibir el archivo)
|
||||
- `GET /api/attachments/:id/download` · `DELETE /api/attachments/:id`
|
||||
|
||||
### Notas (`/api/notes`)
|
||||
- `GET /api/notes` — solo las del usuario autenticado, ordenadas por `updated_at` descendente.
|
||||
- `POST /api/notes` — `{ content }`. `PUT /api/notes/:id` — `{ content }`. `DELETE /api/notes/:id`.
|
||||
- `POST /api/notes` — `{ content }`. `PUT /api/notes/:id` — `{ content, editVersion }`. `DELETE /api/notes/:id`.
|
||||
- Siempre privadas: una nota de otro usuario responde `404` (no `403`, para no revelar que
|
||||
existe). Sin restricción de rol — cualquier autenticado tiene las suyas.
|
||||
|
||||
### Equipos (`/api/devices`) — superadmin / admin / it_manager (tokens: solo superadmin / admin)
|
||||
- `GET /api/devices?q=&kind=&status=&stale=1&diskFull=1` · `GET /api/devices/:id` (con hardware,
|
||||
red, software e historial) · `PUT /api/devices/:id` — `{ status, assignedUserId, departmentId, notes }`.
|
||||
red, software e historial) · `PUT /api/devices/:id` — `{ status, assignedUserId, departmentId, notes, editVersion }`.
|
||||
- `GET /api/devices/dashboard` — KPIs y top (SO, tipo, software). `GET /api/devices/software` ·
|
||||
`GET /api/devices/software/devices?name=` — software transversal.
|
||||
- `GET /api/devices/access` — `{canView, canEdit, canManage}` del usuario (lo usa el menú). Lectura (`GET` de
|
||||
@@ -184,8 +200,8 @@
|
||||
- `GET /api/audit?entityType=project&entityId=1`
|
||||
|
||||
### Configuración SMTP (`/api/settings`) — solo Superadministrador
|
||||
- `GET /api/settings/smtp` — `{ host, port, user, from, configured }` (nunca la clave)
|
||||
- `PUT /api/settings/smtp` — `{ host, port, user, from, pass? }` (`pass` vacío = no cambiarla)
|
||||
- `GET /api/settings/smtp` — `{ host, port, user, from, configured, edit_version }` (nunca la clave)
|
||||
- `PUT /api/settings/smtp` — `{ host, port, user, from, pass?, editVersion }` (`pass` vacío = no cambiarla)
|
||||
- `POST /api/settings/smtp/test` — `{ host, port, user, from, pass?, to }` (`pass` vacío = usa la
|
||||
guardada). Envía un correo real con los valores del formulario (aunque no se hayan guardado) y
|
||||
responde `{ sent: true }` o `400` con el error real del servidor SMTP. Rate-limited (10/15min).
|
||||
@@ -195,8 +211,8 @@
|
||||
logoVersion }`; `name` por defecto "LinkedCorp" si nunca se configuró.
|
||||
- `GET /api/company/logo` — público. Devuelve el archivo de imagen del logo, o `404` si no hay
|
||||
ninguno configurado (el cliente cae al logo estático embebido).
|
||||
- `PUT /api/company` — solo Superadministrador, multipart: `name?` (texto) y `logo?` (archivo,
|
||||
PNG/JPG/WEBP/SVG, máx 3MB). Al subir un logo nuevo se borra el archivo anterior (nunca quedan
|
||||
- `PUT /api/company` — solo Superadministrador, multipart: `name?` (texto), `editVersion` y `logo?` (archivo,
|
||||
PNG/JPG/WEBP, máx 3MB; se comprueba la firma real del archivo). Al subir un logo nuevo se borra el archivo anterior (nunca quedan
|
||||
huérfanos). Guardado en `system_settings` (mismo patrón que SMTP), sin tabla nueva.
|
||||
|
||||
## Errores esperados
|
||||
|
||||
Reference in New Issue
Block a user