Milestone 2: the full picture (20261007.12)

Budgets: one amount per category for every month with any month set on its
own, filled from recent spending in one step and copied into the next year.
Home shows what's left to spend, year pacing, insights, balances and upcoming
charges. Insights covers year pacing, money in and out, budget against actual,
categories by month, merchants, balances over time and tags.

Subscriptions and bills are found across every account (rhythm and price
matching plus a built-in catalog), confirmed with one tap, and watched for
price changes, missed charges, charges after cancelling, double billing,
renewals and trials. Alerts are worked out again whenever the data changes.

Also: category, rule, tag and alert settings; Excel and CSV export from a
small built-in writer; the AI module designed in and switched off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 10:59:17 -04:00
parent c3cf0f3eb8
commit 4ecd64132b
62 changed files with 9977 additions and 378 deletions

View File

@@ -0,0 +1,65 @@
CREATE TABLE `alert` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`kind` text NOT NULL,
`subject_type` text NOT NULL,
`subject_id` integer DEFAULT 0 NOT NULL,
`period` text DEFAULT '' NOT NULL,
`area` text DEFAULT 'money' NOT NULL,
`severity` text DEFAULT 'info' NOT NULL,
`title` text NOT NULL,
`body` text,
`link` text,
`rank` integer DEFAULT 0 NOT NULL,
`created_at` text NOT NULL,
`updated_at` text NOT NULL,
`read_at` text,
`dismissed_at` text,
`resolved_at` text
);
--> statement-breakpoint
CREATE UNIQUE INDEX `alert_unique` ON `alert` (`kind`,`subject_type`,`subject_id`,`period`);--> statement-breakpoint
CREATE INDEX `alert_open_idx` ON `alert` (`resolved_at`,`dismissed_at`);--> statement-breakpoint
CREATE TABLE `budget` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`category_id` integer NOT NULL,
`year` integer NOT NULL,
`month` integer DEFAULT 0 NOT NULL,
`amount_cents` integer NOT NULL,
`updated_at` text NOT NULL,
FOREIGN KEY (`category_id`) REFERENCES `category`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE UNIQUE INDEX `budget_unique` ON `budget` (`category_id`,`year`,`month`);--> statement-breakpoint
CREATE INDEX `budget_year_idx` ON `budget` (`year`);--> statement-breakpoint
CREATE TABLE `subscription` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL,
`kind` text DEFAULT 'subscription' NOT NULL,
`merchant` text NOT NULL,
`aliases` text DEFAULT '[]' NOT NULL,
`catalog_key` text,
`cadence` text DEFAULT 'monthly' NOT NULL,
`expected_cents` integer NOT NULL,
`account_id` integer,
`category_id` integer,
`status` text DEFAULT 'suggested' NOT NULL,
`confidence` text DEFAULT 'likely' NOT NULL,
`source` text DEFAULT 'detected' NOT NULL,
`trial_ends_on` text,
`cancelled_on` text,
`first_charge_on` text,
`last_charge_on` text,
`next_expected_on` text,
`manage_url` text,
`note` text,
`alerts_on` integer DEFAULT true 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 set null,
FOREIGN KEY (`category_id`) REFERENCES `category`(`id`) ON UPDATE no action ON DELETE set null
);
--> statement-breakpoint
CREATE INDEX `subscription_merchant_idx` ON `subscription` (`merchant`);--> statement-breakpoint
CREATE INDEX `subscription_status_idx` ON `subscription` (`status`);--> statement-breakpoint
ALTER TABLE `txn` ADD `subscription_id` integer;--> statement-breakpoint
CREATE INDEX `txn_subscription_idx` ON `txn` (`subscription_id`);

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,13 @@
"when": 1791404838766,
"tag": "0001_money_in",
"breakpoints": true
},
{
"idx": 2,
"version": "6",
"when": 1791417594406,
"tag": "0002_full_picture",
"breakpoints": true
}
]
}