7557dffc52
- POST /api/auth/register: primer usuario del sistema -> superadmin con sesion directa (bootstrap, sin correo ni aprobacion); los siguientes quedan pending_verification y reciben un correo con enlace de un solo uso (24h). - GET /api/auth/verify-email: pasa a pending_approval y notifica in-app a los admin/superadmin activos. - admin/superadmin aprueban (POST /api/users/:id/approve, eligen rol y departamento) o rechazan (POST /api/users/:id/reject, borra y audita el email) desde Organizacion -> Usuarios (nuevo badge de estado + acciones). - login() da mensaje especifico segun el status de la cuenta en vez del generico "credenciales invalidas". - Recuperacion de clave (forgot/reset-password): respuesta siempre generica, token de 1 hora de un solo uso. - Nuevo modulo settings: SMTP configurable SOLO por superadmin desde Configuracion -> Correo (SMTP); clave cifrada AES-256-GCM (ENCRYPTION_KEY) en la tabla system_settings, nunca expuesta por la API. sendMail() degrada a modo dev (loguea en vez de enviar) si no hay SMTP configurado, y nunca deja que un fallo de envio tumbe al que lo llama. - Migracion 002_registration_and_smtp.sql: rol superadmin, columnas de ciclo de vida en users (status, tokens), tabla system_settings, y promueve al usuario mas antiguo del sistema a superadmin. - Fix: React.StrictMode disparaba el efecto de VerifyEmailPage dos veces; la segunda llamada (token ya consumido) mostraba "enlace invalido" pese a que la verificacion ya habia funcionado. Se agrega una guarda por token. - Fix (deuda tecnica v1.0.0): se reordena el montaje de rutas en app.js — subtasksRoutes (mount generico en /api) va al final, para no interceptar con su requireAuth interno una request sin token dirigida a un router mas especifico registrado despues. - Documentacion actualizada: AGENTS.md, SPEC.md, API.md, BASE_DE_DATOS.md, CONFIGURACION.md, ESTADO.md, CHANGELOG.md. Version 1.1.0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6.2 KiB
6.2 KiB
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") |
subtasks |
checklist liviano dentro de una actividad |
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.iddepartments.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.idproject_members.project_id -> projects.id,project_members.user_id -> users.idactivities.project_id -> projects.id,activities.status_id -> activity_statuses.id,activities.priority_id -> priorities.id,activities.responsible_user_id -> users.idactivity_dependencies.activity_id / depends_on_activity_id -> activities.idsubtasks.activity_id -> activities.id,subtasks.responsible_user_id -> users.id(nullable)comments.entity_id/attachments.entity_idapuntan aprojects.idoactivities.idsegúnentity_type(sin FK física cruzada — se valida en el servicio)
Reglas de datos
projects.progress_pctyactivities.progress_pctson calculados por el servicio, no editables directo por el cliente: actividad con subtareas = % de subtareas hechas; actividad sin subtareas = manual (0-100); proyecto = promedio del avance de sus actividades.users.password_hashcon bcrypt, nunca texto plano ni reversible.users.status(pending_verification/pending_approval/active) es el ciclo de vida del autorregistro, independiente deis_active(que sigue siendo el interruptor manual del admin para desactivar a alguien ya activo). Un usuariopending_approvalrechazado se borra físicamente (no hay estado "rechazado" — se audita el email enaudit_logantes de borrar).system_settings.valueparasmtp_pass_encva cifrado (AES-256-GCM,ENCRYPTION_KEYdel.env) — nunca en texto plano, nunca se devuelve por la API (soloconfigured: true/false).- Borrado lógico donde aplique (
users.is_active); nunca DELETE físico de usuarios activos con historial (lospending_approvalrechazados sí se borran, ver arriba). - Empresa asumida única (no hay tabla
companiesen el MVP). - Producción siempre usa
192.168.222.32. Desarrollo siempre usa192.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_leveles un campo simple enprojects(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.examplebackend/database/migrations/*.sqlbackend/database/seeds/*.sql
Crear la base de datos en DESARROLLO (.20)
Ya ejecutado para este proyecto (2026-09-03):
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:
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):
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):
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.