-- PostgreSQL Schema for fahrschultermin.de -- Run this BEFORE importing data BEGIN; -- ── Tenants ─────────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS tenants ( id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL, timezone TEXT NOT NULL DEFAULT 'Europe/Berlin', is_active INTEGER NOT NULL DEFAULT 1, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, location_label TEXT DEFAULT '', latitude DOUBLE PRECISION DEFAULT NULL, longitude DOUBLE PRECISION DEFAULT NULL, federal_state TEXT DEFAULT 'BE' ); -- ── Users ───────────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS users ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT REFERENCES tenants(id) ON DELETE CASCADE, role TEXT NOT NULL, email TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, first_name TEXT NOT NULL, last_name TEXT NOT NULL, is_active INTEGER NOT NULL DEFAULT 1, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL ); -- ── Instructors ──────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS instructors ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, first_name TEXT NOT NULL, last_name TEXT NOT NULL, color TEXT NOT NULL, notes TEXT DEFAULT '', is_active INTEGER NOT NULL DEFAULT 1, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, user_id BIGINT REFERENCES users(id) ON DELETE SET NULL, pre_start_buffer_minutes INTEGER NOT NULL DEFAULT 0 ); -- ── License Class Templates ─────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS license_class_templates ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, code TEXT NOT NULL, name TEXT NOT NULL, is_combination INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, UNIQUE (tenant_id, code) ); -- ── License Template Requirements ───────────────────────────────────────────── CREATE TABLE IF NOT EXISTS license_template_requirements ( id BIGSERIAL PRIMARY KEY, template_id BIGINT NOT NULL REFERENCES license_class_templates(id) ON DELETE CASCADE, requirement_key TEXT NOT NULL, label TEXT NOT NULL, required_units INTEGER NOT NULL, sort_order INTEGER NOT NULL DEFAULT 0, phase_label TEXT NOT NULL DEFAULT '' ); -- ── Lesson Types ────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS lesson_types ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, name TEXT NOT NULL, color TEXT NOT NULL, default_duration INTEGER NOT NULL, category TEXT NOT NULL, requirement_key TEXT DEFAULT NULL, is_billable INTEGER NOT NULL DEFAULT 0, is_counted INTEGER NOT NULL DEFAULT 0, is_rest_relevant INTEGER NOT NULL DEFAULT 0, fixed_duration INTEGER NOT NULL DEFAULT 0, sort_order INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, system_key TEXT DEFAULT NULL ); -- ── Lesson Type ↔ Template Visibility ────────────────────────────────────────── CREATE TABLE IF NOT EXISTS lesson_type_template_visibility ( lesson_type_id BIGINT NOT NULL REFERENCES lesson_types(id) ON DELETE CASCADE, template_id BIGINT NOT NULL REFERENCES license_class_templates(id) ON DELETE CASCADE, PRIMARY KEY (lesson_type_id, template_id) ); -- ── Students ────────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS students ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, template_id BIGINT NOT NULL REFERENCES license_class_templates(id), first_name TEXT NOT NULL, last_name TEXT NOT NULL, phone TEXT DEFAULT '', notes TEXT DEFAULT '', status TEXT NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL, email TEXT NOT NULL DEFAULT '', needs_glasses INTEGER NOT NULL DEFAULT 0 ); -- ── Student Requirement Snapshots ────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS student_requirement_snapshots ( id BIGSERIAL PRIMARY KEY, student_id BIGINT NOT NULL REFERENCES students(id) ON DELETE CASCADE, requirement_key TEXT NOT NULL, label TEXT NOT NULL, required_units INTEGER NOT NULL, sort_order INTEGER NOT NULL DEFAULT 0, prior_completed_units INTEGER NOT NULL DEFAULT 0, phase_label TEXT NOT NULL DEFAULT '' ); -- ── Appointments ────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS appointments ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, student_id BIGINT REFERENCES students(id) ON DELETE SET NULL, instructor_id BIGINT NOT NULL REFERENCES instructors(id), lesson_type_id BIGINT NOT NULL REFERENCES lesson_types(id), title TEXT NOT NULL, category TEXT NOT NULL, start_at TIMESTAMPTZ NOT NULL, end_at TIMESTAMPTZ NOT NULL, units INTEGER NOT NULL DEFAULT 1, status TEXT NOT NULL DEFAULT 'planned', notes TEXT DEFAULT '', warning_acknowledged INTEGER NOT NULL DEFAULT 0, created_by BIGINT NOT NULL REFERENCES users(id), updated_by BIGINT NOT NULL REFERENCES users(id), created_at TIMESTAMPTZ NOT NULL, updated_at TIMESTAMPTZ NOT NULL ); -- ── Appointment Units ───────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS appointment_units ( id BIGSERIAL PRIMARY KEY, appointment_id BIGINT NOT NULL REFERENCES appointments(id) ON DELETE CASCADE, requirement_key TEXT DEFAULT NULL, label TEXT DEFAULT NULL, units_counted INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL ); -- ── Settings ─────────────────────────────────────────────────────────────────── CREATE TABLE IF NOT EXISTS settings ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, key_name TEXT NOT NULL, value TEXT NOT NULL, UNIQUE (tenant_id, key_name) ); COMMIT;