# Dominó 2vs2 — PHP + MySQL + Alpine.js + Capacitor

Misma idea del juego (dominó cubano 2vs2, servidor autoritativo, anti-trampa),
pero en tu stack real: PHP/MySQL en tu VPS, frontend con Alpine.js, y
empaquetado a app móvil con Capacitor.

## Arquitectura elegida

- **Tiempo real: Polling simple** (cada 1.4s el cliente pregunta el estado).
  No se necesita websockets ni un proceso Node.js aparte. El timer de 8s y
  la detección de abandono se resuelven de forma "perezosa": el propio
  tráfico de polling de los 4 jugadores dispara esas revisiones dentro de
  `PartidaService::obtenerEstadoParaJugador()`. Cero infraestructura nueva
  que mantener corriendo en el VPS.
- **Auth: sesión propia por token**, no cookies de PHP. Verificamos el
  id_token de Google / access_token de Facebook contra los servidores de
  Google/Facebook, creamos/actualizamos el usuario en tu tabla `usuarios`,
  y emitimos un token propio de 30 días que el cliente guarda en
  `localStorage` y manda como `Authorization: Bearer {token}`. Esto es más
  confiable que cookies dentro de un WebView de Capacitor.
- **Empaquetado: Capacitor con `server.url`**. En vez de compilar un bundle
  estático, Capacitor simplemente abre tu sitio PHP real (ya en producción)
  dentro de un WebView nativo. Es la opción más simple porque tu app YA es
  un sitio web completo — no hay nada que "portar" a JS puro.

## Estructura

```
includes/
  config.php          Credenciales BD, secretos, constantes del juego
  Database.php         PDO singleton
  Auth.php              Verifica Google/Facebook, emite/valida tokens
  DominoEngine.php      Motor de reglas puro (mismo que en la versión Firebase)
  PartidaService.php    Orquesta MySQL + DominoEngine (jugar, timeout, abandono...)
  response.php          Helpers de JSON / CORS
api/
  auth_google.php, auth_facebook.php
  buscar_partida.php, cancelar_busqueda.php
  crear_sala_privada.php, unirse_sala_privada.php, estado_sala_privada.php
  estado_partida.php    <- el endpoint que hace polling (el más importante)
  jugar_ficha.php, pasar_turno.php
  notificar_salida.php, cancelar_abandono.php
  reportar_jugador.php, chat_enviar.php, chat_obtener.php
public/                 Todo esto es tu document root
  index.html            Login
  home.html             Jugar ahora / Sala con amigos
  sala.html             Tablero, mano, timer, chat
  final.html            Resultado
  assets/js/            api.js, auth.js, home.js, sala.js
  assets/css/estilos.css
sql/schema.sql          Todas las tablas
capacitor/              Proyecto Capacitor (empaquetado móvil)
```

## Puesta en marcha en tu VPS

**Para probar todo localmente primero** (juego + módulo de torneos, sin
configurar Apache/Nginx todavía), usa el router incluido:
```bash
mysql -u root -p -e "CREATE DATABASE domino_2v2 CHARACTER SET utf8mb4;"
mysql -u root -p domino_2v2 < sql/schema.sql
mysql -u root -p domino_2v2 < torneos/sql/schema_torneos.sql
# edita includes/config.php con tus credenciales locales de MySQL
php torneos/sql/crear_admin.php admin "tu_clave" "Tu Nombre"
php -S localhost:8000 router.php
```
Luego abre:
- `http://localhost:8000/` → juego online (login)
- `http://localhost:8000/torneos/admin_login.html` → panel del organizador
- `http://localhost:8000/torneos/ranking.html` → ranking público (para proyectar)
- `http://localhost:8000/torneos/portal_jugador.html` → portal del jugador

`router.php` es solo para desarrollo — remapea `/api` y `/torneos/api` a sus
carpetas reales sin necesitar symlinks. En producción, sigue los pasos de
document root + symlinks de abajo.

## Si ya tenías el proyecto instalado (migraciones)

Corre estos archivos en orden, una sola vez, sobre tu base de datos existente.
**Importante:** usa siempre `--default-character-set=utf8mb4` al importar,
o los acentos (á, é, í...) de nombres/descripciones se guardan mal
(ej. "Clásica" se vuelve "ClÃ¡sica") — cada archivo ya trae `SET NAMES
utf8mb4;` al inicio, pero el propio cliente `mysql` también debe abrirse
en esa codificación para que funcione de punta a punta:
```bash
mysql -u tu_usuario -p --default-character-set=utf8mb4 domino_2v2 < sql/migracion_001_rotacion_apertura.sql
mysql -u tu_usuario -p --default-character-set=utf8mb4 domino_2v2 < sql/migracion_002_invitados_y_bots.sql
mysql -u tu_usuario -p --default-character-set=utf8mb4 domino_2v2 < sql/migracion_003_recargas.sql
mysql -u tu_usuario -p --default-character-set=utf8mb4 domino_2v2 < sql/migracion_004_experiencia.sql
mysql -u tu_usuario -p --default-character-set=utf8mb4 domino_2v2 < sql/migracion_005_tienda.sql
```

## Novedades: Experiencia (XP) y Tienda

- **XP**: cada ficha que juega un humano (no bots) suma `XP_POR_JUGADA`
  (`includes/config.php`) a `usuarios.experiencia`. Nivel = 100 XP por
  nivel. Se muestra en la esquina superior izquierda de la sala de juego
  con tu avatar/nombre ("Modo Juego" si entraste como invitado) y una
  barra de progreso.
- **Tienda** (`public/tienda.html`): fichas (skins de color), avatares y
  marcos/coronas comprables con monedas. El skin de fichas es una
  preferencia tuya (afecta cómo VES todas las fichas en pantalla); los
  avatares y marcos se ven también por los demás jugadores en la mesa.
  Los "artículos" solo guardan un `codigo` en la base de datos — todo el
  dibujo (CSS/SVG) vive en `estilos.css`/`sala.html`, así que agregar un
  artículo nuevo no requiere subir imágenes.

## Novedades: Modo Prueba y Recargas de monedas

- **Modo Prueba**: botón "Jugar sin cuenta" en el login (crea un usuario
  invitado temporal) + botón "🤖 Modo Prueba" en Home (arranca una partida
  inmediata contigo + 3 bots, sin esperar matchmaking). Los bots "piensan"
  ~1.2s y juegan solos; no se otorgan monedas ni ELO en este modo
  (`tipo = 'prueba'` queda excluido automáticamente de `liquidarResultadoFinal`
  y de la penalización por abandono).
- **Recargas de monedas**: panel en `torneos/public/admin_monedas.html`
  (mismo login de administrador de torneos) para acreditar monedas a mano
  buscando por id o email. También hay un flujo de autoservicio con Wompi
  (`public/comprar_monedas.html` + `api/wompi_crear_intento.php` +
  `api/wompi_webhook.php`) — configura tus llaves en `includes/config.php`
  y **probá todo en modo sandbox de Wompi antes de manejar dinero real**;
  verifica el algoritmo de firma contra https://docs.wompi.co por si cambió.

## Puesta en marcha en tu VPS (producción)


1. **Base de datos**:
   ```bash
   mysql -u root -p -e "CREATE DATABASE domino_2v2 CHARACTER SET utf8mb4;"
   mysql -u root -p domino_2v2 < sql/schema.sql
   ```
2. **Configura credenciales** en `includes/config.php` (DB, `APP_SECRET`,
   `GOOGLE_CLIENT_ID`, `FACEBOOK_APP_ID/SECRET`).
3. **Document root**: apunta tu vhost (Apache/Nginx) de forma que
   `public/` sea la raíz servida como `https://tu-dominio.com/`, y que
   `api/` sea accesible como `https://tu-dominio.com/api/...`. Ejemplo con
   la estructura de carpetas tal cual (sin mover nada), en Nginx:
   ```nginx
   root /var/www/domino_php/public;   # noten que api/ queda un nivel arriba de public/
   ```
   Como `api/` está al lado de `public/`, no dentro, la forma más simple es
   crear un symlink: `ln -s /var/www/domino_php/api /var/www/domino_php/public/api`
   así `public/api` apunta al mismo código y todo queda bajo un solo
   document root sin duplicar archivos.
4. **HTTPS obligatorio**: Google/Facebook Login y Capacitor con
   `androidScheme: https` lo requieren. Usa Let's Encrypt (certbot) si aún
   no lo tienes en ese dominio.

## Configurar login social

**Google**: consola de Google Cloud → "APIs & Services" → "Credentials" →
crear "OAuth Client ID" tipo "Web application", agrega tu dominio en
"Authorized JavaScript origins". Copia el Client ID a
`includes/config.php` (`GOOGLE_CLIENT_ID`) y a
`public/assets/js/auth.js` (`GOOGLE_CLIENT_ID`, deben coincidir).

**Facebook**: developers.facebook.com → crear App → producto "Facebook
Login" → en "Configuración básica" copia App ID y App Secret a
`includes/config.php`. En "Facebook Login > Settings" agrega tu dominio a
"Allowed Domains for the JavaScript SDK". Copia el App ID también a
`public/assets/js/auth.js` (`FACEBOOK_APP_ID`).

## Empaquetar con Capacitor

```bash
cd capacitor
npm install
npx cap add android
npx cap add ios
```
Edita `capacitor.config.json` → `server.url` con tu dominio real (con
HTTPS). Luego:
```bash
npx cap sync
npx cap open android   # abre Android Studio
npx cap open ios       # abre Xcode (requiere Mac)
```

Plugins usados y para qué:
- `capacitor-plugin-screen-protector`: bloquea capturas/grabación de
  pantalla mientras la app está abierta (equivalente a FLAG_SECURE).
  Se activa/desactiva automáticamente en `sala.js` al entrar/salir de la
  sala de juego.
- `@capacitor/app`: detecta cuando la app pasa a segundo plano, para
  disparar `notificar_salida.php` (abandono de partida rankeada).
- `@capacitor/haptics`: vibración nativa al colocar fichas (con fallback a
  `navigator.vibrate` si corres esto en un navegador normal sin Capacitor).

Nota importante: como `server.url` apunta a tu sitio en producción, cada
vez que actualices el PHP/JS del servidor, la app ya refleja los cambios
sin necesitar recompilar ni volver a subir el APK/IPA a las tiendas —
igual que actualizar cualquier página web. Solo necesitas recompilar si
cambias algo *nativo* (plugins, permisos, ícono, splash screen).

## Reglas de apertura del juego online (`includes/DominoEngine.php` / `PartidaService.php`)

- La partida se juega a varias **manos** hasta que un equipo llega a
  `PUNTOS_PARA_GANAR`.
- **Mano 1**: abre quien tenga el doble-6 (obligatorio jugarlo primero).
- **Mano 2 en adelante**: abre SIEMPRE el jugador a la derecha (siguiente
  posición en el orden de turno) de quien abrió la mano anterior —
  **sin importar qué equipo ganó la mano que se acaba de cerrar**. Ya no se
  exige doble-6 para abrir esas manos: el que le toca abre con cualquier
  ficha de su mano. Esto se rastrea con las columnas nuevas
  `partidas.posicion_abrio_mano` y `partidas.es_primera_mano` (ver
  `sql/migracion_001_rotacion_apertura.sql` si ya tenías la BD creada).

## Qué es 100% funcional aquí

- Motor de reglas completo (reparto, doble-6, validación por extremo,
  tranca, pegada, 100 puntos) — mismo diseño que la versión Firebase,
  ahora en PHP puro.
- Servidor autoritativo real: cada jugada se valida contra la mano
  guardada en MySQL, nunca contra lo que dice el cliente.
- Fichas rivales invisibles: `api/estado_partida.php` solo devuelve
  `mi_mano` filtrando por `usuario_id` de la sesión autenticada; nunca
  hace un SELECT sin ese filtro hacia el cliente.
- Timer de turno de 8s y detección de abandono, ambos resueltos sin cron
  ni websockets (chequeo perezoso en cada poll).
- Login con Google y Facebook verificado server-side.
- Drag & drop táctil con Pointer Events (funciona con mouse y touch),
  chat de stickers, 3 temas de tablero, sonido/vibración, reportes.

## Qué queda como base para pulir

- **Polling vs. batería/datos móviles**: 1.4s es un buen balance para
  dominó (juego por turnos), pero en redes móviles lentas puedes subir el
  intervalo a 2-2.5s sin que se sienta mal, y así ahorrar batería/datos.
- **Assets de sonido reales** en `public/assets/sounds/` (hoy son
  referencias; usa grabaciones CC0 de freesound.org).
- **Verificación JWT local de Google** en vez de golpear su endpoint
  `tokeninfo` en cada login (mejor para volumen alto — cachear las claves
  públicas de Google y verificar la firma tú mismo).
- **Anti-colusión más fino**: hoy solo se cuenta `reportes_recibidos`; el
  cruce real de "estos 2 usuarios siempre juegan juntos" (>70% de
  partidas) se puede armar con una consulta sobre `partida_jugadores`
  agrupando por pares de `usuario_id` que compartieron `partida_id`.
- **Panel de administración** para revisar `reportes` y
  `revision_manual_pendiente` (hoy solo se guardan en la BD).
