152 lines
5.5 KiB
SQL
152 lines
5.5 KiB
SQL
-- Kundencenter Grundschema (MariaDB). utf8mb4_unicode_ci.
|
|
CREATE TABLE settings (
|
|
`key` VARCHAR(100) PRIMARY KEY,
|
|
`value` VARCHAR(1000) NOT NULL,
|
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
|
);
|
|
INSERT INTO settings (`key`,`value`) VALUES ('registration_enabled','false');
|
|
|
|
CREATE TABLE users (
|
|
id CHAR(36) PRIMARY KEY,
|
|
email VARCHAR(254) NOT NULL UNIQUE,
|
|
name VARCHAR(150) NOT NULL,
|
|
password_hash VARCHAR(255) NULL,
|
|
kind ENUM('customer','staff') NOT NULL DEFAULT 'customer',
|
|
staff_role ENUM('support','accounting','admin','superadmin') NULL,
|
|
status ENUM('active','disabled','invited') NOT NULL DEFAULT 'invited',
|
|
email_verified_at DATETIME(3) NULL,
|
|
failed_logins INT NOT NULL DEFAULT 0,
|
|
locked_until DATETIME(3) NULL,
|
|
locale VARCHAR(10) NOT NULL DEFAULT 'de',
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
|
CHECK ((kind = 'staff' AND staff_role IS NOT NULL) OR (kind = 'customer' AND staff_role IS NULL))
|
|
);
|
|
|
|
CREATE TABLE sessions (
|
|
id CHAR(36) PRIMARY KEY,
|
|
user_id CHAR(36) NOT NULL,
|
|
token_hash CHAR(64) NOT NULL UNIQUE,
|
|
csrf_token CHAR(43) NOT NULL,
|
|
mfa_verified TINYINT(1) NOT NULL DEFAULT 0,
|
|
pending_mfa TINYINT(1) NOT NULL DEFAULT 0,
|
|
ip VARCHAR(45) NULL,
|
|
user_agent VARCHAR(255) NULL,
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
last_seen_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
expires_at DATETIME(3) NOT NULL,
|
|
revoked_at DATETIME(3) NULL,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
INDEX (user_id)
|
|
);
|
|
|
|
CREATE TABLE mfa_totp (
|
|
user_id CHAR(36) PRIMARY KEY,
|
|
secret_enc VARCHAR(512) NOT NULL,
|
|
confirmed_at DATETIME(3) NULL,
|
|
last_step BIGINT NULL,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
CREATE TABLE recovery_codes (
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
user_id CHAR(36) NOT NULL,
|
|
code_hash CHAR(64) NOT NULL,
|
|
used_at DATETIME(3) NULL,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
INDEX (user_id)
|
|
);
|
|
|
|
CREATE TABLE organizations (
|
|
id CHAR(36) PRIMARY KEY,
|
|
customer_number VARCHAR(20) NOT NULL UNIQUE,
|
|
name VARCHAR(200) NOT NULL,
|
|
status ENUM('active','suspended','closed') NOT NULL DEFAULT 'active',
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
|
);
|
|
CREATE TABLE customer_sequences (id TINYINT PRIMARY KEY, next_value INT NOT NULL);
|
|
INSERT INTO customer_sequences VALUES (1, 10000);
|
|
|
|
CREATE TABLE billing_profiles (
|
|
org_id CHAR(36) PRIMARY KEY,
|
|
company VARCHAR(200) NULL,
|
|
contact_name VARCHAR(150) NULL,
|
|
street VARCHAR(200) NULL,
|
|
zip VARCHAR(20) NULL,
|
|
city VARCHAR(100) NULL,
|
|
country CHAR(2) NOT NULL DEFAULT 'DE',
|
|
vat_id VARCHAR(30) NULL,
|
|
billing_email VARCHAR(254) NULL,
|
|
phone VARCHAR(50) NULL,
|
|
FOREIGN KEY (org_id) REFERENCES organizations(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE TABLE memberships (
|
|
org_id CHAR(36) NOT NULL,
|
|
user_id CHAR(36) NOT NULL,
|
|
role ENUM('owner','admin','member') NOT NULL DEFAULT 'member',
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
PRIMARY KEY (org_id, user_id),
|
|
FOREIGN KEY (org_id) REFERENCES organizations(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
|
|
-- Einmal-Token: Einladung, Passwort-Reset, E-Mail-Verifizierung
|
|
CREATE TABLE user_tokens (
|
|
id CHAR(36) PRIMARY KEY,
|
|
user_id CHAR(36) NOT NULL,
|
|
purpose ENUM('invite','password_reset','verify_email') NOT NULL,
|
|
token_hash CHAR(64) NOT NULL UNIQUE,
|
|
expires_at DATETIME(3) NOT NULL,
|
|
used_at DATETIME(3) NULL,
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE TABLE audit_events (
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
ts DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
actor_type ENUM('user','system','anonymous') NOT NULL,
|
|
actor_id CHAR(36) NULL,
|
|
org_id CHAR(36) NULL,
|
|
action VARCHAR(100) NOT NULL,
|
|
resource_type VARCHAR(50) NULL,
|
|
resource_id VARCHAR(64) NULL,
|
|
result ENUM('success','denied','failure') NOT NULL,
|
|
error_class VARCHAR(100) NULL,
|
|
connector VARCHAR(50) NULL,
|
|
correlation_id CHAR(36) NULL,
|
|
ip VARCHAR(45) NULL,
|
|
before_json JSON NULL,
|
|
after_json JSON NULL,
|
|
prev_hash CHAR(64) NOT NULL,
|
|
hash CHAR(64) NOT NULL,
|
|
INDEX (ts), INDEX (actor_id), INDEX (org_id), INDEX (action)
|
|
);
|
|
|
|
-- Persistente Aufträge (Outbox), Basis für Worker/Discord; später Provider-Jobs
|
|
CREATE TABLE jobs (
|
|
id CHAR(36) PRIMARY KEY,
|
|
type VARCHAR(100) NOT NULL,
|
|
payload JSON NOT NULL,
|
|
idempotency_key VARCHAR(150) NULL UNIQUE,
|
|
status ENUM('scheduled','running','waiting_external','succeeded','partial','failed','retrying','needs_review') NOT NULL DEFAULT 'scheduled',
|
|
attempts INT NOT NULL DEFAULT 0,
|
|
max_attempts INT NOT NULL DEFAULT 5,
|
|
run_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
locked_at DATETIME(3) NULL,
|
|
last_error VARCHAR(500) NULL,
|
|
correlation_id CHAR(36) NULL,
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
|
INDEX (status, run_at)
|
|
);
|
|
|
|
CREATE TABLE mail_log (
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
to_email VARCHAR(254) NOT NULL,
|
|
template VARCHAR(60) NOT NULL,
|
|
status ENUM('sent','failed','not_configured') NOT NULL,
|
|
error VARCHAR(300) NULL,
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
|
|
);
|