Install LOC guardrails (check-loc.sh, architecture.md, pre-commit hook) and split all 44 files exceeding 500 LOC into domain-focused modules: - consent-service (Go): models, handlers, services, database splits - backend-core (Python): security_api, rbac_api, pdf_service, auth splits - admin-core (TypeScript): 5 page.tsx + sidebar extractions - pitch-deck (TypeScript): 6 slides, 3 UI components, engine.ts splits - voice-service (Python): enhanced_task_orchestrator split Result: 0 violations, 36 exempted (pipeline, tests, pure-data files). Go build verified clean. No behavior changes — pure structural splits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
183 lines
5.8 KiB
Go
183 lines
5.8 KiB
Go
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)
|
|
}
|