-- Finance module tables CREATE TABLE IF NOT EXISTS income_categories ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, tree_id UUID NOT NULL DEFAULT gen_random_uuid(), name VARCHAR(200) NOT NULL, categories JSONB NOT NULL DEFAULT '[]', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE UNIQUE INDEX IF NOT EXISTS income_categories_org_tree_idx ON income_categories(organization_id, tree_id); CREATE TABLE IF NOT EXISTS expense_categories ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, tree_id UUID NOT NULL DEFAULT gen_random_uuid(), name VARCHAR(200) NOT NULL, categories JSONB NOT NULL DEFAULT '[]', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE UNIQUE INDEX IF NOT EXISTS expense_categories_org_tree_idx ON expense_categories(organization_id, tree_id); CREATE TABLE IF NOT EXISTS income_category_overrides ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, record_id VARCHAR(100) NOT NULL, category_id VARCHAR(100) NOT NULL, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(organization_id, record_id) ); CREATE INDEX IF NOT EXISTS income_overrides_org_record_idx ON income_category_overrides(organization_id, record_id); CREATE TABLE IF NOT EXISTS expense_category_overrides ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, record_id VARCHAR(100) NOT NULL, category_id VARCHAR(100) NOT NULL, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(organization_id, record_id) ); CREATE INDEX IF NOT EXISTS expense_overrides_org_record_idx ON expense_category_overrides(organization_id, record_id); CREATE TABLE IF NOT EXISTS auto_detect_trees ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, context VARCHAR(20) NOT NULL CHECK (context IN ('income', 'expense')), tree_id UUID NOT NULL DEFAULT gen_random_uuid(), name VARCHAR(200) NOT NULL, config JSONB NOT NULL DEFAULT '{}', is_primary BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(organization_id, context, tree_id) ); CREATE INDEX IF NOT EXISTS auto_detect_trees_org_idx ON auto_detect_trees(organization_id, context); CREATE TABLE IF NOT EXISTS node_tags ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, color VARCHAR(20) NOT NULL DEFAULT '#2563eb', created_at TIMESTAMP DEFAULT NOW(), UNIQUE(organization_id, name) ); CREATE INDEX IF NOT EXISTS node_tags_org_idx ON node_tags(organization_id); CREATE TABLE IF NOT EXISTS node_tag_assignments ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, node_id VARCHAR(100) NOT NULL, tag_id INTEGER NOT NULL REFERENCES node_tags(id) ON DELETE CASCADE, context VARCHAR(20) NOT NULL CHECK (context IN ('income', 'expense')), created_at TIMESTAMP DEFAULT NOW(), UNIQUE(organization_id, node_id, tag_id, context) ); CREATE INDEX IF NOT EXISTS node_tag_assignments_org_idx ON node_tag_assignments(organization_id, context, node_id); CREATE TABLE IF NOT EXISTS finance_table_settings ( id SERIAL PRIMARY KEY, organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE, section VARCHAR(20) NOT NULL CHECK (section IN ('income', 'expense')), visible_cols JSONB NOT NULL DEFAULT '[]', col_order JSONB NOT NULL DEFAULT '[]', created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), UNIQUE(organization_id, section) );