# Trivy - Documento de Diseño **Fecha:** 2026-01-26 **Versión:** 1.0 **Estado:** Aprobado --- ## 1. Visión General ### 1.1 Descripción Trivy es una aplicación web de trivia multiplayer en tiempo real, inspirada en el formato de Jeopardy. Permite partidas entre 2 equipos de hasta 4 jugadores cada uno, con preguntas organizadas por categorías y niveles de dificultad. ### 1.2 Características Principales - Partidas en tiempo real con WebSockets - 8 categorías temáticas: Nintendo, Xbox, PlayStation, Anime, Música, Películas, Libros, Historia-Cultura - Tablero estilo Jeopardy (5 niveles de dificultad por categoría) - Sistema de "robo" de puntos entre equipos - Validación de respuestas mediante IA (Claude) - Generación automática de preguntas con aprobación de administrador - 5 temas visuales intercambiables - Sistema de logros - Replays de partidas - Sonidos temáticos --- ## 2. Mecánicas del Juego ### 2.1 Flujo de Partida 1. **Creación de sala**: Un jugador crea sala y recibe código de 6 caracteres 2. **Lobby**: Jugadores se unen con el código, eligen equipo (máx 4 por equipo), ingresan nombre 3. **Inicio**: El host inicia cuando hay al menos 1 jugador por equipo 4. **Tablero**: Se muestra el tablero con 8 categorías × 5 preguntas (100-500 pts) 5. **Turno**: El jugador en rotación del equipo activo selecciona una pregunta 6. **Respuesta**: Tiene X segundos (según dificultad) para escribir respuesta 7. **Validación IA**: Claude valida si la respuesta es correcta 8. **Robo opcional**: Si falla, equipo contrario decide si intenta robar 9. **Siguiente turno**: El equipo ganador elige siguiente pregunta 10. **Final**: Partida termina cuando se agotan las preguntas ### 2.2 Sistema de Turnos - **Rotación obligatoria**: Cada pregunta la responde un miembro diferente del equipo - **El que acierta elige**: El equipo que responde correctamente (o roba) elige la siguiente pregunta ### 2.3 Sistema de Puntos y Tiempo | Dificultad | Puntos | Tiempo | |------------|--------|--------| | 1 (Fácil) | 100 | 15 seg | | 2 | 200 | 20 seg | | 3 (Media) | 300 | 25 seg | | 4 | 400 | 35 seg | | 5 (Difícil)| 500 | 45 seg | ### 2.4 Mecánica de Robo - **Voluntario**: El equipo contrario decide si intenta robar o pasar - **Penalización**: Si fallan el robo, pierden la mitad de los puntos de la pregunta - **Tiempo reducido**: El equipo que roba tiene la mitad del tiempo original ### 2.5 Formato de Respuestas - Respuesta abierta (el jugador escribe libremente) - Validación semántica con IA (acepta sinónimos, variaciones, errores de ortografía menores) --- ## 3. Arquitectura Técnica ### 3.1 Stack Tecnológico ``` ┌─────────────────────────────────────────────────────────────┐ │ FRONTEND (React) │ │ - Vite + React 18 + TypeScript │ │ - Tailwind CSS + Framer Motion (animaciones) │ │ - Socket.io-client (tiempo real) │ │ - Zustand (estado global) │ │ - 5 temas visuales intercambiables │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ BACKEND (Python FastAPI) │ │ - FastAPI + Uvicorn │ │ - python-socketio (WebSockets) │ │ - SQLAlchemy (ORM) │ │ - Anthropic SDK (validación IA) │ │ - APScheduler (tareas programadas) │ └─────────────────────────────────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │PostgreSQL│ │ Redis │ │ Claude │ │(datos) │ │ (estado) │ │ (IA) │ └──────────┘ └──────────┘ └──────────┘ ``` ### 3.2 Responsabilidades por Componente - **PostgreSQL**: Preguntas, categorías, historial de partidas, configuración, logros - **Redis**: Estado de salas activas, turnos, temporizadores, sesiones WebSocket - **Claude API**: Validar respuestas, generar preguntas nuevas --- ## 4. Modelo de Datos ### 4.1 PostgreSQL ```sql -- Categorías CREATE TABLE categories ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, icon VARCHAR(50), color VARCHAR(7) ); -- Preguntas CREATE TABLE questions ( id SERIAL PRIMARY KEY, category_id INTEGER REFERENCES categories(id), question_text TEXT NOT NULL, correct_answer VARCHAR(500) NOT NULL, alt_answers TEXT[], -- Respuestas alternativas válidas difficulty INTEGER CHECK (difficulty BETWEEN 1 AND 5), points INTEGER NOT NULL, time_seconds INTEGER NOT NULL, date_active DATE, status VARCHAR(20) DEFAULT 'pending', -- pending, approved, used fun_fact TEXT, created_at TIMESTAMP DEFAULT NOW() ); -- Sesiones de juego CREATE TABLE game_sessions ( id SERIAL PRIMARY KEY, room_code VARCHAR(6) UNIQUE NOT NULL, status VARCHAR(20) DEFAULT 'waiting', -- waiting, playing, finished team_a_score INTEGER DEFAULT 0, team_b_score INTEGER DEFAULT 0, current_team VARCHAR(1), -- 'A' o 'B' questions_used INTEGER[], created_at TIMESTAMP DEFAULT NOW(), finished_at TIMESTAMP ); -- Eventos de juego (para replays) CREATE TABLE game_events ( id SERIAL PRIMARY KEY, session_id INTEGER REFERENCES game_sessions(id), event_type VARCHAR(50) NOT NULL, player_name VARCHAR(100), team VARCHAR(1), question_id INTEGER REFERENCES questions(id), answer_given TEXT, was_correct BOOLEAN, was_steal BOOLEAN DEFAULT FALSE, points_earned INTEGER, timestamp TIMESTAMP DEFAULT NOW() ); -- Administradores CREATE TABLE admins ( id SERIAL PRIMARY KEY, username VARCHAR(100) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT NOW() ); ``` ### 4.2 Redis (Estado Volátil) ``` room:{code} → { players: [{name, team, position, socketId}], teams: {A: [], B: []}, currentTeam: 'A', currentPlayerIndex: {A: 0, B: 0}, status: 'waiting|playing|finished', timer: timestamp, canSteal: false, currentQuestion: questionId } player:{socket_id} → {name, room, team, position} ``` --- ## 5. Sistema de IA ### 5.1 Validación de Respuestas ```python VALIDATION_PROMPT = """ Eres un validador de trivia. Determina si la respuesta del jugador es correcta comparándola con la respuesta oficial. Pregunta: {question} Respuesta correcta: {correct_answer} Respuestas alternativas válidas: {alt_answers} Respuesta del jugador: {player_answer} Considera válido si: - Es sinónimo o variación de la respuesta correcta - Tiene errores menores de ortografía - Usa abreviaciones comunes (ej: "BOTW" = "Breath of the Wild") - Es conceptualmente equivalente Responde SOLO con JSON: {"valid": true/false, "reason": "breve explicación"} """ ``` ### 5.2 Generación de Preguntas ```python GENERATION_PROMPT = """ Genera 5 preguntas de trivia para la categoría {category}. Dificultad: {difficulty} (1=muy fácil, 5=muy difícil) Formato JSON por pregunta: { "question": "texto de la pregunta", "correct_answer": "respuesta principal", "alt_answers": ["variación1", "variación2"], "fun_fact": "dato curioso opcional" } Requisitos: - Las preguntas deben ser verificables y precisas - Evitar ambigüedades - Ajustar complejidad según dificultad - Para gaming: incluir referencias a juegos, personajes, mecánicas - Para cultura: hechos históricos, arte, literatura """ ``` ### 5.3 Flujo de Aprobación 1. Admin solicita generar preguntas desde panel 2. Claude genera batch de preguntas 3. Quedan en estado `pending` 4. Admin revisa, edita si necesario, aprueba o rechaza 5. Preguntas aprobadas se asignan a fecha futura --- ## 6. Temas Visuales ### 6.1 Temas Disponibles | Tema | Paleta Principal | Características | |------|------------------|-----------------| | **DRRR (Dollars)** | Negro, amarillo neón (#FFE135), cyan (#00FFFF) | Chat estilo Dollars, efectos glitch, tipografía urbana, bordes neón pulsantes | | **Retro Arcade** | Púrpura (#9B59B6), rosa (#E91E63), cyan pixelado | Pixel art UI, tipografía 8-bit (Press Start 2P), scanlines, efectos CRT | | **Moderno Minimalista** | Blanco (#FFFFFF), grises, acento azul (#3498DB) | Limpio, sombras suaves, tipografía sans-serif, transiciones elegantes | | **Gaming RGB** | Negro (#0D0D0D) con gradientes RGB | Efectos de luz LED, gradientes animados, bordes brillantes, estilo "gamer" | | **Anime Clásico 90s** | Pasteles, rosa (#FFB6C1), lavanda (#E6E6FA) | Estrellas brillantes, efectos sparkle, bordes redondeados, estilo shoujo | ### 6.2 Implementación ``` /src/themes/ ├── ThemeProvider.tsx # Context para tema activo ├── index.ts # Exporta todos los temas ├── drrr/ │ ├── variables.css │ ├── components.tsx │ └── sounds/ ├── retro-arcade/ ├── minimal/ ├── gaming-rgb/ └── anime-90s/ ``` --- ## 7. Sistema de Sonidos ### 7.1 Eventos con Sonido | Evento | DRRR | Retro | Minimal | RGB | Anime 90s | |--------|------|-------|---------|-----|-----------| | Correcto | Glitch digital | 8-bit coin | Soft chime | Synth rise | Sparkle | | Incorrecto | Static buzz | 8-bit fail | Low tone | Bass drop | Comedic | | Robo | Suspense | Power-up | Click | Laser | Drama sting | | Timer (tick) | Heartbeat | Beeps | Ticks | Pulse | Tension | | Timer (urgente) | Fast heartbeat | Fast beeps | Fast ticks | Fast pulse | Panic | | Victoria | Epic synth | Fanfare | Elegant | EDM drop | Anime victory | | Derrota | Glitch fade | Game over | Soft close | Power down | Sad piano | | Selección | Click neón | 8-bit select | Pop | RGB sweep | Cute pop | ### 7.2 Almacenamiento - Archivos en formato WebM/OGG para compatibilidad - Precargados al seleccionar tema - Volumen configurable por usuario --- ## 8. Sistema de Logros ### 8.1 Lista de Logros | ID | Nombre | Condición | Icono | |----|--------|-----------|-------| | 1 | Primera Victoria | Ganar tu primera partida | 🏆 | | 2 | Racha de 3 | Responder 3 correctas seguidas | 🔥 | | 3 | Racha de 5 | Responder 5 correctas seguidas | 🔥🔥 | | 4 | Ladrón Novato | Primer robo exitoso | 🦝 | | 5 | Ladrón Maestro | 5 robos exitosos en una partida | 🦝👑 | | 6 | Especialista Nintendo | 10 correctas en Nintendo | 🍄 | | 7 | Especialista Xbox | 10 correctas en Xbox | 🎮 | | 8 | Especialista PlayStation | 10 correctas en PlayStation | 🎯 | | 9 | Especialista Anime | 10 correctas en Anime | ⛩️ | | 10 | Especialista Música | 10 correctas en Música | 🎵 | | 11 | Especialista Películas | 10 correctas en Películas | 🎬 | | 12 | Especialista Libros | 10 correctas en Libros | 📚 | | 13 | Especialista Historia | 10 correctas en Historia-Cultura | 🏛️ | | 14 | Invicto | Ganar sin fallar ninguna pregunta | ⭐ | | 15 | Velocista | Responder correctamente en menos de 3 segundos | ⚡ | | 16 | Comeback | Ganar estando 500+ puntos abajo | 🔄 | | 17 | Dominio Total | Responder las 5 preguntas de una categoría correctamente | 👑 | | 18 | Arriesgado | Responder correctamente 3 preguntas de 500 pts | 🎰 | ### 8.2 Almacenamiento - localStorage por navegador (sin cuentas) - Estructura: `{odooId: {achievements: [...], stats: {...}}}` - Mostrados al final de cada partida (nuevos desbloqueados) --- ## 9. Sistema de Replays ### 9.1 Datos Capturados Usando la tabla `game_events`, cada evento registra: - Tipo de evento (question_selected, answer_submitted, steal_attempted, etc.) - Jugador y equipo - Pregunta seleccionada - Respuesta dada - Resultado (correcto/incorrecto) - Puntos ganados/perdidos - Timestamp preciso ### 9.2 Reproducción 1. Al finalizar partida, opción "Ver Replay" 2. Carga eventos ordenados por timestamp 3. Reproduce animación acelerada (x2, x4, x8) 4. Muestra: - Tablero con preguntas revelándose - Respuestas de jugadores - Marcador actualizándose - Momentos de robo 5. Controles: Play/Pause, velocidad, timeline scrubber ### 9.3 Compartir - Código único de replay (basado en session_id) - URL compartible: `/replay/{code}` --- ## 10. Panel de Administración ### 10.1 Funcionalidades ``` ┌─────────────────────────────────────────────────────────────┐ │ PANEL ADMINISTRADOR │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 📊 Dashboard │ │ - Partidas activas en tiempo real │ │ - Estadísticas del día │ │ - Preguntas pendientes de aprobación │ │ │ │ ❓ Gestión de Preguntas │ │ - CRUD de preguntas por categoría │ │ - Generar con IA (botón por categoría/dificultad) │ │ - Cola de aprobación │ │ - Asignar a fechas │ │ - Importar/exportar CSV │ │ │ │ 📅 Calendario │ │ - Vista mensual de preguntas programadas │ │ - Alertas de días sin contenido │ │ │ │ 🎮 Monitor │ │ - Salas activas │ │ - Cerrar salas problemáticas │ │ │ │ ⚙️ Configuración │ │ - Tiempos y puntos por dificultad │ │ - Penalización de robo │ │ - API keys │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ### 10.2 Autenticación - Login con usuario/contraseña - JWT para sesiones - Rutas protegidas `/admin/*` --- ## 11. Comunicación en Partida ### 11.1 Chat de Equipo - Visible solo para miembros del mismo equipo - Mensajes en tiempo real via WebSocket - Historial durante la partida ### 11.2 Reacciones Globales - Emojis predefinidos que todos pueden ver - Limitado para evitar spam (1 cada 3 segundos) - Emojis disponibles: 👏 😮 😂 🔥 💀 🎉 😭 🤔 --- ## 12. Estructura del Proyecto ``` Trivy/ ├── backend/ │ ├── app/ │ │ ├── __init__.py │ │ ├── main.py │ │ ├── config.py │ │ ├── models/ │ │ │ ├── __init__.py │ │ │ ├── category.py │ │ │ ├── question.py │ │ │ ├── game_session.py │ │ │ ├── game_event.py │ │ │ └── admin.py │ │ ├── schemas/ │ │ │ ├── __init__.py │ │ │ ├── question.py │ │ │ ├── game.py │ │ │ └── admin.py │ │ ├── services/ │ │ │ ├── __init__.py │ │ │ ├── ai_validator.py │ │ │ ├── ai_generator.py │ │ │ ├── game_manager.py │ │ │ └── room_manager.py │ │ ├── api/ │ │ │ ├── __init__.py │ │ │ ├── admin.py │ │ │ ├── game.py │ │ │ └── replay.py │ │ └── sockets/ │ │ ├── __init__.py │ │ └── game_events.py │ ├── requirements.txt │ ├── Dockerfile │ ├── alembic.ini │ └── alembic/ │ └── versions/ │ ├── frontend/ │ ├── src/ │ │ ├── components/ │ │ │ ├── game/ │ │ │ │ ├── Board.tsx │ │ │ │ ├── QuestionCard.tsx │ │ │ │ ├── Timer.tsx │ │ │ │ ├── ScoreBoard.tsx │ │ │ │ └── AnswerInput.tsx │ │ │ ├── lobby/ │ │ │ │ ├── CreateRoom.tsx │ │ │ │ ├── JoinRoom.tsx │ │ │ │ ├── TeamSelect.tsx │ │ │ │ └── PlayerList.tsx │ │ │ ├── chat/ │ │ │ │ ├── TeamChat.tsx │ │ │ │ └── EmojiReactions.tsx │ │ │ ├── replay/ │ │ │ │ ├── ReplayPlayer.tsx │ │ │ │ └── ReplayControls.tsx │ │ │ ├── achievements/ │ │ │ │ ├── AchievementPopup.tsx │ │ │ │ └── AchievementList.tsx │ │ │ └── ui/ │ │ │ ├── Button.tsx │ │ │ ├── Modal.tsx │ │ │ ├── Input.tsx │ │ │ └── Toast.tsx │ │ ├── themes/ │ │ │ ├── ThemeProvider.tsx │ │ │ ├── index.ts │ │ │ ├── drrr/ │ │ │ ├── retro-arcade/ │ │ │ ├── minimal/ │ │ │ ├── gaming-rgb/ │ │ │ └── anime-90s/ │ │ ├── hooks/ │ │ │ ├── useSocket.ts │ │ │ ├── useGame.ts │ │ │ ├── useSound.ts │ │ │ └── useAchievements.ts │ │ ├── stores/ │ │ │ ├── gameStore.ts │ │ │ ├── themeStore.ts │ │ │ └── soundStore.ts │ │ ├── pages/ │ │ │ ├── Home.tsx │ │ │ ├── Lobby.tsx │ │ │ ├── Game.tsx │ │ │ ├── Replay.tsx │ │ │ ├── Results.tsx │ │ │ └── admin/ │ │ │ ├── Dashboard.tsx │ │ │ ├── Questions.tsx │ │ │ ├── Calendar.tsx │ │ │ ├── Monitor.tsx │ │ │ └── Settings.tsx │ │ ├── services/ │ │ │ ├── socket.ts │ │ │ └── api.ts │ │ ├── types/ │ │ │ └── index.ts │ │ ├── App.tsx │ │ └── main.tsx │ ├── public/ │ │ └── sounds/ │ ├── package.json │ ├── Dockerfile │ ├── vite.config.ts │ ├── tailwind.config.js │ └── tsconfig.json │ ├── docker-compose.yml ├── .env.example ├── .gitignore ├── README.md └── docs/ └── plans/ └── 2026-01-26-webtriviasmulti-design.md ``` --- ## 13. Despliegue ### 13.1 Docker Compose ```yaml version: '3.8' services: frontend: build: ./frontend ports: - "3000:3000" environment: - VITE_API_URL=http://localhost:8000 - VITE_WS_URL=ws://localhost:8000 backend: build: ./backend ports: - "8000:8000" environment: - DATABASE_URL=postgresql://trivia:trivia@db:5432/trivia - REDIS_URL=redis://redis:6379 - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - JWT_SECRET=${JWT_SECRET} depends_on: - db - redis db: image: postgres:15 volumes: - postgres_data:/var/lib/postgresql/data environment: - POSTGRES_DB=trivia - POSTGRES_USER=trivia - POSTGRES_PASSWORD=trivia redis: image: redis:7-alpine volumes: - redis_data:/data cloudflared: image: cloudflare/cloudflared:latest command: tunnel run environment: - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN} depends_on: - frontend - backend volumes: postgres_data: redis_data: ``` ### 13.2 Variables de Entorno ```env # Backend DATABASE_URL=postgresql://trivia:trivia@db:5432/trivia REDIS_URL=redis://redis:6379 ANTHROPIC_API_KEY=sk-ant-... JWT_SECRET=your-secret-key # Frontend VITE_API_URL=https://trivia.tudominio.com/api VITE_WS_URL=wss://trivia.tudominio.com # Cloudflare CLOUDFLARE_TUNNEL_TOKEN=your-tunnel-token ``` --- ## 14. Roadmap Futuro ### Fase 3 - Competitivo - Ranking global (requiere cuentas opcionales) - Torneos programados - Temporadas con recompensas ### Fase 4 - Social - Compartir resultados en redes - Salas recurrentes - Desafíos diarios ### Fase 5 - Contenido - Categorías rotativas por eventos - Preguntas de la comunidad - Modo "Experto" ### Fase 6 - Técnico - PWA instalable - API pública - Modo offline --- ## 15. Referencias - [FastAPI Documentation](https://fastapi.tiangolo.com/) - [Socket.IO](https://socket.io/) - [Anthropic Claude API](https://docs.anthropic.com/) - [React](https://react.dev/) - [Tailwind CSS](https://tailwindcss.com/) - [Framer Motion](https://www.framer.com/motion/) --- *Documento generado el 2026-01-26*