CREATE TABLE IF NOT EXISTS guilds ( id BIGINT PRIMARY KEY NOT NULL, name TEXT, owner_id BIGINT, volume INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS dice_track ( id UUID PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), guild_id BIGINT NOT NULL, owner_id BIGINT NOT NULL, dice TEXT NOT NULL, user_id BIGINT, value INT, operator TEXT ); CREATE TABLE IF NOT EXISTS events ( id UUID PRIMARY KEY NOT NULL, guild_id BIGINT NOT NULL, author_id BIGINT NOT NULL, title TEXT NOT NULL, date_time TIMESTAMP NOT NULL, description TEXT, rsvp BIGINT[] NOT NULL ); CREATE TABLE IF NOT EXISTS races ( id INTEGER GENERATED ALWAYS AS IDENTITY, name TEXT NOT NULL, size TEXT NOT NULL, source TEXT NOT NULL, data JSON NOT NULL ); CREATE TABLE IF NOT EXISTS classes ( id INTEGER GENERATED ALWAYS AS IDENTITY ); CREATE TABLE IF NOT EXISTS feats ( id INTEGER GENERATED ALWAYS AS IDENTITY ); CREATE TABLE IF NOT EXISTS options_features ( id INTEGER GENERATED ALWAYS AS IDENTITY ); CREATE TABLE IF NOT EXISTS backgrounds ( id INTEGER GENERATED ALWAYS AS IDENTITY ); CREATE TABLE IF NOT EXISTS items ( id INTEGER GENERATED ALWAYS AS IDENTITY ); CREATE TABLE IF NOT EXISTS spells ( id INTEGER GENERATED ALWAYS AS IDENTITY, name TEXT NOT NULL, school TEXT NOT NULL, level INTEGER NOT NULL, ritual BOOLEAN DEFAULT FALSE, concentration BOOLEAN DEFAULT FALSE, classes TEXT[] NOT NULL, damage_inflict TEXT[] NOT NULL, damage_resist TEXT[] NOT NULL, conditions TEXT[] NOT NULL, saving_throw TEXT[] NOT NULL, attack_type TEXT, data JSONB NOT NULL ); CREATE TABLE IF NOT EXISTS conditions ( id INTEGER GENERATED ALWAYS AS IDENTITY ); CREATE TABLE IF NOT EXISTS bestiary ( id INTEGER GENERATED ALWAYS AS IDENTITY ); -- ============================================================ -- Auth / Users -- ============================================================ -- Stores Discord user info, upserted on every successful OAuth login CREATE TABLE IF NOT EXISTS users ( id BIGINT PRIMARY KEY NOT NULL, username TEXT NOT NULL, avatar TEXT, created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW() ); -- ============================================================ -- Grid maps: unbounded canvas, CSPRNG TEXT ids, auth-aware -- ============================================================ CREATE TABLE IF NOT EXISTS grid_maps ( id TEXT PRIMARY KEY NOT NULL, name TEXT NOT NULL, is_public BOOLEAN NOT NULL DEFAULT FALSE, owner_id BIGINT NOT NULL REFERENCES users(id), colors TEXT[] NOT NULL DEFAULT ARRAY[ '#6b7280', '#92400e', '#15803d', '#1d4ed8', '#7c3aed', '#dc2626', '#ca8a04', '#0f172a', '#f9fafb' ], created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW() ); -- Per-map role assignments; owner is auto-inserted on map creation CREATE TABLE IF NOT EXISTS map_permissions ( map_id TEXT NOT NULL REFERENCES grid_maps(id) ON DELETE CASCADE, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, role TEXT NOT NULL CHECK (role IN ('owner', 'editor', 'viewer')), PRIMARY KEY (map_id, user_id) ); -- Composite primary key replaces the old UUID id column CREATE TABLE IF NOT EXISTS grid_cells ( map_id TEXT NOT NULL REFERENCES grid_maps(id) ON DELETE CASCADE, x INTEGER NOT NULL, y INTEGER NOT NULL, color TEXT NOT NULL DEFAULT '#808080', PRIMARY KEY (map_id, x, y) ); CREATE TABLE IF NOT EXISTS grid_tokens ( id TEXT PRIMARY KEY NOT NULL, map_id TEXT NOT NULL REFERENCES grid_maps(id) ON DELETE CASCADE, x INTEGER NOT NULL, y INTEGER NOT NULL, label TEXT NOT NULL, color TEXT NOT NULL DEFAULT '#4444FF' );