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>
This commit is contained in:
145
server/drizzle/0001_money_in.sql
Normal file
145
server/drizzle/0001_money_in.sql
Normal file
@@ -0,0 +1,145 @@
|
||||
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`);
|
||||
Reference in New Issue
Block a user