bb6bd6865c
Actividad -> Tarea, sin nivel "sub" intermedio (no hay una entidad "Tarea" de la que estas fueran sub-, asi que el prefijo sobraba). Tabla subtasks -> tasks (RENAME TABLE idempotente en la migracion 005; 001_initial.sql tambien actualizado para que una instalacion nueva cree la tabla ya con el nombre final, sin pasar por el nombre viejo). Modulo backend, rutas, servicio frontend, pestaña del detalle de actividad, i18n y documentacion actualizados. Sin cambios de comportamiento, solo nombres. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
156 lines
7.7 KiB
Markdown
156 lines
7.7 KiB
Markdown
# Base de Datos - project.linkedcorp.net
|
|
|
|
## Motor
|
|
|
|
- Motor: MariaDB
|
|
- Base principal: `project_linkedcorp`
|
|
- Host desarrollo: `192.168.222.20`
|
|
- Host producción: `192.168.222.32`
|
|
- Puerto: `3306`
|
|
- Charset: `utf8mb4`
|
|
- Collation: `utf8mb4_unicode_ci`
|
|
|
|
## Fuente de verdad
|
|
|
|
- La base ya existe: sí (creada en dev el 2026-09-03, usuario `project_linkedcorp`).
|
|
- Archivo SQL base: `backend/database/migrations/` (SQL idempotente, numerado, `CREATE TABLE IF NOT EXISTS`).
|
|
- Seeds: `backend/database/seeds/` (roles, catálogos, usuario admin de dev).
|
|
|
|
## Tablas principales (MVP)
|
|
|
|
| Tabla | Contenido |
|
|
|---|---|
|
|
| `roles` | catálogo fijo de 6 roles (superadmin, admin, it_manager, project_lead, collaborator, viewer) |
|
|
| `users` | usuarios, con rol, departamento y ciclo de vida de registro (`status`, tokens) |
|
|
| `system_settings` | clave/valor de configuración del sistema (hoy: SMTP, clave cifrada) |
|
|
| `departments` | departamentos/áreas, jerarquía simple vía `parent_id` |
|
|
| `project_types` | catálogo de tipos de proyecto |
|
|
| `priorities` | catálogo de prioridades (baja/media/alta/crítica) |
|
|
| `project_statuses` | catálogo de estados de proyecto |
|
|
| `activity_statuses` | catálogo de estados de actividad |
|
|
| `projects` | proyectos |
|
|
| `project_members` | usuarios asignados a un proyecto (reemplaza "equipos" como módulo aparte) |
|
|
| `activities` | actividades de un proyecto |
|
|
| `activity_dependencies` | dependencias simples entre actividades ("depende de") |
|
|
| `tasks` | checklist liviano dentro de una actividad ("Tareas" en la UI; renombrada desde `subtasks` en v1.8.0) |
|
|
| `comments` | comentarios sobre proyecto o actividad (`entity_type` + `entity_id`) |
|
|
| `attachments` | archivos adjuntos a proyecto o actividad |
|
|
| `notifications` | notificaciones in-app por usuario |
|
|
| `audit_log` | auditoría central (quién, qué, sobre qué, cuándo) |
|
|
|
|
## Relaciones clave
|
|
|
|
- `users.role_id -> roles.id`, `users.department_id -> departments.id`
|
|
- `departments.parent_id -> departments.id` (jerarquía opcional, ej. TI → Desarrollo)
|
|
- `projects.status_id -> project_statuses.id`, `projects.priority_id -> priorities.id`,
|
|
`projects.project_type_id -> project_types.id`, `projects.owner_user_id -> users.id`,
|
|
`projects.requesting_department_id / responsible_department_id -> departments.id`
|
|
- `project_members.project_id -> projects.id`, `project_members.user_id -> users.id`
|
|
- `activities.project_id -> projects.id`, `activities.status_id -> activity_statuses.id`,
|
|
`activities.priority_id -> priorities.id`, `activities.responsible_user_id -> users.id`
|
|
- `activity_dependencies.activity_id / depends_on_activity_id -> activities.id`
|
|
- `tasks.activity_id -> activities.id`, `tasks.responsible_user_id -> users.id` (nullable)
|
|
- `comments.entity_id` / `attachments.entity_id` apuntan a `projects.id` o `activities.id` según
|
|
`entity_type` (sin FK física cruzada — se valida en el servicio)
|
|
|
|
## Reglas de datos
|
|
|
|
- `projects.progress_pct` y `activities.progress_pct` son **calculados por el servicio**, no
|
|
editables directo por el cliente: actividad con tareas = % de tareas hechas; actividad sin
|
|
tareas = manual (0-100); proyecto = promedio del avance de sus actividades.
|
|
- `users.password_hash` con bcrypt, nunca texto plano ni reversible.
|
|
- `users.status` (`pending_verification`/`pending_approval`/`active`/`invited`) es el ciclo de vida
|
|
de la cuenta, independiente de `is_active` (que sigue siendo el interruptor manual del admin
|
|
para desactivar a alguien ya activo). Un usuario `pending_approval` rechazado se **borra**
|
|
físicamente (no hay estado "rechazado" — se audita el email en `audit_log` antes de borrar).
|
|
- `invited`: cuenta placeholder creada al agregar por correo a alguien que aún no es usuario desde
|
|
Miembros de un proyecto (`name`=`email`, `password_hash` aleatorio inservible, reutiliza
|
|
`verification_token`/`verification_token_expires` — 7 días en vez de 24h). Al aceptar la
|
|
invitación (`POST /api/auth/accept-invite`) pasa directo a `active` **sin pasar por
|
|
`pending_approval`** — a diferencia del autorregistro público, aquí quien lo invitó ya lo vetó al
|
|
agregarlo a su proyecto. La fila de `project_members` se crea en el momento de invitar, no al
|
|
aceptar, así que en cuanto acepta ya aparece como miembro sin pasos adicionales.
|
|
- `system_settings.value` para `smtp_pass_enc` va **cifrado** (AES-256-GCM, `ENCRYPTION_KEY` del
|
|
`.env`) — nunca en texto plano, nunca se devuelve por la API (solo `configured: true/false`).
|
|
- Borrado lógico donde aplique (`users.is_active`); nunca DELETE físico de usuarios **activos** con
|
|
historial (los `pending_approval` rechazados sí se borran, ver arriba).
|
|
- `projects.deleted_at`/`deleted_by`: eliminación lógica (quien puede editar el proyecto puede
|
|
"eliminarlo" — se oculta de listados/dashboard, sigue en BD). Borrado físico (`DELETE`, arrastra
|
|
actividades/comentarios/adjuntos por `ON DELETE CASCADE`) solo vía `permanentlyDeleteProject`,
|
|
solo superadmin, y solo sobre un proyecto que ya tiene `deleted_at` (dos pasos, nunca directo).
|
|
- `project_members.role_in_project`: `'owner'` (dueño, se asigna solo al crear el proyecto, nunca
|
|
se toca desde el endpoint de rol), `'admin'` (administrador **de ese proyecto puntual** — un
|
|
proyecto puede tener varios, otorgado por quien ya puede escribir el proyecto, sin importar el
|
|
rol global de a quién se lo otorgan), `NULL`/otro = miembro sin permisos de escritura (salvo que
|
|
además sea `project_lead` global, comportamiento previo sin cambios).
|
|
- Empresa asumida única (no hay tabla `companies` en el MVP).
|
|
- Producción siempre usa `192.168.222.32`. Desarrollo siempre usa `192.168.222.20`. No mezclar.
|
|
|
|
## Riesgos o decisiones
|
|
|
|
- Sin triggers de BD para recalcular avances: toda la lógica vive en la capa `service/` del backend
|
|
(más simple de depurar y de extender en fase 2).
|
|
- `risk_level` es un campo simple en `projects` (bajo/medio/alto) — el módulo completo de Riesgos
|
|
(probabilidad/impacto/mitigación) queda para fase 2, sin necesitar migrar este campo.
|
|
|
|
## Archivos relacionados
|
|
|
|
- `backend/.env.example`
|
|
- `backend/database/migrations/*.sql`
|
|
- `backend/database/seeds/*.sql`
|
|
|
|
---
|
|
|
|
## Crear la base de datos en DESARROLLO (.20)
|
|
|
|
Ya ejecutado para este proyecto (2026-09-03):
|
|
|
|
```bash
|
|
bash /home/mgonzalez/desarrollo/project-md-templates/crear-db-dev.sh project_linkedcorp project_linkedcorp
|
|
```
|
|
|
|
BD `project_linkedcorp` y usuario `project_linkedcorp`@`192.168.222.40` creados en `192.168.222.20`.
|
|
Las credenciales están en `backend/.env` (no versionado).
|
|
|
|
Verificar:
|
|
|
|
```bash
|
|
mysql --defaults-extra-file=~/.config/mysql/dev20-admin.cnf -e "SHOW DATABASES LIKE 'project_linkedcorp';"
|
|
```
|
|
|
|
Aplicar migraciones/seeds (una vez creado `backend/src/scripts/migrate-db.js`):
|
|
|
|
```bash
|
|
cd backend
|
|
set -a && source .env && set +a
|
|
node src/scripts/migrate-db.js
|
|
node src/scripts/seed-db.js
|
|
```
|
|
|
|
---
|
|
|
|
## Setup de base de datos en producción — ejecutado el 2026-09-06
|
|
|
|
BD `project_linkedcorp` creada en `.32` con `crear-db-prod.sh` (grant a `192.168.222.3`). Detalle
|
|
del proceso y estado real en `PRODUCCION.md`.
|
|
|
|
Migración en el servidor de aplicaciones (`.3`):
|
|
|
|
```bash
|
|
ssh deploy@192.168.222.3 -p 2203
|
|
cd /opt/apps/project.linkedcorp.net/source/backend
|
|
set -a && source /opt/apps/project.linkedcorp.net/backend/.env && set +a
|
|
node src/scripts/migrate-db.js
|
|
node src/scripts/seed-db.js # solo catálogos/roles; sin datos de ejemplo en produccion
|
|
node src/scripts/create-admin.js "Nombre" correo@dominio # solo la primera vez, bootstrap manual
|
|
```
|
|
|
|
---
|
|
|
|
## Actualizaciones de esquema en producción
|
|
|
|
Método: archivos SQL idempotentes en `backend/database/migrations/00X-nombre.sql`
|
|
(`CREATE TABLE IF NOT EXISTS` / `information_schema` guards), aplicados con
|
|
`node src/scripts/migrate-db.js`. Siempre backup (`mysqldump --single-transaction`) antes de migrar
|
|
en producción.
|