https://java-tutor-dash.pages.dev/
Este proyecto es el frontend de un dashboard web para estudiantes de Java. Permite registro, inicio de sesión seguro y visualización de estadísticas personalizadas.
Backend: Firebase (Auth + Firestore). Despliegue: Cloudflare Pages + GitHub Actions.
- Flujo de Autenticación:
- Registro de nuevos usuarios (Sign Up) con campos validados como Correo Electrónico, GitHub Username y Matrícula.
- Unicidad garantizada: Sistema de mapeo con transacciones atómicas para prevenir duplicados de GitHub username y matrícula.
- Inicio de sesión (Sign In) flexible: Usa email, matrícula o GitHub username como identificador.
- Verificación de cuenta por correo electrónico.
- Restablecimiento de contraseña.
- Dashboard Personalizado:
- Panel de bienvenida con estadísticas de progreso (pasados, fallados, progreso total).
- Integración con la API de GitHub para cargar el avatar (con cache y retry automático).
- Monitoreo de inactividad con modal de advertencia antes del logout.
- Control multi-tab: sincronización de sesión entre pestañas.
- Gestión de Sesión Robusta:
- Persistencia de sesión (Recordarme).
- Cierre de sesión automático por inactividad (20 min con aviso a los 18 min).
- Cleanup automático de listeners y subscripciones.
- Seguridad:
- Rutas protegidas: El dashboard es inaccesible a menos que el usuario esté autenticado y su correo esté verificado.
- Reglas de seguridad en Firestore para que un usuario solo pueda leer/escribir sus propios datos.
- Sistema de mapeo único: Colecciones separadas (
github_usernames,matriculas) con lookups O(1). - Rollback automático si falla la creación del usuario.
- Logs solo en desarrollo (sin leaks en producción).
- XSS protection: Uso de DOM API en lugar de innerHTML.
- Accesibilidad (A11y):
- ARIA labels completos (
aria-invalid,aria-describedby,aria-live). - Soporte completo de teclado en sidebar y modales.
- Focus management apropiado en errores.
- ARIA labels completos (
- Diseño Moderno:
- Tema oscuro profesional y limpio.
- Diseño responsivo que se adapta a móviles.
| Categoría | Tecnología | Descripción |
|---|---|---|
| Frontend | HTML5, CSS3, JavaScript | Aplicación con Vanilla JS y ES6 Modules. |
| Backend (BaaS) | Firebase | Authentication para el login y Cloud Firestore como base de datos NoSQL. |
| Integraciones | GitHub API | Usada para obtener información de perfil (commit, avatar). |
| Despliegue | Cloudflare Pages | Hosting estático global. |
| CI/CD | GitHub Actions | Automatización del build y despliegue seguro. |
git clone https://github.com/deepdevjose/java-tutor-dash.git
cd java-tutor-dash- Ve a Firebase Console
- Crea un nuevo proyecto o usa uno existente
- Habilita Authentication → Email/Password
- Crea una base de datos Cloud Firestore
- IMPORTANTE: Copia y aplica las reglas de seguridad de
FIRESTORE_RULES.md - Obtén tu configuración de Firebase (Project Settings → General → Your apps)
- Crea el archivo
src/js/firebase-config.jscon tu configuración:
export const firebaseConfig = {
apiKey: "TU_API_KEY",
authDomain: "tu-proyecto.firebaseapp.com",
projectId: "tu-proyecto",
storageBucket: "tu-proyecto.appspot.com",
messagingSenderId: "123456789",
appId: "1:123456789:web:abc123"
};El sistema utiliza 3 colecciones principales:
usuarios/{uid} # Datos completos del usuario
github_usernames/{name} # Mapeo: GitHub username → uid
matriculas/{number} # Mapeo: Matrícula → uid
Ver documentación completa en: FIRESTORE_RULES.md
# Opción 1: Python
python -m http.server 8000
# Opción 2: Node.js
npx serve src
# Opción 3: VS Code Live Server
# Instala la extensión "Live Server" y abre index.htmlNavega a http://localhost:8000
El proyecto implementa un sistema robusto para garantizar la unicidad de GitHub usernames y matrículas:
Anteriormente, usar query() + where() + limit(1) podía devolver resultados ambiguos si había duplicados. La solución usa colecciones de mapeo con transacciones atómicas.
-
Signup (
signup.js):- Crea usuario en Firebase Auth
- Ejecuta transacción atómica que:
- Verifica que
github_usernames/{username}no exista - Verifica que
matriculas/{number}no exista - Crea ambos documentos de mapeo + documento de usuario
- Todo-o-nada: Si falla cualquier paso, hace rollback completo
- Verifica que
-
Signin (
signin.js):- Usa
getDoc()directo (O(1) lookup) en lugar de queries - Busca en
github_usernames/{username}omatriculas/{number} - Obtiene el email directamente del mapeo
- No hay ambigüedad posible
- Usa
- ✅ Garantía de unicidad incluso con concurrencia alta
- ✅ Lookups O(1) (mucho más rápidos que queries)
- ✅ No hay race conditions
- ✅ Rollback automático si falla cualquier paso
Principales medidas:
- Prevención de XSS: Manipulación segura del DOM, sin
innerHTMLpara datos de usuario. - Logging controlado: Solo en desarrollo, sin leaks en producción.
- Validación estricta: Email (Gmail/ITSOEH), GitHub (AbortController), matrícula y grupo.
- Gestión de estado: Flag
isSubmitting, cleanup de listeners, control multi-tab. - Reglas Firestore: Solo el usuario accede a sus datos; mapeos públicos solo para ver disponibilidad.
- Implementar autenticación con GitHub usando
signInWithPopup() - Obtener GitHub ID numérico (más estable que username)
- Verificar propiedad real de la cuenta
- Unit tests para funciones de validación
- E2E tests para flujo completo de signup/signin
- Tests de reglas de Firestore
- Integrar Firebase Analytics
- Tracking de errores con Sentry
- Métricas de performance
- Service Worker para offline support
- Lazy loading de imágenes
- Minificación y bundle con Vite/Webpack
El despliegue se gestiona a través de GitHub Actions que se integra directamente con Cloudflare Pages.
- El workflow (
.github/workflows/deploy-main-to-cloudflare.yml) se dispara con cadapushomergea la ramamain. - El archivo
firebase-config.jsse genera de forma segura en el servidor de build utilizando los Secrets del Repositorio de GitHub, evitando que las llaves secretas se expongan en el código fuente. - La acción
cloudflare/pages-actionsube el contenido de la carpetasrc/al servicio de hosting de Cloudflare Pages.
Si quieres mejorar el proyecto, crea un Issue o abre un Pull Request.