Stand vor Einführung des Nacht-Agenten
This commit is contained in:
commit
4763548bfb
168 changed files with 12726 additions and 0 deletions
152
migrations/001_core.sql
Normal file
152
migrations/001_core.sql
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
-- 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)
|
||||
);
|
||||
40
migrations/002_connectors_resources.sql
Normal file
40
migrations/002_connectors_resources.sql
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
-- Connector-Instanzen (Verbindungen zu Providern) und synchronisierte Ressourcen
|
||||
CREATE TABLE connector_instances (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
connector_key VARCHAR(50) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL UNIQUE,
|
||||
config_json JSON NOT NULL,
|
||||
secrets_enc TEXT NULL,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||
sync_interval_sec INT NOT NULL DEFAULT 300,
|
||||
health ENUM('unknown','ok','down') NOT NULL DEFAULT 'unknown',
|
||||
health_message VARCHAR(300) NULL,
|
||||
capabilities_json JSON NULL,
|
||||
last_ok_at DATETIME(3) NULL,
|
||||
last_sync_at DATETIME(3) NULL,
|
||||
last_error VARCHAR(500) 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)
|
||||
);
|
||||
|
||||
-- Ressource = lokaler Spiegel eines Provider-Objekts (Lizenz, Hosting-Konto, ...). Provider-Rohdaten bleiben im Connector.
|
||||
CREATE TABLE resources (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
instance_id CHAR(36) NOT NULL,
|
||||
external_ref VARCHAR(100) NOT NULL,
|
||||
type VARCHAR(30) NOT NULL,
|
||||
name VARCHAR(300) NOT NULL,
|
||||
state ENUM('active','suspended','expired','error','unknown') NOT NULL DEFAULT 'unknown',
|
||||
org_id CHAR(36) NULL,
|
||||
valid_from DATETIME(3) NULL,
|
||||
valid_until DATETIME(3) NULL,
|
||||
data_json JSON NULL,
|
||||
customer_actions JSON NOT NULL DEFAULT '[]',
|
||||
synced_at DATETIME(3) NOT NULL,
|
||||
missing_since DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE KEY uq_instance_ref (instance_id, external_ref),
|
||||
INDEX (org_id),
|
||||
FOREIGN KEY (instance_id) REFERENCES connector_instances(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (org_id) REFERENCES organizations(id) ON DELETE SET NULL
|
||||
);
|
||||
3
migrations/003_customer_type.sql
Normal file
3
migrations/003_customer_type.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
-- Kundenart: Privatkunde oder Geschäftskunde (bestehende Kunden gelten als Geschäftskunden)
|
||||
ALTER TABLE organizations ADD COLUMN customer_type ENUM('private','business') NOT NULL DEFAULT 'business' AFTER name;
|
||||
ALTER TABLE organizations ADD INDEX idx_customer_type (customer_type);
|
||||
105
migrations/004_catalog_orders_contracts.sql
Normal file
105
migrations/004_catalog_orders_contracts.sql
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
-- Produktkatalog, Bestellungen (mit unveränderlichem Preis-Snapshot) und Verträge
|
||||
CREATE TABLE number_sequences (name VARCHAR(30) PRIMARY KEY, next_value INT NOT NULL);
|
||||
INSERT INTO number_sequences VALUES ('order', 20000), ('contract', 30000);
|
||||
|
||||
CREATE TABLE tax_rates (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
rate_bp INT NOT NULL,
|
||||
active TINYINT(1) NOT NULL DEFAULT 1,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
|
||||
);
|
||||
INSERT INTO tax_rates (id, name, rate_bp) VALUES (UUID(), 'Regelsteuersatz 19 %', 1900), (UUID(), 'Ermäßigter Steuersatz 7 %', 700), (UUID(), 'Steuerfrei 0 %', 0);
|
||||
|
||||
CREATE TABLE products (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
sku VARCHAR(50) NOT NULL UNIQUE,
|
||||
category ENUM('hosting','license','addon','service') NOT NULL,
|
||||
status ENUM('draft','active','retired') NOT NULL DEFAULT 'draft',
|
||||
connector_instance_id CHAR(36) NULL,
|
||||
orderable_by_customer TINYINT(1) NOT NULL DEFAULT 0,
|
||||
requires_approval TINYINT(1) NOT NULL DEFAULT 1,
|
||||
customer_actions JSON NOT NULL DEFAULT '[]',
|
||||
current_version_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),
|
||||
FOREIGN KEY (connector_instance_id) REFERENCES connector_instances(id) ON DELETE SET NULL
|
||||
);
|
||||
-- Versionen sind unveränderlich; jede Preis-/Vertragsänderung erzeugt eine neue Version.
|
||||
CREATE TABLE product_versions (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
product_id CHAR(36) NOT NULL,
|
||||
version INT NOT NULL,
|
||||
name VARCHAR(200) NOT NULL,
|
||||
description TEXT NULL,
|
||||
tax_rate_id CHAR(36) NOT NULL,
|
||||
tax_bp INT NOT NULL,
|
||||
setup_net_cents INT NOT NULL DEFAULT 0,
|
||||
recurring_net_cents INT NOT NULL DEFAULT 0,
|
||||
currency CHAR(3) NOT NULL DEFAULT 'EUR',
|
||||
billing_interval ENUM('once','monthly','yearly') NOT NULL,
|
||||
term_months INT NOT NULL DEFAULT 0,
|
||||
renewal ENUM('auto','none') NOT NULL DEFAULT 'none',
|
||||
renewal_term_months INT NOT NULL DEFAULT 0,
|
||||
notice_days INT NOT NULL DEFAULT 30,
|
||||
provisioning_json JSON NOT NULL DEFAULT '{}',
|
||||
created_by CHAR(36) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE KEY uq_product_version (product_id, version),
|
||||
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (tax_rate_id) REFERENCES tax_rates(id)
|
||||
);
|
||||
|
||||
CREATE TABLE orders (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
number VARCHAR(20) NOT NULL UNIQUE,
|
||||
org_id CHAR(36) NOT NULL,
|
||||
status ENUM('pending_approval','approved','provisioning','completed','failed','rejected','cancelled') NOT NULL,
|
||||
placed_by CHAR(36) NULL,
|
||||
placed_via ENUM('customer','staff') NOT NULL,
|
||||
approval_required TINYINT(1) NOT NULL DEFAULT 1,
|
||||
approved_by CHAR(36) NULL,
|
||||
approved_at DATETIME(3) NULL,
|
||||
note VARCHAR(500) NULL,
|
||||
failure_note VARCHAR(500) NULL,
|
||||
failure_ambiguous TINYINT(1) NOT NULL DEFAULT 0,
|
||||
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 (org_id), INDEX (status),
|
||||
FOREIGN KEY (org_id) REFERENCES organizations(id)
|
||||
);
|
||||
CREATE TABLE order_items (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
order_id CHAR(36) NOT NULL,
|
||||
product_version_id CHAR(36) NOT NULL,
|
||||
quantity INT NOT NULL DEFAULT 1,
|
||||
discount_bp INT NOT NULL DEFAULT 0,
|
||||
snapshot_json JSON NOT NULL,
|
||||
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (product_version_id) REFERENCES product_versions(id)
|
||||
);
|
||||
CREATE TABLE contracts (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
number VARCHAR(20) NOT NULL UNIQUE,
|
||||
org_id CHAR(36) NOT NULL,
|
||||
order_item_id CHAR(36) NOT NULL UNIQUE,
|
||||
product_version_id CHAR(36) NOT NULL,
|
||||
status ENUM('pending','active','suspended','cancelled','expired','failed') NOT NULL DEFAULT 'pending',
|
||||
started_at DATETIME(3) NULL,
|
||||
term_end DATETIME(3) NULL,
|
||||
renewal ENUM('auto','none') NOT NULL DEFAULT 'none',
|
||||
renewal_term_months INT NOT NULL DEFAULT 0,
|
||||
notice_days INT NOT NULL DEFAULT 30,
|
||||
cancel_requested_at DATETIME(3) NULL,
|
||||
cancel_effective_at DATETIME(3) NULL,
|
||||
cancelled_at DATETIME(3) NULL,
|
||||
resource_id CHAR(36) NULL,
|
||||
price_snapshot_json JSON NOT 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 (org_id), INDEX (status),
|
||||
FOREIGN KEY (org_id) REFERENCES organizations(id),
|
||||
FOREIGN KEY (order_item_id) REFERENCES order_items(id),
|
||||
FOREIGN KEY (product_version_id) REFERENCES product_versions(id),
|
||||
FOREIGN KEY (resource_id) REFERENCES resources(id) ON DELETE SET NULL
|
||||
);
|
||||
3
migrations/005_product_external_ref.sql
Normal file
3
migrations/005_product_external_ref.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
-- Herkunft eines Produkts beim Anbieter (z. B. Programm-ID im Lizenzsystem), für die Übernahme aus Verbindungen
|
||||
ALTER TABLE products ADD COLUMN external_ref VARCHAR(100) NULL AFTER connector_instance_id;
|
||||
ALTER TABLE products ADD INDEX idx_products_ref (connector_instance_id, external_ref);
|
||||
4
migrations/006_price_basis.sql
Normal file
4
migrations/006_price_basis.sql
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-- Preisbasis: Beträge sind je nach price_basis Netto- oder Bruttobeträge (Verbraucherpreise sind Bruttopreise und müssen exakt bleiben)
|
||||
ALTER TABLE product_versions RENAME COLUMN setup_net_cents TO setup_cents;
|
||||
ALTER TABLE product_versions RENAME COLUMN recurring_net_cents TO recurring_cents;
|
||||
ALTER TABLE product_versions ADD COLUMN price_basis ENUM('net','gross') NOT NULL DEFAULT 'net' AFTER currency;
|
||||
22
migrations/007_backup_settings_targets.sql
Normal file
22
migrations/007_backup_settings_targets.sql
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
-- Backup-Einstellungen (verschlüsselt mit dem Master-Schlüssel) und externe Ziele
|
||||
CREATE TABLE backup_settings (
|
||||
`key` VARCHAR(50) PRIMARY KEY,
|
||||
value_enc TEXT NOT NULL,
|
||||
updated_by CHAR(36) NULL,
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
||||
);
|
||||
CREATE TABLE backup_targets (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL UNIQUE,
|
||||
type ENUM('sftp','ftp','gdrive','local') NOT NULL,
|
||||
path VARCHAR(500) NOT NULL DEFAULT '',
|
||||
config_json JSON NOT NULL,
|
||||
secrets_enc TEXT NULL,
|
||||
host_key TEXT NULL,
|
||||
enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||
last_test_at DATETIME(3) NULL,
|
||||
last_test_ok TINYINT(1) NULL,
|
||||
last_test_error VARCHAR(400) 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)
|
||||
);
|
||||
3
migrations/008_org_legacy_ref.sql
Normal file
3
migrations/008_org_legacy_ref.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
-- Herkunft übernommener Kunden (z. B. "keyhelp:<Verbindung>:<Kunden-ID>"), verhindert doppelte Übernahme
|
||||
ALTER TABLE organizations ADD COLUMN legacy_ref VARCHAR(150) NULL AFTER customer_type;
|
||||
ALTER TABLE organizations ADD UNIQUE INDEX uq_org_legacy_ref (legacy_ref);
|
||||
1
migrations/009_connector_error_time.sql
Normal file
1
migrations/009_connector_error_time.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE connector_instances ADD COLUMN last_error_at DATETIME(3) NULL AFTER last_error;
|
||||
19
migrations/010_domains.sql
Normal file
19
migrations/010_domains.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
-- Domain-Preisliste: Einkaufspreise je Endung und Staffel, Verkaufspreis = Einkauf + Gewinnaufschlag
|
||||
CREATE TABLE domain_tlds (
|
||||
tld VARCHAR(63) PRIMARY KEY,
|
||||
term_months INT NOT NULL DEFAULT 12,
|
||||
cost1_cents INT NOT NULL, cost2_cents INT NOT NULL, cost3_cents INT NOT NULL, cost4_cents INT NOT NULL,
|
||||
setup_cents INT NOT NULL DEFAULT 0,
|
||||
margin_type ENUM('percent','fixed') NULL, -- NULL = globalen Aufschlag verwenden
|
||||
margin_value INT NULL, -- percent: Basispunkte (2500 = 25 %), fixed: Cent
|
||||
active TINYINT(1) NOT NULL DEFAULT 1,
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
CREATE TABLE domain_settings (
|
||||
id TINYINT PRIMARY KEY,
|
||||
tier TINYINT NOT NULL DEFAULT 1, -- Preisstaffel des Einkaufs (1 = 0-49, 2 = 50-199, 3 = 200-999, 4 = 1000+)
|
||||
margin_type ENUM('percent','fixed') NULL,
|
||||
margin_value INT NULL,
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
INSERT INTO domain_settings (id, tier) VALUES (1, 1);
|
||||
1
migrations/011_domain_rounding.sql
Normal file
1
migrations/011_domain_rounding.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE domain_settings ADD COLUMN rounding TINYINT(1) NOT NULL DEFAULT 1 AFTER margin_value;
|
||||
23
migrations/012_domain_records.sql
Normal file
23
migrations/012_domain_records.sql
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
-- Domain-Aufstellung: je Domain Einkauf (netto), Verkauf (netto/brutto) und Beschaffungsstatus (Bestellung beim Registrar KCS)
|
||||
CREATE TABLE domain_records (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
domain VARCHAR(253) NOT NULL,
|
||||
tld VARCHAR(63) NOT NULL,
|
||||
org_id CHAR(36) NULL,
|
||||
resource_id CHAR(36) NULL,
|
||||
source ENUM('keyhelp','manual') NOT NULL DEFAULT 'manual',
|
||||
term_months INT NULL,
|
||||
cost_net_cents INT NULL, -- Einkauf netto (Preisstaffel zum Zeitpunkt der Erfassung)
|
||||
setup_cost_cents INT NOT NULL DEFAULT 0,
|
||||
sell_net_cents INT NULL, -- errechneter Verkaufspreis netto
|
||||
tax_bp INT NOT NULL DEFAULT 1900,
|
||||
sell_gross_cents INT NULL, -- errechneter Verkaufspreis brutto
|
||||
procurement ENUM('open','ordered','external') NOT NULL DEFAULT 'open', -- open = bei KCS zu bestellen, external = liegt bei anderem Anbieter
|
||||
ordered_at DATETIME(3) NULL,
|
||||
ordered_ref VARCHAR(100) NULL,
|
||||
note VARCHAR(300) NULL,
|
||||
priced_at DATETIME(3) NULL,
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE KEY uq_domain (domain),
|
||||
KEY idx_dr_org (org_id), KEY idx_dr_res (resource_id), KEY idx_dr_proc (procurement)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
3
migrations/013_domain_cost_basis.sql
Normal file
3
migrations/013_domain_cost_basis.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
-- Einkaufspreise laut Liste sind Bruttopreise (inkl. USt); Umstellbar auf netto. Aufstellung speichert beide Werte.
|
||||
ALTER TABLE domain_settings ADD COLUMN cost_basis ENUM('gross','net') NOT NULL DEFAULT 'gross' AFTER rounding;
|
||||
ALTER TABLE domain_records ADD COLUMN cost_gross_cents INT NULL AFTER cost_net_cents;
|
||||
Loading…
Add table
Add a link
Reference in a new issue