Files
Spendlight/server/drizzle/0001_money_in.sql
Chris Olson c3cf0f3eb8 Milestones 0 and 1: foundation and money in (20261007.10)
Foundation: single arm64 container (Hono + SQLite via Drizzle, React + Vite),
local sign-in with long-lived sessions and passkeys, roles (read-only, full
access, admin), nightly and pre-upgrade backups, light and dark themes,
date-based version numbers, and the ideas lightbulb behind IDEAS_ENABLED.

Money in: accounts with balances, CSV import with bank detection, a column
mapping pop-up for unknown layouts, duplicate checks, transfer pairing and
undo; one-tap review with learned rules; activity with search, splits, tags,
notes and cash entries. Statement files are blocked from commits by a
pre-commit hook; tests use synthetic fixtures only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:52:07 -04:00

145 lines
5.6 KiB
SQL

CREATE TABLE `account` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL,
`kind` text NOT NULL,
`institution` text,
`last4` text,
`color` text DEFAULT 'indigo' NOT NULL,
`status` text DEFAULT 'open' NOT NULL,
`balance_cents` integer DEFAULT 0 NOT NULL,
`balance_as_of` text,
`balance_source` text,
`layout_key` text,
`file_name_pattern` text,
`sort_order` integer DEFAULT 0 NOT NULL,
`created_at` text NOT NULL,
`updated_at` text NOT NULL,
`retired_at` text
);
--> statement-breakpoint
CREATE TABLE `category` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`group_id` integer NOT NULL,
`name` text NOT NULL,
`kind` text DEFAULT 'expense' NOT NULL,
`icon` text DEFAULT 'circle' NOT NULL,
`color` text DEFAULT 'slate' NOT NULL,
`archived` integer DEFAULT false NOT NULL,
`sort_order` integer DEFAULT 0 NOT NULL,
FOREIGN KEY (`group_id`) REFERENCES `category_group`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `category_group_idx` ON `category` (`group_id`);--> statement-breakpoint
CREATE TABLE `category_group` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL,
`sort_order` integer DEFAULT 0 NOT NULL
);
--> statement-breakpoint
CREATE TABLE `import_layout` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL,
`signature` text NOT NULL,
`config` text NOT NULL,
`created_at` text NOT NULL
);
--> statement-breakpoint
CREATE TABLE `import` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`account_id` integer NOT NULL,
`file_name` text NOT NULL,
`file_hash` text NOT NULL,
`layout_key` text NOT NULL,
`date_from` text,
`date_to` text,
`row_count` integer DEFAULT 0 NOT NULL,
`added_count` integer DEFAULT 0 NOT NULL,
`duplicate_count` integer DEFAULT 0 NOT NULL,
`skipped_count` integer DEFAULT 0 NOT NULL,
`transfer_count` integer DEFAULT 0 NOT NULL,
`status` text DEFAULT 'committed' NOT NULL,
`previous_balance` text,
`user_id` integer,
`created_at` text NOT NULL,
`undone_at` text,
FOREIGN KEY (`account_id`) REFERENCES `account`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE set null
);
--> statement-breakpoint
CREATE INDEX `import_account_idx` ON `import` (`account_id`);--> statement-breakpoint
CREATE TABLE `rule` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`merchant` text NOT NULL,
`account_id` integer,
`category_id` integer,
`rename_to` text,
`source` text DEFAULT 'learned' NOT NULL,
`hits` integer DEFAULT 0 NOT NULL,
`created_at` text NOT NULL,
`last_used_at` text,
FOREIGN KEY (`account_id`) REFERENCES `account`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`category_id`) REFERENCES `category`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE INDEX `rule_merchant_idx` ON `rule` (`merchant`);--> statement-breakpoint
CREATE TABLE `split` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`transaction_id` integer NOT NULL,
`category_id` integer NOT NULL,
`amount_cents` integer NOT NULL,
`note` text,
FOREIGN KEY (`transaction_id`) REFERENCES `txn`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`category_id`) REFERENCES `category`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `split_txn_idx` ON `split` (`transaction_id`);--> statement-breakpoint
CREATE INDEX `split_category_idx` ON `split` (`category_id`);--> statement-breakpoint
CREATE TABLE `tag` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL,
`color` text DEFAULT 'slate' NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `tag_name_unique` ON `tag` (`name`);--> statement-breakpoint
CREATE TABLE `txn_tag` (
`transaction_id` integer NOT NULL,
`tag_id` integer NOT NULL,
FOREIGN KEY (`transaction_id`) REFERENCES `txn`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`tag_id`) REFERENCES `tag`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE UNIQUE INDEX `txn_tag_pk` ON `txn_tag` (`transaction_id`,`tag_id`);--> statement-breakpoint
CREATE INDEX `txn_tag_tag_idx` ON `txn_tag` (`tag_id`);--> statement-breakpoint
CREATE TABLE `txn` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`account_id` integer NOT NULL,
`import_id` integer,
`date` text NOT NULL,
`posted_date` text,
`amount_cents` integer NOT NULL,
`description` text NOT NULL,
`merchant` text NOT NULL,
`category_id` integer,
`needs_review` integer DEFAULT true NOT NULL,
`suggested_by` text,
`is_split` integer DEFAULT false NOT NULL,
`bank_category` text,
`bank_type` text,
`note` text,
`transfer_peer_id` integer,
`source` text DEFAULT 'import' NOT NULL,
`dedupe_key` text NOT NULL,
`created_at` text NOT NULL,
`updated_at` text NOT NULL,
FOREIGN KEY (`account_id`) REFERENCES `account`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`import_id`) REFERENCES `import`(`id`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`category_id`) REFERENCES `category`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE INDEX `txn_account_date_idx` ON `txn` (`account_id`,`date`);--> statement-breakpoint
CREATE INDEX `txn_date_idx` ON `txn` (`date`);--> statement-breakpoint
CREATE INDEX `txn_category_date_idx` ON `txn` (`category_id`,`date`);--> statement-breakpoint
CREATE INDEX `txn_merchant_idx` ON `txn` (`merchant`);--> statement-breakpoint
CREATE INDEX `txn_dedupe_idx` ON `txn` (`dedupe_key`);--> statement-breakpoint
CREATE INDEX `txn_review_idx` ON `txn` (`needs_review`);--> statement-breakpoint
CREATE INDEX `txn_import_idx` ON `txn` (`import_id`);