# Dashboard de Seguimiento - Guía de Implementación > Sistema KISS de seguimiento académico: Markdown + Basic Auth + PHP + Vanilla JS **Servidor:** qu3v3d0.tech | **Filosofía:** Unix + KISS --- ## Qué hace este sistema ``` Profesor sube tabla-de-seguimiento.md ↓ Alumnos acceden con user/pass SFTP ↓ Cada alumno ve SOLO su progreso ``` --- ## Paso 1: Crear htpasswd para Basic Auth ```bash # Generar archivo de passwords (password = username por defecto) sudo touch /etc/nginx/.htpasswd_sftp for user in alumno{01..20}; do echo "$user:$(openssl passwd -apr1 $user)" | \ sudo tee -a /etc/nginx/.htpasswd_sftp > /dev/null done # Permisos restrictivos sudo chmod 640 /etc/nginx/.htpasswd_sftp sudo chown root:www-data /etc/nginx/.htpasswd_sftp # Verificar sudo cat /etc/nginx/.htpasswd_sftp ``` **✅ Verificación:** ``` alumno01:$apr1$xyz$... alumno02:$apr1$abc$... ... ``` --- ## Paso 2: Crear estructura de directorios ```bash # Crear directorios sudo mkdir -p /home/admin/html/dashboard/data # Permisos sudo chown -R admin:www-data /home/admin/html/dashboard sudo chmod 755 /home/admin/html/dashboard sudo chmod 775 /home/admin/html/dashboard/data ``` **Estructura final:** ``` /home/admin/html/dashboard/ ├── index.html # Cliente (vanilla JS + marked.js) ├── api.php # filtro por usuario ├── style.css # estilo minimalista └── data/ └── tabla-de-seguimiento.md ``` --- ## Paso 3: Crear api.php ```bash sudo tee /home/admin/html/dashboard/api.php > /dev/null << 'EOF' /dev/null << 'EOF' Dashboard de Seguimiento

🎯 Dashboard de Seguimiento

qu3v3d0.tech

Cargando tu progreso...

EOF sudo chown admin:www-data /home/admin/html/dashboard/index.html sudo chmod 644 /home/admin/html/dashboard/index.html ``` --- ## Paso 5: Crear style.css ```bash sudo tee /home/admin/html/dashboard/style.css > /dev/null << 'EOF' :root { --bg: #f5f5f5; --fg: #333; --accent: #0066cc; --success: #28a745; --error: #dc3545; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: system-ui, sans-serif; line-height: 1.6; color: var(--fg); background: var(--bg); min-height: 100vh; display: flex; flex-direction: column; } header { background: var(--accent); color: white; padding: 1.5rem; text-align: center; } header h1 { font-size: 1.8rem; margin-bottom: 0.5rem; } .subtitle { font-size: 0.9rem; opacity: 0.9; } main { flex: 1; max-width: 900px; width: 100%; margin: 2rem auto; background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .loader { text-align: center; padding: 2rem; } .spinner { width: 40px; height: 40px; margin: 1rem auto; border: 4px solid #ddd; border-top-color: var(--accent); border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } h1 { color: var(--accent); border-bottom: 2px solid var(--accent); padding-bottom: 0.5rem; margin-bottom: 1.5rem; } h2 { margin-top: 1.5rem; margin-bottom: 1rem; color: #555; } table { width: 100%; border-collapse: collapse; margin: 1rem 0; } th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #ddd; } th { background: var(--bg); font-weight: 600; color: var(--accent); } tbody tr:hover { background: #f9f9f9; } ul { margin-left: 1.5rem; margin-bottom: 1rem; } li { margin-bottom: 0.5rem; } input[type="checkbox"] { margin-right: 0.5rem; } .error { background: #fff3cd; border: 2px solid #ffc107; border-radius: 8px; padding: 1.5rem; text-align: center; } .error h2 { color: var(--error); margin-bottom: 1rem; } footer { background: #2c3e50; color: white; text-align: center; padding: 1rem; font-size: 0.85rem; } @media (max-width: 768px) { main { margin: 1rem; padding: 1rem; } header h1 { font-size: 1.4rem; } } EOF sudo chown admin:www-data /home/admin/html/dashboard/style.css sudo chmod 644 /home/admin/html/dashboard/style.css ``` --- ## Paso 6: Configurar nginx ```bash sudo tee /etc/nginx/sites-available/dashboard > /dev/null << 'EOF' server { listen 80; server_name dashboard.qu3v3d0.tech; root /home/admin/html/dashboard; index index.html; # Basic Auth auth_basic "Dashboard Alumnos"; auth_basic_user_file /etc/nginx/.htpasswd_sftp; # PHP-FPM location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php-fpm.sock; fastcgi_param REMOTE_USER $remote_user; } # Caché de estáticos location ~* \.(css|js)$ { expires 1h; add_header Cache-Control "public"; } # Proteger data/ location /data/ { deny all; } # Logs access_log /var/log/nginx/dashboard-access.log; error_log /var/log/nginx/dashboard-error.log; autoindex off; } EOF # Activar sudo ln -s /etc/nginx/sites-available/dashboard /etc/nginx/sites-enabled/ # Validar y recargar sudo nginx -t sudo systemctl reload nginx ``` --- ## Paso 7: Crear tabla-de-seguimiento.md ```bash sudo tee /home/admin/html/dashboard/data/tabla-de-seguimiento.md > /dev/null << 'EOF' # Seguimiento - Grupo 2026 ## alumno01 | Tarea | Estado | Fecha | |:------|:------:|------:| | Config nginx básica | ❌ | - | | JSON con CORS | ❌ | - | | Error pages | ❌ | - | | Caché estático | ❌ | - | ## alumno02 | Tarea | Estado | Fecha | |:------|:------:|------:| | Config nginx básica | ❌ | - | | JSON con CORS | ❌ | - | | Error pages | ❌ | - | | Caché estático | ❌ | - | ## alumno03 | Tarea | Estado | Fecha | |:------|:------:|------:| | Config nginx básica | ❌ | - | | JSON con CORS | ❌ | - | | Error pages | ❌ | - | | Caché estático | ❌ | - | EOF sudo chown admin:www-data /home/admin/html/dashboard/data/tabla-de-seguimiento.md sudo chmod 664 /home/admin/html/dashboard/data/tabla-de-seguimiento.md ``` **Formato alternativo con checkboxes:** ```markdown ## alumno01 - [ ] Config nginx básica - [ ] JSON con CORS - [ ] Error pages - [ ] Caché estático ``` --- ## Paso 8: Verificación ```bash # 1. Permisos ls -la /home/admin/html/dashboard/ ls -la /home/admin/html/dashboard/data/ # 2. Nginx sudo nginx -t sudo systemctl status nginx # 3. PHP-FPM sudo systemctl status php*-fpm # 4. Test htpasswd htpasswd -v /etc/nginx/.htpasswd_sftp alumno01 # 5. Test curl curl -u alumno01:alumno01 http://localhost/dashboard/api.php ``` **✅ Debe retornar:** ```markdown # Seguimiento - Grupo 2026 ## alumno01 | Tarea | Estado | Fecha | ... ``` --- ## Paso 9: Test en navegador 1. Abrir: `http://dashboard.qu3v3d0.tech` 2. Login: `alumno01` / `alumno01` 3. Debe mostrar solo la sección de alumno01 4. Probar con alumno02, alumno03... --- ## Uso para el Profesor ### Actualizar tabla via SFTP ``` Host: qu3v3d0.tech User: admin Password: **** Path: /html/dashboard/data/ File: tabla-de-seguimiento.md ``` ### Actualizar desde servidor ```bash ssh admin@qu3v3d0.tech nano ~/html/dashboard/data/tabla-de-seguimiento.md # Editar y guardar ``` ### Formato de la tabla **Emojis de estado:** - ✅ Completado - ❌ Pendiente - ⏳ En progreso **Ejemplo:** ```markdown ## alumno01 | Tarea | Estado | Fecha | |:------|:------:|------:| | Config nginx básica | ✅ | 2026-01-20 | | JSON con CORS | ⏳ | - | | Error pages | ❌ | - | **Observaciones:** Buen progreso, revisar CORS. ``` --- ## Troubleshooting ### Error 401 Unauthorized ```bash # Verificar htpasswd ls -la /etc/nginx/.htpasswd_sftp grep alumno01 /etc/nginx/.htpasswd_sftp htpasswd -v /etc/nginx/.htpasswd_sftp alumno01 ``` ### Error 403 Forbidden ```bash # Verificar permisos ls -la /home/admin/html/dashboard/ ps aux | grep nginx # Usuario debe ser www-data ``` ### PHP no procesa ```bash # Verificar PHP-FPM sudo systemctl status php*-fpm ls -la /var/run/php/php*-fpm.sock sudo tail -f /var/log/nginx/dashboard-error.log ``` ### Página en blanco ```bash # Test API directamente curl -u alumno01:alumno01 http://dashboard.qu3v3d0.tech/api.php # Ver consola navegador (F12) # Verificar que marked.js carga correctamente ``` ### Usuario ve datos de otros ```bash # En api.php, agregar debug temporal: echo "DEBUG: User = $user\n"; # Verificar que ## username coincide exactamente # (sin espacios extras, case-sensitive) ``` --- ## Extensión: Notificación XMPP Notificar cuando profesor actualiza la tabla: ```bash # Script watcher sudo tee /usr/local/bin/dashboard-notify.sh > /dev/null << 'EOF' #!/bin/bash WATCH_FILE="/home/admin/html/dashboard/data/tabla-de-seguimiento.md" inotifywait -m -e close_write "$WATCH_FILE" | while read event; do /usr/local/bin/xmpp-notify.py "📊 Tabla actualizada por el profesor" done EOF sudo chmod +x /usr/local/bin/dashboard-notify.sh # Servicio systemd sudo tee /etc/systemd/system/dashboard-notify.service > /dev/null << 'EOF' [Unit] Description=Dashboard Update Notifier After=network.target [Service] Type=simple ExecStart=/usr/local/bin/dashboard-notify.sh Restart=always [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now dashboard-notify.service ``` --- ## Checklist de Implementación - [ ] htpasswd creado (`/etc/nginx/.htpasswd_sftp`) - [ ] Directorios creados (`/home/admin/html/dashboard/`) - [ ] api.php desplegado (644) - [ ] index.html desplegado (644) - [ ] style.css desplegado (644) - [ ] nginx config creado (`/etc/nginx/sites-available/dashboard`) - [ ] nginx config activado (symlink a sites-enabled) - [ ] nginx reload sin errores (`nginx -t`) - [ ] tabla-de-seguimiento.md inicial (664) - [ ] PHP-FPM corriendo - [ ] Test curl exitoso - [ ] Test navegador alumno01 OK - [ ] Test navegador alumno02 OK - [ ] Cada alumno ve solo sus datos - [ ] Markdown renderiza correctamente - [ ] Responsive en móvil OK --- ## Resumen **Componentes:** - nginx: Auth + routing - PHP: Filtrado por usuario - Markdown: Storage - marked.js: Parsing - Vanilla JS: Cliente **Filosofía KISS:** - 3 archivos principales - Sin DB - Sin frameworks - Sin compilación **Resultado:** Sistema robusto, mantenible, educativo. --- *Implementado: 2026-02-13 | qu3v3d0.tech | fenix + Claude*