first ruggedy draft
This commit is contained in:
323
db/migrations/0001_initial.sql
Normal file
323
db/migrations/0001_initial.sql
Normal file
@@ -0,0 +1,323 @@
|
||||
-- M0: Local household ledger skeleton.
|
||||
-- SQLite-compatible baseline schema. The SQLAlchemy models are the runtime source for dev
|
||||
-- create_all(); this file documents the first relational shape for migration tooling.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS households (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
default_currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
display_name TEXT NOT NULL,
|
||||
email TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS login_identities (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL REFERENCES users(id),
|
||||
provider TEXT NOT NULL,
|
||||
provider_subject TEXT NOT NULL,
|
||||
email TEXT,
|
||||
display_name TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
UNIQUE(provider, provider_subject)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS local_sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL REFERENCES users(id),
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
token_hash TEXT NOT NULL UNIQUE,
|
||||
created_at TEXT NOT NULL,
|
||||
last_seen_at TEXT NOT NULL,
|
||||
expires_at TEXT NOT NULL,
|
||||
revoked_at TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_local_session_token
|
||||
ON local_sessions(token_hash);
|
||||
CREATE INDEX IF NOT EXISTS ix_local_session_user
|
||||
ON local_sessions(user_id, expires_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS accounts (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
owner_user_id TEXT REFERENCES users(id),
|
||||
name TEXT NOT NULL,
|
||||
account_type TEXT NOT NULL,
|
||||
institution_name TEXT,
|
||||
currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
visibility_mode TEXT NOT NULL,
|
||||
is_active INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS raw_observations (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
source_type TEXT NOT NULL,
|
||||
source_account_id TEXT REFERENCES accounts(id),
|
||||
owner_user_id TEXT REFERENCES users(id),
|
||||
observed_at TEXT,
|
||||
received_at TEXT NOT NULL,
|
||||
raw_hash TEXT NOT NULL,
|
||||
source_reference TEXT,
|
||||
provider_transaction_id TEXT,
|
||||
message_id TEXT,
|
||||
raw_text TEXT,
|
||||
raw_file_path TEXT,
|
||||
raw_payload_json TEXT,
|
||||
parsed_json TEXT,
|
||||
parser_name TEXT,
|
||||
parser_version TEXT,
|
||||
confidence NUMERIC(14, 2) NOT NULL DEFAULT 1.00,
|
||||
status TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_observation_dedupe
|
||||
ON raw_observations(household_id, source_type, raw_hash);
|
||||
CREATE INDEX IF NOT EXISTS ix_observation_external_refs
|
||||
ON raw_observations(provider_transaction_id, message_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS categories (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
parent_id TEXT REFERENCES categories(id),
|
||||
name TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
is_active INTEGER NOT NULL DEFAULT 1
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS projects (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
start_date TEXT,
|
||||
end_date TEXT,
|
||||
default_split_rule_id TEXT,
|
||||
status TEXT NOT NULL,
|
||||
currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS financial_events (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
source_account_id TEXT REFERENCES accounts(id),
|
||||
payment_account_id TEXT REFERENCES accounts(id),
|
||||
payer_user_id TEXT REFERENCES users(id),
|
||||
event_type TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
event_date TEXT NOT NULL,
|
||||
booking_date TEXT,
|
||||
due_date TEXT,
|
||||
amount NUMERIC(14, 2) NOT NULL,
|
||||
currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
merchant TEXT,
|
||||
counterparty TEXT,
|
||||
description TEXT,
|
||||
category_id TEXT REFERENCES categories(id),
|
||||
project_id TEXT REFERENCES projects(id),
|
||||
created_by_user_id TEXT REFERENCES users(id),
|
||||
fingerprint TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_events_household_status_date
|
||||
ON financial_events(household_id, status, event_date);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS event_observation_links (
|
||||
id TEXT PRIMARY KEY,
|
||||
event_id TEXT NOT NULL REFERENCES financial_events(id),
|
||||
observation_id TEXT NOT NULL REFERENCES raw_observations(id),
|
||||
relation TEXT NOT NULL,
|
||||
confidence NUMERIC(14, 2) NOT NULL DEFAULT 1.00,
|
||||
created_at TEXT NOT NULL,
|
||||
UNIQUE(event_id, observation_id, relation)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS event_relations (
|
||||
id TEXT PRIMARY KEY,
|
||||
from_event_id TEXT NOT NULL REFERENCES financial_events(id),
|
||||
to_event_id TEXT NOT NULL REFERENCES financial_events(id),
|
||||
relation_type TEXT NOT NULL,
|
||||
confidence NUMERIC(14, 2) NOT NULL DEFAULT 1.00,
|
||||
created_by TEXT NOT NULL DEFAULT 'system',
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS split_lines (
|
||||
id TEXT PRIMARY KEY,
|
||||
event_id TEXT NOT NULL REFERENCES financial_events(id),
|
||||
user_id TEXT NOT NULL REFERENCES users(id),
|
||||
share_amount NUMERIC(14, 2) NOT NULL,
|
||||
share_percent NUMERIC(14, 2),
|
||||
reason TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tags (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
name TEXT NOT NULL,
|
||||
UNIQUE(household_id, name)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS event_tags (
|
||||
event_id TEXT NOT NULL REFERENCES financial_events(id),
|
||||
tag_id TEXT NOT NULL REFERENCES tags(id),
|
||||
PRIMARY KEY(event_id, tag_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS project_participants (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL REFERENCES projects(id),
|
||||
user_id TEXT NOT NULL REFERENCES users(id),
|
||||
role TEXT NOT NULL,
|
||||
default_share_percent NUMERIC(14, 2),
|
||||
UNIQUE(project_id, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS project_budget_lines (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL REFERENCES projects(id),
|
||||
category_id TEXT REFERENCES categories(id),
|
||||
name TEXT NOT NULL,
|
||||
budgeted_amount NUMERIC(14, 2) NOT NULL DEFAULT 0.00,
|
||||
committed_amount_cached NUMERIC(14, 2),
|
||||
paid_amount_cached NUMERIC(14, 2),
|
||||
sort_order INTEGER NOT NULL DEFAULT 0,
|
||||
notes TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS project_planned_items (
|
||||
id TEXT PRIMARY KEY,
|
||||
project_id TEXT NOT NULL REFERENCES projects(id),
|
||||
budget_line_id TEXT REFERENCES project_budget_lines(id),
|
||||
description TEXT NOT NULL,
|
||||
estimated_amount NUMERIC(14, 2) NOT NULL DEFAULT 0.00,
|
||||
committed_amount NUMERIC(14, 2),
|
||||
expected_date TEXT,
|
||||
due_date TEXT,
|
||||
expected_payer_account_id TEXT REFERENCES accounts(id),
|
||||
split_rule_id TEXT,
|
||||
planning_status TEXT NOT NULL,
|
||||
payment_status TEXT NOT NULL,
|
||||
reconciliation_status TEXT NOT NULL,
|
||||
settlement_status TEXT NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS payment_lines (
|
||||
id TEXT PRIMARY KEY,
|
||||
planned_item_id TEXT REFERENCES project_planned_items(id),
|
||||
event_id TEXT REFERENCES financial_events(id),
|
||||
amount NUMERIC(14, 2) NOT NULL,
|
||||
currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
date TEXT NOT NULL,
|
||||
paid_by_user_id TEXT REFERENCES users(id),
|
||||
payment_account_id TEXT REFERENCES accounts(id),
|
||||
source_observation_id TEXT REFERENCES raw_observations(id),
|
||||
status TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recurring_commitments (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
provider TEXT NOT NULL,
|
||||
description TEXT,
|
||||
amount_expected NUMERIC(14, 2) NOT NULL,
|
||||
amount_min NUMERIC(14, 2),
|
||||
amount_max NUMERIC(14, 2),
|
||||
currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
interval TEXT NOT NULL,
|
||||
next_due_date TEXT NOT NULL,
|
||||
payer_account_id TEXT REFERENCES accounts(id),
|
||||
split_rule_id TEXT,
|
||||
category_id TEXT REFERENCES categories(id),
|
||||
project_id TEXT REFERENCES projects(id),
|
||||
notice_period TEXT,
|
||||
renewal_date TEXT,
|
||||
status TEXT NOT NULL,
|
||||
matching_rule_json TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS promised_payments (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
related_event_id TEXT REFERENCES financial_events(id),
|
||||
provider TEXT NOT NULL,
|
||||
amount NUMERIC(14, 2) NOT NULL,
|
||||
currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
created_date TEXT NOT NULL,
|
||||
due_date TEXT NOT NULL,
|
||||
expected_funding_account_id TEXT REFERENCES accounts(id),
|
||||
responsible_user_id TEXT REFERENCES users(id),
|
||||
status TEXT NOT NULL,
|
||||
source_observation_id TEXT REFERENCES raw_observations(id),
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS import_connections (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
owner_user_id TEXT NOT NULL REFERENCES users(id),
|
||||
connection_type TEXT NOT NULL,
|
||||
display_name TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
last_sync_at TEXT,
|
||||
last_error TEXT,
|
||||
secret_storage_ref TEXT,
|
||||
runs_locally INTEGER NOT NULL DEFAULT 1,
|
||||
connector_config_json TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS import_runs (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
connection_id TEXT REFERENCES import_connections(id),
|
||||
actor_user_id TEXT REFERENCES users(id),
|
||||
source_type TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'running',
|
||||
imported_count INTEGER NOT NULL DEFAULT 0,
|
||||
duplicate_count INTEGER NOT NULL DEFAULT 0,
|
||||
created_event_count INTEGER NOT NULL DEFAULT 0,
|
||||
skipped_count INTEGER NOT NULL DEFAULT 0,
|
||||
error TEXT,
|
||||
summary_json TEXT,
|
||||
started_at TEXT NOT NULL,
|
||||
finished_at TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS ix_import_runs_household_started
|
||||
ON import_runs(household_id, started_at);
|
||||
CREATE INDEX IF NOT EXISTS ix_import_runs_connection_started
|
||||
ON import_runs(connection_id, started_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS audit_log (
|
||||
id TEXT PRIMARY KEY,
|
||||
household_id TEXT NOT NULL REFERENCES households(id),
|
||||
actor_user_id TEXT REFERENCES users(id),
|
||||
action TEXT NOT NULL,
|
||||
entity_type TEXT NOT NULL,
|
||||
entity_id TEXT,
|
||||
details_json TEXT,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
Reference in New Issue
Block a user