Datos al 23 de octubre de 2026: 69 tablas en producción y 34 migraciones. Las migraciones de este repositorio crean 39 de esas tablas. Las otras 30, como
players, seasons y season_player_stats, no las crea ninguna migración: las migraciones solo las referencian o las modifican. Las migraciones son la fuente de verdad: si algo no coincide con esta página, manda el SQL.Mapa por áreas
Convenciones
- Las claves primarias son
uuidgenerados congen_random_uuid(), salvo claves naturales comoslug,ticketoevent_id. - Las fechas son
timestamptz. - Los estados son
textcon una restricciónCHECKque lista los valores permitidos. - Los datos de demostración llevan
is_demo = truey se pueden ocultar con ese filtro. - Los nombres de columnas mezclan español e inglés, según la migración que los creó.
Plataforma de torneos
Catálogo público con prefijopt_ (migraciones 28 y 29). Lo lee la API pública y es independiente de los torneos propios de VANTS. Cada torneo, partida y jugador indica su origen en source.
El diagrama muestra solo las columnas principales. Tres detalles que conviene conocer:
pt_matches.equipo_ayequipo_bguardan el nombre del equipo como texto, no una clave foránea.pt_players.team_slugapunta apt_teams.slugsin clave foránea, así que borrar un equipo no toca a sus jugadores.- Torneos, partidas y jugadores son únicos por (
source,external_id), lo que permite importar datos externos sin duplicarlos.
pt_games: valorant, cs2 y dota2 están activos; lol, r6s y cod existen pero están inactivos. No se puede borrar un juego que tenga torneos o partidas.
Torneos de VANTS y presencia
Los torneos propios de VANTS usan sus propias tablas (migración 17).tournament_id es un identificador de texto, no una clave foránea a pt_torneos.
tournament_teams guarda las inscripciones.
tournament_matches guarda el cuadro. Cada fila es única por (tournament_id, ronda, slot).
Cuadro de 8 equipos
El cuadro es de doble eliminación. Cuando un torneo llega a 8 equipos confirmados, un trigger lo siembra una sola vez: los 8 primeros por orden de inscripción forman los 4 cruces de cuartos y se crean vacías el resto de partidas. Con menos de 8 equipos confirmados no hay cuadro. Al marcar una partida comofinal con su ganador, otro trigger mueve a los equipos:
La gran final (
f, slot 0) cierra el cuadro. Si un equipo no avanza solo, el propietario puede colocarlo a mano.
Presencia
presence tiene una fila por jugador conectado.
La web y la app de escritorio envían un latido cada 60 segundos.
Vistas
Para mostrar datos públicos usa estas vistas en lugar de las tablas.Matchmaking
El matchmaking persiste la cola en Postgres (migraciones 21 a 24, 30 a 32) para que sobreviva a los reinicios y el emparejamiento sea transaccional. Cada fila guarda además la identidad del jugador; esas columnas no se detallan aquí.mm_tickets.match_id no es una clave foránea: es la referencia a la partida a la que se asignó el ticket.
Modos
Cada ticket indica
game, mode y region (por defecto EU). Un jugador solo puede tener un ticket activo por juego. El emparejador toma los primeros jugadores de la cola por orden de llegada (FIFO) y crea la partida solo si hay exactamente los necesarios, sin bloquear a otros emparejadores en paralelo.
Estados
Ticket: Partida:propuesto: el emparejador creó la partida y fijóready_deadlinea 120 segundos.reportadoyverificado: un participante reporta el marcador, se aplica el RR a cada jugador y se guardanrr_beforeyrr_after. Aplicar el resultado es idempotente.anulado: venció el plazo sin que todos confirmaran. La anulación es perezosa: la dispara el primer participante que consulta la partida después del plazo. Los tickets quedan como historial y los jugadores pueden volver a ponerse en cola.
Invitaciones
mm_invites guarda invitaciones entre jugadores para jugar duo o team. Caducan a los 10 minutos y pasan de pendiente a aceptada, rechazada, cancelada o expirada. Solo puede haber una pendiente por pareja de jugadores y juego.
Funciones
El cliente web y la app de escritorio usan las mismas funciones SQL, de modo que hay una sola fuente de verdad.
La vista
mm_historial reúne, por jugador, las partidas en las que participó, con su equipo, el marcador, el RR antes y después y el resultado.
Ranked y FACEIT
Escala de rango
El rango se calcula a partir del rating del jugador. El RR que se muestra es el rating multiplicado por 100.
La web de vants-dev-launcher muestra el rango VANTS con el nombre APEX. La web de Vantsgames no muestra estos nombres: en
/ranking#rangos presenta VANTS RANKED, una escalera de 9 rangos por XP que va de CENIZA (0 XP) a SUPREMO (8000 XP) en pasos de 1000 XP. Está definida en vants-server/public/ranking.html y vants-server/public/static/js/perfil_pagina.js.
Sin rating no hay rango y el jugador está en partidas de colocación, que parten de 0.95. Las partidas de FACEIT y las internas aplican la misma regla (migraciones 10 y 22):
El rating siempre queda entre 0.50 y 1.60.
Series
series_ranked guarda series entre un retador y un rival. Las reporta un jugador y las confirma el rival o el propietario (pendiente, confirmada o rechazada). Al confirmarse, se aplica el Elo a players.rating y se actualizan victorias, derrotas, MMR y rango en season_player_stats. La tabla guarda el rating de ambos antes y después. Las funciones son reportar_serie, confirmar_serie, rechazar_serie y mis_series.
FACEIT
faceit_matches: una fila por partida de FACEIT ya procesada.faceit_match_ides único, así que una partida nunca da XP dos veces. Guardaresult(win,lossodraw),xp_awardedyelo_delta.faceit_webhook_events: eventos crudos que llegan por webhook, con supayloady la marcaprocessed. Las funcionesfaceit_procesar_eventosyfaceit_aplicar_resultadolos convierten en partidas.
1 + floor(xp / 500). El procesador soporta cs2 (csgo se normaliza a cs2) y valorant.
Historial de RR
rr_historial registra cada cambio de rating, venga de donde venga.
Es única por (
player_id, fuente, partida_id), así que repetir una llamada no duplica líneas. Las vistas rr_historial_jugador y rr_resumen leen de ella, y rr_temporada_actual devuelve la temporada vigente.
Bus de eventos
Los proyectos de VANTS se comunican con eventos inmutables (migraciones 33 y 34). El diagrama sigue un resultado de FACEIT desdefaceit_webhook_events (migración 09) hasta quienes leen el bus. En mayúsculas aparece lo que no es una tabla: FACEIT y los cursores de flask-agents y de VANTS HUB, que cada uno guarda en un archivo local.
Tipos de evento de ejemplo:
match.finished, clip.published y alert.detected.
Agente
El agente vigila la plataforma y deja su trabajo en estas tablas (migraciones 25 y 26).
La vista
agent_resumen cuenta las incidencias abiertas, los comandos pendientes y el estado de la última ejecución. La vista agent_memoria_resumen cuenta los recuerdos, los archivos y las ejecuciones.
Bot y eventos web
Tablas de la migración 02 y de la migración 01.
El detalle de los comandos del bot está en Bot de Discord.
Otras tablas
Hay además tablas en producción que ninguna migración crea. Por su nombre, parecen pertenecer a estas áreas. Revisa la base de datos antes de depender de ellas:- Soporte:
support_tickets,support_ticket_messages,tickets. - Eventos y comunidad:
events,event_rsvps,postulaciones. - Pase y planes:
pass_progreso,pass_recompensas,plan_content. - Ranked:
ranked_rules,ranked_matches,ranked_history. - Torneos e inscripciones:
tournaments,tournament_entries.
Cómo añadir una migración
Crea un archivo nuevo endb/migrations/ con el siguiente número y escríbelo de forma idempotente. El flujo completo, con pruebas en una rama de Neon, está en VantsBasededatos.
Más información
- VantsBasededatos: estructura del repositorio y flujo de trabajo
- API pública: rutas que leen estas tablas
- Arquitectura: cómo encaja la base de datos con el resto de VANTS
- vants-faceit-webhook: origen de los eventos de FACEIT