renew
This commit is contained in:
@@ -1,278 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
full_name VARCHAR(160) NOT NULL,
|
||||
email VARCHAR(190) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
platform_role ENUM('platform_admin', 'user') NOT NULL DEFAULT 'user',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS password_reset_tokens (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
email VARCHAR(190) NOT NULL,
|
||||
token_hash CHAR(64) NOT NULL UNIQUE,
|
||||
requested_ip_hash CHAR(64) NULL,
|
||||
requested_user_agent_hash CHAR(64) NULL,
|
||||
expires_at DATETIME NOT NULL,
|
||||
consumed_at DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_password_reset_user_created (user_id, created_at),
|
||||
INDEX idx_password_reset_expires (expires_at),
|
||||
CONSTRAINT fk_password_reset_tokens_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rate_limits (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
action_key VARCHAR(80) NOT NULL,
|
||||
bucket_key CHAR(64) NOT NULL,
|
||||
attempts INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
window_start DATETIME NOT NULL,
|
||||
last_attempt_at DATETIME NOT NULL,
|
||||
blocked_until DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uniq_rate_limit_bucket (action_key, bucket_key),
|
||||
INDEX idx_rate_limit_blocked_until (blocked_until),
|
||||
INDEX idx_rate_limit_last_attempt (last_attempt_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenants (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(190) NOT NULL,
|
||||
slug VARCHAR(120) NOT NULL UNIQUE,
|
||||
plan ENUM('starter', 'team', 'business') NOT NULL DEFAULT 'starter',
|
||||
status ENUM('trial', 'active', 'suspended') NOT NULL DEFAULT 'trial',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenant_domains (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
host VARCHAR(190) NOT NULL UNIQUE,
|
||||
is_primary TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_tenant_domains_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenant_memberships (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
role ENUM('owner', 'admin', 'member', 'device') NOT NULL DEFAULT 'member',
|
||||
status ENUM('active', 'invited', 'disabled') NOT NULL DEFAULT 'active',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uniq_tenant_user (tenant_id, user_id),
|
||||
CONSTRAINT fk_memberships_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_memberships_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenant_settings (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
currency_code CHAR(3) NOT NULL DEFAULT 'EUR',
|
||||
default_product_price_cents INT NOT NULL DEFAULT 120,
|
||||
allow_self_service TINYINT(1) NOT NULL DEFAULT 1,
|
||||
allow_paper_lists TINYINT(1) NOT NULL DEFAULT 1,
|
||||
allow_rfid TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uniq_tenant_settings (tenant_id),
|
||||
CONSTRAINT fk_tenant_settings_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS members (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
user_id BIGINT UNSIGNED NULL,
|
||||
display_name VARCHAR(160) NOT NULL,
|
||||
email VARCHAR(190) NULL,
|
||||
access_pin VARCHAR(255) NULL,
|
||||
status ENUM('active', 'archived') NOT NULL DEFAULT 'active',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uniq_member_email (tenant_id, email),
|
||||
CONSTRAINT fk_members_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_members_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS products (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
name VARCHAR(120) NOT NULL,
|
||||
sku VARCHAR(60) NULL,
|
||||
is_active TINYINT(1) NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_products_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS product_prices (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
product_id BIGINT UNSIGNED NOT NULL,
|
||||
price_cents INT NOT NULL,
|
||||
valid_from DATETIME NOT NULL,
|
||||
valid_until DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_product_prices_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_product_prices_product FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS capture_sources (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
code VARCHAR(60) NOT NULL,
|
||||
name VARCHAR(120) NOT NULL,
|
||||
channel ENUM('paper', 'digital', 'admin', 'rfid') NOT NULL,
|
||||
is_system TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uniq_capture_source_code (tenant_id, code),
|
||||
CONSTRAINT fk_capture_sources_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS paper_sheets (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
title VARCHAR(190) NOT NULL,
|
||||
period_label VARCHAR(120) NULL,
|
||||
period_start DATE NULL,
|
||||
period_end DATE NULL,
|
||||
status ENUM('draft', 'posted') NOT NULL DEFAULT 'draft',
|
||||
notes TEXT NULL,
|
||||
created_by_user_id BIGINT UNSIGNED NULL,
|
||||
posted_at DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_paper_sheets_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_paper_sheets_user FOREIGN KEY (created_by_user_id) REFERENCES users (id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS paper_sheet_lines (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
paper_sheet_id BIGINT UNSIGNED NOT NULL,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
member_id BIGINT UNSIGNED NOT NULL,
|
||||
product_id BIGINT UNSIGNED NOT NULL,
|
||||
quantity DECIMAL(8,2) NOT NULL DEFAULT 1.00,
|
||||
effective_at DATETIME NULL,
|
||||
note VARCHAR(255) NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_paper_sheet_lines_sheet FOREIGN KEY (paper_sheet_id) REFERENCES paper_sheets (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_paper_sheet_lines_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_paper_sheet_lines_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_paper_sheet_lines_product FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS consumption_events (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
member_id BIGINT UNSIGNED NOT NULL,
|
||||
product_id BIGINT UNSIGNED NOT NULL,
|
||||
source_id BIGINT UNSIGNED NOT NULL,
|
||||
paper_sheet_line_id BIGINT UNSIGNED NULL,
|
||||
quantity DECIMAL(8,2) NOT NULL DEFAULT 1.00,
|
||||
unit_price_cents INT NOT NULL,
|
||||
total_cents INT NOT NULL,
|
||||
effective_at DATETIME NOT NULL,
|
||||
recorded_at DATETIME NOT NULL,
|
||||
recorded_by_user_id BIGINT UNSIGNED NULL,
|
||||
source_reference VARCHAR(120) NULL,
|
||||
notes TEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_consumption_events_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_consumption_events_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_consumption_events_product FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_consumption_events_source FOREIGN KEY (source_id) REFERENCES capture_sources (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_consumption_events_sheet_line FOREIGN KEY (paper_sheet_line_id) REFERENCES paper_sheet_lines (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_consumption_events_recorded_by FOREIGN KEY (recorded_by_user_id) REFERENCES users (id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ledger_entries (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
member_id BIGINT UNSIGNED NULL,
|
||||
source_id BIGINT UNSIGNED NULL,
|
||||
type ENUM('consumption', 'payment', 'correction', 'credit', 'opening_balance') NOT NULL,
|
||||
reference_type VARCHAR(60) NULL,
|
||||
reference_id BIGINT UNSIGNED NULL,
|
||||
description VARCHAR(255) NOT NULL,
|
||||
occurred_at DATETIME NOT NULL,
|
||||
created_by_user_id BIGINT UNSIGNED NULL,
|
||||
reversal_of_entry_id BIGINT UNSIGNED NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_ledger_entries_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_ledger_entries_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_ledger_entries_source FOREIGN KEY (source_id) REFERENCES capture_sources (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_ledger_entries_user FOREIGN KEY (created_by_user_id) REFERENCES users (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_ledger_entries_reversal FOREIGN KEY (reversal_of_entry_id) REFERENCES ledger_entries (id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ledger_lines (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
ledger_entry_id BIGINT UNSIGNED NOT NULL,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
member_id BIGINT UNSIGNED NULL,
|
||||
account_code ENUM('member_balance', 'cashbox', 'coffee_revenue') NOT NULL,
|
||||
amount_cents INT NOT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_ledger_lines_entry FOREIGN KEY (ledger_entry_id) REFERENCES ledger_entries (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_ledger_lines_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_ledger_lines_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rfid_devices (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
name VARCHAR(120) NOT NULL,
|
||||
location_label VARCHAR(160) NULL,
|
||||
device_token VARCHAR(80) NOT NULL UNIQUE,
|
||||
status ENUM('planned', 'active', 'disabled') NOT NULL DEFAULT 'planned',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_rfid_devices_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rfid_tags (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
member_id BIGINT UNSIGNED NULL,
|
||||
uid_hash CHAR(64) NOT NULL,
|
||||
label VARCHAR(120) NULL,
|
||||
status ENUM('active', 'lost', 'retired') NOT NULL DEFAULT 'active',
|
||||
last_seen_at DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uniq_rfid_tag (tenant_id, uid_hash),
|
||||
CONSTRAINT fk_rfid_tags_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_rfid_tags_member FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rfid_events (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NOT NULL,
|
||||
device_id BIGINT UNSIGNED NULL,
|
||||
external_event_id VARCHAR(120) NULL,
|
||||
uid_hash CHAR(64) NOT NULL,
|
||||
payload_json JSON NULL,
|
||||
status ENUM('received', 'linked', 'ignored', 'error') NOT NULL DEFAULT 'received',
|
||||
received_at DATETIME NOT NULL,
|
||||
processed_at DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uniq_rfid_external_event (tenant_id, external_event_id),
|
||||
CONSTRAINT fk_rfid_events_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_rfid_events_device FOREIGN KEY (device_id) REFERENCES rfid_devices (id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS audit_events (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
tenant_id BIGINT UNSIGNED NULL,
|
||||
actor_user_id BIGINT UNSIGNED NULL,
|
||||
action VARCHAR(120) NOT NULL,
|
||||
target_type VARCHAR(80) NOT NULL,
|
||||
target_id BIGINT UNSIGNED NULL,
|
||||
result ENUM('success', 'failure') NOT NULL,
|
||||
request_id CHAR(36) NOT NULL,
|
||||
ip_hash CHAR(64) NULL,
|
||||
user_agent_hash CHAR(64) NULL,
|
||||
meta_json JSON NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_audit_tenant_created (tenant_id, created_at),
|
||||
CONSTRAINT fk_audit_events_tenant FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_audit_events_user FOREIGN KEY (actor_user_id) REFERENCES users (id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -1,278 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
full_name TEXT NOT NULL,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
platform_role TEXT NOT NULL DEFAULT 'user' CHECK(platform_role IN ('platform_admin', 'user')),
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS password_reset_tokens (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
requested_ip_hash TEXT,
|
||||
requested_user_agent_hash TEXT,
|
||||
expires_at TEXT NOT NULL,
|
||||
consumed_at TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_password_reset_user_created ON password_reset_tokens (user_id, created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_password_reset_expires ON password_reset_tokens (expires_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rate_limits (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
action_key TEXT NOT NULL,
|
||||
bucket_key TEXT NOT NULL,
|
||||
attempts INTEGER NOT NULL DEFAULT 0,
|
||||
window_start TEXT NOT NULL,
|
||||
last_attempt_at TEXT NOT NULL,
|
||||
blocked_until TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE (action_key, bucket_key)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rate_limit_blocked_until ON rate_limits (blocked_until);
|
||||
CREATE INDEX IF NOT EXISTS idx_rate_limit_last_attempt ON rate_limits (last_attempt_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenants (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT NOT NULL UNIQUE,
|
||||
plan TEXT NOT NULL DEFAULT 'starter' CHECK(plan IN ('starter', 'team', 'business')),
|
||||
status TEXT NOT NULL DEFAULT 'trial' CHECK(status IN ('trial', 'active', 'suspended')),
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenant_domains (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
host TEXT NOT NULL UNIQUE,
|
||||
is_primary INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenant_memberships (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
role TEXT NOT NULL DEFAULT 'member' CHECK(role IN ('owner', 'admin', 'member', 'device')),
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'invited', 'disabled')),
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE (tenant_id, user_id),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tenant_settings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL UNIQUE,
|
||||
currency_code TEXT NOT NULL DEFAULT 'EUR',
|
||||
default_product_price_cents INTEGER NOT NULL DEFAULT 120,
|
||||
allow_self_service INTEGER NOT NULL DEFAULT 1,
|
||||
allow_paper_lists INTEGER NOT NULL DEFAULT 1,
|
||||
allow_rfid INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS members (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
user_id INTEGER,
|
||||
display_name TEXT NOT NULL,
|
||||
email TEXT,
|
||||
access_pin TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'archived')),
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE (tenant_id, email),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS products (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
sku TEXT,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS product_prices (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
product_id INTEGER NOT NULL,
|
||||
price_cents INTEGER NOT NULL,
|
||||
valid_from TEXT NOT NULL,
|
||||
valid_until TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS capture_sources (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
code TEXT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
channel TEXT NOT NULL CHECK(channel IN ('paper', 'digital', 'admin', 'rfid')),
|
||||
is_system INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE (tenant_id, code),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS paper_sheets (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
period_label TEXT,
|
||||
period_start TEXT,
|
||||
period_end TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'draft' CHECK(status IN ('draft', 'posted')),
|
||||
notes TEXT,
|
||||
created_by_user_id INTEGER,
|
||||
posted_at TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (created_by_user_id) REFERENCES users (id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS paper_sheet_lines (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
paper_sheet_id INTEGER NOT NULL,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
member_id INTEGER NOT NULL,
|
||||
product_id INTEGER NOT NULL,
|
||||
quantity REAL NOT NULL DEFAULT 1.00,
|
||||
effective_at TEXT,
|
||||
note TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (paper_sheet_id) REFERENCES paper_sheets (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS consumption_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
member_id INTEGER NOT NULL,
|
||||
product_id INTEGER NOT NULL,
|
||||
source_id INTEGER NOT NULL,
|
||||
paper_sheet_line_id INTEGER,
|
||||
quantity REAL NOT NULL DEFAULT 1.00,
|
||||
unit_price_cents INTEGER NOT NULL,
|
||||
total_cents INTEGER NOT NULL,
|
||||
effective_at TEXT NOT NULL,
|
||||
recorded_at TEXT NOT NULL,
|
||||
recorded_by_user_id INTEGER,
|
||||
source_reference TEXT,
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (source_id) REFERENCES capture_sources (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (paper_sheet_line_id) REFERENCES paper_sheet_lines (id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (recorded_by_user_id) REFERENCES users (id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ledger_entries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
member_id INTEGER,
|
||||
source_id INTEGER,
|
||||
type TEXT NOT NULL CHECK(type IN ('consumption', 'payment', 'correction', 'credit', 'opening_balance')),
|
||||
reference_type TEXT,
|
||||
reference_id INTEGER,
|
||||
description TEXT NOT NULL,
|
||||
occurred_at TEXT NOT NULL,
|
||||
created_by_user_id INTEGER,
|
||||
reversal_of_entry_id INTEGER,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (source_id) REFERENCES capture_sources (id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (created_by_user_id) REFERENCES users (id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (reversal_of_entry_id) REFERENCES ledger_entries (id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ledger_lines (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ledger_entry_id INTEGER NOT NULL,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
member_id INTEGER,
|
||||
account_code TEXT NOT NULL CHECK(account_code IN ('member_balance', 'cashbox', 'coffee_revenue')),
|
||||
amount_cents INTEGER NOT NULL,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (ledger_entry_id) REFERENCES ledger_entries (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rfid_devices (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
location_label TEXT,
|
||||
device_token TEXT NOT NULL UNIQUE,
|
||||
status TEXT NOT NULL DEFAULT 'planned' CHECK(status IN ('planned', 'active', 'disabled')),
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rfid_tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
member_id INTEGER,
|
||||
uid_hash TEXT NOT NULL,
|
||||
label TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'lost', 'retired')),
|
||||
last_seen_at TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE (tenant_id, uid_hash),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (member_id) REFERENCES members (id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rfid_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER NOT NULL,
|
||||
device_id INTEGER,
|
||||
external_event_id TEXT,
|
||||
uid_hash TEXT NOT NULL,
|
||||
payload_json TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'received' CHECK(status IN ('received', 'linked', 'ignored', 'error')),
|
||||
received_at TEXT NOT NULL,
|
||||
processed_at TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UNIQUE (tenant_id, external_event_id),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (device_id) REFERENCES rfid_devices (id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS audit_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
tenant_id INTEGER,
|
||||
actor_user_id INTEGER,
|
||||
action TEXT NOT NULL,
|
||||
target_type TEXT NOT NULL,
|
||||
target_id INTEGER,
|
||||
result TEXT NOT NULL CHECK(result IN ('success', 'failure')),
|
||||
request_id TEXT NOT NULL,
|
||||
ip_hash TEXT,
|
||||
user_agent_hash TEXT,
|
||||
meta_json TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
FOREIGN KEY (tenant_id) REFERENCES tenants (id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (actor_user_id) REFERENCES users (id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_tenant_created ON audit_events (tenant_id, created_at);
|
||||
Reference in New Issue
Block a user