Database Schema¶
Esta página se mejorará con alguna alternativa más bonita y legible
El schema está diseñado para PostgreSQL. Las relaciones son explícitas mediante claves foráneas y los ENUMs de PostgreSQL se usan para campos de estado — más eficientes que VARCHAR y autodocumentados.
rarities¶
id UUID PRIMARY KEY
name VARCHAR UNIQUE NOT NULL -- COMMON, UNCOMMON, RARE, LEGENDARY, MYTHIC
multiplier DECIMAL(4,2) NOT NULL -- 1.0, 1.3, 1.8, 2.5, 3.5
recycle_value INTEGER NOT NULL -- 5, 15, 40, 120, 400
users¶
Gestionada por Spring Security. El campo password almacena el hash bcrypt.
id UUID PRIMARY KEY
username VARCHAR UNIQUE NOT NULL
email VARCHAR UNIQUE NOT NULL
password VARCHAR NOT NULL
coins INTEGER DEFAULT 0
last_reward TIMESTAMP DEFAULT '2000-01-01'
created_at TIMESTAMP DEFAULT now()
base_cards¶
Define las cartas del juego. Cada carta tiene stats base y un rango de variación — el generador
Rust sortea entre stat_x_base y stat_x_base + stat_x_range al crear cada instancia, lo que
hace que dos cartas del mismo tipo sean ligeramente distintas.
id UUID PRIMARY KEY
name VARCHAR NOT NULL
stat_hp_min INTEGER NOT NULL
stat_hp_avg INTEGER NOT NULL
stat_hp_max INTEGER NOT NULL
stat_atk_min INTEGER NOT NULL
stat_atk_avg INTEGER NOT NULL
stat_atk_max INTEGER NOT NULL
stat_def_min INTEGER NOT NULL
stat_def_avg INTEGER NOT NULL
stat_def_max INTEGER NOT NULL
stat_spd_min INTEGER NOT NULL
stat_spd_avg INTEGER NOT NULL
stat_spd_max INTEGER NOT NULL
image_url VARCHAR
theme VARCHAR -- "space", "mythology", "summer_2025"...
contributed_by VARCHAR -- username del contribuidor de la comunidad
created_at TIMESTAMP DEFAULT now()
pack_types¶
Define los tipos de sobre disponibles. Un pack de temporada puede limitarse a un pool de cartas específico y desactivarse automáticamente por fecha — sin cambios en el código.
id UUID PRIMARY KEY
name VARCHAR UNIQUE NOT NULL
description VARCHAR
card_count INTEGER NOT NULL DEFAULT 5
cost INTEGER NOT NULL DEFAULT 25
available_from TIMESTAMP -- NULL = siempre disponible
available_until TIMESTAMP -- NULL = siempre disponible
created_at TIMESTAMP DEFAULT now()
| Pack | Cost | Probabilidades |
|---|---|---|
| BASIC | 100 coins | Common 60%, Uncommon 30%, Rare 8%, Legendary 1.5%, Mythic 0.5% |
| GOLD | 250 coins | Common 35%, Uncommon 35%, Rare 20%, Legendary 8%, Mythic 2% |
| PREMIUM | 600 coins | Common 10%, Uncommon 25%, Rare 35%, Legendary 22%, Mythic 8% |
pack_type_cards¶
Relaciona cada pack con las cartas que puede contener. Un pack de temporada solo incluye las cartas de ese tema. Añadir un pack nuevo es solo insertar filas aquí.
pack_type_id UUID REFERENCES pack_types(id)
base_card_id UUID REFERENCES base_cards(id)
PRIMARY KEY (pack_type_id, base_card_id)
El flujo de apertura de sobre: Java consulta esta tabla para obtener el pool de cartas válidas del pack, y se lo pasa a Rust junto con la seed. Rust solo sortea — no decide qué cartas pertenecen a qué pack.
pack_type_rarity_weights¶
Define las probabilidades de cada rareza para cada tipo de sobre.
pack_type_id UUID REFERENCES pack_types(id)
rarity_id UUID REFERENCES rarities(id)
weight DECIMAL(5,4) NOT NULL -- 0.6000, 0.3000, etc.
PRIMARY KEY (pack_type_id, rarity_id)
player_cards¶
Una sola tabla para todas las cartas de todos los jugadores. El índice en owner_id garantiza
que las consultas del tipo "dame las cartas de este jugador" no escaneen la tabla entera.
id UUID PRIMARY KEY
owner_id UUID REFERENCES users(id)
base_card_id UUID REFERENCES base_cards(id)
rarity_id UUID REFERENCES rarities(id)
stat_hp INTEGER NOT NULL
stat_atk INTEGER NOT NULL
stat_def INTEGER NOT NULL
stat_spd INTEGER NOT NULL
pack_seed BIGINT -- seed del sobre del que salió
obtained_at TIMESTAMP DEFAULT now()
INDEX idx_player_cards_owner (owner_id)
pack_opens¶
Historial de sobres abiertos. Guardar el seed permite reproducir exactamente cualquier apertura — útil para auditoría de fairness y para debuggear reportes de jugadores.
id UUID PRIMARY KEY
player_id UUID REFERENCES users(id)
pack_type_id UUID REFERENCES pack_types(id)
seed BIGINT NOT NULL
opened_at TIMESTAMP DEFAULT now()
Trading¶
ENUMs de estado para las tablas de trading:
CREATE TYPE trade_status AS ENUM ('OPEN', 'COMPLETED', 'CANCELLED');
CREATE TYPE offer_status AS ENUM ('PENDING', 'ACCEPTED', 'REJECTED');
trade_listings — "ofrezco X, quiero Y"¶
El primero que tenga la wanted_base_card y acepte ejecuta el swap atómico.
id UUID PRIMARY KEY
owner_id UUID REFERENCES users(id)
offered_card_id UUID REFERENCES player_cards(id)
wanted_base_card_id UUID REFERENCES base_cards(id)
status trade_status DEFAULT 'OPEN'
created_at TIMESTAMP DEFAULT now()
INDEX idx_listings_status (status)
INDEX idx_listings_wanted (wanted_base_card_id)
trade_requests — "quiero X, ¿qué me das?"¶
El dueño publica qué carta quiere y espera ofertas.
id UUID PRIMARY KEY
owner_id UUID REFERENCES users(id)
wanted_base_card_id UUID REFERENCES base_cards(id)
status trade_status DEFAULT 'OPEN'
created_at TIMESTAMP DEFAULT now()
trade_offers — respuestas a un request¶
Cuando el dueño acepta una oferta, el swap se ejecuta en una transacción y todas las demás ofertas de ese request pasan a REJECTED en la misma transacción. No se borran — se conservan para auditoría.
id UUID PRIMARY KEY
request_id UUID REFERENCES trade_requests(id)
offerer_id UUID REFERENCES users(id)
offered_card_id UUID REFERENCES player_cards(id)
status offer_status DEFAULT 'PENDING'
created_at TIMESTAMP DEFAULT now()
INDEX idx_offers_request (request_id)