Póker de dados → online

Juego multijugador online de póker de dados, con física 3D, marketplace de Bules, torneos, retos 1v1, backoffice de administración y apps nativas iOS/Android.

01

Resumen del proyecto

Bule Bule es una webapp multijugador en tiempo real que implementa el juego tradicional de póker de dados (dados AS, K, Q, J, 8, 7). Los jugadores se reúnen en salas con código, turnan para tirar dados, descartar y quedarse con la mejor mano posible. Quien pierde cada ronda rompe un palillo; sin palillos queda en capilla y una derrota más lo elimina. Un Repóker (cinco iguales) libera al jugador de la competición.

Multijugador real

Salas públicas y privadas con código de 4 caracteres. Hasta 10 jugadores. Lobby de espera con vista en tiempo real, invitaciones directas y retos 1v1.

Física 3D

Dados renderizados con Three.js y simulación de física real con Rapier3D. Sombras, rebotes, colisiones deterministas (semilla por tirada) y antialiasing FXAA.

Marketplace y Bules

Moneda virtual del juego (Bules) ganada jugando o comprada (paquete de 1.000 Bules vía Bizum). Se gasta en skins de dados (mármoles, rojo transparente) e items cosméticos de bar (cubata, churros, balón…). Economía cerrada: no canjeable por dinero real.

Torneos con acceso por item

Torneos exclusivos a los que solo se accede poseyendo un item concreto del marketplace (p. ej. el torneo "Bar Doce" requiere el item Churros). Gestionados desde el backoffice, con rango de fechas y niveles de acceso.

Bot IA

Modo 1 vs Bot. La IA evalúa la mano, decide qué dados guardar y cuándo plantarse según probabilidad.

Sistema de vidas

Palillos visuales por jugador. Capilla, liberación por Repóker de X y modo de juego limitado por rondas.

Retos, favoritos e historial

Reto directo 1v1 a otro jugador (online u offline vía push/FCM), favoritos con estrella en el ranking, historial de actividad unificado (partidas y compras) e indicador de estado online.

Notificaciones push nativas

Firebase Cloud Messaging (FCM) para retos e invitaciones aunque la app esté cerrada en Android. Web Push como fallback en navegador.

Mensajería en partida

Reacciones rápidas y burbujas de chat durante la partida (prueba de concepto), visibles para todos los jugadores en la sala, con sonido al pulsar.

Diseño sonoro completo

Cubilete antes de lanzar, rebotes de dados, descarte, palillo roto, música de lobby y de partida. Todo sincronizado con animaciones.

Login y publicidad nativos

Google Sign-In nativo en Android (además de OAuth web) con verificación de token en servidor. AdMob integrado (banners + UMP consent), pendiente de vincular App ID real hasta publicación en producción. Sin login: modo invitado con nombre autogenerado tipo el_pirri_042, persistido en localStorage.

Mobile-first y apps nativas

Agitar el móvil para tirar, gestos táctiles para descartar dados, PWA con service worker. App Android empaquetada con Capacitor (v1.3.37), actualización forzosa por versión mínima gestionada desde el backoffice.

Backoffice de administración

Panel propio (React, servido desde el backend en Railway) para gestionar items del marketplace, torneos, usuarios, feedback, versiones de app publicadas y ajustes globales (límite de jugadores, feature flags).

Reglas de juego implementadas

ManoRangoDescripción
Repóker de X75 iguales → libera al jugador de futuras rondas
Póker64 iguales
Full53 + 2 iguales
Escalera45 valores consecutivos
Trío33 iguales
Dobles parejas22 pares distintos
Pareja12 iguales
Carta alta0Sin combinación

Mecánica del Liberado

Cuando un jugador consigue un Repóker de X (cinco dados iguales), queda liberado:

  • Ya no participa en las tiradas de rondas sucesivas.
  • No puede ser declarado ganador ni perdedor de ninguna ronda posterior.
  • En una partida de 2 jugadores: la partida termina inmediatamente; el rival pierde.
  • En partidas de 3+ jugadores: los demás siguen jugando con normalidad hasta que alguien acumule 3 roturas (capilla).
02

Arquitectura técnica

Cliente

React 18 SPA · Vite

  • Three.js — render 3D
  • Rapier3D — física WASM
  • Socket.io-client
  • @react-oauth/google
  • Web Audio API
  • Service Worker
⟷ WS

Servidor

Node.js · Express · SQLite

  • Socket.io — eventos de juego, marketplace, torneos, retos
  • SQLite persistida en volumen Railway (usuarios, items, torneos, ajustes)
  • web-push + Firebase Admin (FCM) — VAPID y push nativo
  • Rate limiting por socket + limpieza automática de salas
  • Estado de partidas en memoria · lógica de juego pura
  • Backoffice (React) servido como app estática desde el propio backend
→

Infraestructura

Cloud · CI/CD automático

  • Firebase Hosting (frontend) — deploy automático por GitHub Actions
  • Railway Hobby (backend + SQLite en volumen) — deploy automático al hacer push a main
  • GitHub — rama main (producción) + rama dev (trabajo en curso)
  • App Android empaquetada con Capacitor, publicada vía Play Console

Stack completo

CapaTecnologíaVersiónRol
UI frameworkReact18.3Gestión de estado y render
BundlerVite5.4Build, HMR, dev server
3D renderThree.js0.184Escena WebGL, materiales toon, sombras, FXAA post-process
FísicaRapier3D (WASM)0.19Simulación de cuerpos rígidos de dados
Tiempo realSocket.io4.7Comunicación bidireccional cliente-servidor
Auth@react-oauth/google0.13OAuth 2.0 con Google (opcional)
Backend HTTPExpress4.18API REST mínima + VAPID endpoint
Pushweb-push3.6Notificaciones push VAPID/WebPush (fallback navegador)
Push nativoFirebase Admin SDK (FCM)—Notificaciones push nativas en Android para retos e invitaciones
Base de datosSQLite (better-sqlite3)—Usuarios, items, torneos, feedback, ajustes — persistida en volumen Railway
App nativaCapacitor—Empaqueta el frontend web como app Android; Google Sign-In nativo, AdMob, FCM
Publicidad@capacitor-community/admob—Banners + UMP consent; App ID de test hasta publicación en producción
BackofficeReact + Vite (app separada)—Panel de administración servido como estático desde server.js
Hosting frontendFirebase Hosting—CDN global, HTTPS automático, deploy vía GitHub Actions
Hosting backendRailway (Hobby)—Contenedor Node.js + volumen persistente para SQLite, auto-SSL, deploy automático

Estructura de directorios

bule-bule/
├── backend/
│   ├── server.js          # Lógica de servidor (2.241 líneas)
│   ├── gameLogic.js       # Evaluación y comparación de manos (51 líneas)
│   ├── data/               # SQLite (bulebule.db) persistida en volumen Railway
│   ├── backoffice/         # App React separada — panel de administración
│   │   └── src/pages/       # Login, Settings, Items, Tournaments, Users, Feedback
│   ├── Dockerfile
│   └── railway.json
└── frontend/
    ├── android/             # Proyecto Capacitor (build nativo Android)
    ├── public/
    │   ├── assets/          # Imágenes, audios (.mp3), items, dados, sw.js
    │   └── index.html
    └── src/
        ├── App.jsx              # Routing, música, auth, modo invitado
        ├── socket.js            # Singleton Socket.io
        ├── analytics.js
        ├── version.js
        ├── index.css            # Todos los estilos
        ├── hooks/useSheetDrag.js
        ├── utils/                # admob.js, push.js, imgSrc.js
        └── components/
            ├── GameBoard.jsx          # Pantalla de juego principal
            ├── DiceRollerScene.jsx    # Escena 3D Three.js + Rapier
            ├── Marketplace.jsx        # Tienda de Bules e items
            ├── TournamentList.jsx / TournamentLobby.jsx
            ├── ChallengeInvite.jsx    # Retos 1v1
            ├── UserSection.jsx / UserDetailSheet.jsx
            ├── RoomList.jsx / WaitingRoom.jsx / WaitingBar.jsx
            ├── CreateRoom.jsx / CountdownButton.jsx
            ├── AdBanner.jsx           # Banner AdMob
            ├── AnimacionNextPlayer.jsx / AnimacionPalilloRoto.jsx
            ├── Die.jsx
            └── AlaCaidaToast.jsx

Flujo de comunicación

Cliente                            Servidor
  │                                    │
  │─── create_room / join_room ────────▶│  rooms{} en memoria
  │◀── room_state (broadcast) ─────────│
  │                                    │
  │─── roll { keptIndices } ───────────▶│  rollDie() × descartados
  │◀── room_state ──────────────────────│  nueva semilla + rollSeed
  │                                    │
  │─── report_faces { faces } ─────────▶│  sincroniza caras físicas 3D
  │─── stand / continue_turn ──────────▶│  finishTurn / proceedTurn
  │◀── room_state ──────────────────────│
  │                                    │
  │─── bot_ready ──────────────────────▶│  botAct() → siguientes tiradas
  │◀── room_state ──────────────────────│
  │                                    │
  │─── buy_item / buy_bules_pack ──────▶│  descuenta/añade Bules en SQLite
  │─── get_marketplace / get_user_items▶│  catálogo + inventario del usuario
  │◀── ok / error (callback) ──────────│
  │                                    │
  │─── join_tournament ────────────────▶│  valida item requerido, inscribe
  │─── challenge_user ──────────────────▶│  crea reto, envía push/FCM si offline
  │◀── get_settings (público) ─────────│  maxPlayersLimit + featureFlags

Backoffice — panel de administración

App React independiente (backend/backoffice/) compilada a estático y servida desde el propio backend en /backoffice, protegida con token de administrador. Permite gestionar items del marketplace, torneos, versiones de app publicadas, feedback de usuarios, usuarios registrados y, desde julio de 2026, una sección de Ajustes con el máximo de jugadores por sala y una lista de feature flags on/off — pensada para poder aplicar reglas por país o segmento en el futuro sin rehacer el modelo de datos. Los flags se guardan en la tabla config pero ningún flag real se consume todavía en el juego.

03

Histórico de commits — línea de vida

5 junio 2026 — Día 1: Fundamentos y primer deploy
ecf1070featInitial commit — estructura base, lógica de juego (manos, comparación), servidor Socket.io, cliente React con dados 2D.
6e95c0f–1145085infraDeploy Railway — PORT env var, CORS para producción, health check endpoint, URL frontend apuntando al backend.
d30910afeatNavbar persistente, scoreboard con 5 dados, preservación de posiciones al re-tirar.
8e46001–3c8b832featSonido sintético en tirada + shake-to-roll en móvil. Primer prototipo jugable end-to-end.
8 junio 2026 — Día 2: Multiplayer completo + 3D branch merge
046d7d8featGoogle OAuth — login con Google, perfil con avatar.
d4cf675featSistema de salas — lobby, listado de partidas públicas, creación con nombre y código.
2c53366featAjustes de usuario — pantalla de perfil, edición de nombre, gestión de notificaciones.
a08e34bfeatBot IA — modo 1 vs Bot con lógica de decisión serverside (keeps, stand-off).
086052f–ea601d7featGestos táctiles — swipe y tap para descartar dados. Mínimo 1 descarte para re-tirar.
5f4d086–46bd548featWeb Push + invitaciones — VAPID auto-generado, búsqueda de amigos, invitación en tiempo real y por push offline.
60fba58featMerge rama 3D — primera versión con Three.js + Rapier física en el dice-box.
9 junio 2026 — Día 3: 3D physics completo + visual polish
f196beb–440cb77featDados 3D con Rapier — física real, gravedad, rebotes, detección de asentamiento. Caras generadas por canvas procedural. Layout 2+3.
143ecbbfeatOrientación física — los dados se alinean al slot con la cara correcta arriba (cuaternión).
5ee7db7featCaras físicas — report_faces sincroniza la cara real visible con el servidor.
92660eefeatImagen de fondo A Coruña, fade-in inicial, corrección caras K/Q.
e44a65b–912a111featMúsica de lobby en bucle, con pausa al entrar en partida y fade controlado.
e7f193bfeatZona de descarte 3D — dados descartados se mueven al fondo con borde rojo y opacidad 50%.
f71a87cfixDouble-fire touchend+click — preventDefault en touchend para móvil.
10 junio 2026 — Día 4: Sistema de vidas + sonido completo + shadows
1a9c09efeatSistema de palillos — 3 vidas por jugador, capilla, liberación por Repóker. Lógica backend + UI visual.
8712917featPausa entre turnos — overlay "jugada a superar", awaitContinue serverside, contador de 30s.
1ae8507featAnimación palillo roto — overlay al final de cada ronda con efecto visual.
9a687cc–c61273cfeatAnimación cambio de jugador — dos imágenes ("ÉS TU TURNO" / "ÉS EL TURNO DE"), nombre + palillos del jugador.
c589639featSonido cubilete — la física se lanza solo al terminar el mp3.
de29e9cfeatSincronización eliminar_dados — fade α→0 durante exactamente la duración del mp3.
21832b2featSombras 3D — PCFSoftShadowMap, directional light con frustum ajustado, ShadowMaterial en suelo.
740eaffperfFísica +15% — world.timestep × 1.15. Ghost colliders fijos para dados quietos.
10 junio 2026 — Día 5: Visual 3D avanzado + mecánica Liberado + salas privadas
99203b4featRepóker de X — la quintilla pasa a llamarse "Repóker de K", "Repóker de AS", etc., usando el valor del dado.
8dd37aefeatSnap cuaternión al asentar — los dados rotan a la cara correcta arriba mediante slerp durante el tween de agrupación.
61711dffeatCell-shading — dados color crema #E4D9C3, borde negro outline. Caras con colores diferenciados (rojo/negro).
c0dd8fdfixDados dentro del dice-box — techo físico + startZ seguro para que los dados no salgan por arriba.
851ce30featSolo Play + multi-bot — modo contra bots, sin solapamiento al asentar, shadow fix PCF.
8e8273afeatZoom de cámara — zoom-in al asentar, zoom-out en nueva tirada, sin cambio al descartar.
b8ecb16fixFix Liberado — lógica correcta de exención de rondas; applyRoundLoss extraído como helper.
d9b8671–f175f5cfeatSalas privadas — backend — flag isPrivate, aparecen en el listado; sanitizeForList incluye el estado de privacidad.
6dc5823featSalas privadas — frontend — icono de candado en la lista, modal de código al intentar unirse, toggle switch en CreateRoom. Borde 2px en dados 2D. Dados ordenados por valor.
11 junio 2026 — Día 6: UX invitado + correcciones de juego
d47539afeatModo invitado — nombre autogenerado (el_pirri_042, moreno_das_amorosas_317…) persistido en localStorage. Lista de partidas y botón "Nueva partida" visibles sin login.
210ed30fixTarjeta invitado — fondo blanco sólido idéntico a la tarjeta de usuario. Login de Google como botón independiente encima.
bef4f16fixAnti-doble click "Tirar dados" — flag rolling deshabilita el botón desde el primer click hasta que el servidor confirma la tirada.
3447228featZoom adaptativo al descartar — 4 dados descartados → (0, 7.25, 5.65); 5 dados → (0, 9.0, 7.0). Vuelve al zoom cerrado al quitar descartes.
a4169bdfeatFin inmediato por Liberado (2 jugadores) — cuando quedan ≤1 jugadores no-liberados, endRound termina la partida con endReason: 'liberado'.
3f0cb8dfixFix Liberado en 3+ jugadores — finishTurn comprueba nonLiberado.length (total) en lugar de pending.length (en-ronda), evitando que se corte el turno de jugadores pendientes.
12–22 junio 2026 — Estabilización y persistencia
b37c9ee–8c10382fixReconexión móvil — reingreso al lobby con el mismo nombre expulsando el socket antiguo; se restaura el estado de host tras una reconexión.
e27af81featPersistencia en SQLite — usuarios, email y suscripciones push sobreviven a un reinicio de Railway (hasta entonces, todo se perdía).
c463316featScoring y pulido de UI — nombres de invitado mejorados, ads.txt, ajustes de layout.
26 junio 2026 — Release v0.3.0: retos, torneos y favoritos
e0be156featRelease v0.3.0 — sistema de retos 1v1, perfiles de usuario, banner de invitación.
88367d5featBanner de reto con opción de compartir por WhatsApp.
9dce6b6featFicha de usuario — estadísticas, items propios y botón de reto directo.
b164f18featTournamentList / TournamentLobby — primeros componentes de torneos.
86c8bd7featTorneos por niveles — jugadores de tier superior pueden acceder a torneos de tier inferior.
4785c2c–94787e9featFavoritos + AdSense — filtros de ranking/salas, mejoras de UI, primera integración de publicidad web.
40ecdf6featRediseño de tarjetas de reto y fix del control segmentado.
29 junio 2026 — Rename a Bules, skins de dados y hardening de seguridad
8044cd6refactorRename puntos → Bules en toda la UI. Nace el nombre definitivo de la moneda del juego.
1dbfd8efeatPaquete de 1.000 Bules — primera vía de compra, pago único por Bizum.
c72e112–6370a7efeatSistema de skins de dados — texturas de mármol (azul, negro, rojo, verde) seleccionables desde el marketplace.
87523f2–43e8a0dfeatDados rojos transparentes — skin plano por jugador, mayor transparencia, nuevos items de marketplace.
22f5c52featAction sheet de items — items clicables en el perfil; renombrado a "Mármol Azul".
8b72f8dfeatItems de bar — cubata, churros y balón añadidos al marketplace.
c77227d–fb63ed1–c31cbe4featTorneo con acceso por item — el torneo "Bar Doce" solo es accesible poseyendo el item Churros; se muestra el item requerido en la tarjeta del torneo.
38fb594featHistorial de actividad unificado — timeline con partidas y compras de items en un único feed.
074110ffeatRate limiting por socket — límites diferenciados por tipo de acción (juego, salas, social, compras, lecturas).
fae8ae9featCORS restringido vía variable de entorno ALLOWED_ORIGIN, sustituyendo el origin: '*' original.
b6109a0featLimpieza automática de salas — barrido cada 5 minutos de salas finished/inactivas.
30 junio 2026 — Backoffice, AdMob y Google Sign-In nativo
611b6fffeatPanel de backoffice — primera versión, servida desde Railway junto al backend.
933c240–1eb60cf–c034f72fixEndurecimiento del backoffice — token de admin persistido en SQLite, subida de imágenes en el panel de items, build pre-compilado del backoffice para simplificar el Dockerfile.
9367c09featIntegración AdMob para Android + borrado por lotes en el backoffice.
01269f0featGoogle Sign-In nativo en Android — login nativo con verificación de token en servidor, swipe-to-dismiss en sheets.
ab0cc1bperfReutilización de objetos Audio, constante IS_MOBILE extraída del render, limpieza de usuarios invitados al desconectar.
abc25e1featEstrella de favoritos en el ranking + invitar favoritos desde el hall.
1–2 julio 2026 — AdMob UMP consent, FCM y POC de mensajería
716f347–f6f9572fixFixes de banner AdMob — deja de recrearse cada turno, corrige condición de carrera.
63c2902fixConsentimiento UMP de AdMob integrado; fix de bloqueo con jugador liberado; puntos de ronda por jugador.
78a4e4ffixFix bloqueo del formulario de consentimiento — impedía mostrar el banner indefinidamente.
fd6c25e–32b6cebfixFCM — timing de registro de token corregido; retos a usuarios offline resueltos por fallback a base de datos.
84f7ab3–9688611–f819132–7751d0a–436f8dcfeatPOC de mensajería en partida — reacciones rápidas y burbujas de chat visibles para todos los jugadores; se revierte temporalmente por un bug y se reintroduce corregido; sonido al pulsar emoji y barra visible también antes del propio turno.
20–30 julio 2026 — Ajustes del backoffice, actualización forzosa y blindaje de conexión
c27d28ffeatFiltro de estado online, fixes de sincronización de dados y sección de Ajustes en el backoffice (límite de jugadores, feature flags).
2582fcffeatVersiones de app publicadas gestionadas desde el backoffice.
bc4c175featActualización forzosa por versión mínima — la app bloquea el acceso si la versión instalada es inferior a la mínima publicada; fix de guardado de ajustes.
f5eba29featBotón de quejas/sugerencias + fix de evaluación de repóker + ajustes de UI.
6d9b1acfixEtiquetas y valores corregidos en la ficha de crear partida.
03b3631fixFeedback de conexión en partida y blindaje del backend — corrige el bug de app minimizada durante una partida (bots colgados / desconexiones fantasma) en server.js, App.jsx y GameBoard.jsx.
73418cfchorev1.3.37 (versionCode 62) — versión Android actual a fecha de este documento.
04

Backend — server.js + gameLogic.js

Estado global

rooms{} — diccionario en memoria indexado por código de sala. Cada sala contiene la lista de jugadores, fase de juego, índice del jugador activo, timers y metadatos de ronda.

registeredUsers{} — usuarios registrados en la sesión (Google u otros). Mapea userId → { name, email, picture, socketId, pushSubscription, fcmToken }, cargado en memoria al arrancar desde SQLite.

socketToUser{} — índice invertido socketId → userId para lookup O(1) en desconexiones y broadcasts dirigidos.

Desde junio de 2026, usuarios, items del marketplace, torneos, feedback y ajustes globales se persisten en SQLite (volumen de Railway), sobreviviendo a reinicios del proceso.

⚠ Atención: Las partidas en curso (rooms{}) siguen viviendo solo en memoria del proceso Node. Un reinicio de Railway durante una partida activa la destruye — la persistencia cubre usuarios/economía/configuración, no el estado de juego en vivo.
⚠ Riesgo real y pendiente: el fichero SQLite no tiene backup automático. Es la prioridad técnica número uno antes de crecer en usuarios (ver Roadmap, sección 5).

gameLogic.js — Evaluación de manos

Módulo puro sin efectos secundarios. Exporta rollDie(), evaluateHand(dice[]) y compareHands(h1, h2). El rango 7 (Repóker de X) devuelve { rank: 7, name: 'Repóker de K', topKey: 'K', … }.

⚠ Atención: rollDie() usa Math.random() en servidor. El cliente usa rollSeed solo para la animación visual. Si report_faces diverge del resultado servidor, la mano mostrada puede no coincidir con la evaluada.

Marketplace y economía de Bules

Eventos get_marketplace, buy_item, buy_bules_pack, get_user_items y get_user_history. Los items tienen categoría (skin, bar, pack) e imagen gestionadas desde el backoffice. El paquete pack-1000-bules se cobra por Bizum fuera de la app; el servidor solo acredita el saldo tras confirmación manual del admin.

✓ Economía cerrada: los Bules se ganan jugando o se compran con dinero real, pero nunca son canjeables de vuelta a dinero. Esto mantiene la actividad fuera del ámbito de la Ley 13/2011 (ver sección 11).

Torneos con acceso por item

Eventos get_tournaments, join_tournament, leave_tournament. Un torneo puede requerir la posesión de un item concreto (requiredItemId) para poder inscribirse — validado server-side contra el inventario del usuario en SQLite antes de aceptar el join_tournament. Gestión completa (crear, editar, fechas, item requerido) desde el backoffice.

Ciclo de vida de una sala

lobby → playing → results → playing → ... → finished
  • lobby: jugadores se unen. El host arranca con start_game.
  • playing: ronda activa. Ciclo de turnos con timers.
  • results: entre rondas. El host avanza con next_round.
  • finished: partida terminada (endReason: capilla | rounds | liberado). El host puede hacer revancha.

Mecánica Liberado — lógica serverside

En finishTurn: si el jugador acaba de conseguir Repóker, se fija player.liberado = true y player.hand = null (excluido de la comparación de rondas). Se comprueba nonLiberado.length — si ≤1, se llama a endRound.

En endRound: si hay un liberado y nonLiberado.length ≤ 1, la partida termina inmediatamente con endReason: 'liberado'. En rondas sucesivas, los liberados tienen done = true desde el inicio (startRound).

Salas privadas

Al crear una sala con isPrivate: true, el código de 4 caracteres actúa como contraseña. Las salas privadas aparecen en el listado público (con indicador visual), pero el cliente valida el código antes de emitir join_room.

⚠ Error potencial: La validación del código es solo clientside. Un cliente modificado puede llamar directamente a join_room sin pasar por la modal, saltándose la protección. Para seguridad real, el servidor debería rechazar join_room si el código no coincide.

Gestión de turnos — timers

TimerDuraciónAcción al expirar
turnTimerId30sSi no ha tirado: tira automático. Si ya tiró: planta.
continueTimerId30s (human) / 3s (bot)Llama a proceedTurn, arrancando el turno.

Desconexión de jugadores

Al desconectarse, el jugador se elimina de la sala con un retraso de 20 segundos para permitir reconexiones. Desde el fix del 30 de julio (03b3631), la app minimizada en Android ya no deja al jugador colgado ni provoca comportamiento errático del bot: el frontend muestra feedback de conexión explícito y el backend está blindado contra las caídas de socket que este escenario provocaba.

⚠ Atención: Durante esos 20s el jugador desconectado puede seguir siendo el currentPlayer; el turno queda bloqueado hasta que expire el turnTimer (hasta 30s adicionales). El fix de julio mejora el feedback visual del resto de jugadores durante esa ventana, pero el mecanismo de espera en sí no ha cambiado.

report_faces — Superficie de ataque

⚠ Error potencial: El servidor acepta cualquier combinación de 5 valores enviados por el cliente. Un cliente modificado podría enviar siempre "Repóker de AS". No existe verificación de coherencia con la semilla ni con los dados generados serverside.

Notificaciones push — Web Push (VAPID) y FCM nativo

Web Push (VAPID) para navegador y Firebase Cloud Messaging para la app Android nativa. Los retos a usuarios offline consultan primero el token FCM y, si no está disponible, hacen fallback a la suscripción Web Push guardada en SQLite.

⚠ Atención: Sin las env vars VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY fijadas en Railway, cada reinicio generaría claves nuevas e invalidaría las suscripciones Web Push existentes. En producción están fijadas como variables de entorno.

Recursos acotados — hardening de julio 2026

A diferencia de las primeras versiones, el servidor ahora limita explícitamente el uso de recursos:

  • Rate limiting por socket — límites diferenciados por tipo de acción: action (roll/stand/discard) 15/5s, room (crear/unir/salir) 5/min, social (retos/búsqueda) 10/min, buy (compras) 5/min, read (consultas) 30/10s.
  • Límite de salas por usuario — máximo MAX_ROOMS_PER_USER = 2 salas activas como host simultáneas.
  • Limpieza automática de salas — barrido cada 5 minutos que elimina salas finished o inactivas; además, cada fase tiene un timeout de seguridad de 2h como red de protección ante partidas atascadas.
  • CORS restringido — ALLOWED_ORIGIN reemplaza el origin: '*' original tanto en Express como en Socket.io.

API REST de administración — /api/admin/*

Endpoints protegidos con middleware requireAdmin (token de admin persistido en SQLite), usados exclusivamente por el backoffice: items, tournaments, settings, app-versions, feedback, users y upload (subida de imágenes). El evento de socket público get_settings expone maxPlayersLimit y featureFlags sin autenticación, para que el cliente del juego los consuma en tiempo real.

Actualización forzosa por versión mínima

El backoffice publica versiones de la app Android (app-versions) marcando cuál es la versión mínima soportada. El cliente compara su versionCode local contra ese mínimo al arrancar y bloquea el acceso si está desactualizado, mostrando un aviso de actualización obligatoria.

05

Frontend — Componentes y casos de uso

App.jsx — Controlador raíz

Gestiona la pantalla activa, el estado de usuario, la música (lobby + partida), el service worker, el modo invitado y la comprobación de versión mínima al arrancar.

  • Modo invitado: loadGuestName() genera un nombre tipo el_pirri_042 la primera vez (pool de nombres galegos/españoles) y lo persiste en localStorage.
  • Login Google: handleLogin reemplaza el nombre invitado por el nombre real y registra al usuario en el backend. En Android usa Google Sign-In nativo con verificación de token en servidor; en web, @react-oauth/google.
  • Singleton de socket importado de socket.js — una sola conexión para toda la sesión.
  • utils/admob.js y utils/push.js encapsulan la inicialización de AdMob (banners + UMP consent) y el registro de token FCM/Web Push respectivamente.

RoomList.jsx — Pantalla principal

Visible sin login. Muestra:

  • Sin login: botón "Iniciar sesión con Google" (encima) + tarjeta blanca de invitado con nombre autogenerado.
  • Con login: tarjeta de usuario (foto, nombre, email, saldo de Bules, ajustes).
  • Salas privadas: icono de candado junto al nombre. Al hacer click en "Unirse", aparece una modal para introducir el código de 4 caracteres.
  • Filtro de estado online y estrella de favoritos, con invitación directa a favoritos desde el listado.

GameBoard.jsx — Pantalla de juego

Componente principal durante la partida (~1.050 líneas). Incluye:

  • Anti-doble click: flag rolling deshabilita el botón "Tirar dados" desde el click hasta que el servidor confirma (socket.emit('roll', …, cb)). También bloquea shake-to-roll.
  • pendingDiscards[], sceneValues, rollingIndices, rollSeed — datos para la escena 3D.
  • Animación cambio de jugador, palillo roto, scoreboard con dados ordenados por valor, feedback visual de estado de conexión (tras el fix del 30 de julio).
  • Mensajería POC: reacciones rápidas y burbujas de chat, visibles para todos los jugadores de la sala.
  • Constante IS_MOBILE calculada una sola vez a nivel de módulo (no en cada render).
⚠ Atención: El timer de turno (turnDeadline) usa Date.now() cliente vs timestamp servidor. Desincronización de reloj puede mostrar contador inexacto.

Marketplace.jsx — Tienda de Bules e items

Catálogo de items (skins de dados, items de bar, paquete de Bules), inventario del usuario, historial de compras unificado con el historial de partidas. Al comprar un skin de dados, se aplica de inmediato en DiceRollerScene.jsx para ese jugador.

TournamentList.jsx / TournamentLobby.jsx — Torneos

Listado de torneos activos con rango de fechas; si un torneo requiere un item concreto, se muestra su nombre e imagen y el botón de inscripción queda deshabilitado hasta que el usuario lo posea.

ChallengeInvite.jsx / UserSection.jsx / UserDetailSheet.jsx — Social

Reto directo 1v1 a otro jugador (con notificación push si está offline), ficha de perfil con estadísticas e items, sección de usuario con historial de actividad unificado (partidas + compras) e indicador de estado online.

DiceRollerScene.jsx — Escena 3D

El componente más complejo. Gestiona el ciclo completo: sonidos → física → animación → callback.

  • Cell-shading: MeshToonMaterial + outline pass con geometría escalada al 108%.
  • FXAA: EffectComposer + ShaderPass(FXAAShader) en lugar de antialias nativo. Resuelve el efecto pixelado del borde negro del outline.
  • Snap cuaternión: al agruparse, los dados rotan a la cara correcta arriba vía slerpQuaternions(fq, tq, t).
  • Zoom adaptativo al descartar: con 4 dados en zona de descarte (x ±2.67) la cámara se mueve a (0, 7.25, 5.65); con 5 (x ±3.56) a (0, 9.0, 7.0). Vuelve al zoom cerrado si los descartes bajan de 4.
⚠ Error potencial: Rapier se carga de forma asíncrona (WASM). Si la primera tirada llega antes de que Rapier inicialice, se guarda en ctx.pendingRoll. Si el componente se desmontó mientras cargaba, la tirada se pierde silenciosamente.

Sistema de audio

ArchivoTriggerImplementación
dado1/2/3.mp3Rebote físico dadoRotación cíclica, volumen proporcional al impacto
cubilete.mp3Antes de lanzar dadosLa física espera al evento ended
eliminar_dados.mp3Fade-out de dadosDuración del mp3 = duración del tween α→0
cogerdado.mp3Marcar dado para descartarClick táctil/ratón + bot picking
romper_palillo.mp3Fin de ronda con perdedorSimultáneo con AnimacionPalilloRoto
button_press.mp3Cualquier botónListener global en document
bule-escaleira.mp3Pantalla de inicioLoop, pausa al entrar en partida
dice-lemonlight.mp3Durante la partidaLoop vol 0.2, para al volver al lobby

La mayoría de objetos Audio se instancian una sola vez a nivel de módulo y se reutilizan entre reproducciones (perf, junio 2026), en lugar de crear un new Audio() en cada evento.

AdBanner.jsx — Publicidad AdMob

Banner de @capacitor-community/admob con formulario de consentimiento UMP integrado (obligatorio en la UE). Usa IDs de test de Google mientras la app no esté publicada en producción en Play Store; el App ID real está pendiente de vincular hasta ese momento.

06

Roadmap y mejoras futuras

Estado actual: producto mucho más completo que el MVP original — marketplace, torneos, retos, backoffice y apps nativas ya en producción de desarrollo. El riesgo principal ya no es de funcionalidad sino de datos: no hay backup automático de SQLite. Esa es la prioridad número uno antes de cualquier crecimiento de usuarios.

Ya completado desde la primera versión del roadmap

Estas eran "deuda técnica prioritaria" o "features pendientes" en la versión anterior de este documento y ya están implementadas — verificado directamente en el código:

  • ✓ hecho Rate limiting por socket, con límites diferenciados por tipo de evento.
  • ✓ hecho CORS restringido vía ALLOWED_ORIGIN en Express y Socket.io.
  • ✓ hecho Limpieza automática de salas inactivas/finalizadas cada 5 minutos.
  • ✓ hecho Límite de salas activas por usuario (MAX_ROOMS_PER_USER).
  • ✓ hecho Índice invertido socketId → userId para lookups O(1).
  • ✓ hecho Persistencia de usuarios/economía en SQLite — sobrevive a reinicios de Railway.
  • ✓ hecho Reutilización de objetos Audio y IS_MOBILE extraído del render.
  • ✓ hecho CI/CD automático — GitHub Actions (frontend) + integración Railway (backend), deploy al hacer push a main.
  • ✓ hecho App nativa Android (Capacitor), con Google Sign-In y push nativos.
  • ✓ hecho Chat en sala — POC de mensajería con reacciones y burbujas.
  • ✓ hecho Ranking global / favoritos y sistema de torneos (con acceso condicionado por item).

Deuda técnica prioritaria — pendiente hoy

  1. Backups automáticos de SQLite — riesgo real y activo: el fichero único en el volumen de Railway no tiene copia de seguridad. Máxima prioridad antes de cualquier otra cosa.
  2. Lanzamiento a producción en Play Store — prerrequisito para vincular el App ID real de AdMob y empezar a monetizar con publicidad. Vídeo, capturas, mockups y feature graphic ya listos; falta subir la ficha/build.
  3. Validación serverside del código de sala privada — el código sigue viajando en el listado público (sanitizeForList incluye code); la "privacidad" es solo visual (candado + modal), no una protección real.
  4. Validación serverside de caras — report_faces sigue sin verificar coherencia con la semilla generada en servidor.
  5. Modularizar server.js (2.241 líneas) en módulos por dominio (juego, marketplace, torneos, admin).
  6. Dividir GameBoard.jsx y RoomList.jsx (~1.050–1.060 líneas cada uno) en subcomponentes.
  7. Limpieza de registeredUsers{} inactivos en memoria — hoy crece sin cota con el histórico de usuarios.
  8. Notificación de desconexión — informar a la sala cuando un jugador se desconecta, más allá del feedback visual ya añadido en julio.

Features pendientes

🎮 Juego

  • Espectadores (modo solo lectura)
  • Revancha abierta a todos (no solo host)
  • Variantes de reglas configurables
  • Historial de manos de la partida
  • Estadísticas de jugador ampliadas (W/L, manos)
  • Consumir el primer feature flag real desde el backoffice

👤 Social

  • Torneos en formato bracket (eliminación directa)
  • Compartir resultado de partida
  • Avatares personalizados
  • Más paquetes de Bules vía Stripe (además del actual por Bizum)

🏗 Infraestructura

  • Backups automáticos de SQLite (urgente)
  • Monitoring y alertas (Sentry)
  • Tests unitarios e integración
  • Logs estructurados
  • Reglas de negocio por país/segmento sobre los feature flags ya existentes

📱 Cliente

  • Publicación en producción en Play Store
  • App iOS (actualmente solo Android)
  • App ID real de AdMob (pendiente de publicación)
  • Haptic feedback en móvil
  • Accesibilidad (ARIA, alto contraste)
  • i18n (castellano / galego / inglés)

Escalabilidad — plan por tramos de usuarios

Análisis vigente a fecha de este documento. Arquitectura actual: SQLite de fichero único sin réplica, estado de partidas en memoria (no distribuible entre instancias), Socket.io sin adapter de Redis (un solo proceso Node), sin caché de rankings, servidor monolítico. Capacidad estimada sin cambios: ~500–2.000 usuarios concurrentes cómodamente.

UmbralQué falla primeroCambio necesario
~1.000 usuariosRankings recalculados en cada consulta; riesgo de pérdida de datos sin backupCaché de rankings + backups automáticos del volumen SQLite (urgente, no depende del nº de usuarios)
~5.000 usuariosSQLite de fichero único no soporta la concurrencia de escrituraMigrar a PostgreSQL
~20.000 usuariosUn solo proceso Node no reparte la carga de Socket.ioRedis adapter para Socket.io + múltiples instancias
~100.000 usuariosServidor monolítico, sin CDN para assets 3DMicroservicios + CDN dedicado

Propuesta de arquitectura escalable

                    ┌─────────────────────┐
                    │   Firebase Hosting   │  (CDN estática, igual)
                    └──────────┬──────────┘
                               │ HTTPS / WSS
                    ┌──────────▼──────────┐
                    │   Load Balancer     │  (Railway / Fly.io)
                    └──┬──────────────┬──┘
              ┌────────▼───┐    ┌─────▼──────┐
              │  Node.js 1 │    │  Node.js 2 │
              └────────┬───┘    └─────┬──────┘
                       └──────┬───────┘
                    ┌─────────▼──────────┐
                    │       Redis        │  (estado rooms + Socket.io adapter)
                    └─────────┬──────────┘
                    ┌─────────▼──────────┐
                    │    PostgreSQL      │  (users, stats, historial, reemplaza SQLite)
                    └────────────────────┘
07

Monetización — opciones y viabilidad

Actualización: a diferencia de versiones anteriores de este documento, el modelo de moneda virtual ya no es una propuesta — está implementado y en producción de desarrollo desde finales de junio de 2026. Los jugadores ganan y compran Bules (paquete de 1.000 vía Bizum), los gastan en un marketplace de items cosméticos y en el acceso a torneos exclusivos, y la economía es cerrada (los Bules nunca se canjean de vuelta a dinero real). El análisis legal que sigue explica por qué se descartó la apuesta de dinero real entre jugadores y por qué el modelo de moneda virtual es la opción que finalmente se construyó.

Inicialmente se planteó que los jugadores apostaran entre sí un importe real por partida. A continuación se analizan todas las opciones técnicas y legales evaluadas en su momento, ordenadas de menos a más viable para un MVP sin burocracia.

Opciones no viables ●

No viable

Bizum como pasarela de cobro (API)

Bizum no dispone de API pública para terceros. Funciona exclusivamente dentro de las apps bancarias españolas. No existe integración técnica posible desde una web o app propia.

No viable

Stripe / PayPal para apuestas de dinero real entre jugadores

En España, cualquier plataforma que intermedie en apuestas de dinero real está sujeta a la Ley 13/2011 de Regulación del Juego y requiere licencia de la DGOJ (Dirección General de Ordenación del Juego). Stripe y PayPal prohíben explícitamente el juego de azar no licenciado en sus Terms of Service y cierran la cuenta al detectarlo.

  • Coste de una licencia DGOJ: proceso largo, depósito de garantía de decenas de miles de euros, auditorías técnicas.
  • Sanción por operar sin licencia: hasta 50 millones de euros (Ley 13/2011, art. 41).
No viable

Cobrar un porcentaje de dinero real (rake) sin licencia PSP

Actuar como intermediario de pagos (recibir dinero de jugadores y redistribuirlo menos una comisión) requiere una licencia de Entidad de Pago o trabajar con un PSP licenciado. Sin ella, la actividad es ilegal independientemente del método de pago.

Opciones dudosas ●

Descartado en favor del modelo final

Stripe con moneda virtual no canjeable

Los jugadores compran "fichas" con Stripe (venta normal de producto digital). Las fichas se usan como apuesta dentro del juego. El ganador acumula fichas. Si las fichas no son canjeables por dinero real (ni directa ni indirectamente), la actividad queda fuera del ámbito de la DGOJ según la interpretación mayoritaria.

Por qué se descartó (de momento): requiere abrirse cuenta en Stripe e implementar webhooks. Se optó primero por un canal de pago más simple (Bizum, sin integración técnica ni comisión de pasarela) para validar la demanda de compra de Bules antes de invertir en la integración con Stripe. Es el paso siguiente natural una vez validado el modelo.

Pendiente de producción

Publicidad — AdMob

El SDK @capacitor-community/admob ya está integrado en la app Android con banners y formulario de consentimiento UMP (obligatorio en la UE). Actualmente funciona con IDs de test de Google.

Por qué está pendiente: vincular el App ID real de producción en AdMob requiere que la app esté publicada en producción en Play Console — no es suficiente con una pista de prueba cerrada o interna. Es decir, AdMob real depende del lanzamiento a producción en Play Store (ver sección 9).

Modelo implementado ●

En producción desde junio 2026

Bules — moneda virtual + marketplace + torneos con acceso por item

Los jugadores ganan Bules jugando partidas, o compran un paquete de 1.000 Bules por 1 € vía Bizum (pago manual, sin pasarela integrada — el saldo se acredita tras confirmación del admin desde el backoffice). Los Bules se gastan en el Marketplace: skins de dados (mármol azul/negro/rojo/verde, dados rojos transparentes) e items cosméticos de bar (cubata, churros, balón…). Algunos items funcionan además como llave de entrada a torneos exclusivos — por ejemplo, el torneo "Bar Doce" solo es accesible poseyendo el item Churros.

  • ✓ Economía cerrada: los Bules no se canjean de vuelta a dinero real → no requiere licencia DGOJ, no requiere PSP licenciado.
  • ✓ Ya implementado y en uso: rename puntos→Bules, marketplace, skins, items de bar, torneos con acceso condicionado, todo gestionable desde el backoffice.
  • ✓ El paquete de 1.000 Bules por Bizum ya genera el primer ingreso real, aunque sea manual y de bajo volumen.
  • ✗ El cobro por Bizum es manual (no escalable) — el siguiente paso es integrar Stripe para pagos automáticos y más paquetes.
  • ✗ Todavía no hay AdMob en producción (pendiente de publicación en Play Store) ni suscripción premium.

Siguientes pasos de monetización, en orden:

  1. Lanzamiento a producción en Play Store → habilita AdMob real (banners con ingresos reales por impresión/click).
  2. Más paquetes de Bules vía Stripe (pagos automáticos, sin intervención manual del admin).
  3. Explorar suscripción premium o cuota B2B a bares como se planteó originalmente (ver secciones 8–9), ahora como complemento a la economía de Bules ya validada.

Resumen comparativo

Opción Registro necesario Licencia DGOJ Implementación Viabilidad
Bizum API — — Imposible No viable
Stripe / apuestas reales Sí (Stripe + empresa) Sí (DGOJ) Compleja No viable
Rake sobre dinero real Sí (PSP o licencia) Sí Muy compleja No viable
Moneda virtual vía Stripe (paquetes adicionales) Sí (Stripe) Probablemente no Media Pendiente — siguiente paso
AdMob en producción Sí (Play Console) No Baja (ya integrado) Pendiente publicación
Bules + Marketplace + torneos por item No (Bizum manual) No Ya implementado ✓ En producción
08

Costes de desarrollo — Claude vs. equipo humano

Todo el proyecto Bule Bule se ha construido usando Claude Code como herramienta principal de desarrollo. A continuación se analiza el coste real en tokens, el coste equivalente con un equipo humano, y la estimación de escalar el proyecto en ambos escenarios.

Coste real con Claude — uso de tokens

Estimación basada en el análisis de los ficheros de sesión (~40 MB de historial JSONL). Los costes varían según la tasa de cache hit; se asume un 65 % de tokens en caché (Anthropic prompt caching, TTL 5 min). Modelo: Claude Sonnet 4.6 · Tarifa: $3/MTok input · $0.30/MTok cached · $15/MTok output.

~20 M
Tokens de entrada
~7M no cacheados · ~13M cacheados
~2.7 M
Tokens de salida
Código generado, análisis, respuestas
~386
Commits
18 días activos entre el 5 jun y el 30 jul 2026
≈ $65
Coste total en API
≈ €60 · rango real: $45–$90

Estimación proporcional al crecimiento del proyecto (×3,6 commits) desde la cifra de referencia calculada el 26 de junio de 2026 (~5,5M tokens de entrada, ~750k de salida, ≈$23). No se ha vuelto a analizar el historial completo de sesiones para este documento.

Coste equivalente sin Claude — equipo de desarrollo humano

Estimación para un desarrollador senior full-stack en España (€60–70/h) construyendo el mismo producto desde cero.

Módulo Horas estimadas Coste (€65/h) Notas
Arquitectura + setup inicial 16 h €1,040 Socket.io, Firebase, estructura de proyecto
Backend — lógica de juego 90 h €5,850 6 fases, liberado, capilla, privadas, bots
Sistema 3D — Three.js + Rapier3D 120 h €7,800 Física, texturas, toon shader, cámara adaptativa, 10+ animaciones
Frontend React + UI/CSS 70 h €4,550 Modo invitado, OAuth, salas privadas, scoreboard
Auth, deployment, CI 20 h €1,300 Google OAuth, Firebase Hosting, pipeline
Testing + debugging 60 h €3,900 Multijugador cross-device, edge cases del juego
Documentación técnica 24 h €1,560 HTML + PDF con histórico, arquitectura, roadmap
Subtotal MVP (26 jun 2026) 400 h €26,000 Estado del documento anterior
Marketplace + economía de Bules 60 h €3,900 Rename, catálogo, compras, paquete Bizum, inventario
Skins de dados + items de bar 30 h €1,950 Texturas de mármol, dados transparentes, action sheet
Sistema de torneos + acceso por item 40 h €2,600 Listado, lobby, inscripción, validación server-side
Backoffice de administración 100 h €6,500 App React separada, CRUD items/torneos/usuarios/versiones/ajustes, auth de admin
App nativa Android + AdMob + push nativo 90 h €5,850 Capacitor, Google Sign-In nativo, UMP consent, FCM
Retos, favoritos, historial, estado online 50 h €3,250 1v1, push offline, timeline unificado
Mensajería en partida (POC) 20 h €1,300 Reacciones y burbujas de chat en tiempo real
Hardening de seguridad del backend 25 h €1,625 Rate limiting, limpieza de salas, CORS, índice invertido
Migración a persistencia SQLite 30 h €1,950 Usuarios, items, torneos, feedback, ajustes
Testing + debugging adicional 45 h €2,925 Multiplataforma (web + Android), edge cases de economía
Actualización de documentación técnica 8 h €520 Esta regeneración (v0.5)
TOTAL a fecha de este documento ~898 h ≈€58,370 Sin overhead ni herramientas
× 900
Factor de eficiencia económica.
≈€60 en tokens de Claude producen el equivalente a ≈€58.400 en tiempo de desarrollo senior.
El mismo proyecto habría requerido 5–7 meses de trabajo de un desarrollador senior (o 3–4 meses con un equipo de 2). Con Claude Code se completó en 18 días naturales de desarrollo activo, repartidos en ~8 semanas de calendario.

Escenarios de escalado

Actualización: las Fases 1 y 2 de este plan (planteadas en la versión anterior del documento) están, en la práctica, ya completadas: base de datos persistente (SQLite), rate limiting, hardening de seguridad, marketplace, torneos y backoffice. Lo que queda pendiente de la Fase 2 es sobre todo backups automáticos (no implementados) y tests formales. La Fase 3 (Redis, CDN dedicado, anti-cheat, escalado multi-instancia) sigue sin empezar.

¿Qué coste implicaría llevar Bule Bule a una producción robusta y escalable a partir de aquí?

✓ Escenario A — Continuar con Claude

  • Fase 1 — MVP mejorado — ✓ completado: marketplace, torneos, retos, historial.
  • Fase 2 — Backend robusto — ✓ mayormente completado: SQLite, rate limiting, CORS, limpieza de salas. Pendiente: backups automáticos (urgente) y tests formales → $20–40 en tokens
  • Fase 3 — Escalado real (2 meses, sin empezar): PostgreSQL, Redis + Socket.io adapter, CDN para assets 3D, monitoring → $150–300 en tokens
  • Hosting en producción: €15–50/mes (100 partidas simultáneas), €80–200/mes (1.000 partidas)

Coste restante hasta escalado real: $170–340 en API + €200–600 en hosting/año

✗ Escenario B — Equipo de desarrollo tradicional

  • Fase 1 — MVP mejorado (2 semanas, 1 senior): €8,000–12,000
  • Fase 2 — Backend robusto (1 mes, 1 senior): €12,000–16,000
  • Fase 3 — Escalado real (2 meses, 2 personas): €28,000–40,000
  • Mantenimiento ongoing: €4,000–8,000/mes (1 desarrollador part-time)
  • Hosting en producción: mismo coste de infraestructura que el escenario A

Coste total para llegar a producción robusta: €48,000–68,000 + €48,000–96,000/año en mantenimiento

Concepto Con Claude Sin Claude Ratio
Desarrollo hasta hoy (estado actual) ≈ $65 / 18 días activos ≈ €58,400 / 5–7 meses ~900×
Hasta escalado real (Fase 3 restante) $170–340 adicionales €28,000–40,000 ~100–200×
Mantenimiento / iteración anual $500–1,500/año €50,000–100,000/año 50–100×
Velocidad de iteración (feature nueva) 1–4 horas 2–5 días 10–30×
Barrera de entrada Ninguna Contratación, onboarding, gestión —
09

Análisis de mercado — A Coruña

Nota de vigencia: este análisis es estratégico e hipotético, no una descripción de lo construido. Modela un escenario de ingresos basado en suscripción de usuario + cuota B2B a bares, que sigue sin implementarse. Lo que realmente se construyó es la economía de Bules + marketplace (sección 6), más cercana en espíritu a la "moneda virtual no canjeable" descrita aquí como opción dudosa que a una suscripción de pago. Los números de tamaño de mercado (TAM/SAM/SOM) y el diagnóstico de efecto red siguen siendo relevantes; las proyecciones de ingresos concretas deben leerse como escenario, no como plan ejecutado. La app sigue sin publicarse en producción en Play Store, así que ningún número de usuarios reales existe todavía.

Escenario de comercialización: ciudad de A Coruña como mercado inicial. Usuario objetivo: personas que juegan a los dados (cubilete / bule bule) habitualmente en bares y podrían trasladar esa actividad (total o parcialmente) a formato online.

Datos de partida

246 k
Habitantes (municipio)
~380k área metropolitana · INE 2023
~155 k
Adultos 18–65 años
Público objetivo potencial
~1.600
Bares y cafeterías
Una de las densidades más altas de España
Alta
Cultura de bar
Galicia: bar/habitante entre los más altos de Europa

Tamaño del mercado (TAM / SAM / SOM)

Embudo desde la población adulta hasta usuarios activos mensuales (MAU) realistas en el primer año.

Nivel Definición Estimación A Coruña Criterio de filtro
TAM — Mercado total Adultos que conocen y juegan dados/cubilete en bares 8.000–12.000 personas ~20% de los 50.000 adultos que van a bares semanalmente · "bule bule" es juego regional muy conocido en Galicia
SAM — Mercado disponible De los anteriores, con smartphone y disposición a probar una app de dados 2.400–4.800 personas 30–40% del TAM · filtra personas sin interés en apps o sin smartphone frecuente
SOM (orgánico) — Año 1 sin marketing Captación boca a boca, compartir en grupos de WhatsApp 120–240 MAU 3–5% del SAM · crecimiento natural en redes sociales cercanas
SOM (activo) — Año 1 con marketing local Campaña en redes + acuerdos con bares + prensa local 400–800 MAU 10–15% del SAM · bajo presupuesto de €1.000–2.000 en difusión

Modelo de recurrencia

El juego presencial en bar y la app online no son sustitutos perfectos — son complementarios. La app cubre los momentos en que el grupo no puede juntarse físicamente.

Cuándo juegan online

  • Grupo disperso por trabajo / viaje
  • Sobremesa remota (videollamada + partida)
  • Torneo organizado con hora fija
  • Esperas largas (transporte, guardia, etc.)
  • Sustitución del bar en días de lluvia / invierno

Frecuencia estimada por perfil

  • Usuario activo (20% base): 3–5 sesiones/semana
  • Usuario medio (40% base): 1–2 sesiones/semana
  • Usuario casual (40% base): 2–4 sesiones/mes
  • Promedio ponderado: ~2,2 sesiones/semana
  • Duración media de partida: 15–25 minutos

Riesgo principal: efecto red

  • El juego requiere otros usuarios activos simultáneos
  • Con <100 MAU, encontrar partida puede ser difícil
  • Mitigación ya implementada: bot player
  • Solución adicional: torneos programados con hora fija
  • Sin masa crítica inicial, el producto no engancha

Escenarios de ingresos

Modelo MAU base Conversión Ingreso/mes Coste infra/mes Resultado
Sistema de honor (actual) 300 0 % €0 €5–10 Proyecto gratuito
Donaciones voluntarias (ko-fi) 300 1–2 % €15–45 €5–10 Simbólico
Suscripción premium (€2,99/mes) 500 8–12 % €120–180 €10–20 Cubre costes
B2B — bares (€20/mes por bar) — 30–60 bares €600–1.200 €20–40 Viable A Coruña
Expansión Galicia (B2C + B2B) 5.000–15.000 5 % suscripción + 200 bares €4.750–6.250 €80–200 Negocio viable

Viabilidad — diagnóstico

✗ B2C puro · solo A Coruña
El mercado ciudad es demasiado pequeño para monetización directa. 300–500 MAU generan ingresos simbólicos con suscripción. Problema de masa crítica: pocos usuarios → pocas partidas → abandono.
~ Producto gratuito · crecimiento orgánico
Viable como proyecto personal o de comunidad sin coste de mantenimiento significativo. Puede alcanzar 200–600 usuarios fieles en 6 meses. No genera ingresos pero construye base de usuarios para escalar.
✓ B2B con bares · A Coruña
El modelo más viable a escala ciudad. 30–60 bares × €20/mes = €600–1.200/mes cubre costes + margen. Propuesta de valor clara: "QR en la mesa → tus clientes juegan mientras esperan".

Hoja de ruta para la viabilidad

Paso 1 — Masa crítica (gratis)

Llegar a 300–500 usuarios activos en A Coruña mediante grupos de WhatsApp, Instagram local, y menciones en bares. Sin coste. Objetivo: demostrar tracción antes de monetizar.

Paso 2 — Torneos semanales

Programar torneos con hora fija (viernes 21h, por ejemplo). Esto resuelve el problema de masa crítica, crea hábito de uso y genera contenido compartible. Implementación: ~1 día con Claude.

Paso 3 — Canal B2B bares

Visita presencial a 10–15 bares con propuesta: QR en mesa, personalización del nombre del bar, estadísticas de uso. €20/mes. Con 30 bares = €600/mes. ROI positivo desde el primer mes.

Paso 4 — Expansión Galicia

El juego es galego-español: el salto a Vigo, Santiago, Ferrol, Lugo es natural. Misma app, misma cultura. Con 5× usuarios y 200 bares, el negocio se vuelve un negocio real de €4.000–6.000/mes.

Conclusión: A Coruña sola no es mercado suficiente para un negocio sostenible por B2C. Sí es mercado suficiente para validar el producto y construir el pitch para escalar. El camino más corto a ingresos reales es el modelo B2B con bares locales como prueba de concepto, expandiendo a Galicia en una segunda fase. El coste técnico de llegar ahí con Claude es insignificante — el cuello de botella es la captación comercial, no el desarrollo.

Proyección financiera — cuatro escenarios

Todos los escenarios asumen el modelo mixto: B2B bares + suscripción de usuario (el único con rentabilidad real a escala A Coruña / Galicia). Los costes de desarrollo son los de Claude (ver Sección 7) — se asume que no hay equipo asalariado. Se incluye el coste de oportunidad del fundador como referencia. Horizonte: 3 años.

Supuestos comunes: tarifa bares €20-25/mes · suscripción usuario €2,99/mes · tasa conversión suscripción 6-10% MAU · hosting escala con usuarios · marketing = único gasto variable significativo.

Escenario 0 — Producto muere

Sin acción comercial ni solución al efecto red

El mayor riesgo de cualquier juego multijugador: los primeros usuarios llegan, no encuentran partida y se van. Sin masa crítica inicial, el producto entra en espiral de abandono.

~40
MAU pico
Antes del abandono masivo
€0
Ingresos totales
Sin monetización activa
−€80
Costes / año
Solo hosting (Firebase free)
−€80
Resultado / año
Proyecto abandonado en 6-9 meses

Cómo evitarlo: torneos programados con hora fija (resuelve el problema de concurrencia), captación activa del primer grupo de 50 usuarios habituales, bots ya implementados como fallback.

Escenario mínimo — Hobby sostenible

Sin equipo · sin inversión en marketing · solo A Coruña · suscripción básica

El fundador dedica ~3-4h semanales. Sin presupuesto de marketing. Crecimiento orgánico por WhatsApp y boca a boca. Se lanza suscripción a los 6 meses. No se busca B2B activo.

Año 1 Año 2 Año 3
MAU medio 150 280 400
Bares B2B 5 12 18
Ingresos suscripción €270 (6% × 150 × €2.99 × 6 meses) €600 €860
Ingresos B2B bares €600 (5 bares × 6 meses) €2.880 €4.320
Ingresos totales €870 €3.480 €5.180
Costes (hosting + Claude) €220 €480 €720
Beneficio neto €650 €3.000 €4.460
Retribución fundador (€60/h · 3h/sem) €9.360 coste oportunidad €9.360 €9.360

Veredicto: cubre costes técnicos ampliamente pero no justifica el tiempo invertido como negocio. Válido como proyecto lateral que genera ingresos residuales con muy poco esfuerzo de mantenimiento.

Escenario realista — Pequeño negocio

Fundador dedicado · expansión Galicia en Año 2 · canal B2B activo · marketing €1.000-3.000/año

Se invierte tiempo real en ventas B2B (visitas a bares), redes sociales, y torneos semanales para construir masa crítica. En Año 2 se expande a Vigo, Santiago y Ferrol. En Año 3, norte de España.

Año 1 (A Coruña) Año 2 (Galicia) Año 3 (Norte España)
MAU medio 500 2.200 6.000
Bares B2B 30 100 260
Ingresos suscripción €1.076 (7% × 500 × €2.99 × 10 meses) €7.907 €21.528
Ingresos B2B bares €5.400 (30 × €20 × 9 meses) €24.000 €74.880
Ingresos totales €6.476 €31.907 €96.408
Costes (hosting + Claude + marketing) €1.800 €5.200 €12.000
Beneficio neto €4.676 €26.707 €84.408
¿Justifica dedicación completa? (umbral €30k/año) No (proyecto lateral) Sí, desde mitad de año Sí, con margen

Punto de inflexión: ~80 bares activos + 1.500 MAU → ingresos recurrentes de €2.000+/mes → negocio sostenible. Alcanzable en 12-18 meses con dedicación real al canal B2B.

Escenario máximo — Escala nacional

Cobertura mediática · viral en redes · expansión España + LATAM · torneos con patrocinadores

El producto aparece en prensa especializada o viral en TikTok/Instagram. Se expande al mercado hispanohablante donde el cubilete / dados es cultura popular (México, Argentina, Venezuela, Cuba…). Se añaden patrocinios de marcas de bebidas.

Año 1 Año 2 Año 3
MAU medio 3.500 22.000 80.000
Bares / locales B2B 120 600 2.000
Ingresos suscripción €12.558 €79.074 €287.520
Ingresos B2B locales €21.600 €162.000 €600.000
Torneos y patrocinios €0 €15.000 €80.000
Ingresos totales €34.158 €256.074 €967.520
Costes (infra + marketing + equipo mínimo) €12.000 €65.000 €220.000
Beneficio neto €22.158 €191.074 €747.520

Probabilidad: baja pero no despreciable — el cubilete tiene cultura profunda en todo el mundo hispanohablante (500M+ personas). LATAM no requiere ningún cambio en el producto. El riesgo principal es la competencia de apps ya existentes y la necesidad de un equipo real a partir del Año 2.

Resumen comparativo — Beneficio neto a 3 años

Escenario Año 1 Año 2 Año 3 acumulado Condición clave
Producto muere −€80 −€80 −€240 Sin acción. Efecto red no resuelto.
Mínimo €650 €3.000 €8.110 Solo A Coruña, 3h/sem, orgánico.
Realista ← recomendado €4.676 €26.707 €107.791 B2B activo + expansión Galicia en A2.
Máximo €22.158 €191.074 €960.752 Viral + LATAM + equipo + patrocinios.
18 meses
Tiempo estimado hasta independencia financiera (escenario realista).
Invertir ~15h/semana en captación B2B de bares + mantenimiento de producto con Claude. Sin equipo. Sin inversión externa. Sin licencias ni burocracia.
Inversión total en tecnología hasta ese punto: <$200 en tokens de Claude + ~€600 en hosting.
10

Plan de acción — equipo de 2 personas

Estado real a 31 de julio de 2026: el desarrollo de producto ha avanzado muy por delante del plan comercial de esta sección. Ya están hechos: marketplace + Bules, sistema de torneos con acceso por item, retos 1v1, backoffice de administración completo (items, torneos, usuarios, feedback, versiones de app, ajustes/feature flags), app nativa Android con Google Sign-In y AdMob integrado. Siguen pendientes los tres bloqueantes reales: backups automáticos de SQLite (riesgo de datos, cero coste técnico para resolverlo), el lanzamiento a producción en Play Store (prerrequisito para todo lo demás: AdMob real, visibilidad pública, reseñas) y, por tanto, el App ID real de AdMob. El plan comercial de bares/suscripción que sigue no se ha ejecutado — sigue siendo la hoja de ruta de negocio propuesta, no un hecho consumado.

Escenario elegido: B2B bares + suscripción de usuario · expansión Galicia en año 2. Es el camino de menor riesgo, menor inversión y mayor probabilidad de generar ingresos reales en un plazo razonable. No requiere licencias, inversión externa ni equipo adicional.

Roles y responsabilidades

● Persona 1 — UX / Fullstack

  • Desarrollo de producto con Claude (features, bugs, mejoras)
  • Diseño de UX/UI: demos visuales, materiales para pitch a bares
  • Infraestructura y despliegue (Firebase, servidor)
  • Dashboard de analytics y métricas de negocio
  • Soporte técnico a bares (onboarding, incidencias)
  • Dedicación estimada: 8–12 h/semana (fase 1) → full-time (fase 3)

● Persona 2 — Inversor / Comercial

  • Prospección y visitas a bares: demo en móvil + propuesta de valor
  • Gestión de contratos B2B y cobro mensual
  • Comunidad de usuarios: WhatsApp, Instagram, TikTok
  • Organización de torneos semanales presenciales/online
  • Relaciones con prensa local (La Voz de Galicia, medios hostelería)
  • Aportación de capital inicial: €2.000–3.000 (ver inversión)
  • Dedicación estimada: 10–15 h/semana (fase 1) → full-time (fase 2)

Hitos en el tiempo

0
Semanas 1–2
Preparación
€0 MRR
1
Mes 3
Validación
€600 MRR
2
Mes 6
Tracción
€1.500 MRR
3
Mes 9
Galicia
€2.500 MRR
4
Mes 18
Norte España
€8.000 MRR

Fases detalladas

Fase 0 — Preparación del producto comercial

Semanas 1–2 · Sin ingresos · Inversión: €0 en tecnología

Objetivo: tener un producto demostrable y un pitch listo para el primer bar.

  • Dev Pantalla de liquidación (€ por palillo) — superado: en su lugar se construyó la economía de Bules + marketplace, un modelo distinto pero que cumple el mismo objetivo de monetización sin tocar dinero real entre jugadores.
  • Dev Analytics básico — frontend/src/analytics.js ya trackea eventos clave (creación de sala, compras, etc.).
  • Dev Landing page atractiva con captura de email y demo en vivo embebida — pendiente
  • Dev Backups automáticos de SQLite — pendiente, prioridad técnica real número uno
  • Dev Publicar ficha y build en producción en Play Console — pendiente; assets (vídeo, capturas, feature graphic, mockups) ya están listos
  • Comercial Identificar los 20 bares target en A Coruña (zona Juan Flórez, Orzán, zona vella) — pendiente
  • Comercial Crear pitch de 1 página: propuesta de valor, precio, qué gana el bar — pendiente
  • Ambos Definir precio B2B (propuesta: 30 días gratis → €20/mes sin permanencia) — pendiente
  • Comercial Crear perfil de Instagram y grupo de WhatsApp "Bule Bule A Coruña" — pendiente
🏁 Criterio de salida: hacer la primera demo en un bar real y que el dueño diga "esto tiene buena pinta".

Fase 1 — Validación A Coruña

Meses 1–3 · Meta: 30 bares · €600 MRR · 400 MAU

Objetivo: demostrar que el modelo B2B funciona y que los usuarios vuelven.

  • Comercial 5 visitas/semana a bares con demo en móvil — apuntar objeciones y mejorar pitch
  • Dev Página personalizada por bar: logo, nombre, QR imprimible para la mesa — ~4h con Claude
  • Comercial Torneos de jueves o viernes a las 21h — anunciados en WhatsApp/Instagram con 48h de antelación
  • Dev Notificación push "Tu torneo empieza en 15 min" — ya implementado tecnicamente, solo activar
  • Comercial Recoger feedback semanal: ¿qué rompe la experiencia? ¿qué falta? — pasar al Dev
  • Dev 1–2 mejoras de producto por semana según feedback (velocidad clave en esta fase)
  • Ambos Revisar métricas cada lunes: MAU, partidas/día, churn de bares, MRR
💶 Hito mes 3: 30 bares firmados × €20 = €600/mes recurrentes. Si no se alcanza: revisar pitch, precio o zona geográfica antes de escalar.

Fase 2 — Expansión Galicia

Meses 4–9 · Meta: 100 bares · €2.500 MRR · 2.000 MAU

Objetivo: replicar el modelo en Vigo, Santiago, Ferrol, Lugo y Ourense.

  • Comercial Expandir a las 5 ciudades gallegas principales — misma dinámica de visitas presenciales
  • Dev Lanzar suscripción de usuario premium (€2,99/mes): historial de partidas, estadísticas, perfil
  • Dev Función "Invitar amigos" con link directo a partida — palanca de crecimiento orgánico clave
  • Dev Dashboard para el dueño del bar: partidas jugadas este mes, usuarios activos, horarios pico
  • Comercial Enviar nota de prensa a La Voz de Galicia, El Correo Gallego y blogs de hostelería
  • Comercial Buscar acuerdo con 1–2 distribuidores de hostelería gallegos para canal indirecto
  • Ambos Subir el precio a €25/mes para nuevos clientes si el churn es <10%
🚀 Hito mes 9: €2.500/mes cubre los costes de ambas personas a tiempo parcial. Punto de inflexión: el proyecto es financieramente autosuficiente.

Fase 3 — Escalado Norte de España

Meses 10–18 · Meta: 260 bares · €8.000 MRR · 6.000 MAU

Objetivo: independencia financiera completa para ambas personas.

  • Comercial Expandir a Asturias, Cantabria y País Vasco — cultura de bar muy similar a Galicia
  • Dev Sistema de torneos con inscripción de pago (€1–2/torneo) — ingresos adicionales sin licencia DGOJ
  • Dev App móvil nativa (PWA instalable o React Native) para mejorar retención
  • Comercial Negociar patrocinio con 1–2 marcas de bebidas para torneos (Estrella Galicia, Mahou...)
  • Ambos Evaluar contratar 1 persona comercial para liberar tiempo al fundador comercial
  • Dev Preparar infraestructura para LATAM si el MRR supera €10.000 (sin cambios en el producto)
🎯 Hito mes 18: €8.000 MRR = €4.000 netos/persona/mes. Independencia financiera alcanzada. Base para valorar inversión externa o expansión nacional.

Métricas clave a seguir

Métrica Qué mide Frecuencia Umbral de alerta
MRR (Monthly Recurring Revenue) Ingresos recurrentes mensuales garantizados Semanal < €200 al mes 2 → revisar pitch
Churn rate bares % de bares que cancelan al mes Mensual > 15% → llamar a todos y pedir feedback
MAU Usuarios activos mensuales — salud del producto Semanal Decrecimiento 2 semanas seguidas → investigar
Partidas/día Actividad real — proxy de engagement Diaria < 5 partidas/día pasado el mes 1 → problema de masa crítica
Conversión premium % MAU que pagan suscripción Mensual < 3% al mes 6 → revisar propuesta de valor premium
Tiempo de sesión medio Engagement por partida — ¿les engancha? Mensual < 8 min → el juego no retiene lo suficiente

Riesgos y mitigaciones

🔴 Efecto red — no hay con quién jugar

Probabilidad: alta si no se actúa. Mitigación: torneos a hora fija (jueves 21h), bot ya implementado como fallback, lanzamiento concentrado en 1 sola zona de la ciudad.

🔴 El comercial no cierra suficientes bares

El cuello de botella más probable. Mitigación: objetivo mínimo de 3 visitas/día, demo en 2 minutos en el propio móvil del dueño, 30 días gratis sin compromiso.

🟡 Bar paga pero sus clientes no juegan

El bar cancela al mes 2. Mitigación: onboarding activo (el comercial enseña el QR al camarero), torneo inaugural en el propio bar la primera semana.

🟡 Competencia de apps similares

No existe competencia directa en bule bule gallego. Riesgo en juego de dados genérico. Ventaja: conocimiento local, relaciones con bares, cultura del juego.

🟢 Costes técnicos se disparan

Riesgo bajo. Firebase escala en precio solo cuando hay volumen (problema bueno). Claude API: <$200/año hasta escala nacional. Hosting: <€50/mes hasta 5.000 MAU.

🟢 Problemas legales de juego

El modelo de honor (app no toca el dinero) está fuera del ámbito de la DGOJ. Los torneos con inscripción pequeña (<€50 bote) también están en zona segura.

Inversión inicial y reparto

Inversión total estimada: €2.000–3.000

ConceptoImporte
Material impreso (QR, roll-ups para bares)€400–600
Publicidad en redes sociales (Meta Ads)€500–800
Dominio, certificados, herramientas€100–150
Hosting primer año (Railway + Firebase)€120–300
Desplazamientos y demos presenciales€300–500
Claude API todo el año~€180 ($200)
Total€1.600–2.530

Estructura sugerida

  • Persona 2 (inversor) aporta el 100% del capital inicial (€2.000–3.000) como préstamo participativo o a cambio de equity acordado.
  • Persona 1 (dev) aporta el trabajo técnico (producto, infraestructura) valorado en €15.000–20.000 equivalente.
  • Reparto de beneficios desde mes 1: 50/50 o ajustado según aportación real (a negociar entre ambos).
  • No se necesita constituir sociedad hasta superar €3.000/mes de ingresos — hasta entonces, autónomos o facturación puntual.
  • El breakeven de la inversión inicial se alcanza con ~15 bares firmados.
18 m
De €0 a independencia financiera en 18 meses · inversión inicial: €2.000–3.000.
No se necesita inversión externa, licencias ni equipo adicional. El único cuello de botella real es la captación de bares — todo lo demás está resuelto o es barato de resolver con Claude. Breakeven técnico: 15 bares · Breakeven financiero completo (ambas personas): ~80 bares.
11

Glosario de términos

Definiciones de todos los acrónimos, métricas y términos técnicos usados en este documento.

MAU Monthly Active Users Métricas

Usuarios activos en un mes natural. En Bule Bule, un usuario cuenta como activo si completa al menos 1 partida en los últimos 30 días. No basta con abrir la app o registrarse — se requiere engagement real con el juego.

Ej: 500 MAU significa 500 personas distintas que terminaron una partida en el mes.

WAU Weekly Active Users Métricas

Usuarios que completan al menos 1 partida en los últimos 7 días. Métrica más sensible que el MAU para detectar caídas de engagement a corto plazo. Un MAU alto con WAU bajo indica usuarios que juegan esporádicamente.

DAU Daily Active Users Métricas

Usuarios activos en un día concreto. En juegos sociales como Bule Bule, el DAU tiene picos los jueves-viernes noche y fines de semana. La ratio DAU/MAU indica la frecuencia media de uso: si es 0.1, cada usuario juega ~3 días al mes.

MRR Monthly Recurring Revenue Métricas

Ingresos recurrentes garantizados cada mes, procedentes de contratos activos (bares B2B) y suscripciones de usuario. Es la métrica de salud financiera más importante para un negocio de suscripción: predecible, acumulable y difícil de inflar.

Ej: 30 bares × €20/mes + 50 suscripciones × €2.99 = €749,50 MRR.

Churn rate Tasa de cancelación Métricas

Porcentaje de clientes o usuarios que dejan de usar el servicio en un período dado. Un churn del 10% mensual en bares significa que 1 de cada 10 bares cancela al mes — insostenible. Por debajo del 5% mensual se considera saludable para un producto en fase inicial.

Ej: 30 bares activos, 3 cancelan ese mes → churn rate = 10%.

KPI Key Performance Indicator Métricas

Métrica concreta y medible que indica si el negocio avanza hacia sus objetivos. Un buen KPI es específico, temporal y accionable: si cae por debajo del umbral, sabes exactamente qué investigar. No todos los datos son KPIs — elegir 4-6 métricas clave evita la parálisis por análisis.

ROI Return on Investment Métricas

Beneficio obtenido en relación a lo invertido, expresado como porcentaje o ratio. Un ROI de ×1.200 (como el calculado para el desarrollo con Claude) significa que por cada euro invertido en API se obtiene el equivalente a 1.200 euros de valor en trabajo humano.

Fórmula: (beneficio − inversión) / inversión × 100.

LTV Lifetime Value Métricas

Ingresos totales que genera un cliente durante toda su relación con el producto. Para un bar que paga €20/mes durante 18 meses, el LTV es €360. Para ser rentable, el LTV debe ser al menos 3× el coste de adquirir ese cliente (CAC).

CAC Customer Acquisition Cost Métricas

Coste total de conseguir un nuevo cliente: tiempo del comercial, desplazamientos, materiales de marketing. Si visitar 10 bares cuesta 5 horas de trabajo y se consiguen 2 clientes, el CAC es 2.5h × €0 (sin salario aún) + materiales. Cuando se pague salario, el CAC definirá si el canal B2B es rentable.

Tasa de conversión Métricas

Porcentaje de usuarios que pasan de un estado a otro: de visita a registro, de registro a partida jugada, de usuario gratuito a suscriptor de pago. En las proyecciones del informe se usa una conversión del 6-10% de MAU a suscripción premium.

Ej: 500 MAU × 8% conversión = 40 suscriptores de pago.

TAM Total Addressable Market Negocio

El mercado total al que el producto podría llegar si capturara el 100% de sus posibles usuarios, sin restricciones de distribución o recursos. Es el techo teórico. Para Bule Bule en A Coruña: ~8.000-12.000 personas que juegan dados en bares.

SAM Serviceable Addressable Market Negocio

La parte del TAM a la que realmente se puede llegar con el modelo de negocio y canal de distribución actuales. Filtra a quienes no tienen smartphone, no usarían una app o están fuera del alcance geográfico/comercial. Siempre menor que el TAM.

SOM Serviceable Obtainable Market Negocio

La cuota de mercado realista a capturar a corto plazo, teniendo en cuenta los recursos disponibles, la competencia y el tiempo. Es el número que debe aparecer en los objetivos de negocio reales, no el TAM ni el SAM. Para Bule Bule año 1: 120-800 MAU según el nivel de inversión en marketing.

B2B Business to Business Negocio

Modelo de negocio donde se vende a otras empresas o negocios, no al consumidor final. En Bule Bule, el canal B2B es vender a bares (€20-25/mes) la herramienta para que sus clientes jueguen. El bar es el cliente que paga; sus clientes usan la app gratis.

B2C Business to Consumer Negocio

Modelo donde se vende directamente al usuario final. En Bule Bule, el B2C corresponde a la suscripción premium de usuario (€2,99/mes). Requiere mayor volumen de usuarios que el B2B para generar ingresos equivalentes.

MVP Minimum Viable Product Negocio

Primera versión lanzable de un producto que incluye solo las funcionalidades esenciales para aportar valor real a los primeros usuarios y validar hipótesis de negocio. No es un producto incompleto — es un producto completo para un caso de uso concreto. Bule Bule en su estado actual ya es un MVP funcional.

SaaS Software as a Service Negocio

Modelo de distribución de software en el que el usuario paga una cuota periódica (mensual/anual) para acceder a la aplicación vía internet, sin instalar nada localmente. La suscripción premium de Bule Bule (€2,99/mes) es un modelo SaaS B2C.

Rake Negocio

Comisión que cobra la plataforma (la "casa") sobre cada apuesta o bote acumulado en el juego. Es el modelo de ingresos estándar de casinos y salas de póker online. En España requiere licencia DGOJ para ser legal. Bule Bule no implementa rake — el dinero nunca pasa por la app.

Efecto red Network effect Negocio

Fenómeno por el que el valor de un producto crece de forma no lineal con el número de usuarios. En un juego multijugador como Bule Bule, sin usuarios no hay partidas, sin partidas no hay retención, sin retención no hay usuarios nuevos. Es el mayor riesgo en la fase inicial y la mayor ventaja una vez alcanzada la masa crítica.

Masa crítica Negocio

Número mínimo de usuarios activos simultáneos que hace que el producto sea útil de forma autónoma. Por debajo de ese umbral, los usuarios no encuentran partida y abandonan. Para Bule Bule se estima en ~50-80 MAU concentrados en la misma zona horaria. Se mitiga con torneos programados y bot players.

Coste de oportunidad Negocio

El valor de la mejor alternativa a la que se renuncia al tomar una decisión. En el contexto de Bule Bule: si el desarrollador dedica 10h/semana al proyecto en lugar de a trabajo remunerado (€60/h), el coste de oportunidad anual es ~€31.200. El proyecto solo es financieramente racional cuando los ingresos generados superan ese umbral.

Break-even Punto de equilibrio Negocio

Momento en que los ingresos igualan a los costes y el negocio deja de perder dinero. Hay dos break-even relevantes en Bule Bule: el técnico (cubrir hosting + herramientas, ~15 bares) y el financiero completo (cubrir el tiempo de ambas personas a jornada completa, ~80 bares).

LATAM Latinoamérica Negocio

Mercado hispanohablante de ~450 millones de personas en América Latina. Relevante para Bule Bule porque el cubilete y los juegos de dados tienen arraigo cultural profundo en países como México, Cuba, Venezuela, Argentina y Colombia. No requeriría cambios en el producto para operar allí.

API Application Programming Interface Tecnología

Interfaz que define cómo dos sistemas de software pueden comunicarse entre sí. En Bule Bule: la API de Google permite el login con cuenta de Google, la API de Anthropic permite usar Claude para el desarrollo, y el servidor expone una API interna vía Socket.io para el juego en tiempo real.

WebSockets Tecnología

Protocolo de comunicación que mantiene una conexión persistente y bidireccional entre el navegador y el servidor. A diferencia del HTTP clásico (el navegador pregunta, el servidor responde y cierra), con WebSockets el servidor puede enviar datos al cliente en cualquier momento. Imprescindible para juegos multijugador en tiempo real.

Socket.io Tecnología

Librería JavaScript que facilita la comunicación bidireccional en tiempo real, construida sobre WebSockets con fallbacks automáticos. Gestiona reconexiones, salas de jugadores y eventos nombrados. Es la columna vertebral de toda la lógica multijugador de Bule Bule.

WebAssembly (WASM) Tecnología

Formato binario que permite ejecutar código compilado de lenguajes como C++ o Rust directamente en el navegador, con rendimiento cercano al nativo. En Bule Bule, el motor de física Rapier3D está compilado en WASM, lo que permite simular colisiones y física de dados a 60fps sin necesidad de servidor de física.

Rapier3D Tecnología

Motor de física 3D de alta precisión compilado en WebAssembly. Simula cuerpos rígidos, colisiones, gravedad y fricción en tiempo real. En Bule Bule se usa para que los dados reboten de forma realista sobre el tablero, con física determinista: la misma semilla numérica produce exactamente el mismo resultado en todos los dispositivos.

Three.js Tecnología

Librería JavaScript para crear y renderizar escenas 3D en el navegador usando WebGL. Abstrae la complejidad de WebGL (shaders, matrices de transformación, gestión de GPU) en una API de alto nivel. En Bule Bule gestiona los dados, la cámara, las luces, las sombras y todos los efectos visuales.

Firebase Tecnología

Plataforma de backend de Google que incluye hosting estático, autenticación (Google, email, anónimo), base de datos en tiempo real, almacenamiento y funciones cloud. Bule Bule usa Firebase Hosting para servir el frontend. La capa gratuita cubre holgadamente las necesidades hasta varios miles de usuarios.

OAuth Open Authorization Tecnología

Protocolo estándar que permite a una aplicación verificar la identidad de un usuario a través de un proveedor externo (Google, GitHub, Facebook) sin necesidad de gestionar contraseñas. El usuario autoriza a Bule Bule a leer su nombre y email de Google; Google devuelve un token seguro que la app verifica.

CDN Content Delivery Network Tecnología

Red de servidores distribuidos geográficamente que sirven el contenido estático (imágenes, JS, CSS, assets 3D) desde el servidor más cercano al usuario, reduciendo la latencia. Firebase Hosting incluye CDN global automático. Relevante para Bule Bule porque los assets 3D (texturas, sonidos) pesan varios MB.

CI/CD Continuous Integration / Delivery Tecnología

Prácticas de automatización que ejecutan pruebas y despliegan el código automáticamente cada vez que se hace un commit. Eliminan los errores manuales del proceso de release. En Bule Bule actualmente el despliegue es manual (firebase deploy); un pipeline CI/CD automatizaría esto en cada push a main.

Toon shader Cel-shading Tecnología

Técnica de renderizado 3D que imita el estilo visual de un cómic o dibujo animado: sombras cuantizadas en bandas planas (en lugar de degradado suave) y contornos negros marcados alrededor de los objetos. En Bule Bule le da a los dados ese aspecto visual característico que los distingue de un simulador de física realista.

FXAA Fast Approximate Anti-Aliasing Tecnología

Técnica de post-procesado para suavizar los bordes dentados ("serrucho") que aparecen en escenas 3D cuando los polígonos se alinean en ángulos oblicuos a los píxeles. FXAA es una versión ligera que opera sobre la imagen final en lugar de renderizar a resolución mayor, lo que la hace adecuada para móviles.

VAPID Voluntary Application Server Identification Tecnología

Protocolo de autenticación para el envío de notificaciones push en aplicaciones web. Consiste en un par de claves pública/privada que identifican de forma segura al servidor que envía la notificación, evitando que terceros suplanten la identidad de la app. En Bule Bule se usa para notificar al usuario cuando le invitan a una partida.

JSONL JSON Lines Tecnología

Formato de fichero en el que cada línea es un objeto JSON independiente y completo, separado por salto de línea. Ideal para logs, streaming de datos y exportaciones grandes porque se puede leer línea a línea sin cargar el fichero entero en memoria. Las sesiones de Claude Code se almacenan en este formato.

TTL Time to Live Tecnología

Tiempo máximo que un dato almacenado en caché se considera válido antes de descartarse y recalcularse. En el prompt caching de Anthropic el TTL es de 5 minutos: si el intervalo entre llamadas supera ese tiempo, el contexto no se puede reutilizar y hay que enviarlo de nuevo completo (mayor coste).

MTok Millón de tokens Tecnología

Unidad de medida estándar para la facturación de modelos de lenguaje como Claude. Un token equivale aproximadamente a 4 caracteres de texto en inglés o 3 en español. Un mensaje de 1.000 palabras son ~1.400 tokens. El precio de Claude Sonnet 4.6: $3/MTok de entrada, $15/MTok de salida.

Prompt caching Tecnología

Sistema de Anthropic que almacena en caché partes del contexto de una conversación para reutilizarlas en llamadas sucesivas sin reenviarlas al modelo. Reduce el coste de los tokens de entrada en un 90% (de $3 a $0.30/MTok) cuando se produce un hit de caché. Clave para que el desarrollo con Claude Code sea económico.

PWA Progressive Web App Tecnología

Aplicación web que puede instalarse en el dispositivo del usuario (como una app nativa) directamente desde el navegador, sin pasar por la App Store o Google Play. Tiene acceso a funciones del dispositivo como notificaciones push, modo offline y pantalla completa. Una posible evolución de Bule Bule en la fase 3 del plan de acción.

DGOJ Dirección General de Ordenación del Juego Legal

Organismo del Ministerio de Consumo de España responsable de regular, supervisar y licenciar los juegos de azar online. Cualquier plataforma que intermedie en apuestas de dinero real entre usuarios necesita su licencia. El proceso es largo, costoso (garantías de decenas de miles de euros) y con auditorías técnicas. Las sanciones por operar sin licencia alcanzan los 50M€ (Ley 13/2011).

PSP Payment Service Provider Legal

Entidad autorizada por el Banco de España (o el BCE) para procesar, liquidar y gestionar pagos entre partes. Ejemplos: Stripe, PayPal, Adyen. Actuar como intermediario de pagos sin ser un PSP autorizado es ilegal en la UE (PSD2). Por eso Bule Bule no puede cobrar ni redistribuir dinero entre jugadores directamente.

INE Instituto Nacional de Estadística Legal / Mercado

Organismo oficial español que publica estadísticas demográficas, económicas y sociales. Los datos de población de A Coruña usados en el análisis de mercado (246.056 habitantes, 2023) proceden del padrón municipal del INE.

Usuario activo (Bule Bule) Producto

En Bule Bule se considera usuario activo quien completa al menos 1 partida en el período de referencia (mes para MAU, semana para WAU). No basta con abrir la app, registrarse o unirse a una sala. Se requiere completar el flujo de juego. Los usuarios invitados (guest) cuentan igual que los registrados si completan una partida.

No cuenta: abrir la app, ver la lista de salas, unirse y salir antes de terminar.

Sistema de honor Producto

Modelo de monetización en el que la app calcula cuánto debe cada jugador al final de la partida (según el importe por palillo configurado), pero el dinero nunca pasa por la plataforma. Los jugadores se pagan entre sí por Bizum, efectivo u otro medio externo. No requiere licencia DGOJ ni cuenta de pagos.

Liberado Producto

Estado especial en Bule Bule al que llega un jugador que consigue un Repóker (cinco dados con el mismo valor). El jugador liberado deja de participar en las rondas siguientes hasta que otro jugador pierda la partida. En una partida de 2 jugadores, el liberado gana automáticamente.

En capilla Producto

Estado en el que un jugador ha perdido todos sus palillos (vidas) y está en la última ronda antes de ser eliminado. Si vuelve a perder la ronda estando en capilla, queda eliminado de la partida. El término es parte del argot tradicional del juego de cubilete español.

Bules Producto

Moneda virtual del juego (llamada "puntos" hasta el rename de junio de 2026). Se gana jugando partidas o se compra con dinero real (paquete de 1.000 Bules por 1 € vía Bizum). Se gasta en el Marketplace en items cosméticos y acceso a torneos exclusivos. Es una economía cerrada: los Bules nunca se canjean de vuelta a dinero real, lo que mantiene la actividad fuera del ámbito de la Ley 13/2011 de regulación del juego.

Torneo con acceso por item Producto

Torneo del que solo puede participar quien posea un item concreto del marketplace, comprado con Bules. El item funciona como "llave de entrada". Ejemplo: el torneo "Bar Doce" solo es accesible poseyendo el item Churros. La validación de que el usuario posee el item se hace en el servidor al recibir join_tournament, no solo en el cliente.

Backoffice Tecnología

Panel de administración interno, no visible para jugadores, usado para gestionar el contenido y la configuración del juego: items del marketplace, torneos, usuarios, feedback, versiones de app publicadas y ajustes globales (feature flags, límite de jugadores). En Bule Bule es una app React independiente (backend/backoffice/) servida como estático desde el propio backend, protegida por token de administrador.

Feature flag Bandera de funcionalidad Tecnología

Interruptor remoto que activa o desactiva una funcionalidad sin necesidad de publicar una nueva versión de la app. En Bule Bule se gestionan desde la sección Ajustes del backoffice y se guardan en la tabla config de SQLite; el evento de socket público get_settings los expone al cliente. A fecha de este documento, el mecanismo existe pero ningún flag real se consume todavía en el juego — está listo para cuando se necesite aplicar reglas distintas por país o segmento de usuarios.

UMP consent User Messaging Platform Tecnología

Formulario de consentimiento de publicidad personalizada de Google (User Messaging Platform), obligatorio en la Unión Europea antes de mostrar anuncios de AdMob que usen datos personales. Bule Bule lo integra en AdBanner.jsx; hasta que la app se publique en producción en Play Store, se prueba con IDs de AdMob de test.

No se encontraron términos para esa búsqueda.

12

Marco legal — Ley 13/2011 de Regulación del Juego

Análisis del coste y viabilidad de operar Bule Bule como juego regulado bajo la normativa española de juego online, gestionada por la DGOJ (Dirección General de Ordenación del Juego).

Estado actual — sigue aplicando sin cambios: el sistema de Bules implementado en producción (sección 6) es exactamente el escenario "juego social sin dinero real" descrito en la sección 11.4: moneda virtual ganada jugando o comprada con dinero real, gastada en items y acceso a torneos, nunca canjeable de vuelta a dinero. Todo el análisis de esta sección — y en particular la conclusión de que el modelo regulado con apuestas reales es inviable para un equipo pequeño — sigue vigente sin ninguna modificación.

Clasificación del juego

El póker de dados combina azar (tirada de dados) y estrategia (elección de descartes). Bajo la Ley 13/2011, la componente aleatoria dominante lo clasifica como juego de azar, lo que activa los requisitos más exigentes de licencia.

Modalidad Juego de azar Dados → aleatoriedad dominante
Organismo regulador DGOJ Ministerio de Consumo
Ley aplicable Ley 13/2011 + RD 1613/2011

Costes de entrada — licencia DGOJ

La barrera más significativa es el aval bancario, una garantía que la DGOJ exige al operador para cubrir posibles deudas con jugadores. Es un depósito inmovilizado, no un gasto consumido.

Concepto Coste estimado Tipo
Aval bancario (garantía DGOJ) €1.500.000 – €3.000.000 Capital inmovilizado
Tasas DGOJ (tramitación licencia) €15.000 – €30.000 Pago único
Certificación técnica del software (GLI / BMM) €50.000 – €150.000 Pago único + renovación
Sistemas AML + KYC obligatorios €80.000 – €200.000 Implementación
Herramientas de juego responsable €30.000 – €80.000 Obligatorio DGOJ
Legal y compliance inicial €100.000 – €200.000 Asesoría especializada
TOTAL inversión inicial €1,8M – €3,6M Sin contar el aval

Costes anuales recurrentes

Tasa anual licencia DGOJ €20K – €60K
Equipo compliance + legal €150K – €300K
Auditorías técnicas anuales €30K – €60K
Impuesto sobre el juego (GGR) 20% del margen bruto Sobre ganancia bruta del operador

Coste anual total estimado: €200K – €420K + 20% GGR — antes de contar personal de producto y tecnología.

Alternativas con menor barrera

Juego social sin dinero real

Moneda virtual, sin premios en metálico. Sin obligación de licencia DGOJ. Coste regulatorio: €0. Es el modelo actual de Bule Bule.

Modelo B2B a bares (cuota SaaS)

Los bares pagan una cuota mensual por acceso. Los jugadores no apuestan dinero directamente. Sin licencia de juego si no hay premio en metálico entre jugadores. El modelo más viable a corto plazo.

Licencia Malta (MGA) + geofencing

Operar desde Malta con jugadores españoles. Coste de licencia MGA: €25K–50K. Zona gris legal en España desde la Ley 13/2011 — riesgo de bloqueo por la DGOJ.

Torneos de habilidad

Si se acredita componente de habilidad dominante, puede reclasificarse como concurso. Regulación más ligera, pero requiere dictamen jurídico. A estudiar con abogado especializado.

Conclusión: Para un equipo de 2 personas, el modelo regulado con apuestas reales es inviable en fase inicial — el aval bancario de €1,5M–3M es una barrera insuperable sin inversión institucional. La ruta recomendada es operar como juego social (sin dinero real) y monetizar vía B2B a bares, sin cruzar el umbral de "juego de azar" según la Ley 13/2011.