---
title: Personal Finance App
status: final
created: 2026-05-25
updated: 2026-05-25
project: financials
owner: sayre@outlook.com
---

# Personal Finance App — Product Requirements Document

## 1. Overview

A self-hosted personal finance web application that gives a single user full visibility and control over spending, budgets, debt, and financial patterns. The app imports real bank/card statements, plans credit card paydown with multiple strategies, and surfaces spending insights over time.

**Stack:** Python 3.x (Flask) · SQLite · HTML/JS/CSS · Primer CSS  
**Hosting:** Self-hosted, Apache + mod_wsgi (or reverse proxy to Flask dev server)  
**Scope:** Single user · No authentication required · No external API integrations

---

## 2. Goals & Non-Goals

### Goals
- Provide a single dashboard that shows budget burn, upcoming bills, recent transactions, and debt paydown progress at a glance.
- Enable manual transaction entry and category management from day one.
- Calculate and present credit card paydown plans across five strategies; let the user select and monitor one active plan.
- Import 6+ months of PDF statements from 7 card/bank issuers with smart parsing: auto-categorization, duplicate detection, merchant normalization.
- Surface spending patterns, subscription detection, and budget recommendations driven by actual history.

### Non-Goals
- Multi-user or household sharing.
- Cloud hosting, external auth, or any third-party login.
- Bank API/Plaid integration.
- Mobile app or native application.
- Net worth snapshot or investment tracking.
- Push/email/SMS notifications — all monitoring is in-app only.

---

## 3. Phased Delivery Plan

| Phase | Scope | Unlock Condition |
|-------|-------|-----------------|
| **Phase 1** | Core foundation: dashboard, manual transactions, budgets, bills/debts, Paydown Planner | Deployable baseline |
| **Phase 2** | Smart PDF import: multi-issuer parser, bulk historical load (~6 months), duplicate detection | Phase 1 shipped |
| **Phase 3** | Analytics layer: spending pattern analysis, subscription detection, history-driven budget recommendations | ≥2 months of imported transaction history |

---

## 4. Feature Requirements

### 4.1 Dashboard (Phase 1)

**FR-1.1** The dashboard is the default landing page and renders without page reload after initial load.

**FR-1.2** Dashboard surface includes all of the following widgets:
- **Budget Burn** — progress bars per category showing spent vs. budgeted this month, color-coded (green/yellow/red by percentage used).
- **Upcoming Bills** — next 30 days of bill due dates with amounts and days-until-due.
- **Debt Paydown Progress** — if an active paydown plan exists, show per-card progress and projected payoff timeline.
- **Recent Transactions** — last 10 transactions with date, merchant, amount, category.
- **Monthly Spending Summary** — current month total vs. prior month total, delta highlighted.

**FR-1.3** Each widget links to its full management view.

---

### 4.2 Transaction Management (Phase 1)

**FR-1.4** User can manually add a transaction with: date, merchant/payee, amount, category, account, optional notes.

**FR-1.5** User can edit or delete any transaction.

**FR-1.6** Transactions are categorized. Default category set includes: Housing, Groceries, Dining, Transportation, Utilities, Healthcare, Entertainment, Shopping, Subscriptions, Personal Care, Debt Payments, Income, Transfers, Uncategorized.

**FR-1.7** User can create, rename, and delete custom categories.

**FR-1.8** Transaction list view supports filtering by date range, category, account, and amount range, plus free-text search on merchant/notes.

**FR-1.9** Transaction list is paginated (50 per page default) and sortable by date, amount, merchant.

---

### 4.3 Budget Management (Phase 1)

**FR-1.10** User can set a monthly budget amount per category.

**FR-1.11** On first use (or when fewer than 2 months of data exist), the app offers a 50/30/20 budget template: 50% needs, 30% wants, 20% savings/debt. User can accept as-is or adjust allocations before saving.

**FR-1.12** Once ≥2 months of transaction history exists, the budget recommendation engine activates and suggests per-category budgets based on the user's own 3-month rolling average spend, rounded to the nearest $5. Recommendations are surfaced as a "Refresh recommendations" prompt — not applied automatically.

**FR-1.13** Budget view shows: budgeted amount, amount spent to date this month, remaining amount, and percentage used, per category.

**FR-1.14** Budgets roll monthly. Unused amounts do not carry forward.

**FR-1.15** User can view historical budget vs. actuals for any prior month.

---

### 4.4 Settings (Phase 1)

**FR-1.15a** A Settings page allows the user to enter a monthly net income figure. This value is used by the analytics layer (FR-3.4) for income-relative spending flags. It is not a transaction; it is a single stored value updated manually as needed.

---

### 4.5 Bills & Debts Tracking (Phase 1)

**FR-1.16** User can add a recurring bill with: name, amount, due date (day of month or specific date), account/payee, category, and active/inactive status.

**FR-1.17** Bills view lists all bills sorted by next due date, showing amount, status (upcoming / due today / overdue), and days until due.

**FR-1.18** User can mark a bill as paid for the current cycle, which logs a transaction and advances the next due date.

**FR-1.19** User can add a debt (non-credit-card) with: name, current balance, interest rate, minimum payment, due date. These appear in the bills list and feed the dashboard upcoming bills widget.

---

### 4.6 Paydown Planner (Phase 1)

**FR-1.20** User inputs one or more credit card accounts, each with: card name/issuer, current balance, APR, minimum payment, credit limit.

**FR-1.21** User inputs a total monthly extra payment amount available for paydown beyond minimums.

**FR-1.22** The planner calculates and presents plans under all five strategies simultaneously for comparison:

| Strategy | Description |
|----------|-------------|
| **Avalanche** | Direct extra payment to highest-APR card first. Minimizes total interest paid. |
| **Snowball** | Direct extra payment to lowest-balance card first. Fastest early wins. |
| **Highest Balance First** | Direct extra payment to highest-balance card first. |
| **Proportional** | Distribute extra payment proportionally across all cards by current balance. |
| **Custom** | User specifies a fixed monthly extra payment amount per card manually. |

**FR-1.23** Each strategy plan displays: per-card payoff month/year, total interest paid, total months to debt-free, a month-by-month amortization table (expandable), and a payoff timeline chart.

**FR-1.24** User selects one strategy to "activate." Only one plan is active at a time.

**FR-1.25** The active plan is monitored on the dashboard (FR-1.2) and in a dedicated Paydown Monitor view showing: actual vs. planned balance per card per month, deviation alerts (in-app flag if a card's actual balance exceeds the plan's projected balance by >5%), and projected vs. actual payoff date.

**FR-1.26** User can update card balances monthly to keep monitoring accurate. Updates are logged with a timestamp.

**FR-1.27** User can switch the active strategy at any time; the prior plan is archived with a timestamp and the new plan recalculates from current balances.

---

### 4.7 PDF Statement Import (Phase 2)

**FR-2.1** User can upload one or more PDF files via the import UI. Supported issuers: Chase, Bank of America, Apple Card, Kohls, Discover, DCU Credit Union, Target.

**FR-2.2** The system detects the issuer automatically from the PDF content (header text, layout patterns) before parsing. If detection confidence is low, the user is prompted to confirm the issuer.

**FR-2.3** The parser extracts for each transaction: date, merchant/description (raw), amount, debit/credit flag, and statement period. Parsed transactions are staged for review before any are committed to the database.

**FR-2.4** The staging review screen shows all extracted transactions in a table. User can edit merchant name, category, or amount on any row before confirming.

**FR-2.5** Auto-categorization applies merchant name matching against a built-in merchant→category map. Unrecognized merchants are flagged as Uncategorized for user review. User corrections to merchant→category mappings are saved and reapplied on future imports.

**FR-2.6** Merchant name normalization cleans raw statement strings (e.g., "AMZN*MARKETPLACE 04/22" → "Amazon") using a configurable normalization table.

**FR-2.7** Duplicate detection: a transaction is flagged as a probable duplicate if another transaction with the same date, amount, and normalized merchant exists within a 3-day window. Flagged duplicates are shown to the user for confirm-keep or dismiss-skip before commit.

**FR-2.8** After user review and confirmation, transactions are committed to the main transaction table tagged with their source account and import batch ID.

**FR-2.9** Import history log records: upload date, issuer, statement period, transaction count imported, duplicates skipped, and any parse errors.

**FR-2.10** Parse errors (pages or rows that could not be extracted) are surfaced per-file with enough context (page number, raw text sample) for the user to manually enter the missed transactions.

---

### 4.8 Analytics & Insights (Phase 3)

**FR-3.1** Spending pattern view shows monthly spend by category as a stacked bar chart covering all available history, with a trend line per category.

**FR-3.2** Year-over-year and month-over-month comparisons are available for any category or total spend.

**FR-3.3** Subscription detector scans transactions for recurring charges: same merchant, similar amounts (within ±$1), on a recurring interval (weekly, monthly, annual). Detected subscriptions are listed with: merchant, estimated amount, recurrence, and total paid in the last 12 months.

**FR-3.4** Bad spending pattern flags surface automatically when: a category exceeds its budget by >20% for 2 consecutive months; a subscription has not had a matching transaction in 60+ days (possible cancelled but still charged); or total dining/entertainment exceeds 15% of the monthly income figure entered in Settings (FR-1.15a).

**FR-3.5** Budget recommendation engine (described in FR-1.12) is powered by at least 2 months of imported history. Recommendations include the suggested amount, the 3-month average that drove it, and a comparison to the current budget.

**FR-3.6** Merchant spend summary view: top 20 merchants by total spend, sortable by total amount or transaction count, filterable by date range.

---

## 5. Non-Functional Requirements

**NFR-1 Performance.** Dashboard renders in under 2 seconds on the host machine. PDF import parse+stage completes in under 30 seconds per statement file.

**NFR-2 Data integrity.** SQLite WAL mode enabled. All writes transactional. Import uses a staged commit (nothing written to main tables until user confirms review).

**NFR-3 Recoverability.** A manual database backup/export function downloads the SQLite file. Export of all transactions to CSV available from the transaction view.

**NFR-4 Usability.** All primary flows (add transaction, run paydown plan, import PDF, check dashboard) completable in ≤3 clicks/steps from the main nav. Primer CSS provides consistent, accessible UI patterns throughout.

**NFR-5 Browser support.** Modern desktop browsers (Chrome, Firefox, Edge — current stable). No mobile optimization required.

**NFR-6 No external calls.** The application makes no outbound network requests. All computation is local. No analytics, telemetry, or CDN dependencies.

---

## 6. Technical Constraints

**TC-1** Python 3.10+ · Flask 3.x · SQLite (single file at configurable path) · `pdfplumber` for PDF extraction · `pandas` for aggregation and analysis.

**TC-2** Primer CSS loaded from a local copy (no CDN) per NFR-6.

**TC-3** PDF parsers are issuer-specific modules. Each issuer (Chase, BofA, Apple, Kohls, Discover, DCU, Target) requires a dedicated extraction profile due to differing PDF layouts. Parsers are isolated and independently testable.

**TC-4** No JavaScript framework. Vanilla JS only for interactivity (chart rendering, dynamic form updates, AJAX calls to Flask JSON endpoints). Chart library: Chart.js (local copy).

**TC-5** Flask app served via Apache mod_wsgi or a local reverse proxy. Not intended for public internet exposure — LAN/localhost only.

---

## 7. Data Model (Summary)

| Entity | Key Fields |
|--------|-----------|
| `settings` | id, monthly_income |
| `accounts` | id, name, issuer, type (credit/debit/loan), credit_limit, apr, min_payment |
| `transactions` | id, date, merchant_raw, merchant_normalized, amount, category_id, account_id, import_batch_id, is_manual |
| `categories` | id, name, is_system |
| `budgets` | id, category_id, month, year, amount |
| `bills` | id, name, amount, due_day, payee, category_id, is_active, last_paid_date |
| `debts` | id, name, current_balance, interest_rate, min_payment, due_date |
| `paydown_plans` | id, strategy, created_at, is_active, extra_monthly_payment |
| `paydown_plan_cards` | id, plan_id, account_id, monthly_allocation |
| `paydown_balance_updates` | id, account_id, balance, updated_at |
| `import_batches` | id, issuer, statement_period_start, statement_period_end, imported_at, transaction_count |
| `merchant_mappings` | id, merchant_raw_pattern, merchant_normalized, category_id |

---

## 8. Open Items

| # | Item | Phase | Priority |
|---|------|-------|----------|
| OQ-3 | Apple Card PDF uses a non-standard table layout; may require OCR fallback (e.g., `pytesseract`). Needs implementation spike. | Phase 2 | High |
| OQ-4 | Target RedCard is issued as both credit and debit; parser must handle both statement types. | Phase 2 | Medium |
| OQ-5 | DCU Credit Union PDF format is less standardized than major issuers; may need a manually configured extraction template. | Phase 2 | Medium |

---

## 9. Out of Scope (All Phases)

- Investment or retirement account tracking
- Net worth calculation
- Tax reporting or export
- Receipt scanning / photo capture
- Multi-currency support
- Bank API or Plaid integration
- User authentication / login
- Data sharing or export to third-party tools
- Mobile-responsive layout
