-
This commit is contained in:
+276
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Budget;
|
||||
|
||||
final class Schema
|
||||
{
|
||||
/** @return list<string> */
|
||||
public static function statements(string $driver): array
|
||||
{
|
||||
return $driver === 'mysql' ? self::mysql() : self::sqlite();
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
private static function sqlite(): array
|
||||
{
|
||||
return [
|
||||
'CREATE TABLE IF NOT EXISTS settings (
|
||||
setting_key TEXT PRIMARY KEY,
|
||||
setting_value TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)',
|
||||
'CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
totp_secret TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)',
|
||||
'CREATE TABLE IF NOT EXISTS monthly_plans (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
month TEXT NOT NULL UNIQUE,
|
||||
starting_income NUMERIC NOT NULL DEFAULT 0,
|
||||
rollover_in NUMERIC NOT NULL DEFAULT 0,
|
||||
rolling_enabled INTEGER NOT NULL DEFAULT 1,
|
||||
rollover_source_month TEXT,
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)',
|
||||
'CREATE TABLE IF NOT EXISTS income_entries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
month TEXT NOT NULL,
|
||||
label TEXT NOT NULL,
|
||||
amount NUMERIC NOT NULL,
|
||||
received_on TEXT NOT NULL,
|
||||
withholding_amount NUMERIC NOT NULL DEFAULT 0,
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_income_month ON income_entries(month)',
|
||||
'CREATE TABLE IF NOT EXISTS categories (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
color TEXT NOT NULL DEFAULT "#7c5cff",
|
||||
monthly_limit NUMERIC NOT NULL DEFAULT 0,
|
||||
active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)',
|
||||
'CREATE TABLE IF NOT EXISTS budget_items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
month TEXT NOT NULL,
|
||||
category_id INTEGER,
|
||||
name TEXT NOT NULL,
|
||||
planned_amount NUMERIC NOT NULL DEFAULT 0,
|
||||
due_date TEXT,
|
||||
recurrence TEXT NOT NULL DEFAULT "none",
|
||||
series_key TEXT,
|
||||
status TEXT NOT NULL DEFAULT "active",
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL
|
||||
)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_budget_items_month ON budget_items(month)',
|
||||
'CREATE UNIQUE INDEX IF NOT EXISTS idx_budget_items_series_month ON budget_items(series_key, month) WHERE series_key IS NOT NULL',
|
||||
'CREATE TABLE IF NOT EXISTS transactions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
month TEXT NOT NULL,
|
||||
budget_item_id INTEGER,
|
||||
category_id INTEGER,
|
||||
merchant TEXT NOT NULL,
|
||||
amount NUMERIC NOT NULL,
|
||||
transacted_on TEXT NOT NULL,
|
||||
dead_pull_amount NUMERIC NOT NULL DEFAULT 0,
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (budget_item_id) REFERENCES budget_items(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL
|
||||
)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_transactions_month ON transactions(month)',
|
||||
'CREATE TABLE IF NOT EXISTS dead_account_entries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
month TEXT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
amount NUMERIC NOT NULL,
|
||||
source_type TEXT,
|
||||
source_id INTEGER,
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_dead_month ON dead_account_entries(month)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_dead_source ON dead_account_entries(source_type, source_id)',
|
||||
'CREATE TABLE IF NOT EXISTS calendar_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
month TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
event_date TEXT NOT NULL,
|
||||
event_type TEXT NOT NULL DEFAULT "note",
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)',
|
||||
'CREATE TABLE IF NOT EXISTS alert_logs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
budget_item_id INTEGER NOT NULL,
|
||||
alert_date TEXT NOT NULL,
|
||||
window_days INTEGER NOT NULL,
|
||||
recipient TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
response TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE (budget_item_id, alert_date, window_days, recipient),
|
||||
FOREIGN KEY (budget_item_id) REFERENCES budget_items(id) ON DELETE CASCADE
|
||||
)',
|
||||
'CREATE TABLE IF NOT EXISTS visits (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
route TEXT NOT NULL,
|
||||
visitor_hash TEXT NOT NULL,
|
||||
visited_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_visits_date ON visits(visited_at)',
|
||||
'CREATE TABLE IF NOT EXISTS audit_logs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER,
|
||||
action TEXT NOT NULL,
|
||||
entity_type TEXT,
|
||||
entity_id INTEGER,
|
||||
metadata TEXT,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
|
||||
)',
|
||||
];
|
||||
}
|
||||
|
||||
/** @return list<string> */
|
||||
private static function mysql(): array
|
||||
{
|
||||
return [
|
||||
'CREATE TABLE IF NOT EXISTS settings (
|
||||
setting_key VARCHAR(191) PRIMARY KEY,
|
||||
setting_value LONGTEXT NOT NULL,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS users (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
totp_secret VARCHAR(64) NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS monthly_plans (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
month CHAR(7) NOT NULL UNIQUE,
|
||||
starting_income DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
rollover_in DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
rolling_enabled TINYINT(1) NOT NULL DEFAULT 1,
|
||||
rollover_source_month CHAR(7) NULL,
|
||||
notes TEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS income_entries (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
month CHAR(7) NOT NULL,
|
||||
label VARCHAR(255) NOT NULL,
|
||||
amount DECIMAL(14,2) NOT NULL,
|
||||
received_on DATE NOT NULL,
|
||||
withholding_amount DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
notes TEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_income_month (month)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS categories (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(191) NOT NULL UNIQUE,
|
||||
color VARCHAR(16) NOT NULL DEFAULT "#7c5cff",
|
||||
monthly_limit DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
active TINYINT(1) NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS budget_items (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
month CHAR(7) NOT NULL,
|
||||
category_id BIGINT UNSIGNED NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
planned_amount DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
due_date DATE NULL,
|
||||
recurrence VARCHAR(16) NOT NULL DEFAULT "none",
|
||||
series_key VARCHAR(64) NULL,
|
||||
status VARCHAR(24) NOT NULL DEFAULT "active",
|
||||
notes TEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_budget_items_month (month),
|
||||
UNIQUE KEY idx_budget_items_series_month (series_key, month),
|
||||
CONSTRAINT fk_item_category FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS transactions (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
month CHAR(7) NOT NULL,
|
||||
budget_item_id BIGINT UNSIGNED NULL,
|
||||
category_id BIGINT UNSIGNED NULL,
|
||||
merchant VARCHAR(255) NOT NULL,
|
||||
amount DECIMAL(14,2) NOT NULL,
|
||||
transacted_on DATE NOT NULL,
|
||||
dead_pull_amount DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
notes TEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_transactions_month (month),
|
||||
CONSTRAINT fk_transaction_item FOREIGN KEY (budget_item_id) REFERENCES budget_items(id) ON DELETE SET NULL,
|
||||
CONSTRAINT fk_transaction_category FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS dead_account_entries (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
month CHAR(7) NOT NULL,
|
||||
kind VARCHAR(32) NOT NULL,
|
||||
amount DECIMAL(14,2) NOT NULL,
|
||||
source_type VARCHAR(32) NULL,
|
||||
source_id BIGINT NULL,
|
||||
notes TEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_dead_month (month),
|
||||
INDEX idx_dead_source (source_type, source_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS calendar_events (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
month CHAR(7) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
event_date DATE NOT NULL,
|
||||
event_type VARCHAR(24) NOT NULL DEFAULT "note",
|
||||
notes TEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS alert_logs (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
budget_item_id BIGINT UNSIGNED NOT NULL,
|
||||
alert_date DATE NOT NULL,
|
||||
window_days INT NOT NULL,
|
||||
recipient VARCHAR(255) NOT NULL,
|
||||
status VARCHAR(24) NOT NULL,
|
||||
response TEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY alert_unique (budget_item_id, alert_date, window_days, recipient),
|
||||
CONSTRAINT fk_alert_item FOREIGN KEY (budget_item_id) REFERENCES budget_items(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS visits (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
route VARCHAR(191) NOT NULL,
|
||||
visitor_hash VARCHAR(64) NOT NULL,
|
||||
visited_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_visits_date (visited_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
'CREATE TABLE IF NOT EXISTS audit_logs (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id BIGINT UNSIGNED NULL,
|
||||
action VARCHAR(191) NOT NULL,
|
||||
entity_type VARCHAR(64) NULL,
|
||||
entity_id BIGINT NULL,
|
||||
metadata LONGTEXT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_audit_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4',
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user