package database import ( "context" "fmt" ) // migrateSchool creates school management tables: schools, classes, // students, teachers, parents, timetable, attendance, grades, // class diary, parent meetings, Matrix integration (Phase 9). func migrateSchool(db *DB) error { ctx := context.Background() migrations := []string{ // ============================================= // Phase 9: Schulverwaltung / School Management // Matrix-basierte Kommunikation für Schulen // ============================================= // Schools table `CREATE TABLE IF NOT EXISTS schools ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name VARCHAR(255) NOT NULL, short_name VARCHAR(50), type VARCHAR(50) NOT NULL, address TEXT, city VARCHAR(100), postal_code VARCHAR(20), state VARCHAR(50), country VARCHAR(2) DEFAULT 'DE', phone VARCHAR(50), email VARCHAR(255), website VARCHAR(255), matrix_server_name VARCHAR(255), logo_url TEXT, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() )`, // School years `CREATE TABLE IF NOT EXISTS school_years ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), school_id UUID NOT NULL REFERENCES schools(id) ON DELETE CASCADE, name VARCHAR(20) NOT NULL, start_date DATE NOT NULL, end_date DATE NOT NULL, is_current BOOLEAN DEFAULT FALSE, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(school_id, name) )`, // Subjects `CREATE TABLE IF NOT EXISTS subjects ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), school_id UUID NOT NULL REFERENCES schools(id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, short_name VARCHAR(10) NOT NULL, color VARCHAR(7), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(school_id, short_name) )`, // Classes `CREATE TABLE IF NOT EXISTS classes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), school_id UUID NOT NULL REFERENCES schools(id) ON DELETE CASCADE, school_year_id UUID NOT NULL REFERENCES school_years(id) ON DELETE CASCADE, name VARCHAR(20) NOT NULL, grade INT NOT NULL, section VARCHAR(5), room VARCHAR(50), matrix_info_room VARCHAR(255), matrix_rep_room VARCHAR(255), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(school_id, school_year_id, name) )`, // Students `CREATE TABLE IF NOT EXISTS students ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), school_id UUID NOT NULL REFERENCES schools(id) ON DELETE CASCADE, class_id UUID NOT NULL REFERENCES classes(id) ON DELETE CASCADE, user_id UUID REFERENCES users(id) ON DELETE SET NULL, student_number VARCHAR(50), first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, date_of_birth DATE, gender VARCHAR(1), matrix_user_id VARCHAR(255), matrix_dm_room VARCHAR(255), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() )`, // Teachers `CREATE TABLE IF NOT EXISTS teachers ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), school_id UUID NOT NULL REFERENCES schools(id) ON DELETE CASCADE, user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, teacher_code VARCHAR(10), title VARCHAR(20), first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, matrix_user_id VARCHAR(255), is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(school_id, user_id) )`, // Class teachers assignment `CREATE TABLE IF NOT EXISTS class_teachers ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), class_id UUID NOT NULL REFERENCES classes(id) ON DELETE CASCADE, teacher_id UUID NOT NULL REFERENCES teachers(id) ON DELETE CASCADE, is_primary BOOLEAN DEFAULT FALSE, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(class_id, teacher_id) )`, // Teacher subjects assignment `CREATE TABLE IF NOT EXISTS teacher_subjects ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), teacher_id UUID NOT NULL REFERENCES teachers(id) ON DELETE CASCADE, subject_id UUID NOT NULL REFERENCES subjects(id) ON DELETE CASCADE, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(teacher_id, subject_id) )`, // Parents `CREATE TABLE IF NOT EXISTS parents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, matrix_user_id VARCHAR(255), first_name VARCHAR(100) NOT NULL, last_name VARCHAR(100) NOT NULL, phone VARCHAR(50), emergency_contact BOOLEAN DEFAULT FALSE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(user_id) )`, // Student-parent relationships `CREATE TABLE IF NOT EXISTS student_parents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), student_id UUID NOT NULL REFERENCES students(id) ON DELETE CASCADE, parent_id UUID NOT NULL REFERENCES parents(id) ON DELETE CASCADE, relationship VARCHAR(20) NOT NULL, is_primary BOOLEAN DEFAULT FALSE, has_custody BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(student_id, parent_id) )`, // Parent representatives `CREATE TABLE IF NOT EXISTS parent_representatives ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), class_id UUID NOT NULL REFERENCES classes(id) ON DELETE CASCADE, parent_id UUID NOT NULL REFERENCES parents(id) ON DELETE CASCADE, role VARCHAR(20) NOT NULL, elected_at TIMESTAMPTZ NOT NULL, expires_at TIMESTAMPTZ, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ DEFAULT NOW() )`, } for _, migration := range migrations { if _, err := db.Pool.Exec(ctx, migration); err != nil { return fmt.Errorf("migrateSchool: %w", err) } } // Run the second batch (timetable, attendance, grades, etc.) return migrateSchoolPart2(db) }