Free-text annotation up to 1024 chars. Nullable so existing rows need
no backfill; an empty or whitespace-only input will be normalised to
NULL in the service layer. Alembic batch_alter_table handles the
SQLite table rebuild automatically.
Refs #13
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A month is a snapshot of the budget. MonthEntry holds the copied planned
amount plus applied and origin_name/origin_planned so the UI can mark
edited rows. source_entry_id links back to the budget but is nullable
with ON DELETE SET NULL, so deleting a budget row after snapshot leaves
the month intact. MonthDebtTarget is one row per month via CASCADE from
month.
Refs #3
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Runs at env module load so the backup fires ahead of offline and
online migration paths, as well as alembic current / revision. A
failing backup does not stop the migration: this is defense in depth,
not a hard prerequisite, and the common failure case is "DB does not
exist yet" on a fresh checkout.
Refs #5
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entry stores one row per section entry (name, amount, timestamps).
DebtTarget is a singleton table (CHECK id = 1) with a nullable
foreign key to Entry using ON DELETE SET NULL so deleting the
referenced Debt Minimums row clears the pointer.
Refs #1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>