13a69aadc3
Vacio = se repite sin fin (comportamiento previo). Al completar un ciclo cuyo proximo vencimiento supera "hasta", la tarea se desactiva sola. Probado en dev con curl (3 ciclos seguidos, se desactiva justo al superar la fecha) y validacion de que "hasta" no puede ser anterior al proximo vencimiento. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
131 lines
7.3 KiB
Markdown
131 lines
7.3 KiB
Markdown
# API - project.linkedcorp.net
|
|
|
|
## Base URL
|
|
|
|
- Desarrollo: `http://localhost:4019/api`
|
|
- Producción: `https://project.linkedcorp.net/api`
|
|
|
|
## Autenticacion
|
|
|
|
- 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).
|
|
|
|
## Formato de respuesta
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {},
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
## Endpoints principales
|
|
|
|
### Auth
|
|
- `POST /api/auth/login` — `{ email, password }` → `{ token, user }`. Si el usuario no esta
|
|
`active` (`pending_verification`/`pending_approval`) o `is_active=0`, `403` con mensaje especifico.
|
|
- `POST /api/auth/register` — público. `{ name, email, password }` → si es el primer usuario del
|
|
sistema: `{ bootstrap: true, token, user }` (superadmin, sesion directa); si no:
|
|
`{ bootstrap: false }` y se envia (o loguea, sin SMTP) un correo de verificación.
|
|
- `GET /api/auth/verify-email?token=...` — público. Pasa el usuario a `pending_approval` y notifica
|
|
in-app a los `admin`/`superadmin` activos.
|
|
- `GET /api/auth/invite?token=...` — público. `{ email }` de la invitación (para prellenar el
|
|
formulario), o `400` si es inválida/expiró.
|
|
- `POST /api/auth/accept-invite` — público. `{ token, name, password }` → completa la cuenta
|
|
creada por `POST /api/projects/:id/members` con `{ email }` (ver arriba): elige nombre y clave,
|
|
pasa a `active` directo (sin aprobación — quien invitó ya la vetó) y devuelve `{ token, user }`
|
|
con sesión iniciada, igual que el bootstrap del primer usuario.
|
|
- `POST /api/auth/forgot-password` — público. `{ email }` → respuesta **siempre genérica**.
|
|
- `POST /api/auth/reset-password` — público. `{ token, password }`.
|
|
- `PUT /api/auth/change-password` — autenticado. `{ currentPassword, newPassword }`, exige la
|
|
clave actual (distinto de `reset-password`, que usa un token de correo sin sesión).
|
|
- `POST /api/auth/logout`
|
|
- `GET /api/auth/me` — usuario actual
|
|
|
|
### 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/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`
|
|
- `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
|
|
superadmin; `permanent` exige que el proyecto ya esté en la papelera (400 si no).
|
|
- `POST /api/projects/:id/members` — `{ userId }` (usuario existente) o `{ email }` (si el correo
|
|
no pertenece a nadie todavía, crea una cuenta `invited` y le manda un correo de invitación para
|
|
que complete su registro; la fila de `project_members` ya queda creada de una vez). `roleInProject`
|
|
opcional: `'admin'` = administrador del proyecto. Responde `{ members, invited }`.
|
|
- `PUT /api/projects/:id/members/:userId/role` (`{ admin: true|false }`, otorga o quita el rol de
|
|
administrador **de ese proyecto** — un proyecto puede tener uno o más administradores, sin
|
|
importar el rol global del usuario; nunca toca al `owner`) ·
|
|
`DELETE /api/projects/:id/members/:userId`
|
|
|
|
### Actividades (`/api/activities`)
|
|
- `GET /api/projects/:projectId/activities` · `POST /api/projects/:projectId/activities`
|
|
- `GET /api/activities/:id` · `PUT /api/activities/:id`
|
|
- `POST /api/activities/:id/dependencies` · `DELETE /api/activities/:id/dependencies/:dependsOnId`
|
|
|
|
### Tareas (`/api/activities/:activityId/tasks`)
|
|
- `GET` · `POST` · `PUT /api/tasks/:id` · `PATCH /api/tasks/:id/done` · `DELETE /api/tasks/:id`
|
|
|
|
### Tareas recurrentes (`/api/recurring-tasks`) — menú propio, independiente de Proyectos
|
|
- `GET` · `POST` · `PUT /api/recurring-tasks/:id` · `DELETE /api/recurring-tasks/:id`
|
|
- `POST /api/recurring-tasks/:id/complete` — cierra el ciclo actual y calcula el próximo
|
|
vencimiento sumando la periodicidad (`interval_value` + `interval_unit`).
|
|
- `POST /api/recurring-tasks/from-task/:taskId` — crea una tarea recurrente a partir de una tarea
|
|
puntual de una actividad (la original no se borra); mismo body que `POST /`.
|
|
- Body: `{ name, description?, projectId?, responsibleUserId?, intervalUnit: 'days'|'months'|'years',
|
|
intervalValue, nextDueDate, endDate?, reminderDaysBefore, reminderHour: 0-23 }`. `endDate` vacío
|
|
= se repite sin fin; al completar un ciclo que la supera, `is_active` pasa a `false` solo.
|
|
- Recordatorio por correo: un job en el propio proceso del backend revisa cada 15 minutos
|
|
(`src/jobs/recurringTaskReminders.js`) y manda el correo cuando `next_due_date -
|
|
reminderDaysBefore` cae hoy, a la hora `reminderHour`. Un solo envío por ciclo
|
|
(`last_reminder_sent_at`, se limpia al completar el ciclo).
|
|
|
|
### Comentarios (`/api/comments`)
|
|
- `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/:id/download` · `DELETE /api/attachments/:id`
|
|
|
|
### Notificaciones (`/api/notifications`)
|
|
- `GET /api/notifications` · `PATCH /api/notifications/:id/read` · `PATCH /api/notifications/read-all`
|
|
|
|
### Dashboard (`/api/dashboard`)
|
|
- `GET /api/dashboard/summary` — KPIs (activos, atrasados, pendientes/vencidas/hoy, avance promedio)
|
|
- `GET /api/dashboard/calendar?month=2026-09` — actividades por fecha límite
|
|
- `GET /api/projects/:id/gantt` — actividades con fechas/avance para el Gantt
|
|
|
|
### Catálogos (`/api/catalogs`) — lectura general, escritura solo Superadministrador
|
|
- `GET/POST/PUT/DELETE /api/catalogs/project-statuses`
|
|
- `GET/POST/PUT/DELETE /api/catalogs/activity-statuses`
|
|
- `GET/POST/PUT/DELETE /api/catalogs/priorities`
|
|
- `GET/POST/PUT/DELETE /api/catalogs/project-types`
|
|
|
|
### Auditoría (`/api/audit`) — solo Superadministrador / Administrador / Jefe de TI
|
|
- `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)
|
|
- `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).
|
|
|
|
## Errores esperados
|
|
|
|
- `400` validación
|
|
- `401` no autenticado / token inválido o expirado
|
|
- `403` sin permisos para la acción (según rol)
|
|
- `404` no encontrado (incluye cuando el recurso existe pero no pertenece al usuario/alcance)
|
|
- `500` error interno (sanitizado, sin detalle de stack en producción)
|