Portal interno INSTA: base de conocimiento con Magic Login y permisos por rol
Base de conocimiento para el personal del Instituto Santiago Tapia: oferta educativa (en tarjetas y en tabla), requisitos y titulacion, becas y fechas de inscripcion, links de clases de Google Meet, preguntas frecuentes, mensajes listos y datos del instituto. Acceso con Magic Login: enlace de un solo uso, 15 minutos de vigencia, y en la base solo se guarda el SHA-256 del token. El canje es atomico, asi que dos canjes simultaneos del mismo enlace no pueden crear dos sesiones. Tres roles con 19 permisos. El catalogo lo edita direccion; los links de clases, direccion y administracion; el resto del equipo consulta. El menu se pinta con lo que el servidor autoriza y cada endpoint exige la misma clave, asi que no hay pantallas alcanzables escribiendo la direccion a mano. Toda edicion pasa por una lista blanca de campos validados y queda en la bitacora. Un precio vacio no se guarda como cero, un link que no es una direccion se rechaza, y no se puede marcar una validez oficial como confirmada sin numero de acuerdo. Pensado para leerse comodo: texto de 17 px, contraste AA, areas de toque de 44 px, tema claro y bloques plegados en telefono. La oferta, los costos, las becas, los requisitos y el contacto son los reales del instituto, tomados del CSV de oferta educativa y de la base de conocimiento. Los usuarios de acceso y los links de Meet son de demostracion. Verificado: 103 comprobaciones de API y 51 pruebas en WebKit escritorio y iPhone 13. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
+297
@@ -0,0 +1,297 @@
|
||||
-- =====================================================================
|
||||
-- Portal Interno INSTA — esquema
|
||||
-- Instituto Santiago Tapia · Morelia, Michoacán
|
||||
-- MySQL 8.0 · utf8mb4
|
||||
-- =====================================================================
|
||||
-- El portal es una base de conocimiento: oferta educativa, requisitos,
|
||||
-- becas y fechas, links de clases, preguntas frecuentes y contacto.
|
||||
-- El catálogo lo edita dirección; los links de clases, dirección y
|
||||
-- administración. Toda edición queda en la bitácora.
|
||||
--
|
||||
-- El esquema se reconstruye completo en cada `npm run db:reset`.
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
DROP TABLE IF EXISTS bitacora;
|
||||
DROP TABLE IF EXISTS sesiones;
|
||||
DROP TABLE IF EXISTS magic_tokens;
|
||||
DROP TABLE IF EXISTS clases;
|
||||
DROP TABLE IF EXISTS programas_modalidades;
|
||||
DROP TABLE IF EXISTS requisitos;
|
||||
DROP TABLE IF EXISTS programas;
|
||||
DROP TABLE IF EXISTS modalidades;
|
||||
DROP TABLE IF EXISTS niveles;
|
||||
DROP TABLE IF EXISTS promociones;
|
||||
DROP TABLE IF EXISTS guiones;
|
||||
DROP TABLE IF EXISTS kb_articulos;
|
||||
DROP TABLE IF EXISTS titulacion_opciones;
|
||||
DROP TABLE IF EXISTS institucional;
|
||||
DROP TABLE IF EXISTS discrepancias;
|
||||
DROP TABLE IF EXISTS roles_permisos;
|
||||
DROP TABLE IF EXISTS permisos;
|
||||
DROP TABLE IF EXISTS usuarios;
|
||||
DROP TABLE IF EXISTS roles;
|
||||
|
||||
-- Tablas de la versión anterior del portal, ya retiradas.
|
||||
DROP TABLE IF EXISTS prospectos_etiquetas;
|
||||
DROP TABLE IF EXISTS prospectos;
|
||||
DROP TABLE IF EXISTS pendientes;
|
||||
DROP TABLE IF EXISTS cotizaciones;
|
||||
DROP TABLE IF EXISTS metricas_crm;
|
||||
DROP TABLE IF EXISTS etiquetas;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- 1. Identidad, roles y permisos
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE roles (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
clave VARCHAR(32) NOT NULL UNIQUE,
|
||||
nombre VARCHAR(64) NOT NULL,
|
||||
nivel TINYINT NOT NULL COMMENT '3 dirección · 2 administración · 1 empleado',
|
||||
color CHAR(7) NOT NULL DEFAULT '#4275B7',
|
||||
descripcion VARCHAR(255) NOT NULL DEFAULT ''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE permisos (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
clave VARCHAR(48) NOT NULL UNIQUE COMMENT 'seccion.accion',
|
||||
seccion VARCHAR(32) NOT NULL,
|
||||
descripcion VARCHAR(255) NOT NULL DEFAULT ''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE roles_permisos (
|
||||
rol_id INT NOT NULL,
|
||||
permiso_id INT NOT NULL,
|
||||
PRIMARY KEY (rol_id, permiso_id),
|
||||
CONSTRAINT fk_rp_rol FOREIGN KEY (rol_id) REFERENCES roles(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_rp_permiso FOREIGN KEY (permiso_id) REFERENCES permisos(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE usuarios (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nombre VARCHAR(96) NOT NULL,
|
||||
email VARCHAR(160) NOT NULL UNIQUE,
|
||||
puesto VARCHAR(96) NOT NULL DEFAULT '',
|
||||
rol_id INT NOT NULL,
|
||||
iniciales CHAR(2) NOT NULL DEFAULT '??',
|
||||
extension VARCHAR(16) NOT NULL DEFAULT '',
|
||||
activo TINYINT(1) NOT NULL DEFAULT 1,
|
||||
es_demo TINYINT(1) NOT NULL DEFAULT 1 COMMENT 'visible en el acceso rápido de la demo',
|
||||
ultimo_acceso DATETIME NULL,
|
||||
creado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_usuario_rol FOREIGN KEY (rol_id) REFERENCES roles(id),
|
||||
INDEX idx_usuarios_rol (rol_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Magic Login: el token nunca se guarda en claro, solo su SHA-256.
|
||||
CREATE TABLE magic_tokens (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
usuario_id INT NOT NULL,
|
||||
token_hash CHAR(64) NOT NULL UNIQUE,
|
||||
proposito VARCHAR(32) NOT NULL DEFAULT 'login',
|
||||
creado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expira_en DATETIME NOT NULL,
|
||||
usado_en DATETIME NULL,
|
||||
ip_origen VARCHAR(64) NOT NULL DEFAULT '',
|
||||
CONSTRAINT fk_token_usuario FOREIGN KEY (usuario_id) REFERENCES usuarios(id) ON DELETE CASCADE,
|
||||
INDEX idx_tokens_usuario (usuario_id),
|
||||
INDEX idx_tokens_expira (expira_en)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE sesiones (
|
||||
id CHAR(64) PRIMARY KEY COMMENT 'SHA-256 del id que viaja en la cookie',
|
||||
usuario_id INT NOT NULL,
|
||||
creada_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expira_en DATETIME NOT NULL,
|
||||
user_agent VARCHAR(255) NOT NULL DEFAULT '',
|
||||
ip_origen VARCHAR(64) NOT NULL DEFAULT '',
|
||||
CONSTRAINT fk_sesion_usuario FOREIGN KEY (usuario_id) REFERENCES usuarios(id) ON DELETE CASCADE,
|
||||
INDEX idx_sesiones_usuario (usuario_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE bitacora (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
usuario_id INT NULL,
|
||||
actor VARCHAR(96) NOT NULL DEFAULT 'sistema',
|
||||
rol VARCHAR(32) NOT NULL DEFAULT '',
|
||||
accion VARCHAR(64) NOT NULL,
|
||||
entidad VARCHAR(48) NOT NULL DEFAULT '',
|
||||
entidad_id VARCHAR(48) NOT NULL DEFAULT '',
|
||||
resultado VARCHAR(16) NOT NULL DEFAULT 'ok' COMMENT 'ok · denegado · error',
|
||||
detalle VARCHAR(500) NOT NULL DEFAULT '',
|
||||
ip_origen VARCHAR(64) NOT NULL DEFAULT '',
|
||||
creado_en DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
CONSTRAINT fk_bitacora_usuario FOREIGN KEY (usuario_id) REFERENCES usuarios(id) ON DELETE SET NULL,
|
||||
INDEX idx_bitacora_creado (creado_en),
|
||||
INDEX idx_bitacora_accion (accion)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- 2. Oferta educativa
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE niveles (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
clave VARCHAR(32) NOT NULL UNIQUE,
|
||||
nombre VARCHAR(64) NOT NULL,
|
||||
orden TINYINT NOT NULL DEFAULT 0
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE modalidades (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
clave VARCHAR(32) NOT NULL UNIQUE,
|
||||
nombre VARCHAR(64) NOT NULL,
|
||||
color CHAR(7) NOT NULL DEFAULT '#5E35B1',
|
||||
detalle VARCHAR(200) NOT NULL DEFAULT ''
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE programas (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nivel_id INT NOT NULL,
|
||||
clave VARCHAR(48) NOT NULL UNIQUE,
|
||||
nombre VARCHAR(120) NOT NULL,
|
||||
nombre_corto VARCHAR(48) NOT NULL,
|
||||
duracion VARCHAR(48) NOT NULL,
|
||||
fecha_inicio VARCHAR(32) NOT NULL,
|
||||
inscripcion_lista DECIMAL(10,2) NOT NULL,
|
||||
inscripcion_beca DECIMAL(10,2) NOT NULL,
|
||||
mensualidad_lista DECIMAL(10,2) NOT NULL,
|
||||
mensualidad_beca DECIMAL(10,2) NOT NULL,
|
||||
ciclo_semanas SMALLINT NULL,
|
||||
rvoe_acuerdo VARCHAR(48) NOT NULL DEFAULT '',
|
||||
rvoe_fecha DATE NULL,
|
||||
rvoe_autoridad VARCHAR(120) NOT NULL DEFAULT '',
|
||||
rvoe_estado VARCHAR(24) NOT NULL DEFAULT 'confirmado' COMMENT 'confirmado · revisar · por-confirmar',
|
||||
rvoe_nota VARCHAR(500) NOT NULL DEFAULT '',
|
||||
beneficios VARCHAR(500) NOT NULL DEFAULT '',
|
||||
color CHAR(7) NOT NULL DEFAULT '#17A171',
|
||||
orden TINYINT NOT NULL DEFAULT 0,
|
||||
activo TINYINT(1) NOT NULL DEFAULT 1,
|
||||
actualizado_por INT NULL,
|
||||
actualizado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_programa_nivel FOREIGN KEY (nivel_id) REFERENCES niveles(id),
|
||||
CONSTRAINT fk_programa_usuario FOREIGN KEY (actualizado_por) REFERENCES usuarios(id) ON DELETE SET NULL,
|
||||
INDEX idx_programas_nivel (nivel_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE programas_modalidades (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
programa_id INT NOT NULL,
|
||||
modalidad_id INT NOT NULL,
|
||||
dias VARCHAR(64) NOT NULL DEFAULT '',
|
||||
hora_inicio VARCHAR(8) NOT NULL DEFAULT '',
|
||||
hora_fin VARCHAR(8) NOT NULL DEFAULT '',
|
||||
nota VARCHAR(160) NOT NULL DEFAULT '',
|
||||
CONSTRAINT fk_pm_programa FOREIGN KEY (programa_id) REFERENCES programas(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_pm_modalidad FOREIGN KEY (modalidad_id) REFERENCES modalidades(id) ON DELETE CASCADE,
|
||||
INDEX idx_pm_programa (programa_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE requisitos (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nivel_id INT NOT NULL,
|
||||
texto VARCHAR(160) NOT NULL,
|
||||
nota VARCHAR(200) NOT NULL DEFAULT '',
|
||||
orden TINYINT NOT NULL DEFAULT 0,
|
||||
CONSTRAINT fk_requisito_nivel FOREIGN KEY (nivel_id) REFERENCES niveles(id) ON DELETE CASCADE,
|
||||
INDEX idx_requisitos_nivel (nivel_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE titulacion_opciones (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nombre VARCHAR(64) NOT NULL,
|
||||
descripcion VARCHAR(255) NOT NULL DEFAULT '',
|
||||
orden TINYINT NOT NULL DEFAULT 0
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- 3. Becas, promociones y fechas de inscripción
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE promociones (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
clave VARCHAR(48) NOT NULL UNIQUE,
|
||||
nombre VARCHAR(120) NOT NULL,
|
||||
resumen VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'la frase que se le dice al interesado',
|
||||
aplica_a VARCHAR(24) NOT NULL COMMENT 'inscripcion · mensualidad · ambos',
|
||||
vigencia VARCHAR(120) NOT NULL DEFAULT '',
|
||||
acumulable TINYINT(1) NOT NULL DEFAULT 0,
|
||||
condiciones VARCHAR(900) NOT NULL DEFAULT '',
|
||||
activo TINYINT(1) NOT NULL DEFAULT 1,
|
||||
orden TINYINT NOT NULL DEFAULT 0
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- 4. Links de clases (Google Meet)
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE clases (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
programa_id INT NOT NULL,
|
||||
materia VARCHAR(120) NOT NULL,
|
||||
docente VARCHAR(96) NOT NULL DEFAULT '',
|
||||
grupo VARCHAR(48) NOT NULL DEFAULT '' COMMENT 'generación o grupo',
|
||||
dias VARCHAR(64) NOT NULL DEFAULT '',
|
||||
hora_inicio VARCHAR(8) NOT NULL DEFAULT '',
|
||||
hora_fin VARCHAR(8) NOT NULL DEFAULT '',
|
||||
enlace VARCHAR(500) NOT NULL DEFAULT '',
|
||||
notas VARCHAR(300) NOT NULL DEFAULT '',
|
||||
activo TINYINT(1) NOT NULL DEFAULT 1,
|
||||
orden SMALLINT NOT NULL DEFAULT 0,
|
||||
actualizado_por INT NULL,
|
||||
actualizado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
creado_en DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_clase_programa FOREIGN KEY (programa_id) REFERENCES programas(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_clase_usuario FOREIGN KEY (actualizado_por) REFERENCES usuarios(id) ON DELETE SET NULL,
|
||||
INDEX idx_clases_programa (programa_id),
|
||||
INDEX idx_clases_materia (materia)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- 5. Conocimiento, contacto y datos por confirmar
|
||||
-- ---------------------------------------------------------------------
|
||||
|
||||
CREATE TABLE guiones (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
categoria VARCHAR(48) NOT NULL,
|
||||
titulo VARCHAR(160) NOT NULL,
|
||||
cuerpo TEXT NOT NULL,
|
||||
canal VARCHAR(24) NOT NULL DEFAULT 'whatsapp',
|
||||
orden SMALLINT NOT NULL DEFAULT 0,
|
||||
INDEX idx_guiones_categoria (categoria)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE kb_articulos (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
seccion VARCHAR(48) NOT NULL,
|
||||
pregunta VARCHAR(255) NOT NULL,
|
||||
respuesta TEXT NOT NULL,
|
||||
palabras_clave VARCHAR(255) NOT NULL DEFAULT '',
|
||||
fuente VARCHAR(120) NOT NULL DEFAULT 'Base de conocimiento INSTA',
|
||||
orden SMALLINT NOT NULL DEFAULT 0,
|
||||
INDEX idx_kb_seccion (seccion)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE institucional (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
grupo VARCHAR(32) NOT NULL,
|
||||
clave VARCHAR(48) NOT NULL UNIQUE,
|
||||
etiqueta VARCHAR(96) NOT NULL,
|
||||
valor TEXT NOT NULL,
|
||||
orden SMALLINT NOT NULL DEFAULT 0,
|
||||
INDEX idx_institucional_grupo (grupo)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE discrepancias (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
titulo VARCHAR(180) NOT NULL,
|
||||
detalle VARCHAR(900) NOT NULL DEFAULT '',
|
||||
ambito VARCHAR(48) NOT NULL DEFAULT 'rvoe',
|
||||
prioridad VARCHAR(16) NOT NULL DEFAULT 'media',
|
||||
estado VARCHAR(24) NOT NULL DEFAULT 'abierto' COMMENT 'abierto · en-proceso · aclarado',
|
||||
responsable VARCHAR(96) NOT NULL DEFAULT 'Dirección',
|
||||
orden SMALLINT NOT NULL DEFAULT 0
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
Reference in New Issue
Block a user