# API Reference - Trivy ## Base URL ``` http://localhost:8000/api ``` ## Autenticación El panel de administración usa autenticación básica HTTP. ```bash # Ejemplo con curl curl -u admin:admin123 http://localhost:8000/api/admin/questions ``` --- ## Endpoints REST ### Game #### GET /game/categories Obtiene todas las categorías disponibles. **Response:** ```json [ { "id": 1, "name": "Nintendo", "icon": "🍄", "color": "#E60012" }, { "id": 2, "name": "Xbox", "icon": "🎮", "color": "#107C10" } ] ``` #### GET /game/today-questions Obtiene las preguntas activas para hoy (sin respuestas). **Response:** ```json { "1": [ { "id": 1, "category_id": 1, "question_text": "¿En qué año se lanzó la NES?", "difficulty": 1, "points": 100, "time_seconds": 15 } ] } ``` --- ### Admin - Preguntas #### GET /admin/questions Lista todas las preguntas. **Query Parameters:** - `status` (optional): `pending`, `approved`, `used` - `category_id` (optional): ID de categoría **Response:** ```json [ { "id": 1, "category_id": 1, "question_text": "¿En qué año se lanzó la NES?", "correct_answer": "1983", "alt_answers": ["1984"], "difficulty": 1, "points": 100, "time_seconds": 15, "date_active": "2024-01-26", "status": "approved", "fun_fact": "La NES salvó la industria del videojuego", "created_at": "2024-01-25T10:00:00Z" } ] ``` #### POST /admin/questions Crea una nueva pregunta. **Request Body:** ```json { "category_id": 1, "question_text": "¿Cuál es el nombre del fontanero de Nintendo?", "correct_answer": "Mario", "alt_answers": ["Super Mario"], "difficulty": 1, "points": 100, "time_seconds": 15, "date_active": "2024-01-26", "status": "approved", "fun_fact": "Mario apareció por primera vez en Donkey Kong" } ``` **Response:** `201 Created` #### PUT /admin/questions/{id} Actualiza una pregunta existente. #### DELETE /admin/questions/{id} Elimina una pregunta. --- ### Admin - Categorías #### GET /admin/categories Lista todas las categorías. #### POST /admin/categories Crea una nueva categoría. **Request Body:** ```json { "name": "Ciencia", "icon": "🔬", "color": "#00BCD4" } ``` --- ### Admin - Salas #### GET /admin/rooms/active Obtiene las salas activas en Redis. **Response:** ```json [ { "code": "ABC123", "status": "playing", "host": "Player1", "teams": { "A": [{"name": "Player1", "team": "A"}], "B": [{"name": "Player2", "team": "B"}] }, "scores": {"A": 500, "B": 300}, "current_team": "A" } ] ``` --- ## WebSocket Events ### Conexión ```javascript import { io } from 'socket.io-client'; const socket = io('http://localhost:8000', { transports: ['websocket', 'polling'] }); ``` --- ### Eventos Cliente → Servidor #### create_room Crea una nueva sala de juego. ```javascript socket.emit('create_room', { player_name: 'MiNombre' }); ``` #### join_room Unirse a una sala existente. ```javascript socket.emit('join_room', { room_code: 'ABC123', player_name: 'MiNombre', team: 'A' // o 'B' }); ``` #### change_team Cambiar de equipo en el lobby. ```javascript socket.emit('change_team', { team: 'B' }); ``` #### start_game Iniciar el juego (solo host). ```javascript socket.emit('start_game', {}); ``` #### select_question Seleccionar una pregunta del tablero. ```javascript socket.emit('select_question', { question_id: 1, category_id: 1 }); ``` #### submit_answer Enviar respuesta a la pregunta actual. ```javascript socket.emit('submit_answer', { answer: 'Mi respuesta', question: { /* objeto pregunta */ }, is_steal: false }); ``` #### steal_decision Decidir si intentar robar. ```javascript socket.emit('steal_decision', { attempt: true, // o false para pasar question_id: 1, answer: 'Mi respuesta' // solo si attempt=true }); ``` #### chat_message Enviar mensaje al chat general. ```javascript socket.emit('chat_message', { message: 'Hola a todos!' }); ``` #### team_message Enviar mensaje al chat de equipo. ```javascript socket.emit('team_message', { room_code: 'ABC123', team: 'A', player_name: 'MiNombre', message: 'Mensaje privado del equipo' }); ``` #### send_reaction Enviar reacción emoji. ```javascript socket.emit('send_reaction', { emoji: '🎉', room_code: 'ABC123', player_name: 'MiNombre' }); ``` --- ### Eventos Servidor → Cliente #### room_created Confirmación de sala creada. ```javascript socket.on('room_created', (data) => { console.log(data.room.code); // 'ABC123' }); ``` **Payload:** ```json { "room": { "code": "ABC123", "status": "waiting", "host": "Player1", "teams": {"A": [...], "B": []}, "scores": {"A": 0, "B": 0} } } ``` #### player_joined Un jugador se unió a la sala. ```javascript socket.on('player_joined', (data) => { console.log('Nuevo jugador:', data.room.teams); }); ``` #### player_left Un jugador abandonó la sala. ```javascript socket.on('player_left', (data) => { console.log('Jugador salió'); }); ``` #### game_started El juego ha comenzado. ```javascript socket.on('game_started', (data) => { // data.room.board contiene el tablero con las preguntas console.log('Categorías:', Object.keys(data.room.board)); }); ``` **Payload:** ```json { "room": { "status": "playing", "board": { "1": [ { "id": 1, "question_text": "...", "difficulty": 1, "points": 100, "answered": false } ] }, "current_team": "A", "current_player_index": {"A": 0, "B": 0} } } ``` #### question_selected Se seleccionó una pregunta. ```javascript socket.on('question_selected', (data) => { console.log('Pregunta:', data.question_id); }); ``` #### answer_result Resultado de una respuesta. ```javascript socket.on('answer_result', (data) => { if (data.valid) { console.log('¡Correcto! +', data.points_earned); } else { console.log('Incorrecto:', data.reason); } }); ``` **Payload:** ```json { "valid": true, "reason": "Respuesta correcta", "points_earned": 100, "was_steal": false, "room": { /* estado actualizado */ } } ``` #### steal_prompt Oportunidad de robo disponible. ```javascript socket.on('steal_prompt', (data) => { console.log('¡Puedes robar!'); }); ``` #### game_finished El juego ha terminado. ```javascript socket.on('game_finished', (data) => { console.log('Ganador:', data.winner); console.log('Puntuación final:', data.room.scores); }); ``` #### new_reaction Nueva reacción de un jugador. ```javascript socket.on('new_reaction', (data) => { console.log(data.player_name, 'reaccionó con', data.emoji); }); ``` #### team_message Mensaje de chat de equipo. ```javascript socket.on('team_message', (data) => { console.log(`[Equipo] ${data.player_name}: ${data.message}`); }); ``` #### error Error del servidor. ```javascript socket.on('error', (data) => { console.error('Error:', data.message); }); ``` --- ## Códigos de Error | Código | Mensaje | Descripción | |--------|---------|-------------| | `room_not_found` | Room not found | La sala no existe | | `room_full` | Room is full | La sala está llena | | `not_host` | Only the host can start | Solo el host puede iniciar | | `need_players` | Both teams need players | Ambos equipos necesitan jugadores | | `not_your_turn` | Not your turn | No es tu turno | | `question_answered` | Question already answered | Pregunta ya contestada | --- ## Rate Limiting - API REST: 100 requests/minuto por IP - WebSocket: Sin límite específico (controlado por lógica de juego) ## Timeouts - Preguntas: 15-35 segundos según dificultad - Robo: 50% del tiempo original - Sala inactiva: 3 horas (configurable)