Documento estático Este manual es consultable directamente desde el sistema de archivos (sin servidor) y también vía web una vez desplegado. Cubre la arquitectura, la integración con el OMNI API CORE [1001] y la guía completa de despliegue y configuración.
1. Stack y arquitectura
Plataforma LAMP pura: PHP 8 nativo (sin frameworks, sin Composer, sin Docker), MySQL/MariaDB con PDO, HTML5 + CSS3 + JavaScript Vanilla. La autenticación es centralizada en el OMNI API CORE [1001]; la base de datos local solo persiste la lógica de la academia (progreso, asistencia, telemetría, puntos, certificación), usando el ID de empleado de OMNI como llave de referencia.
Todas las rutas internas son relativas y se resuelven contra una <base href> calculada dinámicamente, de modo que el proyecto funciona igual desplegado en la raíz del dominio o en una subcarpeta.
2. Guía de despliegue y configuración
2.1 Requisitos
- PHP 8.0+ con extensiones
pdo_mysql,curl,mbstring. - MySQL 5.7+ / MariaDB 10.3+.
- Apache con
mod_rewriteymod_headers; HTTPS recomendado en producción. - Acceso de red del servidor PHP hacia el OMNI API CORE.
2.2 Copia de archivos y DocumentRoot
El DocumentRoot debe apuntar a la carpeta public/. El resto de carpetas (config/, includes/, sdk_omni/, templates/, data/, lib/, downloads/) quedan fuera del webroot por diseño y llevan además un .htaccess que niega el acceso directo.
Opción A — en la raíz del dominio:
<VirtualHost *:443>
ServerName academia.josepan360.com
DocumentRoot /var/www/josepan-academia/public
<Directory /var/www/josepan-academia/public>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Opción B — en una subcarpeta (p. ej. https://intranet.josepan360.com/academia/): basta con publicar public/ bajo ese alias. Como todas las URLs son relativas, no hay que tocar el código.
Alias /academia /var/www/josepan-academia/public
<Directory /var/www/josepan-academia/public>
AllowOverride All
Require all granted
</Directory>
SCRIPT_NAME y la publica en <base href>. Las redirecciones del servidor usan la misma base mediante el helper url(). No es necesario configurar ninguna URL absoluta.2.3 Autoinstalador
Mientras el sistema no esté instalado, cualquier acceso se redirige a install/. Abre esa ruta en el navegador y completa el asistente:
- Verificación del entorno: comprueba versión de PHP, extensiones y permisos de escritura en
config/ydownloads/. - Parámetros: datos de la base de datos local y URL base del OMNI API CORE, además de sesión, roles y modo desarrollo.
- Despliegue: crea la base de datos si no existe, carga
schema.sqly ejecuta los seeders (cursos, 4 sesiones, niveles y parámetros). - Configuración: genera
config/config.phpcon los valores validados. - Candado: crea
config/installed.lock; a partir de ahí el instalador queda bloqueado.
Como alternativa por consola: mysql -u root -p nombre_bd < schema.sql y luego configurar config/config.php manualmente a partir de config/config.example.php.
2.4 Parámetros de configuración
| Constante | Descripción |
|---|---|
DB_HOST / DB_PORT / DB_NAME / DB_USER / DB_PASS | Conexión a la base de datos local de la academia. |
API_CORE_BASE | URL base del OMNI API CORE (sin barra final), p. ej. https://omni.josepan.es. |
API_PREFIX | Prefijo del API, por defecto /api/v1. |
SESSION_SECURE | true para enviar la cookie solo por HTTPS (producción). |
SESSION_IDLE_MIN | Minutos de inactividad antes de cerrar sesión. |
ADMIN_ROLES / ADMIN_PERMS | Roles del perfil OMNI y permisos (academia.admin) que conceden administración. |
DEV_MODE / DEV_USER / DEV_PASS | Acceso de prueba si OMNI no responde. Desactivar en producción. |
2.5 Documentos de la biblioteca
Sube los PDF a la carpeta downloads/ con los nombres indicados en data/documentos.php. Se sirven exclusivamente a través de descargar.php, que valida la sesión activa.
2.6 Seguridad posterior
- Elimina o renombra el directorio
public/install/tras instalar. - Verifica que
config/installed.lockexiste y queconfig/config.phpno es accesible por web. - Activa HTTPS y pon
SESSION_SECURE = true.
3. Integración con el OMNI API CORE [1001]
El login no consulta la base de datos local: instancia el SDK OmniCoreClient (carpeta sdk_omni/) e invoca su método login(), que hace POST {API_CORE_BASE}{API_PREFIX}/auth/login.
POST /api/v1/auth/login
{ "usuario": "herman.torres", "password": "********" }
→ { "data": {
"token": "JWT-HS256...",
"user": { "id", "nombre", "rol", "tienda", "email" },
"permissions": ["academia.admin", "inventory.read", "..."]
} }
$omni = new OmniCoreClient(API_CORE_BASE, API_PREFIX, API_TIMEOUT);
$res = $omni->login($usuario, $password);
if ($res['ok']) {
establish_session($res['token'], $res['user'], $res['permissions']);
}
El JWT, el perfil y los permissions[] se guardan en la sesión PHP (cookie HttpOnly, SameSite=Lax, Secure según configuración). El cliente tolera alias de campos (token/accessToken, user/profile, rol/role/cargo, tienda/sede/franquicia).
4. Modelo de datos local (MySQL)
Tablas InnoDB utf8mb4. La PK de empleados es el ID de empleado de OMNI; las tablas transaccionales referencian a empleados y a cursos con FK ON DELETE CASCADE.
- Maestras (seeders):
cursos,cursos_sesiones(UNIQUEcurso_id, sesion_num),niveles,parametros. empleados— cache del perfil OMNI.usuarios_progreso— fila por(empleado, curso, sesión). UNIQUE(empleado_id, curso_id, sesion_id).asistencias— asistencia por sesión marcada por admin.telemetria_tiempos— apertura de módulo ysegundos_activosacumulados.cursos_puntuacion— puntos, nivel,estado_aprobaciony emisión de certificado.
5. Telemetría
Al abrir un curso, assets/js/telemetria.js hace POST api/track_open.php y recibe un id. Acumula solo el tiempo con la pestaña visible (visibilitychange) y lo envía cada 30 s con fetch; en beforeunload/pagehide usa navigator.sendBeacon. El servidor suma de forma atómica (segundos_activos = segundos_activos + :seg) con un tope defensivo de 120 s por ping. Los endpoints exigen sesión y cabecera X-CSRF-Token.
6. Gamificación y certificados
Cada sesión leída suma 25 pts; aprobar el módulo añade 50 pts (valores en la tabla parametros). El nivel global se deriva de la suma de puntos: Aprendiz → Operativo → Referente → Líder → Embajador JOSEPAN (tabla niveles). El certificado (certificado.php, PDF generado por lib/PdfBuilder.php sin FPDF/TCPDF) se emite solo con el 100% de sesiones completadas y estado_aprobacion = aprobado.
7. Mapa de archivos
config/ config.php (lo genera el instalador), database.php
sdk_omni/ OmniCoreClient.php — SDK de autenticación OMNI [1001]
includes/ base.php, bootstrap.php, auth.php, functions.php,
gamification.php, models/ (Empleado, Curso, Parametros,
Progreso, Telemetria, Asistencia, Certificado)
lib/ PdfBuilder.php (PDF nativo)
data/ cursos.php, documentos.php, seeders.php
templates/ header/footer + layout de manuales
downloads/ PDFs reales (servidos vía descargar.php)
schema.sql Esquema de la base de datos local
manual-tecnico.html Este documento (raíz, estático)
public/ DocumentRoot
install/index.php Autoinstaller
index.php login.php logout.php curso.php perfil.php biblioteca.php
descargar.php certificado.php manual-tecnico.html manual-usuario.php
assets/ api/ admin/
8. Seguridad
- PDO con sentencias preparadas en toda la capa de datos local.
htmlspecialchars()en toda salida HTML; token CSRF en formularios y AJAX.session_regenerate_id()tras login y cierre por inactividad.- Descargas con whitelist y
basename()anti-traversal; PDFs fuera del webroot. - Carpetas sensibles fuera del
DocumentRooty con.htaccessde denegación.