package main import ( "database/sql" "log" "strings" ) func runMigrations(database *sql.DB) { migrations := []string{ `ALTER TABLE events ADD COLUMN description TEXT DEFAULT ''`, `ALTER TABLE events ADD COLUMN user_id INTEGER REFERENCES users(id)`, // Users may have email, phone, or both. Add whichever column is missing. `ALTER TABLE users ADD COLUMN phone TEXT UNIQUE`, `ALTER TABLE users ADD COLUMN email TEXT UNIQUE`, // Verification codes use a generic identifier column. `ALTER TABLE verification_codes ADD COLUMN identifier TEXT NOT NULL DEFAULT ''`, // Indexes for auth tables (created here so they run after column migrations). `CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id)`, `CREATE INDEX IF NOT EXISTS idx_verification_codes_identifier ON verification_codes(identifier)`, // Dedupe RSVPs: keep earliest per (event_id, name). `DELETE FROM rsvps WHERE id NOT IN (SELECT MIN(id) FROM rsvps GROUP BY event_id, name COLLATE NOCASE)`, // Plus-one tracking for RSVPs. `ALTER TABLE rsvps ADD COLUMN plus_one INTEGER NOT NULL DEFAULT 0`, // Drop legacy phone/email columns from verification_codes. They were // NOT NULL with no default, so inserts using only identifier failed. `DROP INDEX IF EXISTS idx_verification_codes_phone`, `DROP INDEX IF EXISTS idx_verification_codes_email`, `ALTER TABLE verification_codes DROP COLUMN phone`, `ALTER TABLE verification_codes DROP COLUMN email`, // SMS consent logging for Twilio compliance. `CREATE TABLE IF NOT EXISTS sms_consents ( id INTEGER PRIMARY KEY AUTOINCREMENT, phone TEXT NOT NULL, ip_address TEXT NOT NULL DEFAULT '', user_agent TEXT NOT NULL DEFAULT '', created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP )`, } for _, m := range migrations { _, err := database.Exec(m) if err != nil { if strings.Contains(err.Error(), "duplicate column name") || strings.Contains(err.Error(), "no such column") { continue } log.Printf("migration warning: %v", err) } } }