← Volver al Dashboard

📖 Manual del Programador

Documentación técnica viva del proyecto Games Bakuryu — Dominó MVP

📥 Descargar MD


1. Arquitectura General

Internet → Cloudflare
    ├── domino.bakuryu.com → Nginx → Godot Web Export
    ├── cdn.bakuryu.com    → Worker → GCS edge
    ├── api.bakuryu.com    → Nginx → Docker (8 servicios Go)
    ├── web.bakuryu.com    → Landing page
    └── d.bakuryu.com      → Dev dashboard (este sitio)
  

2. Servicios

ServicioRESTgRPCPropósito
auth-service40015001Login, JWT, KYC
wallet-service40025002Billetera, ledger HMAC
subscription-service4003-Free/Premium
social-service4004-Amigos, chat
shop-service4005-Cosméticos
ranking-service40065003ELO
audit-service40075004Auditoría
domino-service40105010Juego dominó

3. API Reference

3.1 Registro

curl -s4 -X POST https://api.bakuryu.com/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","username":"testuser","password":"SecurePass123!"}'

3.2 Login

curl -s4 -X POST https://api.bakuryu.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"SecurePass123!","remember_me":true}'

3.3 Perfil

curl -s4 https://api.bakuryu.com/auth/profile \
  -H "Authorization: Bearer <JWT_TOKEN>"

3.4 Lobby

curl -s4 https://api.bakuryu.com/api/lobby \
  -H "Authorization: Bearer <JWT_TOKEN>"

3.5 Crear Partida

curl -s4 -X POST https://api.bakuryu.com/api/games \
  -H "Authorization: Bearer <JWT_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mode":"fvd","max_players":4,"bet":0,"is_ranked":true}'

4. CDN

Worker: Cloudflare domino-cdn (cdn.bakuryu.com)

Bucket: gs://bakuryu/domino/ (1,187 assets)

Key GCP: /etc/gcp/gcp-key.json

Estructura:

cdn.bakuryu.com/
├── 2d/
│   ├── tiles/{classic,gold,jade,marble,obsidian,wood,flat}/tile_{X}_{Y}.png  (28+1 c/u)
│   └── avatars/{avatar_blue,gold,green,red}.png
├── 3d/tiles/{classic,gold,jade,marble,obsidian,rosewood,amber}/tile_{X}_{Y}.glb  (28+1 c/u)
├── environments/
│   ├── cantina_caracas/bg/scene_4k.png
│   ├── vip_club/bg/scene_4k.png
│   ├── playa_margarita/bg/scene_4k.png
│   ├── taberna_andalucia/bg/scene_4k.png
│   └── maracaibo/bg/scene_4k.png
├── audio/
│   ├── sfx/{13 sonidos}.mp3
│   ├── music/{7 tracks}.mp3
│   └── voices/{personaje}/{emocion}{##}.mp3  (416 archivos)
├── ui/{button_*,panel_*,icon_*,badge_*,reactions/*}.png
└── props/{candle_flicker,ceiling_fan,chandelier_sway,...}/*.png
  

Carga en Godot: environment_manager.gd usa CDN_BASE = https://cdn.bakuryu.com (sin /domino/ — el Worker lo agrega). tile_renderer.gd usa CDN_TILES con paths directos. Fallback procedural si CDN no responde.

5. WebSocket Opcodes

OpcodeDirecciónDescripción
auth:login→ ServidorHandshake con JWT
auth:login_ack← ClienteConfirmación + estado
game:hand_deal← ClienteRepartición de fichas
game:state← ClienteEstado del tablero
play_tile→ ServidorJugar ficha {"ficha":[6,4],"extremo":"izq"}
pass_turn→ ServidorPasar turno
buy_tile→ ServidorComprar del pozo
chat:msgChat (max 500 chars)
heartbeatKeep-alive 15s

6. GameManager

internal/ws/game_manager.go — bridge entre WS y engine. Métodos:

MétodoDescripción
CreateGameCrea partida con creator como North
JoinGameAsigna posición libre (East/South/West)
StartGameLlena slots vacíos con bots, inicia Round
PlayTileValida + aplica jugada, log a DB, broadcast
PassTurnPasa turno, trigger bot automático
BuyTileCompra del pozo, broadcast estado

7. Redis Persistence

internal/ws/redis_store.go — snapshot JSON de ManagedGame.

Key: domino:game:{gameID}  TTL: 72h
saveToRedisLocked()   → tras cada broadcast
LoadAllActive()        → restore al arrancar server
deleteFromRedisLocked() → al finalizar partida

8. gRPC Endpoints

internal/server/grpc.go vía proto/domino/domino.proto:

EndpointRetorna
GetGameStateEstado de partida activa (score, ronda, variante)
GetGameResultResultado final de partida
ListActiveGamesResumen de partidas activas

9. Vitácora de Errores

#ErrorCausaSolución
1.1Wrangler auth failIPv6 no whitelistedUsar curl -4 para API
1.2SyntaxError: exportES module vs Service WorkerUsar addEventListener
1.3nginx PID missing2 instancias nginxkill -HUP directo al PID
1.4Environment 404Ruta GCS incorrectaVerificar estructura GCS
1.5service nginx failDocker nginx ocupa puertosNo iniciar systemd nginx
2.1WS no procesa jugadashandleOnMessage limitadoGameManager bridge implementado
2.2gRPC server vacíoSin handlers reales3 endpoints implementados
2.3Sin RedisEstado no persistidoredis_store.go con save/load/delete
3.1WebSocket sin token en Web exportGodot 4.4.1 Web export no envía custom headersToken vía query string ?token=<jwt>, Go server lo extrae con r.URL.Query().Get("token")
3.2_ready() no se ejecuta en Web exportBug Godot 4.4.1 headless modePatrón init() llamado desde scene_controller.gd; _ready() queda vacío
3.3Color(r,g,b) parse error en TSCNBug Godot 4.4.1 export headless con colores nestedRemover colores de .tscn, aplicar programáticamente vía _apply_styles()
3.4Nginx /ws route 404Trailing slash en location /ws/ no matchea /wsCambiar a location /ws (sin slash al final)
3.5player_position int vs stringGo model Position como int, handler enviaba "north"type Position string en Go, handler envía "north"

10. Godot Web Export — Gotchas

Versión: Godot 4.4.1 (headless mode usado para export)

11. Asset Inventory

Ver archivo ASSET_INVENTORY.md para inventario completo de los 1,187 assets en GCS, incluyendo: