-- Nachklang e.V. Tickets module — initial schema for TICKETS_DB -- Apply manually against the TICKETS_DB database (separate from CALENDAR_DB -- and FEEDBACK_DB). See nachklang-tickets/docs/plan-ticket-shop.md for the -- full design rationale. -- -- Apply with e.g.: -- mysql -h -u -p < 001_init.sql -- -- Deliberately no USE statement here: the target database is selected via -- the mysql command line above (whatever TICKETS_DB is actually named in -- .env), not hardcoded to a literal schema name. -- -- `event_id` columns below refer to Calendar's `events.event_id` (a -- different database). Deliberately no cross-database foreign key — -- Tickets reads Calendar events via events.service.ts in the same Node -- process, not via a DB-level join. -- 1. voucher_codes -------------------------------------------------------- CREATE TABLE voucher_codes ( code VARCHAR(12) NOT NULL PRIMARY KEY, status ENUM('UNUSED','REDEEMED','VOID') NOT NULL DEFAULT 'UNUSED', max_guests INT NOT NULL DEFAULT 2, prefill_name VARCHAR(255) NULL, prefill_email VARCHAR(255) NULL, batch_id VARCHAR(36) NULL, created_by_email VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, KEY idx_vc_batch (batch_id), KEY idx_vc_status (status) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 2. voucher_code_events (join: which concerts a code may be redeemed for) - CREATE TABLE voucher_code_events ( voucher_code_event_id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(12) NOT NULL, event_id INT NOT NULL, CONSTRAINT fk_vce_code FOREIGN KEY (code) REFERENCES voucher_codes(code) ON DELETE CASCADE, UNIQUE KEY uq_vce_code_event (code, event_id), KEY idx_vce_event (event_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 3. event_ticket_settings (per-concert voucher config) --------------------- -- One row per Calendar event_id that has ever had voucher settings -- configured. Absent row == uncapped, no deadline, address not collected -- (see docs/plan-ticket-shop.md — "absence over sentinels"). CREATE TABLE event_ticket_settings ( event_id INT NOT NULL PRIMARY KEY, capacity INT NULL, redemption_deadline DATETIME NULL, collect_address TINYINT(1) NOT NULL DEFAULT 0, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 4. redemptions ------------------------------------------------------------ -- `status` is soft-state rather than a hard delete on undo, so guest data -- and history survive an undo for the audit trail. Capacity/reporting -- queries filter status = 'ACTIVE'. A code that gets redeemed again after -- being undone creates a new row here rather than reviving the old one. CREATE TABLE redemptions ( redemption_id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(12) NOT NULL, event_id INT NOT NULL, status ENUM('ACTIVE','UNDONE') NOT NULL DEFAULT 'ACTIVE', contact_name VARCHAR(255) NOT NULL, contact_email VARCHAR(255) NOT NULL, contact_address TEXT NULL, guest_count INT NOT NULL, redeemed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_red_code FOREIGN KEY (code) REFERENCES voucher_codes(code), KEY idx_red_event_status (event_id, status), KEY idx_red_code (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 5. redemption_guests -------------------------------------------------------- -- One row per attendee, including the primary contact (position 0). CREATE TABLE redemption_guests ( redemption_guest_id INT AUTO_INCREMENT PRIMARY KEY, redemption_id INT NOT NULL, name VARCHAR(255) NOT NULL, position INT NOT NULL DEFAULT 0, CONSTRAINT fk_rg_redemption FOREIGN KEY (redemption_id) REFERENCES redemptions(redemption_id) ON DELETE CASCADE, KEY idx_rg_redemption (redemption_id, position) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 6. voucher_audit_log ---------------------------------------------------- -- Lightweight admin-action history per code (not a full version-history -- system) — who did what and why. Covers EDIT/VOID/UNDO only; the guest's -- own redemption isn't an admin action so it isn't logged here (it's -- already timestamped on `redemptions.redeemed_at`). CREATE TABLE voucher_audit_log ( audit_id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(12) NOT NULL, redemption_id INT NULL, admin_email VARCHAR(255) NOT NULL, action ENUM('EDIT','VOID','UNDO') NOT NULL, change_summary JSON NULL, reason VARCHAR(500) NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT fk_val_code FOREIGN KEY (code) REFERENCES voucher_codes(code) ON DELETE CASCADE, CONSTRAINT fk_val_redemption FOREIGN KEY (redemption_id) REFERENCES redemptions(redemption_id) ON DELETE SET NULL, KEY idx_val_code_time (code, created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;