br-office-suite/database/migrations/002_core_schema.sql
2026-05-10 10:46:05 +02:00

269 lines
9.2 KiB
SQL

CREATE TABLE IF NOT EXISTS committee (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(120) NOT NULL,
committee_type VARCHAR(50) NOT NULL DEFAULT 'general',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS app_user (
id BIGSERIAL PRIMARY KEY,
full_name VARCHAR(120) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash TEXT NOT NULL DEFAULT '',
role role_type NOT NULL DEFAULT 'member',
committee_id BIGINT REFERENCES committee(id),
is_active BOOLEAN NOT NULL DEFAULT TRUE,
security_classification VARCHAR(30) NOT NULL DEFAULT 'standard',
force_password_reset BOOLEAN NOT NULL DEFAULT FALSE,
two_factor_enabled BOOLEAN NOT NULL DEFAULT FALSE,
last_mfa_at TIMESTAMPTZ,
last_login_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS refresh_token (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
token_hash TEXT NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS br_case (
id BIGSERIAL PRIMARY KEY,
case_number VARCHAR(50) UNIQUE NOT NULL,
title VARCHAR(255) NOT NULL,
case_type VARCHAR(50) NOT NULL,
status VARCHAR(50) NOT NULL DEFAULT 'neu',
priority VARCHAR(20) NOT NULL DEFAULT 'mittel',
confidentiality_level conf_level NOT NULL DEFAULT 'intern',
summary TEXT,
affected_employee_name VARCHAR(120),
department VARCHAR(120),
committee_id BIGINT REFERENCES committee(id),
owner_user_id BIGINT NOT NULL REFERENCES app_user(id),
legal_hold BOOLEAN NOT NULL DEFAULT FALSE,
created_by BIGINT REFERENCES app_user(id),
updated_by BIGINT REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS deadline (
id BIGSERIAL PRIMARY KEY,
case_id BIGINT REFERENCES br_case(id) ON DELETE CASCADE,
title VARCHAR(255) NOT NULL,
deadline_type VARCHAR(50) NOT NULL,
due_date TIMESTAMPTZ NOT NULL,
status VARCHAR(30) NOT NULL DEFAULT 'offen',
remind_days_before INTEGER NOT NULL DEFAULT 2,
created_by BIGINT REFERENCES app_user(id),
updated_by BIGINT REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS meeting (
id BIGSERIAL PRIMARY KEY,
meeting_number VARCHAR(50) UNIQUE NOT NULL,
title VARCHAR(255) NOT NULL,
meeting_type VARCHAR(50) NOT NULL DEFAULT 'ordentlich',
meeting_date DATE NOT NULL,
start_time TIME,
end_time TIME,
location VARCHAR(255),
status VARCHAR(30) NOT NULL DEFAULT 'geplant',
protocol_text TEXT,
is_quorate BOOLEAN,
quorum_recorded_at TIMESTAMPTZ,
quorum_recorded_by BIGINT REFERENCES app_user(id),
committee_id BIGINT REFERENCES committee(id),
chair_user_id BIGINT REFERENCES app_user(id),
secretary_user_id BIGINT REFERENCES app_user(id),
created_by BIGINT REFERENCES app_user(id),
updated_by BIGINT REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS meeting_agenda_item (
id BIGSERIAL PRIMARY KEY,
meeting_id BIGINT NOT NULL REFERENCES meeting(id) ON DELETE CASCADE,
agenda_number VARCHAR(20) NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
duration_minutes INTEGER,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS decision (
id BIGSERIAL PRIMARY KEY,
decision_number VARCHAR(50) UNIQUE NOT NULL,
meeting_id BIGINT REFERENCES meeting(id) ON DELETE SET NULL,
agenda_item_id BIGINT REFERENCES meeting_agenda_item(id) ON DELETE SET NULL,
case_id BIGINT REFERENCES br_case(id) ON DELETE SET NULL,
title VARCHAR(255) NOT NULL,
decision_text TEXT NOT NULL,
status VARCHAR(30) NOT NULL DEFAULT 'offen',
votes_yes INTEGER NOT NULL DEFAULT 0,
votes_no INTEGER NOT NULL DEFAULT 0,
votes_abstain INTEGER NOT NULL DEFAULT 0,
responsible_user_id BIGINT REFERENCES app_user(id),
due_date TIMESTAMPTZ,
created_by BIGINT REFERENCES app_user(id),
updated_by BIGINT REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS task (
id BIGSERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
status VARCHAR(30) NOT NULL DEFAULT 'offen',
priority VARCHAR(20) NOT NULL DEFAULT 'mittel',
assigned_user_id BIGINT REFERENCES app_user(id),
backup_user_id BIGINT REFERENCES app_user(id),
case_id BIGINT REFERENCES br_case(id) ON DELETE SET NULL,
meeting_id BIGINT REFERENCES meeting(id) ON DELETE SET NULL,
decision_id BIGINT REFERENCES decision(id) ON DELETE SET NULL,
due_date TIMESTAMPTZ,
confidentiality_level conf_level NOT NULL DEFAULT 'intern',
created_by BIGINT REFERENCES app_user(id),
updated_by BIGINT REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS document_item (
id BIGSERIAL PRIMARY KEY,
document_number VARCHAR(50) UNIQUE NOT NULL,
title VARCHAR(255) NOT NULL,
document_type VARCHAR(50) NOT NULL,
description TEXT,
version_label VARCHAR(30) NOT NULL DEFAULT 'v1',
file_name VARCHAR(255),
storage_path TEXT,
storage_provider VARCHAR(20) NOT NULL DEFAULT 'local',
mime_type VARCHAR(100),
size_bytes BIGINT,
sha256_hash VARCHAR(64),
confidentiality_level conf_level NOT NULL DEFAULT 'intern',
case_id BIGINT REFERENCES br_case(id) ON DELETE SET NULL,
meeting_id BIGINT REFERENCES meeting(id) ON DELETE SET NULL,
decision_id BIGINT REFERENCES decision(id) ON DELETE SET NULL,
uploaded_by BIGINT REFERENCES app_user(id),
is_signed BOOLEAN NOT NULL DEFAULT FALSE,
scan_status scan_status_type NOT NULL DEFAULT 'pending',
scan_engine VARCHAR(50),
scan_result TEXT,
uploaded_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS document_scan_event (
id BIGSERIAL PRIMARY KEY,
document_id BIGINT NOT NULL REFERENCES document_item(id) ON DELETE CASCADE,
scanned_by_user_id BIGINT REFERENCES app_user(id),
status scan_status_type NOT NULL,
engine VARCHAR(50) NOT NULL,
result_text TEXT,
scanned_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS comment_item (
id BIGSERIAL PRIMARY KEY,
entity_type VARCHAR(50) NOT NULL,
entity_id BIGINT NOT NULL,
comment_text TEXT NOT NULL,
visibility VARCHAR(30) NOT NULL DEFAULT 'intern',
author_user_id BIGINT REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ
);
CREATE TABLE IF NOT EXISTS template_item (
id BIGSERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
category VARCHAR(50) NOT NULL,
description TEXT,
content TEXT NOT NULL,
version_label VARCHAR(30) NOT NULL DEFAULT 'v1',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_by BIGINT REFERENCES app_user(id),
updated_by BIGINT REFERENCES app_user(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS notification_item (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
notification_type VARCHAR(50) NOT NULL,
title VARCHAR(255) NOT NULL,
entity_type VARCHAR(50),
entity_id BIGINT,
is_read BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS audit_log (
id BIGSERIAL PRIMARY KEY,
actor_user_id BIGINT REFERENCES app_user(id),
action VARCHAR(100) NOT NULL,
entity_type VARCHAR(50),
entity_id BIGINT,
metadata JSONB,
ip_address INET,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS auth_challenge (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
challenge_type VARCHAR(40) NOT NULL,
challenge_value TEXT NOT NULL,
metadata JSONB,
expires_at TIMESTAMPTZ NOT NULL,
used_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS webauthn_challenge (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
flow_type VARCHAR(40) NOT NULL,
challenge TEXT NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
used_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS webauthn_credential (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES app_user(id) ON DELETE CASCADE,
credential_id TEXT NOT NULL UNIQUE,
public_key TEXT NOT NULL,
counter BIGINT NOT NULL DEFAULT 0,
transports JSONB,
credential_device_type VARCHAR(50),
credential_backed_up BOOLEAN NOT NULL DEFAULT FALSE,
nickname VARCHAR(120),
last_used_at TIMESTAMPTZ,
revoked_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS user_totp_secret (
user_id BIGINT PRIMARY KEY REFERENCES app_user(id) ON DELETE CASCADE,
secret_base32 TEXT NOT NULL,
is_verified BOOLEAN NOT NULL DEFAULT FALSE,
verified_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);