Skip to content

dabaez/futelo2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

100 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Futelo — Telegram Mini App

A letter-economy chat game. Every character costs inventory. Every message has a coin consequence.

UI language: Spanish. All user-facing text is in Spanish.


Project Structure

futelo/
├── README.md
├── deploy.sh             One-shot deployment script
├── backend/              Node.js server
├── frontend/             React + Vite + Tailwind SPA
├── nginx/                Production reverse-proxy config
└── data/                 SQLite files (auto-created, gitignored)

Quick Start (Local Dev)

1. Backend

cd backend
cp .env.example .env
# Minimum required for dev: set DEV_MODE=true (no bot token needed)
npm install
npm run dev

2. Frontend

cd frontend
cp .env.example .env
npm install
npm run dev

Open http://localhost:5173 in a browser.


Environment Variables

backend/.env

Variable Required Description
DEV_MODE dev only Set true to skip Telegram auth entirely. Accepts dev:USER_ID:username:First Name tokens. Never true in production.
SERVER_PORT yes Port the Express server listens on. Default: 3001.
BOT_TOKEN prod only Telegram bot token from @BotFather. Not needed when DEV_MODE=true.
BOT_TOKEN_HASH prod only Pre-computed HMAC key used to validate Telegram WebApp initData. Set to the same value as BOT_TOKEN — the server derives the key itself. Leave blank to have it computed automatically.
ADMIN_USER_IDS optional Comma-separated Telegram user IDs allowed to mark, reopen, or delete feature requests. Example: 123456,789012.
ADMIN_USER_IDS optional Comma-separated Telegram user IDs allowed to mark, reopen, or delete feature requests. Example: 123456,789012.
WEBHOOK_DOMAIN prod, webhook Full HTTPS URL of your server, e.g. https://your-domain.com. Used to register the webhook with Telegram.
MINI_APP_URL prod URL where the frontend is served, e.g. https://your-domain.com. Shown in the /start group reply button.
MINI_APP_DIRECT_LINK prod Direct Mini App deeplink from BotFather (format: https://t.me/your_bot/your_app). Without this the /start button opens a plain URL with no Telegram context.
DOMAIN prod Bare domain name, e.g. your-domain.com. Used by deploy scripts and Nginx config.
NOTIFY_CHANNEL_ID optional Telegram channel ID where game notifications are posted. The bot must be an admin. Leave empty to disable.

Minimal dev setup — only two variables are needed:

DEV_MODE=true
SERVER_PORT=3001

Minimal production setup:

DEV_MODE=false
SERVER_PORT=3001
BOT_TOKEN=123456:ABC-your-token
BOT_MODE=webhook
WEBHOOK_DOMAIN=https://your-domain.com
MINI_APP_URL=https://your-domain.com
MINI_APP_DIRECT_LINK=https://t.me/your_bot_username/your_app_name
DOMAIN=your-domain.com

frontend/.env

Variable Required Description
VITE_BACKEND_URL prod only Full URL of the backend API, e.g. https://your-domain.com. Leave empty in local dev — Vite proxies /api and /socket.io to localhost:3001 automatically.

Local dev — leave the file empty (or omit it entirely):

VITE_BACKEND_URL=

Production:

VITE_BACKEND_URL=https://your-domain.com

Testing Without Telegram

When DEV_MODE=true and you open the app in a plain browser, a Dev User Picker screen appears. Preset users (Alice, Bob, etc.) all share a default Dev Room (-1001). Open a second tab and pick a different user to simulate two players chatting.

The custom user form also accepts a Chat ID and Chat Title to test multi-room isolation — enter different chat IDs to put users in separate rooms.

⚠️ Never set DEV_MODE=true in production — it completely bypasses Telegram authentication.


Production Deployment

bash deploy.sh

Requires:

  • Node.js 20+, npm, pm2 (sudo npm i -g pm2)
  • Nginx installed and running
  • A valid SSL cert via Certbot (certbot --nginx -d your-domain.com)
  • backend/.env fully populated

Bot Setup

  1. Create a bot via @BotFather.
  2. In BotFather, set the Mini App URL: /newapp → point to https://your-domain.com.
  3. Add the bot to any Telegram group as Admin with "Delete messages" permission. Each group automatically gets its own isolated room — prompts, market listings, lottery rounds, and chat streaks are all per-group.
  4. Set BOT_MODE=webhook and WEBHOOK_DOMAIN=https://your-domain.com in .env.

GROUP_CHAT_ID is not required. The bot handles all groups it is a member of automatically.


Game Rules

Coin Tiers

Tier Condición Monedas Efecto extra
1 Diferente usuario habló último +10
2 Propio mensaje, racha = 2 0 Aviso de spam
3 Propio mensaje, racha ≥ 3 −50 1 letra del inventario bloqueada 5 min

Las letras son niveles de desbloqueo (no se consumen). inventory["a"] = 3 significa que puedes usar hasta 3 as por mensaje. Los tiers nunca otorgan letras — las letras solo se obtienen con el bono de primer mensaje (26 aleatorias) o comprando cajas en la Tienda.

Shop (Tienda)

Item Coste Efecto
Abrir caja 50 🪙 base + 2 🪙 × niveles totales Obtén letras según rareza del resultado
Lanzar un prompt configurable 🪙 Inicia un prompt comunitario inmediatamente
Vender letra (mercado normal) Lista la letra; comprador paga; 20% comisión
Vender letra (mercado negro) Sin comisión, pero con riesgo de multa
Pico (minas) 150 🪙 base + 2 🪙 × niveles totales Obtén 1000 golpes para usar en las minas

Cajas — Rareza del resultado

Rareza Letras ganadas Probabilidad
📦 Común 3 ~40%
✨ Bueno 5 ~35%
⭐ Raro 7 ~18%
💫 Épico 11 ~6%
🏆 Legendario 16 ~1%

Media de letras por tirada: ~5.

Las raridades más altas muestran animaciones, efectos y haptics en la UI de Telegram.

Inventario al límite (nivel cap)

Cuando todas las letras del inventario están al máximo (MAX_LETTER_LEVEL = 6), el servidor:

  • Anula el coste de la tirada.
  • Otorga monedas en su lugar (CAP_OVERFLOW_COINS_PER_LETTER × letras del tier).

Esto aplica también a las minas (swing con inventario lleno → monedas) y a la lotería (niveles desbordados → monedas). Los niveles de bono nunca se desperdician en silencio.

Animación de apertura

Al abrir una caja, la interfaz muestra:

  1. Una tira de ruleta horizontal que decelera hasta la rareza ganada.
  2. Cartas boca abajo — una por letra ganada — que el jugador toca para revelarlas.

Si el inventario está lleno, las fases de cartas se omiten y se muestra directamente el bonus de monedas.

Letter Market

Mercado normal — 20% comisión quemada en cada venta. El vendedor recibe el 80% del precio. Las notificaciones de venta se persisten en la DB, así que los vendedores offline las ven al reconectarse.

Mercado negro — sin comisión, con riesgo:

  • El nivel de letra queda en escrow mientras está listado.
  • Algo vigila. Si te atrapan, recibes una multa. Hablar de ello empeora las cosas.
  • Los listados no duran para siempre.
  • Acceso: triple-toca el botón de la tienda en menos de 1.5 s.

Community Prompts

Una ronda de preguntas y respuestas con temporizador.

  • Se activa automáticamente tras un período de inactividad, o se compra en la tienda.
  • Cualquier jugador puede responder; los demás votan con ❤️.
  • Al expirar el tiempo, las monedas se distribuyen a las respuestas más votadas.
  • Solo un prompt activo a la vez.
  • Al cerrarse, se publica un mensaje del sistema en el feed indicando el ganador.

Letter Gambling (Lotería)

Un mini-juego de apuestas periódico:

  • Alguien inicia la ronda gastando monedas.
  • Los jugadores apuestan letras de su inventario como predicción de la letra secreta.
  • La 2ª apuesta en adelante tiene una probabilidad de error escalante (1 − 0.5^k).
  • Al cerrarse la ronda se revela la letra secreta.
  • Los acertantes reciben +2 niveles de la letra ganada más monedas del bote.
  • Si nadie acierta, las letras se convierten en monedas y el bote se acumula.
  • Al cerrarse, se publica un mensaje del sistema en el feed con el resultado.

Minas de Letras

Un mini-juego de exploración individual:

  • Compra un pico en la tienda por 150 🪙 base + 2 🪙 por cada nivel de inventario que ya tengas (mismo escalado que las cajas). Otorga 1000 golpes.
  • Toca la roca en la pestaña ⛏️ Minas para gastar un golpe.
  • Cada golpe tiene un 1% de probabilidad de encontrar un objeto aleatorio del pool mineable: letras (a-z, ñ), grupo de números _numbers o grupo de símbolos _symbols (+1 nivel, máx. 6). De media, ~1 hallazgo cada 100 golpes.
  • Si todo el inventario mineable ya está al máximo, el golpe otorga monedas en lugar de un hallazgo.
  • Los picos se acumulan — puedes comprar varios seguidos.
  • Es una actividad en solitario; no se emiten eventos a otros jugadores.

System Messages

Después de cerrar prompts y rondas de lotería, el servidor publica un mensaje de sistema (userId = 0) visible para todos, incluidos los jugadores que estaban offline (los mensajes se persisten en la DB y se muestran en el feed como pills centradas).

El mensaje de pedir ayuda ("🙏 Pedir ayuda" en la tienda cuando el jugador no tiene letras ni monedas) también se publica como mensaje de sistema persistente con un payload JSON {type:"beg", ...}. El feed lo renderiza como una tarjeta ámbar con un botón Dar 10 🪙 — así todos los jugadores, incluyendo los que se conecten después, pueden donar.

Emoji Forge

Un taller de creación de emojis:

  • Abre la interfaz desde el botón 🧪 en el teclado.
  • Elige entre 2 y 6 caracteres del inventario como "ingredientes".
  • El nivel de cada ingrediente queda reservado durante 1 hora mientras la mezcla está activa.
  • Si la combinación coincide con una receta conocida, el emoji queda desbloqueado permanentemente y usable en cualquier sala.
  • Si no hay receta, los niveles se devuelven (+1 por ingrediente, máx. MAX_LETTER_LEVEL).
  • Completar al instante: paga ceil(segundos_restantes × 0.02) 🪙.
  • Pista: compra una pista críptica sobre un emoji que aún no tienes. El servidor garantiza que no se repiten pistas y rechaza la compra cuando ya tienes todas las pistas disponibles de los emojis que te faltan. Las pistas se persisten en la DB y vuelven a aparecer al reabrir el modal.
  • Una vez desbloqueado, el emoji aparece en la barra rápida del teclado para insertarlo con un toque.
  • Las mezclas activas, pistas compradas y emojis desbloqueados son por sala (per-room).
  • GET /api/config expone la lista de emojis (EMOJI_DEFS) con clave, carácter y nombre — sin revelar recetas ni pistas. El frontend no tiene ninguna lista hardcodeada; siempre usa la del servidor.

Achievements (Logros)

Sistema de logros que recompensa hitos del juego con monedas.

  • 50+ logros distribuidos en categorías: Mensajes, Teclado, Tienda, Mercado, Mina, Apuestas, Emojis, Community.
  • Se otorgan automáticamente cuando se cumple la condición (tras cada acción relevante).
  • El progreso, estadísticas y logros son independientes por cada sala (per-room).
  • El premio se acredita en la sala donde ocurrió el evento.
  • Los logros ya ganados no se repiten en la misma sala.
  • Ver el panel de logros desde el icono 🏅 en el header.

Notifications

Las alertas por usuario (p.ej. "tu letra se vendió") se persisten en la DB. Si estás offline cuando tu listado se vende, el toast queda en cola y se muestra la próxima vez que te conectes.

DevInfo Modal

Toca el nombre "💬 Futelo" en la esquina superior izquierda para abrir el panel de información de desarrollo con tres pestañas:

  • 📋 Parches — historial de versiones con cambios por versión.
  • 💡 Ideas — lista de solicitudes de funcionalidades enviadas por la comunidad. Cualquier jugador puede enviar una idea (5–300 caracteres) y votar por las existentes (votos ilimitados). El ranking es por votos.
  • ✅ Hechas — ideas ya implementadas.

Los usuarios en ADMIN_USER_IDS ven botones adicionales para marcar/reabrir/eliminar solicitudes directamente desde la interfaz.

Leaderboard

Toca el saldo de monedas en el header para abrir la tabla de posiciones con tres categorías:

  • 🔤 Letras — jugadores con más niveles de inventario totales (puntuación visible).
  • 🪙 Monedas — jugadores con más monedas, pero sin mostrar la cantidad (solo posición).
  • 💬 Mensajes — jugadores con más mensajes enviados en la sala (puntuación visible).

La tabla muestra los 10 primeros. Tu propia fila queda resaltada. Los puestos 1–3 muestran medallas 🥇🥈🥉.

Feature Request CLI

Herramienta interactiva de terminal para gestionar solicitudes directamente en el servidor de producción (acceso directo a la misma DB sin pasar por la API):

cd backend
npm run cli

Controles: ↑/↓ o j/k navegar · d marcar/desmarcar como implementada · x eliminar · n nueva idea · Tab cambiar vista · q salir.


Tests

cd backend && npm test   # Jest + supertest  (309 tests, 10 suites)
cd frontend && npm test  # Vitest + Testing Library  (55 tests, 2 suites)

Backend test suites

Suite Tests What it covers
auth.test.js 18 Telegram HMAC + dev-token validation
engine.test.js 34 letterRequirements, all tiers, first-message bonus (cap-ceiling), coin floor, shopRoll (allCapped path, steering to uncapped)
market.test.js 27 Regular and black-market list/buy/cancel, commission, bmBuyListing
blackMarket.test.js 16 Heat decay, catchProbability, runCatchCheck, expiry
mining.test.js 21 buyPickaxe (scaled cost), swing, hit/miss probability, _numbers/_symbols finds, all-caps coin fallback
prompt.test.js 21 buyPrompt, submitReply, castVote, closePrompt with all edge cases
lottery.test.js 14 startLottery, placeBet, closeLottery, getActiveLottery, cap overflow coins
api.test.js 81 All REST endpoints end-to-end with a real SQLite DB; includes regression for my-listings open-only filter, reaction coin correctness (room coins not global), hint persistence via status; leaderboard shape (coins score hidden); devinfo CRUD + admin guard
emojiForge.test.js 28 inventoryKey, matchRecipe, startMerge (validation + deduction), instantComplete, buyHint (no-duplicate guard, all-hints-purchased guard, persists to DB), getStatus (returns merge + emojis + hints)
achievements.test.js 40 checkAchievements – all event types, already-earned guard, multi-award transaction, stat counter updates

Frontend test suites

Suite Tests What it covers
RestrictedKeyboard.test.jsx 28 Rendering, badges, disabled states, pointer interactions, caps/shift toggle, all 22 symbol keys, ⌫ position stability across modes
MessageBubble.test.jsx 27 Text, sender names, coin delta badges, tier labels, layout, miso-soup replacement, system pill, beg card + socket interaction

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages