apiVersion: v1 kind: ConfigMap metadata: name: {{ include "invy.fullname" . }}-db-schema labels: {{- include "invy.labels" . | nindent 4 }} app.kubernetes.io/component: database data: init.sql: | -- Invy — Full Database Init Schema -- Runs only on a FRESH (empty) data directory. -- For existing production DBs run migrate_production.sql manually. CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- ── Users ────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), email TEXT NOT NULL UNIQUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); -- ── Events ───────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS events ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name TEXT NOT NULL, date TIMESTAMP WITH TIME ZONE, location TEXT, partner1_name TEXT, partner2_name TEXT, venue TEXT, event_time TEXT, guest_link TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_events_created_at ON events(created_at); CREATE INDEX IF NOT EXISTS idx_events_guest_link ON events(guest_link); -- ── Event members (authorization) ────────────────────────────────────── CREATE TABLE IF NOT EXISTS event_members ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, role TEXT NOT NULL DEFAULT 'admin' CHECK (role IN ('admin', 'editor', 'viewer')), display_name TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, UNIQUE(event_id, user_id) ); CREATE INDEX IF NOT EXISTS idx_event_members_event_id ON event_members(event_id); CREATE INDEX IF NOT EXISTS idx_event_members_user_id ON event_members(user_id); CREATE INDEX IF NOT EXISTS idx_event_members_event_user ON event_members(event_id, user_id); -- ── Guests v2 ────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS guests_v2 ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE, added_by_user_id UUID NOT NULL REFERENCES users(id), first_name TEXT NOT NULL, last_name TEXT NOT NULL DEFAULT '', email TEXT, phone TEXT, phone_number TEXT, rsvp_status TEXT NOT NULL DEFAULT 'invited' CHECK (rsvp_status IN ('invited', 'confirmed', 'declined')), meal_preference TEXT, has_plus_one BOOLEAN DEFAULT FALSE, plus_one_name TEXT, table_number TEXT, side TEXT, owner_email TEXT, source TEXT NOT NULL DEFAULT 'manual' CHECK (source IN ('google', 'manual', 'self-service')), notes TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_guests_v2_event_id ON guests_v2(event_id); CREATE INDEX IF NOT EXISTS idx_guests_v2_added_by ON guests_v2(added_by_user_id); CREATE INDEX IF NOT EXISTS idx_guests_v2_phone_number ON guests_v2(phone_number); CREATE INDEX IF NOT EXISTS idx_guests_v2_event_phone ON guests_v2(event_id, phone_number); CREATE INDEX IF NOT EXISTS idx_guests_v2_event_status ON guests_v2(event_id, rsvp_status); CREATE INDEX IF NOT EXISTS idx_guests_v2_owner_email ON guests_v2(event_id, owner_email); CREATE INDEX IF NOT EXISTS idx_guests_v2_source ON guests_v2(event_id, source); -- ── RSVP tokens ──────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS rsvp_tokens ( token TEXT PRIMARY KEY, event_id UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE, guest_id UUID REFERENCES guests_v2(id) ON DELETE SET NULL, phone TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP WITH TIME ZONE, used_at TIMESTAMP WITH TIME ZONE ); CREATE INDEX IF NOT EXISTS idx_rsvp_tokens_event_id ON rsvp_tokens(event_id); CREATE INDEX IF NOT EXISTS idx_rsvp_tokens_guest_id ON rsvp_tokens(guest_id); -- ── updated_at trigger ───────────────────────────────────────────────── CREATE OR REPLACE FUNCTION _update_updated_at() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$; DO $$ BEGIN CREATE TRIGGER trg_guests_v2_updated_at BEFORE UPDATE ON guests_v2 FOR EACH ROW EXECUTE FUNCTION _update_updated_at(); EXCEPTION WHEN duplicate_object THEN NULL; END $$; DO $$ BEGIN CREATE TRIGGER trg_events_updated_at BEFORE UPDATE ON events FOR EACH ROW EXECUTE FUNCTION _update_updated_at(); EXCEPTION WHEN duplicate_object THEN NULL; END $$;