diff --git a/misc/ENSAYO_PRESENTACION.md b/misc/ENSAYO_PRESENTACION.md new file mode 100644 index 0000000..4328868 --- /dev/null +++ b/misc/ENSAYO_PRESENTACION.md @@ -0,0 +1,191 @@ +# 🎤 Guión de Ensayo — Presentación OnAPB +### Taller de Integración — FCYT UADER | 7 de Abril 2026, 18:30 hs +**Presentadores:** Lautaro · Fabricio + +--- + +> **Objetivo de la demo:** ~20 minutos en total. +> Mostrar el sistema funcionando en producción (onapb.com) de principio a fin. +> El hilo conductor es una historia: *un jugador real pide un QR para un partido, y el admin lo escanea en la puerta.* + +--- + +## 🎬 Estructura general + +| Bloque | Quién | Tiempo estimado | +|---|---|---| +| **Introducción** (qué es OnAPB y qué problema resuelve) | Lautaro | 2 min | +| **Demo pública** (home, eventos, noticias, promos) | Fabricio | 3 min | +| **Demo jugador** (login, solicitar QR, ver QRs) | Lautaro | 5 min | +| **Demo admin** (panel, gestión, escanear QR) | Fabricio | 6 min | +| **Demo técnica** (tests, backup) | Lautaro | 2 min | +| **Cierre** (conclusiones, pendientes, mejoras) | Ambos | 2 min | + +--- + +## 🟠 Bloque 1 — Introducción (Lautaro) + +**Lautaro dice:** + +> *"Buenas tardes. Somos Lautaro y Fabricio, y vamos a presentar OnAPB: un sistema web de gestión para asociaciones de básquetbol.* +> +> *El problema que resuelve es simple: hasta ahora, la administración de clubes, jugadores y el acceso a los partidos se hacía completamente en papel o con planillas de Excel desconectadas. Nosotros digitalizamos eso.* +> +> *El sistema está en producción en onapb.com y tiene cargados actualmente 35 equipos y alrededor de 3500 jugadores reales. Fue construido con Laravel 12, MySQL y Bootstrap 5."* + +👉 **Abrí el navegador en onapb.com mientras hablás.** + +--- + +## 🟢 Bloque 2 — Demo Pública (Fabricio) + +**Fabricio toma el control del teclado/mouse.** + +### 2.1 Home +- Mostrá el carrusel/hero de la portada. Decí brevemente: + > *"Esta es la página pública. Cualquier persona, sin registrarse, puede ver la cartelera de partidos, las noticias y los sponsors de la liga."* + +### 2.2 Eventos +- Navegá a `/eventos`. +- Hacé clic en un partido concreto (elegí uno que tenga equipos asignados y estado *Próximo*). + > *"Acá se ve el detalle del partido: los equipos, la categoría, la fecha y la sede."* + +### 2.3 Torneos (posiciones + goleadores) +- Navegá a la sección de torneos. +- Mostrá la tabla de posiciones y la tabla de goleadores. + > *"El sistema también gestiona torneos con grupos, posiciones acumuladas y ranking de goleadores. Cuando hay playoffs, se genera el bracket automáticamente."* + +### 2.4 Promos y Noticias (rápido) +- 15 segundos nomás: mostrá que existen. + > *"También tenemos noticias publicables y locales con beneficios para los miembros."* + +--- + +## 🔵 Bloque 3 — Demo Jugador (Lautaro) + +**Lautaro toma el control. Este es el bloque más importante de cara a la historia principal.** + +### 3.1 Login como Jugador +- Ir a la pantalla de login (botón en el menú). +- Pestaña *"Jugadores / Aficionados"*. +- Ingresar un DNI y contraseña reales de un jugador de prueba. + > *"Los jugadores se loguean con su DNI y contraseña. El captcha de Cloudflare Turnstile protege contra bots."* +- Clic en **Ingresar**. El sistema redirige a la home ya logueado. + +### 3.2 Panel de Usuario +- Ir a `/panel-usuario`. + > *"Este es el panel personal del jugador. Ve sus datos, a qué club pertenece, a qué equipo está asignado, y su categoría, que se calcula automáticamente en base a la fecha de nacimiento."* + +### 3.3 ⭐ Solicitar QR para un Partido *(paso a paso detallado)* + +Este es el **momento central de la demo**. Hacelo con calma. + +1. Desde el panel o desde el menú, navegá a `/eventos`. +2. Hacé clic en el partido preparado con anticipación (uno con estado *Próximo* y que tenga al jugador logueado en uno de los equipos). +3. Mostrá el detalle del partido. + > *"En el detalle del evento, el jugador puede solicitar su QR. El sistema verifica automáticamente si pertenece a alguno de los equipos del partido."* +4. Hacé clic en **"Solicitar QR"**. +5. El sistema procesa y redirige a "Mis QRs". + > *"Como el jugador pertenece al equipo local, el sistema le genera 3 QRs: uno para él y dos para que les dé a familiares o acompañantes. Si fuera de categoría Libre, obtendría 1 QR con 50% de descuento."* + +### 3.4 Mis QRs +- Mostrá la pantalla de Mis QRs. +- Ampliá uno de los QR para que se vea bien grande. + > *"Cada QR es único, tiene un solo uso. Su estado es 'Válido' hasta que es escaneado, momento en que pasa a 'Usado'.* + > + > *Además, el jugador recibe estos QRs por correo electrónico automáticamente."* + +- **Consejo:** si podés, mostrá que el correo llegó a la bandeja (tené el mail abierto en otra pestaña). + +### 3.5 Cerrar sesión del jugador +- Clic en **Cerrar sesión**. + +--- + +## 🔴 Bloque 4 — Demo Administrador (Fabricio) + +**Fabricio toma el control.** + +### 4.1 Login como SuperAdmin +- Login con usuario y contraseña del superadmin. + > *"Ahora ingresamos como Súper Administrador."* +- Clic en **Ingresar**. + +### 4.2 Dashboard Admin +- Mostrá el dashboard con las estadísticas globales (clubes, equipos, jugadores totales). + > *"El panel de administración tiene visión global de todo el sistema."* + +### 4.3 Gestión de Jugadores (rápido) +- Ir a `/admin/jugadores`. +- Mostrá el listado con búsqueda. + > *"Podemos buscar cualquier jugador. Hay 3500 cargados actualmente."* +- Hacé clic en un jugador para mostrar el formulario de edición. No guardes nada. + > *"El admin puede editar datos, cambiar el club o eliminar un jugador. Si se elimina, usamos SoftDelete: no se borra físicamente, es recuperable."* + +### 4.4 Importación CSV (30 segundos) +- Mostrá el botón de importar en `/admin/jugadores`. + > *"Una funcionalidad clave fue la importación masiva desde CSV. El sistema soporta el formato oficial de CAB — la Confederación Argentina de Básquet — y también formatos internos. Importamos los 3500 jugadores desde esas planillas."* + +### 4.5 Gestión de Eventos (rápido) +- Ir a `/admin/eventos`. + > *"El admin calendariza los partidos, asigna equipos y controla el estado. Cuando se cargan los resultados, el evento pasa automáticamente a Finalizado y los puntos impactan en la tabla de posiciones."* + +### 4.6 ⭐ Escanear el QR *(paso a paso detallado)* + +Este es el **cierre de la historia**. Hacelo en vivo. + +1. Ir a `/admin/escanear-qr`. + > *"Esta es la herramienta para usar en la puerta del gimnasio el día del partido. El admin de turno selecciona el evento."* +2. Seleccioná el mismo partido del que Lautaro sacó el QR antes. +3. Activá la cámara o usá el campo de texto para ingresar el ID del QR. + > *"El árbitro o responsable escanea el código. El sistema valida en tiempo real."* +4. Escaneá (o pegá el ID del QR generado antes). + > *"¿Ven? El sistema muestra el nombre del titular, el tipo de QR —en este caso 'invitado'— y lo pasa a estado Usado. Si alguien intentara entrar con ese mismo QR de nuevo, el sistema lo rechazaría."* +5. Mostrá el resultado: QR validado, nombre del jugador, estado actualizado. + +--- + +## 🟣 Bloque 5 — Demo Técnica (Lautaro) + +**Lautaro toma el control. Abrí una terminal.** + +### 5.1 Correr los tests +```bash +php artisan test +``` + > *"El proyecto tiene una suite de pruebas automatizadas con PHPUnit. Tenemos 5 archivos de Feature Tests que cubren el login de los 3 tipos de usuario, el acceso denegado, la solicitud de QR y la prevención de duplicados."* + +- Mostrá que todos pasan en verde. + +### 5.2 Sistema de Backup +```bash +php artisan backup:run --only-db --disable-notifications +``` + > *"También integramos spatie/laravel-backup para las copias de seguridad automáticas de la base de datos. Esto cubre el requisito de recuperación ante fallos."* + +### 5.3 SoftDeletes (explicación verbal, sin demo) + > *"Además, los modelos críticos —Club, Equipo, Jugador, Evento— implementan SoftDeletes. Esto significa que ningún dato crítico se borra permanentemente: si un admin elimina algo por error, los registros siguen en la base de datos con un timestamp de eliminación y son recuperables."* + +--- + +## ⚪ Bloque 6 — Cierre (Ambos) + +**Turno de Fabricio primero:** + +> *"En cuanto a lo que quedó pendiente: la integración de pagos con Banco Macro —que llamamos Fase 6— no se implementó porque requiere credenciales y aprobación formal del banco, algo que está fuera del alcance académico. Sin embargo, la arquitectura está preparada para recibirla: tenemos el modelo `PagoMp` y la estructura de datos lista."* + +**Cierre de Lautaro:** + +> *"Como reflexión del equipo: el mayor desafío fue modelar correctamente la lógica de negocio real de una asociación de básquet —categorías por edad, pases entre clubes, permisos por rol— sin que el sistema se volviera rígido. El uso de SoftDeletes, servicios desacoplados y el scheduler nos permitió tener algo robusto y mantenible.* +> +> *Quedamos a disposición para preguntas."* + +--- + +## ⚠️ Tips para el día de la presentación + +- **Elegí con anticipación** el jugador de prueba y el evento para el demo del QR. Verificá que el jugador esté en uno de los equipos del partido. +- **Tené el correo abierto** en una pestaña aparte para mostrar que llegó el mail con el QR. +- Si el profesor pregunta algo que no saben, **no inventen**: digan *"ese detalle lo tenemos en el código, si quiere lo revisamos juntos"*. +- **Turno de hablar**: si uno habla, el otro maneja el mouse, y viceversa. No hablen los dos a la vez. +- **Cronometren** el ensayo. Si lleva más de 25 minutos, recorten las partes "rápido". diff --git a/misc/GESTION-JUGADORES.md b/misc/GESTION-JUGADORES.md new file mode 100644 index 0000000..6bddf71 --- /dev/null +++ b/misc/GESTION-JUGADORES.md @@ -0,0 +1,43 @@ +# Gestión de Jugadores: Roles y Funcionalidades + +Este documento detalla las capacidades y restricciones para los distintos tipos de administradores al crear o importar jugadores en el sistema OnAPB. + +## 1. Creación Manual (Formulario Individual) + +| Característica | Súper Administrador (Rol 1) | Administrador de Club (Rol 2) | +| :--- | :--- | :--- | +| **Club de Origen** | **Editable:** Puede seleccionar cualquier club registrado. | **Editable:** Puede seleccionar cualquier club registrado (ej: para pases entre clubes). | +| **Club Actual** | **Editable:** Puede asignar al jugador a cualquier club. | **Bloqueado:** El jugador se asigna automáticamente a su propio club. | +| **Validación de DNI** | Bloqueado si el DNI ya existe. Muestra el club actual del jugador. | Bloqueado si el DNI ya existe. Muestra el club actual del jugador. | +| **Generación de ID** | Automática: Basada en Club Origen + Año Nacimiento + Secuencia. | Automática: Basada en Club Origen + Año Nacimiento + Secuencia. | +| **Estado Inicial** | Siempre `Inactivo`. Debe completarse en `/asociate`. | Siempre `Inactivo`. Debe completarse en `/asociate`. | + +## 2. Importación Masiva (Archivo .CSV) + +**Formato del archivo:** `DNI; Apellido; Nombre; ddmmaaaa; id_club_origen` + +| Característica | Súper Administrador (Rol 1) | Administrador de Club (Rol 2) | +| :--- | :--- | :--- | +| **Clubes de Origen Permitidos** | Cualquier ID de club. | **Solo su propio Club** o ID 99 (Default). | +| **Asignación de Club Actual** | Se asigna el mismo ID del Club de Origen. | **Forzado** al ID del club del administrador. | +| **Gestión de Errores** | Omite duplicados si el DNI ya existe. | Omite duplicados; bloquea filas con IDs de otros clubes. | + +--- + +## Reglas Generales de Validación + +### Control de Duplicados (DNI) +Independientemente del rol, el sistema no permite registros duplicados por DNI. +- **Mensaje de Error:** *"No se puede registrar al jugador dado que ya pertenece al club [Nombre del Club]."* +- Esta validación asegura que no se creen registros paralelos para el mismo jugador. + +### Generación del `id_jugador` +El ID del jugador es un código único compuesto: `CCYYSSS`. +- `CC`: ID del Club de Origen. +- `YY`: Últimos dos dígitos del año de nacimiento. +- `SSS`: Secuencia incremental (ej: 01, 02) para ese club y ese año. + +### Datos Automáticos +- **Edad:** Se calcula automáticamente a partir de la fecha de nacimiento. +- **Categoría:** Es dinámica. Se calcula cada año basándose en el año de nacimiento (ej: U15 para jugadores que cumplen 14 o 15 años en el año corriente). +- **Contraseña:** Si no se especifica, queda pendiente hasta la activación por el usuario. diff --git a/misc/HOJA-DE-RUTA.md b/misc/HOJA-DE-RUTA.md new file mode 100644 index 0000000..7f53696 --- /dev/null +++ b/misc/HOJA-DE-RUTA.md @@ -0,0 +1,92 @@ +# Hoja de Ruta - Migración a Laravel + +## Fase 1: Fundamentos (✅ Completado) +- Modelos Eloquent +- Controladores RESTful +- Rutas API +- Layout base + Welcome + +## Fase 2: Autenticación (✅ Completado) +- AuthController (login/logout player + admin) +- Recuperar contraseña (token + email + vista reset ✅) +- Registro de jugadores/aficionados +- Middlewares de autenticación + +## Fase 3: Vistas Públicas (✅ Completado) +- Vista eventos (lista) +- Vista evento_detalle +- Vista promos (mapa/lista) +- Vista asociate (registro) +- Vista noticias + +## Fase 4: Panel de Usuario (✅ Completado) +- Dashboard usuario +- Mis QRs +- Solicitar QR para eventos ✅ +- Generar QR para promociones ✅ + +## Fase 5: Admin - Gestión (✅ Completado) +- [x] ABM Clubes (API ✅, vistas ✅) +- [x] ABM Equipos (API ✅, vistas ✅) +- [x] ABM Jugadores (API ✅, vistas ✅) +- [x] ABM Eventos (API ✅, CRUD completo ✅) +- [x] ABM Promociones/Lugares (✅) +- [x] ABM Noticias (API ✅, vistas ✅) +- [x] Escanear/validar QR (✅) + +## Fase 6: Pagos - Banco Macro (⏳ Pendiente - esperando credenciales) + +### 6.1 Configuración Inicial +- [ ] Obtener credenciales de Banco Macro (CLIENT_ID, CLIENT_SECRET) +- [ ] Configurar ambiente sandbox +- [ ] Configurar webhook + +### 6.2 Modelado de Datos +- [ ] Crear modelo ConceptoPago +- [ ] Crear modelo Deuda +- [ ] Extender modelo PagoMp existente + +### 6.3 Backend - API +- [ ] CRUD conceptos de pago +- [ ] CRUD deudas +- [ ] Generación masiva de deudas (ej: cuota a todos) +- [ ] Integración Botón Integrado Macro Click +- [ ] Endpoint webhook para notificaciones +- [ ] Endpoint validación de pagos + +### 6.4 Frontend - Panel Usuario +- [ ] Sección "Mis Pagos" en panel usuario +- [ ] Listado de deudas pendientes +- [ ] Historial de pagos +- [ ] Componente Botón Integrado (formulario embebido) +- [ ] Estados de éxito/error del pago + +### 6.5 Panel Admin - Gestión de Pagos +- [ ] Dashboard de deudas y cobros +- [ ] Crear sanción individual a jugador +- [ ] Generar cuotas masivas por club/equipo +- [ ] Validación manual de pagos +- [ ] Reportes (Excel/PDF) + +## Fase 7: Panel Usuario - QRs y Pagos (✅ Completado parcial) +- [x] Solicitar QR para evento (desde detalle de evento) +- [x] Generar QR tras solicitud (sin pago por ahora, Fase 6 pendiente) +- [x] Visualizar mis QRs activos (con estado válido/usado) +- [x] Generar QR para promociones (desde vista de promos) +- [ ] Integrar generación de QR tras pago exitoso (depende de Fase 6) + +## Fase 8: Varias (✅ Completado parcial) +- [x] Completar recuperar contraseña (vista reset + proceso completo) +- [x] Fix formulario recuperar contraseña (HTML roto) +- [ ] Envío de emails (deuda generada, pago confirmado) — depende de config SMTP +- [x] Limpieza links admin (editar/eliminar desde detalle evento, promos admin) +- [ ] Testing webhooks — depende de Fase 6 + +--- + +## Notas + +- **Fase 6 reemplaza MercadoPago** por Macro Click de Banco Macro +- La integración será mediante **Botón Integrado** (pago dentro de la app) +- El sistema permitirá autogestión de pagos por parte de los jugadores +- **Reset password** incluye enlace de desarrollo directo (en producción, se enviaría por email) diff --git a/misc/MANUAL_USUARIO.md b/misc/MANUAL_USUARIO.md new file mode 100644 index 0000000..3d43190 --- /dev/null +++ b/misc/MANUAL_USUARIO.md @@ -0,0 +1,648 @@ +# 📖 Manual de Usuario — OnAPB +### Sistema de Gestión de Asociación de Básquet +> **Sitio:** [onapb.com](https://onapb.com) + +--- + +## ¿A quién está dirigido este manual? + +OnAPB es utilizado por cuatro tipos de personas. Este manual explica paso a paso qué puede hacer cada una: + +| Capítulo | Perfil | +|---|---| +| [Capítulo 1](#cap1) | Visitantes (sin cuenta) | +| [Capítulo 2](#cap2) | Jugadores federados | +| [Capítulo 3](#cap3) | Aficionados / Hinchas | +| [Capítulo 4](#cap4) | Administradores de Club | +| [Capítulo 5](#cap5) | Súper Administradores (OnAPB) | + +--- + + +## 📌 Capítulo 1 — Visitante (Sin cuenta) + +Cualquier persona puede ingresar a **onapb.com** sin necesidad de registrarse y acceder a información pública de la liga. + +### 1.1 Página de Inicio (`/`) + +Al entrar al sitio el visitante encuentra: + +- **Carrusel / Hero**: Diapositivas destacadas configuradas por la asociación (noticias importantes, convocatorias, avisos). +- **Próximos Partidos**: Listado de los eventos más cercanos con día, hora y equipos. +- **Noticias recientes**: Artículos publicados por OnAPB. +- **Sponsors**: Franja rotativa con los patrocinadores de la liga visible en el pie de página. + +### 1.2 Cartelera de Eventos (`/eventos`) + +- Ver todos los partidos programados: próximos, en curso y finalizados. +- Cada tarjeta de evento muestra: equipos, categoría, fecha, hora y sede. +- Hacer clic en un evento abre el **detalle del partido** con información completa. +- Si el partido ya fue jugado, se muestran los marcadores finales. + +### 1.3 Tabla de Posiciones y Goleadores de Torneo + +- Desde la sección de torneos se puede ver: + - **Posiciones** por grupo o categoría. + - **Tabla de goleadores** del torneo con puntos acumulados. + - **Bracket de Playoffs**: diagrama del cuadro eliminatorio cuando corresponde. + +### 1.4 Noticias (`/noticias`) + +- Listado de artículos publicados por la asociación con imagen, título y texto completo. + +### 1.5 Promociones y Lugares con Beneficios (`/promos`) + +- Mapa y/o listado de locales comerciales asociados que ofrecen descuentos a miembros de OnAPB. +- Ver información de cada comercio (nombre, dirección, beneficio). +- Para **obtener el QR de descuento** es necesario tener una cuenta y estar logueado. + +### 1.6 Registrarse (`/asociate`) + +Para obtener todos los beneficios del sistema, el visitante puede crear una cuenta. Existen dos vías: + +#### Vía A — Registrarse como Aficionado +1. Ir a `/asociate` y seleccionar la pestaña **"Soy Aficionado"**. +2. Completar el formulario: Nombre, Apellido, DNI, Email, Fecha de Nacimiento (opcional), Teléfono (opcional), Localidad (opcional), Contraseña. +3. Resolver el **captcha de seguridad** (Cloudflare Turnstile). +4. Hacer clic en **Registrarme**. +5. El sistema envía un **correo de bienvenida** a la dirección ingresada. +6. ✅ Listo. Ya se puede iniciar sesión con DNI y contraseña. + +#### Vía B — Activar cuenta como Jugador Federado +> *Para jugadores que ya fueron cargados en el sistema por el administrador de su club.* + +1. Ir a `/asociate` y seleccionar la pestaña **"Soy Jugador"**. +2. Ingresar Nombre, Apellido y DNI (tal como aparecen en la ficha). +3. Aceptar los términos y hacer clic en **Buscar**. +4. El sistema valida los datos con el padrón. Si hay coincidencia, muestra la ficha del jugador (nombre, club, categoría). +5. Completar el formulario de activación: Email, Teléfono (opcional), Contraseña. +6. Resolver el **captcha de seguridad**. +7. Hacer clic en **Activar mi cuenta**. +8. El sistema envía un **correo de bienvenida**. +9. ✅ Listo. La cuenta queda activa y se puede iniciar sesión. + +> **Nota:** Si el DNI no se encuentra en el padrón de jugadores, el sistema sugiere registrarse como Aficionado. + +### 1.7 Iniciar Sesión + +- Desde el menú superior hacer clic en **"Iniciar Sesión"** o ir a la pantalla de login. +- Se muestra un formulario con dos pestañas: + - **Jugadores / Aficionados**: ingresar DNI y contraseña + captcha. + - **Administradores**: ingresar usuario y contraseña + captcha. + +### 1.8 Recuperar Contraseña (`/recuperar`) + +En caso de olvidar la contraseña: +1. Ir a `/recuperar`. +2. Ingresar el **DNI** y la **dirección de email** asociados a la cuenta. +3. El sistema envía un enlace de restablecimiento válido por **1 hora**. +4. Hacer clic en el enlace del correo y establecer la nueva contraseña (mínimo 6 caracteres, requiere confirmación). + +--- + + +## 🏅 Capítulo 2 — Jugador Federado + +Un jugador que ya activó su cuenta (Vía B de `/asociate`) tiene acceso a un **Panel de Usuario** con funcionalidades específicas para deportistas federados. + +### 2.1 Iniciar Sesión + +- En la pantalla de login, pestaña **"Jugadores / Aficionados"**. +- Ingresar **DNI** y **contraseña**. +- El sistema detecta automáticamente si la cuenta corresponde a un Jugador o Aficionado. + +### 2.2 Panel de Usuario (`/panel-usuario`) + +Al acceder al panel, el jugador ve de un vistazo: + +- Sus **datos personales**: nombre, DNI, club, categoría calculada automáticamente por edad. +- Sus **equipos asignados** (puede pertenecer a varios equipos dentro de su club). +- **Resumen de QRs**: cantidad de pases de eventos solicitados. +- **Notificaciones** del sistema (ícono en el menú superior con contador). + +### 2.3 Solicitar QR para un Partido + +Esta es la funcionalidad principal del jugador federado. Permite obtener un **código QR de acceso** a un evento. + +**Pasos:** +1. Desde el menú público o desde el panel, ir a **Eventos** y buscar el partido deseado. +2. Entrar al **detalle del partido**. +3. Si el partido está en estado *Próximo* o *En Curso*, aparece el botón **"Solicitar QR"**. +4. Hacer clic en el botón. El sistema verifica automáticamente: + - Si el jugador **pertenece a uno de los equipos** del partido → genera la cantidad de QRs configurada (por defecto 3, para repartir entre familiares/acompañantes). Tipo: `invitado`. + - Si el jugador es de **categoría Libre** pero no juega ese partido → genera 1 QR con descuento del 50%. Tipo: `libre_50`. + - Si el jugador no cumple ninguna condición → el botón no estará disponible o muestra un mensaje explicativo. +5. ✅ El sistema genera los QRs y envía un **correo con los códigos** al email registrado. +6. El jugador es redirigido automáticamente a **Mis QRs** para ver los códigos generados. + +> **Restricción:** Solo se puede solicitar QR una vez por partido. Si ya se solicitó, el botón queda inhabilitado con un mensaje informativo. + +### 2.4 Mis QRs (`/panel-usuario/mis-qrs`) + +- Lista de todos los códigos QR del jugador, ordenados del más reciente al más antiguo. +- Cada QR muestra: + - Imagen del código QR (escaneable) + - Evento al que pertenece (equipos, fecha, hora) + - Estado: **Válido** / **Usado** (según si fue escaneado en puerta) + - Tipo de QR (invitado, libre_50, etc.) +- Se puede filtrar por evento específico. + +### 2.5 Beneficios de Promociones + +1. Ir a **Promos** desde el menú principal. +2. Ver el mapa/listado de locales con beneficios. +3. Hacer clic en **"Obtener mi QR de beneficio"** en el local deseado. +4. El sistema genera un **QR de descuento único** para ese local. +5. Ver el QR en pantalla para presentarlo en el comercio. + +> **Restricción:** Solo se puede generar 1 QR por local por usuario. + +### 2.6 Seguir Equipos + +- Desde la página pública de un equipo (`/equipos/{id}`), hacer clic en **"Seguir"**. +- Acceder a **Mis Equipos Seguidos** desde el Panel para ver el historial de partidos de los equipos favoritos. +- Hacer clic nuevamente en "Seguir" en un equipo ya seguido lo deja de seguir (toggle). + +### 2.7 Notificaciones (`/notificaciones`) + +- El ícono de campana en el menú muestra la cantidad de notificaciones no leídas. +- Las notificaciones pueden ser generadas por el sistema automáticamente (ej: "Tus QRs para el partido del sábado están disponibles"). +- Desde el centro de notificaciones se puede: + - **Marcar como leída** una notificación individual. + - **Marcar todas como leídas**. + - **Eliminar** notificaciones individuales. + - **Eliminar todas** las notificaciones. + +### 2.8 Editar Datos Personales + +Desde el Panel de Usuario, sección **"Mi Cuenta"**: +- Actualizar **email** y **teléfono**. +- Los jugadores no pueden modificar su nombre, DNI o fecha de nacimiento (esos datos son gestionados por el admin del club). + +### 2.9 Cambiar Contraseña + +Desde el Panel de Usuario, sección **"Seguridad"**: +1. Ingresar la contraseña actual. +2. Ingresar la nueva contraseña (mínimo 6 caracteres). +3. Confirmar la nueva contraseña. +4. Guardar cambios. + +### 2.10 Cerrar Sesión + +- Hacer clic en **"Cerrar Sesión"** en el menú (esquina superior derecha o menú hamburguesa en móvil). +- La sesión se cierra de forma segura. + +--- + + +## 🎉 Capítulo 3 — Aficionado / Hincha + +El aficionado tiene las mismas capacidades que el jugador en lo que respecta a disfrute de la plataforma, con algunas diferencias en la lógica de los QRs. + +### 3.1 Inicio de Sesión y Registro + +Idéntico al Jugador: login con DNI + contraseña. El registro es mediante la **Vía A** descripta en el Capítulo 1. + +### 3.2 Panel de Usuario + +Igual al del Jugador, con las siguientes diferencias visibles: +- **No se muestra** información de club ni categoría federada. +- El campo **"Localidad"** sí es editable (además de email y teléfono). + +### 3.3 Solicitar QR para un Partido + +El aficionado puede solicitar 1 QR por partido. A diferencia del jugador federado: +- No hay distinción por equipo ni categoría. +- Se genera 1 QR de tipo `publico`. +- En el futuro (Fase 6), este QR estará sujeto al pago de la entrada; actualmente se genera de forma directa. + +El proceso es idéntico a los pasos 1–5 del apartado 2.3. + +### 3.4 Mis QRs, Promociones, Notificaciones y Cuenta + +Funciona exactamente igual que para el Jugador (ver apartados 2.4 al 2.10). + +--- + + +## 🏢 Capítulo 4 — Administrador de Club + +El Admin de Club es el responsable designado de gestionar su institución dentro de OnAPB. Accede al panel de administración pero con alcance limitado exclusivamente a los datos de su club. + +### 4.1 Inicio de Sesión + +- En la pantalla de login, pestaña **"Administradores"**. +- Ingresar **usuario** (asignado por un Súper Admin) y **contraseña**. + +### 4.2 Dashboard del Admin de Club (`/admin`) + +Al ingresar, el Admin de Club ve: +- **Estadísticas rápidas** de su club: cantidad de equipos, jugadores y eventos relacionados. +- Nombre e identificación de su club. +- Accesos rápidos a los módulos disponibles. + +### 4.3 Gestión de Jugadores (`/admin/jugadores`) + +#### Ver listado de jugadores +- Lista de todos los jugadores pertenecientes a su club. +- Búsqueda por nombre, apellido o DNI. +- Cada jugador muestra: nombre, DNI, fecha de nacimiento, categoría (calculada automáticamente) y estado (activo/inactivo). + +#### Crear un nuevo jugador +1. Hacer clic en **"Nuevo Jugador"**. +2. Completar el formulario: + - DNI, Nombre, Apellido, Fecha de Nacimiento. + - Club de Origen (puede ser cualquier club del sistema — útil para jugadores con pase). + - El campo "Club Actual" se asigna automáticamente al club del administrador. +3. Guardar. +4. El jugador se crea con estado **inactivo**. Necesitará completar su registro en `/asociate` para activar su cuenta. + +> **Validación:** Si el DNI ya existe en el sistema, se muestra un error indicando a qué club pertenece el jugador actualmente. + +#### Editar un jugador +- Modificar datos básicos (nombre, apellido, fecha de nacimiento, teléfono). +- No puede cambiar el club actual del jugador (eso requiere un pase gestionado por el SuperAdmin). + +#### Eliminar un jugador +- El jugador se marca como eliminado (SoftDelete). No se borra físicamente. + +#### Importar jugadores desde CSV +1. Hacer clic en **"Importar CSV"**. +2. Subir un archivo CSV en formato CAB (Argentina Basketball) o formato interno. +3. El sistema detecta automáticamente el formato y procesa cada fila. +4. Al finalizar, muestra un resumen: nuevos creados, omitidos (ya existían), errores. + +#### Exportar jugadores a CSV +- Descargar el listado completo de jugadores del club en formato CSV. +- Compatible con el reimportador interno del sistema. + +### 4.4 Gestión de Equipos (`/admin/equipos`) + +#### Ver listado de equipos +- Lista de los equipos del club con cantidad de jugadores. + +#### Crear un nuevo equipo +1. Hacer clic en **"Nuevo Equipo"**. +2. Seleccionar **Categoría** (ej: U13, U15, U17, Primera) y Division (A, B, etc.). +3. El club se asigna automáticamente. + +#### Editar y eliminar equipos +- Modificar categoría y división. +- Eliminar (SoftDelete). + +#### Gestionar jugadores del equipo +1. Desde el listado de equipos, hacer clic en el ícono de jugadores (**"Ver Plantel"**). +2. Ver la lista de jugadores asignados a ese equipo. +3. **Agregar jugador**: buscar por nombre/apellido/DNI (búsqueda en tiempo real) y hacer clic en "Agregar". + - Solo se pueden agregar jugadores del mismo club. + - El sistema previene la asignación duplicada. +4. **Remover jugador**: hacer clic en "Quitar" al lado del jugador. + +### 4.5 Editar Identidad Visual del Club (`/admin/clubes/{id}/editar`) + +El Admin de Club puede personalizar la apariencia de su club dentro del sistema: + +- **Logo/Escudo**: subir una imagen (JPEG, PNG, WEBP, máx. 1MB) que aparecerá asociada al club en toda la plataforma. +- **Fondo de QR** (QR Background): subir una imagen que se usará como fondo decorativo en los códigos QR generados para los partidos de su club. +- **Color de texto del QR**: ingresar un color hexadecimal para personalizar la tipografía sobre el QR. + +### 4.6 Gestión de Pases / Traspasos (`/admin/pases`) + +Los pases son solicitudes formales para transferir un jugador de un club a otro. + +#### Solicitar un pase +1. Ir a **Pases** y hacer clic en **"Nuevo Pase"**. +2. Seleccionar el jugador a transferir y el club de destino. +3. Enviar la solicitud. +4. El Súper Admin recibirá la solicitud para aprobarla o rechazarla. + +#### Ver estado de pases +- Listado de todos los pases solicitados por el club. +- Estado posible: **Pendiente**, **Aprobado**, **Rechazado**. + +### 4.7 Escanear QR en Eventos (`/admin/escanear-qr`) + +Esta funcionalidad es para usar en la puerta del evento el día del partido. + +1. Ir a **"Escanear QR"** en el menú. +2. Seleccionar el **evento** (partido) a gestionar. Solo aparecen eventos relacionados con su club. +3. Activar la **cámara** del dispositivo o ingresar manualmente el código del QR. +4. El sistema valida el QR en tiempo real: + - ✅ **QR Válido**: muestra nombre del titular, tipo de QR y pasa el estado a "Usado". + - ❌ **QR Inválido o Ya Usado**: muestra el error correspondiente. + +### 4.8 Cerrar Sesión + +- Hacer clic en **"Cerrar Sesión"** en el menú del panel administrador. + +--- + + +## 👑 Capítulo 5 — Súper Administrador (OnAPB) + +El Súper Admin tiene control total sobre todas las entidades del sistema. Es el personal de la asociación OnAPB. + +### 5.1 Inicio de Sesión + +Igual que el Admin de Club: pestaña "Administradores", usuario y contraseña. + +### 5.2 Dashboard del Súper Admin (`/admin`) + +Al ingresar, el Súper Admin ve: +- **Estadísticas globales**: total de clubes, equipos, jugadores, eventos, promociones y noticias en todo el sistema. +- Accesos rápidos a todos los módulos. + +--- + +### 5.3 Módulo de Clubes (`/admin/clubes`) + +#### Ver todos los clubes +- Lista de todos los clubes registrados con conteo de equipos y jugadores. + +#### Crear un club +1. Clic en **"Nuevo Club"**. +2. Ingresar ID Club (numérico) y Nombre. +3. Guardar. + +#### Editar un club +- Modificar nombre, logo, fondo de QR y color de texto. (Igual que el Admin de Club pero con acceso a cambiar el nombre también). + +#### Eliminar un club +- El club se marca como eliminado (SoftDelete). Los equipos y jugadores asociados quedan preservados. + +--- + +### 5.4 Módulo de Equipos (`/admin/equipos`) + +Idéntico al del Admin de Club pero con visión global (todos los clubes). Al crear un equipo, el Súper Admin puede seleccionar cualquier club del sistema. + +--- + +### 5.5 Módulo de Jugadores (`/admin/jugadores`) + +#### Ver todos los jugadores +- Lista global de todos los jugadores de todos los clubes. +- Filtro por nombre, apellido o DNI. +- Paginación de 25 registros por página. + +#### Crear, editar, eliminar jugador +- Idéntico al Admin de Club pero con acceso a cambiar el **Club Actual** (útil para finiquitar traspasos). + +#### Importar / Exportar CSV +- Importación masiva de jugadores en formato CAB, Interno o Legado. +- Importar para un club específico (seleccionado en el formulario). + +--- + +### 5.6 Módulo de Eventos / Partidos (`/admin/eventos`) + +#### Ver todos los eventos +- Lista de todos los partidos con filtros por estado: Próximos, En Curso, Finalizados. + +#### Crear un nuevo partido +1. Clic en **"Nuevo Evento"**. +2. Completar: + - **Nombre del evento** (generado automáticamente en base a equipos). + - **Equipo Local** y **Equipo Visitante** (deben ser de la misma categoría y grupo si pertenecen a un torneo). + - **Fecha**, **Hora de Inicio** y **Hora de Fin**. + - **Sede**. + - **Torneo** (opcional): asignar el evento a un torneo existente. + - **Límite de QRs por jugador** (configurable). +3. Guardar. El evento queda en estado **"Próximo"**. + +#### Editar un partido +- Modificar cualquier campo del evento. + +#### Registrar resultados +1. Desde el listado de eventos, entrar al evento. +2. Ir a la sección **"Cargar Estadísticas"** o **"Resultado"**. +3. Ingresar marcador local y marcador visitante. +4. Registrar puntos individuales por jugador (para la tabla de goleadores). +5. Guardar. El evento cambia automáticamente a estado **"Finalizado"**. + +#### Eliminar un evento +- El evento se marca como eliminado (SoftDelete). Los QRs asociados se limpian. + +--- + +### 5.7 Módulo de Torneos (`/admin/torneos`) + +#### Crear un torneo +1. Clic en **"Nuevo Torneo"**. +2. Ingresar nombre y año. +3. Guardar. + +#### Añadir equipos al torneo +Desde la vista del torneo: +1. Buscar el equipo a agregar. +2. Asignarle un **grupo** (ej: Grupo A, Grupo B) si aplica. +3. Guardar. + +#### Generar Fixture de Fase Regular +1. Desde el torneo, ir a **"Generar Fixture"**. +2. Configurar la cantidad de vueltas (ida, ida y vuelta). +3. El sistema genera un **preview** de todos los partidos a jugarse. +4. Confirmar para crear los eventos en el sistema. + +#### Importar resultados históricos +- Subir un CSV con resultados de partidos ya jugados para cargar históricos de torneos anteriores. + +#### Gestionar Playoffs +1. Al finalizar la fase regular, ir a **"Playoffs"**. +2. Configurar cuántos equipos clasifican a playoffs. +3. Generar el bracket eliminatorio. +4. A medida que se juegan los partidos, **"Avanzar ganador"** al siguiente cruce. + +#### Ver posiciones y goleadores +- Desde `/torneos/{id}/posiciones`: tabla de posiciones filtrable por grupo/categoría. +- Desde `/torneos/{id}/goleadores`: ranking de anotadores. +- Desde `/torneos/{id}/playoffs`: bracket visual del cuadro eliminatorio. + +--- + +### 5.8 Módulo de Pases / Traspasos (`/admin/pases`) + +#### Ver todos los pases +- Lista de todas las solicitudes de traspaso pendientes, aprobadas y rechazadas. + +#### Aprobar o rechazar un pase +1. Desde el listado, hacer clic en el pase pendiente. +2. Revisar los datos: jugador, club origen, club destino. +3. Hacer clic en **"Aprobar"** → el jugador cambia de club automáticamente. +4. O hacer clic en **"Rechazar"** → el pase queda como rechazado y el jugador permanece en su club actual. + +#### Crear un pase directamente +El Súper Admin puede ejecutar una transferencia sin necesidad de solicitud previa, seleccionando jugador, club destino y guardando. + +--- + +### 5.9 Módulo de Noticias (`/admin/noticias`) + +#### Crear una noticia +1. Clic en **"Nueva Noticia"**. +2. Completar: Título, Contenido (texto largo), Imagen (opcional). +3. Guardar. La noticia aparece en `/noticias`. + +#### Editar y eliminar noticias +- Actualizar cualquier campo. +- Eliminar elimina la noticia del sitio público. + +--- + +### 5.10 Módulo de Promociones (`/admin/promociones`) + +#### Crear una promoción / local con beneficio +1. Clic en **"Nueva Promoción"**. +2. Completar: Nombre del local, Descripción del beneficio, Dirección, Imagen, Coordenadas (para el mapa). +3. Guardar. El local aparece en `/promos`. + +#### Editar y eliminar promociones +- Actualizar información del local. +- Eliminar la promoción del sistema. + +--- + +### 5.11 Módulo de Carrusel / Hero (`/admin/carousel`) + +El carrusel es la sección de diapositivas destacadas en la portada del sitio. + +#### Agregar una diapositiva +1. Clic en **"Nueva Diapositiva"**. +2. Subir una imagen (recomendado: formato ancho/horizontal). +3. Completar un enlace opcional (ej: enlace a una noticia o evento). +4. Guardar. + +#### Editar y eliminar diapositivas +- Actualizar imagen o enlace. +- Eliminar la diapositiva del carrusel. + +--- + +### 5.12 Módulo de Sponsors (`/admin/sponsors`) + +#### Agregar un sponsor +1. Clic en **"Nuevo Sponsor"**. +2. Subir el logo del patrocinador. +3. Ingresar URL del sitio del sponsor (opcional). +4. Guardar. El logo aparece en la franja rotativa del pie de página. + +#### Editar y eliminar sponsors +- Reemplazar logo o cambiar URL. +- Eliminar el sponsor de la franja. + +--- + +### 5.13 Módulo de Usuarios Administradores (`/admin/usuarios`) + +#### Ver todos los administradores +- Lista de todos los usuarios con acceso al panel de administración. + +#### Crear un nuevo administrador +1. Clic en **"Nuevo Usuario Admin"**. +2. Ingresar: + - **Usuario** (nombre de login). + - **Contraseña**. + - **Rol**: `1 = Súper Admin` o `2 = Admin de Club`. + - **Club** (solo si rol 2): asociar al club que administrará. +3. Guardar. + +#### Editar y eliminar administradores +- Cambiar contraseña, rol o club asignado. +- Eliminar el acceso de un administrador. + +--- + +### 5.14 Módulo de Categorías (`/admin/categorias`) + +Las categorías definen los rangos de edad de los jugadores (ej: U13 = 12-13 años). + +#### Crear una categoría +1. Ingresar nombre (ej: "U13"), edad mínima (ej: 12) y edad máxima (ej: 13). +2. Marcar si es **"Categoría Libre"** (los jugadores de esta categoría obtienen 50% de descuento en entradas). +3. Guardar. + +#### Editar y eliminar categorías +- Las categorías modificadas se aplican automáticamente a todos los jugadores ya existentes (la categoría se calcula dinámicamente). + +--- + +### 5.15 Escanear QR en Eventos (`/admin/escanear-qr`) + +Idéntico al del Admin de Club, pero con visión de todos los eventos del sistema. Ver apartado 4.7 para el proceso detallado. + +--- + +### 5.16 Configuración General (`/admin/configuracion`) + +Ajustes globales del sistema: +- Frecuencia de backups automáticos. +- Otros parámetros de comportamiento del sistema. + +--- + +### 5.17 OnAPB Genius — Asistente de IA + +El portal incluye un asistente conversacional basado en IA (Google Gemini) que permite consultar y operar el sistema mediante lenguaje natural. Se invoca desde el botón flotante del chat. + +**Quién puede usar qué:** + +| Rol | Tools disponibles | +|---|---| +| Visitante / Aficionado / Jugador | Chat de ayuda general del portal (sin acceso a operaciones) | +| Administrador de Club | Solo tools de **lectura** | +| Súper Administrador | Lectura + **escritura** + **rollback** | + +**Tools disponibles para Súper Admin:** + +**Lectura (consulta de datos):** +- `listar_torneos` — Lista todos los torneos con ID, nombre y fechas. Usala cuando necesites buscar el ID de un torneo por su nombre. +- `listar_equipos` — Lista equipos. Filtros opcionales: `id_torneo`, `grupo` ("A", "B", ...). +- `listar_eventos` — Lista partidos. Filtros opcionales: `fecha_desde`, `fecha_hasta` (formato YYYY-MM-DD), `id_torneo`. + +**Escritura (modifican la base de datos — requieren tu confirmación explícita):** +- `crear_partido` — Crea un nuevo partido. Campos: `id_equipo_local`, `id_equipo_visitante`, `fecha_evento`, `hora_inicio`, `hora_fin`, `sede`, `id_torneo`. +- `cargar_puntaje` — Actualiza el marcador de un partido existente. Campos: `id_evento` (UUID), `marcador_local`, `marcador_visitante`. +- `redactar_noticia` — Publica una noticia. Campos: `titulo`, `contenido`, `id_torneo` (opcional), `categoria` (opcional). + +**Rollback (deshacer una creación):** +- `eliminar_noticia` — Borra una noticia por su `id_noticia` (numérico). +- `eliminar_partido` — Borra (soft delete) un partido por su `id_evento` (UUID). + +**Cómo se usa (flujo típico):** + +1. Escribí en lenguaje natural lo que querés ("creá una noticia sobre el partido del sábado", "qué equipos hay en el torneo Apertura", "cargá el marcador del partido de ayer 78 a 65"). +2. Si pedís una acción de escritura, Genius **primero te muestra un resumen** con los datos a usar y te pregunta "¿Confirmás?". Tenés que responder "sí", "dale", "confirmo" u "ok" para que ejecute. +3. Tras crear algo, Genius te devuelve el ID del recurso. Guardalo por si querés revertir. +4. Para deshacer: pedile "eliminá la noticia ID X" o "borrá el partido que acabás de crear". Volverá a pedir confirmación antes de borrar. + +**Buenas prácticas:** + +- Si mencionás un torneo/equipo por nombre, Genius usa `listar_torneos` / `listar_equipos` para resolver el ID. No hace falta que lo sepas de memoria. +- Verificá siempre el resumen de confirmación antes de responder "sí". La IA puede interpretar mal fechas o nombres ambiguos. +- Si algo sale mal, revisá `storage/logs/laravel.log` donde quedan registrados los errores de las tools. +- Los límites de la cuenta gratuita de Gemini están configurados en `.env` (`GENIUS_MAX_MESSAGES_PER_SESSION`, `GENIUS_SESSION_WINDOW_MINUTES`). Podés ajustarlos si cambia el uso. + +--- + +## ❓ Preguntas Frecuentes + +**¿Cómo sé si ya tengo una cuenta de jugador?** +Si sos jugador federado, tu DNI ya está en el sistema cargado por el admin de tu club. Solo debés ir a `/asociate` → pestaña "Soy Jugador" e ingresar tus datos para activar la cuenta. + +**¿Puedo tener cuenta de jugador Y de aficionado con el mismo DNI?** +No. El sistema detecta si ya existe un registro (como jugador o aficionado) y te informa antes de permitir el registro. + +**¿Qué pasa si el QR que generé fue escaneado?** +El estado del QR cambia a "Usado" y no puede ser utilizado nuevamente. Cada QR tiene un solo uso. + +**¿Puedo generar el QR de una promo más de una vez?** +No. Por cada usuario y cada promoción, solo se puede generar un QR de beneficio. + +**¿Qué significa cada tipo de QR?** +- `invitado` → Jugador que pertenece a un equipo del partido. Puede generar múltiples (para acompañantes). +- `libre_50` → Jugador de categoría Libre. Obtiene descuento del 50% en la entrada. +- `publico` → Aficionado. Acceso estándar. + +--- + +*Manual redactado para el Proyecto Integrador OnAPB — Taller de Integración, FCYT UADER 2026.* diff --git a/misc/OnAPB - Manual de Usuario.pdf b/misc/OnAPB - Manual de Usuario.pdf new file mode 100644 index 0000000..76ffe70 Binary files /dev/null and b/misc/OnAPB - Manual de Usuario.pdf differ diff --git a/misc/analisis_requerimientos.md b/misc/analisis_requerimientos.md new file mode 100644 index 0000000..0129b6b --- /dev/null +++ b/misc/analisis_requerimientos.md @@ -0,0 +1,42 @@ +# Análisis de Requisitos del Sistema (OnAPB) + +En base a la imagen `requerimientos.jpeg` y la inspección del código fuente actual, aquí está el detalle de qué puntos cumple el sistema, cuáles faltan por desarrollar, y cuáles dependen exclusivamente de la presentación oral. + +## ✅ Requisitos Cumplidos (Implementados en Software) + +| Punto | Descripción | Estado en el Sistema | +| :---: | :--- | :--- | +| **1** | **Innovación** | **Cumple.** La implementación de un sistema de códigos QR digitales para el acceso a eventos y manejo de "Pases" de jugadores digitaliza procesos típicamente manuales o en papel. | +| **2** | **Investigación durante el desarrollo** | **Cumple.** Se evidencia el uso del framework Laravel 11, sistema de autenticación custom (aficionados/jugadores/admin), y estructuración de base de datos relacional. | +| **6** | **Justificación de Ingeniería de Software** | **Cumple.** El sistema utiliza un patrón arquitectónico claro (MVC provisto por Laravel), ORM (Eloquent), migraciones de base de datos y un enrutamiento ordenado. | +| **7** | **Conocimiento del negocio** | **Cumple.** El software modela perfectamente la lógica de una asociación de básquet: Clubes, Equipos, Jugadores, pases interclubes, categorías por edad y gestión de aforos de QRs por partido. | +| **9** | **Completitud de software** | **Parcialmente Cumplido.** El sistema tiene paneles de usuario y admin muy completos (fases 1 a 5 de la Hoja de Ruta). Sin embargo, la **Fase 6 (Pagos con Banco Macro)** está pendiente. | + +--- + +## ❌ Requisitos Faltantes (Deuda Técnica a Resolver) + +| Punto | Descripción | Lo que falta hacer | +| :---: | :--- | :--- | +| **8** | **Pruebas y errores, end-to-end** | **FALTA.** La carpeta `tests/` está vacía (solo tiene el test de ejemplo de Laravel). No hay pruebas unitarias (PHPUnit) ni pruebas de integración o E2E (Laravel Dusk) configuradas ni ejecutadas. | +| **10** | **Recuperación ante fallos/desastres** | **FALTA.** No hay un sistema de copias de seguridad de la base de datos (ej. Laravel Backup). Además, los modelos actuales **no usan SoftDeletes**, por lo que si un admin elimina un equipo, jugador o evento, los datos **se pierden permanentemente** (Hard Delete) y pueden romper relaciones. | +| **13** | **Documentación Técnica y de Usuario** | **FALTA.** El archivo `README.md` del repositorio es el que viene por defecto con Laravel original en inglés. La `HOJA-DE-RUTA.md` es solo un checklist. Se necesita redactar un manual de usuario (ej: cómo usar el panel admin) y un manual técnico (cómo instalar el proyecto, variables de entorno, esquema de BD). | + +--- + +## 🗣️ Requisitos que NO dependen del software (Evaluación Oral/Grupal) + +Estos puntos no se programan, sino que se evaluarán durante la defensa del proyecto: + +* **3 - Tiempo/dedicación en finalizar.** (Se demuestra presentando el volumen de trabajo hecho, que es bastante amplio). +* **4 - Exposición oral.** +* **5 - Evaluación de dinámica grupal.** +* **11 - Revisiones de procesos y sugerencias por parte de los profesionales.** (Conclusiones del grupo). +* **12 - Pruebas y errores durante la exposición (datos reales).** (Asegúrense de tener la base de datos poblada con clubes, jugadores y eventos reales o realistas el día de la presentación). + +--- + +### 🚀 Siguientes pasos recomendados para aprobar: +1. Reemplazar el `README.md` por documentación real técnica y de usuario. +2. Añadir `SoftDeletes` a las tablas críticas (`jugadores`, `clubes`, `equipos`, `eventos`) para cumplir el Punto 10. +3. Escribir al menos 3 o 4 Tests básicos (Feature tests) simulando el login y la emisión de QRs para cubrir el Punto 8. diff --git a/misc/onapb-security-hardening.md b/misc/onapb-security-hardening.md new file mode 100644 index 0000000..2cfc70b --- /dev/null +++ b/misc/onapb-security-hardening.md @@ -0,0 +1,334 @@ +# Blueprint de Seguridad — onapb.com +**Generado por:** The Architect +**Fecha:** 2026-04-01 +**Para ejecutar con:** Claude Code en el repositorio del sistema + +--- + +## Contexto + +Este documento es una instrucción completa y autónoma para que Claude Code implemente todas las mejoras de seguridad detectadas en el sitio **onapb.com**. + +- **Stack:** Laravel (PHP 8.4.11) + LiteSpeed + Hostinger +- **Framework detectado:** Laravel (confirmado por cookies `laravel-session` y `XSRF-TOKEN`) +- **Dev responsable:** único desarrollador con acceso completo al repositorio + +Ejecutá cada paso en orden. No saltes pasos. Al final, hacé deploy a producción. + +--- + +## CLAUDE.md para este proyecto + +``` +Sos el implementador de seguridad del sitio onapb.com. +Tu tarea es implementar los cambios de seguridad descritos en este archivo en orden. +El stack es Laravel. No rompas funcionalidad existente. +Al terminar cada paso, confirmá que los tests pasen antes de avanzar. +``` + +--- + +## Orden de implementación + +### PASO 1 — Middleware de Security Headers + +**Problema:** Faltan 5 headers de seguridad críticos: +- `Strict-Transport-Security` (HSTS) +- `X-Frame-Options` +- `X-Content-Type-Options` +- `X-XSS-Protection` +- `Content-Security-Policy` (actualmente solo tiene `upgrade-insecure-requests`) + +**Qué hacer:** + +1. Crear el archivo `app/Http/Middleware/SecurityHeaders.php`: + +```php +headers->set('X-Frame-Options', 'SAMEORIGIN'); + $response->headers->set('X-Content-Type-Options', 'nosniff'); + $response->headers->set('X-XSS-Protection', '1; mode=block'); + $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin'); + $response->headers->set( + 'Permissions-Policy', + 'camera=(), microphone=(), geolocation=()' + ); + $response->headers->set( + 'Strict-Transport-Security', + 'max-age=31536000; includeSubDomains; preload' + ); + $response->headers->set( + 'Content-Security-Policy', + "default-src 'self'; " . + "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " . + "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " . + "font-src 'self' data: https://fonts.gstatic.com; " . + "img-src 'self' data: https:; " . + "connect-src 'self'; " . + "frame-ancestors 'self';" + ); + + return $response; + } +} +``` + +2. Registrar el middleware en `app/Http/Kernel.php`, dentro de `$middlewareGroups['web']`, al final del array: + +```php +\App\Http\Middleware\SecurityHeaders::class, +``` + +3. Verificar: hacer `php artisan route:list` y luego una request curl local para confirmar que los headers aparecen. + +--- + +### PASO 2 — Ocultar versión de PHP y stack + +**Problema:** El header `X-Powered-By: PHP/8.4.11` y `Server: LiteSpeed` revelan el stack exacto. + +**Qué hacer:** + +1. En el archivo `public/.htaccess`, agregar al inicio (después de `` o antes): + +```apache +# Ocultar headers de servidor + + Header unset X-Powered-By + Header always unset X-Powered-By + Header unset Server + +``` + +2. Si tenés acceso a `php.ini` (en Hostinger hPanel → PHP → php.ini personalizado): + +```ini +expose_php = Off +``` + +3. Si usás un archivo `php.ini` en la raíz del proyecto, agregar esa línea ahí también. + +--- + +### PASO 3 — Forzar HTTPS y HSTS en .htaccess + +**Problema:** El sitio no sirve headers HSTS. El HSTS del Paso 1 solo actúa cuando ya estás en HTTPS, pero si alguien entra por HTTP no hay redirect forzado a nivel servidor. + +**Qué hacer:** + +En `public/.htaccess`, asegurar que exista este bloque (Laravel suele tenerlo pero verificar): + +```apache + + RewriteEngine On + + # Forzar HTTPS + RewriteCond %{HTTPS} off + RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] + + # Resto de reglas de Laravel... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + +``` + +--- + +### PASO 4 — Proteger archivo .env y rutas sensibles + +**Problema:** Laravel ya protege `.env` por defecto, pero verificar que las rutas de storage no sean accesibles. + +**Qué hacer:** + +En `public/.htaccess`, agregar: + +```apache +# Bloquear acceso a archivos sensibles + + Order allow,deny + Deny from all + + +# Bloquear acceso directo a /storage si está symlinkado + + RewriteRule ^storage/app/(.*)$ - [F,L] + +``` + +--- + +### PASO 5 — Mejorar robots.txt + +**Problema:** El `robots.txt` actual tiene `Disallow: ""` (vacío), lo que permite que todos los bots indexen todo, incluidas rutas como `/recuperar` y rutas de admin. + +**Qué hacer:** + +Reemplazar el contenido de `public/robots.txt` (o crearlo si no existe): + +``` +User-agent: * +Disallow: /admin +Disallow: /recuperar +Disallow: /api/ +Disallow: /storage/ +Disallow: /vendor/ +Allow: / + +Sitemap: https://onapb.com/sitemap.xml +``` + +--- + +### PASO 6 — Agregar security.txt + +**Problema:** No existe `/well-known/security.txt`. Es una buena práctica de divulgación responsable. + +**Qué hacer:** + +1. Crear el directorio `public/.well-known/` +2. Crear el archivo `public/.well-known/security.txt`: + +``` +Contact: mailto:admin@onapb.com +Expires: 2027-04-01T00:00:00Z +Preferred-Languages: es, en +Canonical: https://onapb.com/.well-known/security.txt +``` + +(Reemplazar `admin@onapb.com` con el email real del responsable de seguridad.) + +--- + +### PASO 7 — Rate limiting en rutas críticas + +**Problema:** No se detectó rate limiting explícito. Rutas como `/recuperar` (recuperación de contraseña) son vectores de ataque por fuerza bruta y enumeración de usuarios. + +**Qué hacer:** + +En `routes/web.php` o en el middleware de rutas, asegurar rate limiting en rutas sensibles: + +```php +Route::middleware(['throttle:5,1'])->group(function () { + Route::post('/recuperar', [PasswordController::class, 'sendResetLink']); + Route::post('/login', [AuthController::class, 'login']); +}); +``` + +El `5,1` significa 5 intentos por minuto. Ajustar según la lógica del negocio. + +Si el proyecto usa Laravel Breeze o Fortify, ya tiene esto incorporado — verificar que esté habilitado en `config/fortify.php`: + +```php +'limiters' => [ + 'login' => 'login', +], +``` + +--- + +### PASO 8 — Configurar Content Security Policy estricta (opcional pero recomendado) + +**Problema:** La CSP del Paso 1 usa `'unsafe-inline'` y `'unsafe-eval'` como fallback seguro. Si el proyecto no necesita eval, endurecerla. + +**Qué hacer:** + +Una vez que el sitio esté corriendo con el middleware del Paso 1, revisar la consola del navegador por errores de CSP. Si no hay errores de scripts inline, cambiar en `SecurityHeaders.php`: + +```php +"script-src 'self';" // quitar unsafe-inline y unsafe-eval +``` + +Esto requiere que todos los scripts estén en archivos externos, no inline. + +--- + +## Pasos que requieren acción MANUAL (fuera del repositorio) + +Estos cambios no se hacen en el código — son configuraciones del servidor/DNS. Documentarlos para hacerlos en paralelo: + +### A — Cerrar puerto 3306 (CRÍTICO — hacer YA) +- En Hostinger hPanel → Seguridad → Firewall +- Bloquear acceso externo al puerto 3306 (MySQL) +- Solo debe aceptar conexiones desde `127.0.0.1` (localhost) +- Verificar en `.env`: `DB_HOST=127.0.0.1` + +### B — Deshabilitar FTP (puerto 21) +- En Hostinger hPanel → Archivos → Administrador FTP +- Deshabilitar FTP o cambiar a SFTP (puerto 22) + +### C — Migrar DNS a Cloudflare (recomendado para WAF) +- Crear cuenta en cloudflare.com +- Agregar el dominio `onapb.com` +- Cambiar los nameservers en Registrar.eu (registrar actual) a los de Cloudflare +- Habilitar WAF en plan gratuito +- Habilitar DNSSEC en Cloudflare (un click) +- Habilitar proxy (nube naranja) para ocultar IP real + +### D — Configurar DMARC + endurecer SPF +En el panel DNS (Hostinger o Cloudflare): + +**Cambiar SPF existente** (`~all` → `-all`): +``` +v=spf1 include:_spf.mail.hostinger.com -all +``` + +**Agregar registro DMARC** (nuevo TXT en `_dmarc.onapb.com`): +``` +v=DMARC1; p=quarantine; rua=mailto:admin@onapb.com; fo=1 +``` + +### E — Verificar DKIM +En Hostinger hPanel → Email → Configuración de dominio → habilitar DKIM si no está activo. + +--- + +## Orden de deploy + +Una vez implementados los pasos de código (1 al 8): + +1. Correr tests: `php artisan test` +2. Verificar que la app levanta: `php artisan serve` + revisar consola del browser +3. Hacer commit con mensaje: `security: add security headers middleware and hardening` +4. Push a rama de staging si existe, sino directo a `main` +5. Deploy a producción (según el proceso actual del proyecto) +6. Verificar headers en producción: usar [securityheaders.com](https://securityheaders.com) con `onapb.com` +7. Verificar que el sitio funciona 100% antes de cerrar puertos (paso manual A) + +--- + +## Verificación post-deploy + +Correr estos checks para confirmar que todo quedó bien: + +| Check | Herramienta | URL | +|-------|-------------|-----| +| Headers HTTP | Security Headers | securityheaders.com | +| SSL/TLS | SSL Labs | ssllabs.com/ssltest | +| HSTS | hstspreload.org | hstspreload.org | +| Reputación IP | VirusTotal | virustotal.com | +| Puertos | Shodan | shodan.io | + +--- + +## Resultado esperado + +Al completar todos los pasos, el sitio debe: +- Obtener calificación **A** en securityheaders.com (actualmente F) +- No exponer versión de PHP ni stack en headers +- Tener HSTS activo con preload +- No tener puertos de base de datos expuestos a internet +- Tener protección WAF básica via Cloudflare +- Tener autenticación de email (SPF + DKIM + DMARC) diff --git a/misc/requerimientos.jpeg b/misc/requerimientos.jpeg new file mode 100644 index 0000000..2f44deb Binary files /dev/null and b/misc/requerimientos.jpeg differ