d7478d0f21
Al agregar un miembro, el popup ahora permite elegir un usuario existente o escribir un correo nuevo. Si ese correo no pertenece a nadie, se crea una cuenta en estado 'invited' (nombre/clave placeholder) y se le manda un correo con un enlace de un solo uso para que complete su registro (elige su nombre y clave). La fila de project_members se crea de una vez al invitar, asi que en cuanto acepta ya es miembro sin pasos adicionales. A diferencia del autorregistro publico, no pasa por aprobacion de un admin -- quien lo agrego a su proyecto ya lo vetó. Nuevos endpoints publicos GET /api/auth/invite y POST /api/auth/accept-invite. Nueva pagina AcceptInvitePage (/aceptar-invitacion). Migracion 004 agrega el status 'invited' al enum de users. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
117 lines
6.2 KiB
Markdown
117 lines
6.2 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`
|
|
|
|
### Subtareas (`/api/activities/:activityId/subtasks`)
|
|
- `GET` · `POST` · `PUT /api/subtasks/:id` · `PATCH /api/subtasks/:id/done` · `DELETE /api/subtasks/:id`
|
|
|
|
### 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)
|