Repository navigation
Funcionalidades
Qué ve el usuario, qué reglas se aplican y en qué clases está cada cosa.
-
/registropide email, nombre y contraseña.RegistroFormvalida formato y longitudes. -
UsuarioService.crearpasa el email a minúsculas y comprueba que no exista. - La contraseña se cifra con BCrypt (no se puede recuperar la original; máximo 72 bytes).
- El usuario empieza con 1.000 moneditas (HU-14).
Spring Security con el formulario /login. Tras 5 contraseñas incorrectas, la cuenta se bloquea 15 minutos. Al entrar, RecargaAlEntrarHandler aplica la recarga si toca.
- El saldo se ve siempre en la cabecera.
- Cada 7 días se suman 200 moneditas gratis (al iniciar sesión o abrir Mi cuenta). No se acumulan.
- El saldo cambia con
cargar(al apostar; si no hay saldo,SaldoInsuficienteException),abonar(cancelar, cobrar) yajustar(resolver o corregir). - Si dos operaciones cambian el mismo saldo a la vez, la segunda se rechaza con un aviso (bloqueo optimista).
- En el login, ¿Has olvidado tu contraseña? lleva a
/recuperar, donde se escribe el email. - Si existe la cuenta,
RecuperacionServicecrea un código aleatorio, guarda solo su resumen SHA-256 en la tablatoken_recuperacion(caduca a los 30 minutos) y envía el enlace/recuperar/nueva?token=…. Pedir otro enlace anula el anterior. - La respuesta es la misma exista o no la cuenta, para no desvelar qué emails están registrados.
- Con el enlace se pone la contraseña nueva (mismas reglas que en el registro). El enlace queda gastado, se cierran las sesiones abiertas y se olvida el bloqueo por intentos fallidos.
- Sin servidor de correo (lo normal en tu ordenador), el enlace se escribe en la consola de la aplicación. Para enviarlo de verdad, ver Ejecutar y desplegar.
Cambiar nombre y contraseña (pidiendo la actual). Al cambiar la contraseña se cierran las sesiones abiertas en otros navegadores.
- En
apostar.htmlel jugador elige el resultado y el importe; JavaScript enseña la ganancia potencial. -
ApuestaControllervalida el formulario y llama aApuestaService.apostar. - El servicio, en una transacción:
- comprueba los límites de la casa (importe 1–500, número de selecciones);
- comprueba que no es el creador;
- comprueba que el evento admite apuestas (programado y sin empezar);
- calcula la cuota actual y, si es distinta de la que vio el jugador, se lo enseña para que decida;
- comprueba la cuota total máxima (1.000) y el juego responsable;
- descuenta el saldo y guarda la apuesta.
- Redirige a
/apuestascon "Apuesta realizada" o vuelve al formulario con el error.
Cancelar y cambiar el importe (HU-26, HU-27): mientras ninguno de sus partidos haya empezado. Al cancelar se devuelve todo; al cambiar, se cobra o devuelve la diferencia con las cuotas del momento.
- Al pulsar una cuota, la selección va al boleto (vive en la sesión).
- No se repite un partido: otro resultado del mismo partido sustituye al anterior.
- Máximo 10 selecciones (límite editable).
- Cuota total = producto de las cuotas. Ejemplo: 1,80 × 2,10 × 1,50 = 5,67; con 10 moneditas se ganan 56,70. Máximo 1.000.
- Con una sola selección es una apuesta simple.
- Si una cuota cambia, se enseñan las nuevas y hay que aceptarlas.
- Se gana solo si se aciertan todas; un partido anulado cuenta con cuota 1,00.
Al introducir el resultado (el creador o la API), ResolucionService.introducirResultado:
- Marca el evento como
FINALIZADO. - Para cada selección de ese evento llama a
apuesta.resolver(...). - La selección queda
ACERTADAoFALLADAy la apuesta se reevalúa. - Si la apuesta cambia de estado, el jugador recibe un aviso.
La regla de Apuesta.reevaluar():
- alguna selección fallada → PERDIDA (debe pagarse 0);
- si no, alguna pendiente → ACTIVA;
- todas anuladas → ANULADA (se devuelve el importe);
- si no → GANADA (importe × producto de cuotas).
Después usuario.ajustar(loQueDebePagar − loYaPagado). Así corregir un resultado funciona solo: se quita o se paga la diferencia. El saldo puede quedar negativo; es una decisión documentada en docs/decisiones/0002: mientras sea negativo no se puede apostar.
Suspender solo impide apostar. Anular pone las selecciones con cuota 1,00 y reevalúa las apuestas.
Doble oportunidad, más/menos de 2,5 goles y ambos marcan (ver Algoritmo de cuotas). En fútbol el creador introduce el marcador y el resultado sale de ahí. Si solo se marca el ganador, las de goles y ambos marcan se anulan.
Un mercado ("¿Quién ganará el Balón de Oro?") tiene varios candidatos con cuotas fijadas por el creador. Se apuesta en /mercados hasta el cierre. El creador puede cerrarlo, marcar el ganador (se resuelve igual que un partido), corregirlo o anularlo (se devuelve todo).
| Función | Detalles |
|---|---|
| Alta de competiciones y equipos (HU-01) | Con deporte y calidad 0–10. Sin nombres repetidos |
| Editar un equipo (HU-02, HU-50) | Calidad, forma, escudo y jugadores con su nota |
| Alta de eventos | Competición, local y visitante distintos, fecha y fase |
| Editar o borrar un evento (HU-46) | Solo si no ha empezado. Con apuestas no se cambian los equipos ni se borra: se anula |
| Detalle de un evento (HU-04, HU-05, HU-06) | Dinero apostado a cada resultado; resultado o marcador (debe coincidir); suspender, reactivar o anular |
| Límites (HU-07) | Importe mínimo y máximo, selecciones por combinada, interruptor del juego responsable |
| Mercados (HU-45) | Crear, candidatos, cuotas, cerrar, ganador, anular |
| Cuentas de la casa (HU-54) | Apostado, pagado, beneficio, en juego; margen real frente al teórico (6,5 %); por tipo y por deporte |
| Sincronizar ahora / Descargar plantillas | Lanza a mano la sincronización con la API |
-
Ficha (
/equipos/{id}, HU-31): últimos 10 resultados, racha de 5, balance, clasificación (3 puntos por victoria, 1 por empate) y próximos 5 partidos. - Gráfico de evolución (HU-32): puntos acumulados partido a partido.
- Plantilla y alineación (HU-49): jugadores por posición con su nota; alineación probable en 4-3-3.
- Cara a cara (HU-33): racha de cada equipo y enfrentamientos anteriores.
- Ranking (HU-36): por saldo, ganancias o % de aciertos (mínimo 5 apuestas resueltas). No aparecen el creador ni las cuentas eliminadas.
- Perfil público (HU-48): puesto, saldo, aciertos y balance, sin enseñar las apuestas.
- Ligas privadas (HU-51): código de 6 caracteres sin letras confusas (sin 0/O ni 1/I/L); ranking solo entre sus miembros; máximo 10 ligas por jugador; el creador la borra y los demás salen.
- Avisos (HU-37): al ganar, perder o anularse una apuesta; la campana muestra los no leídos.
- Límites personales (HU-10): máximo apostado en 24 horas y en 7 días.
- Pausa: 1, 7 o 30 días sin apostar. El creador puede desactivar el juego responsable.
-
Eliminar la cuenta (HU-18): pide la contraseña. Se cancelan las apuestas cancelables, se borran avisos y ligas propias, se cierran las otras sesiones y la cuenta se anonimiza (email
eliminado-<id>@apuestas.invalid, nombre "Usuario eliminado", saldo 0). La fila se conserva para que las cuentas de la casa cuadren.
Esta wiki se genera desde el repositorio: las páginas salen de docs/wiki, las actas de los sprints de docs/scrum/sprints y los diagramas de docs/diseno/uml.md. Lo que se edite aquí directamente se pierde en la siguiente publicación: para cambiar una página, edita su archivo en el repositorio con un pull request.
El proyecto
Cómo funciona
Técnico
Proceso
Sprints
Ayuda