577 lines
26 KiB
Markdown
577 lines
26 KiB
Markdown
# PFM — Personal Finance Manager
|
||
|
||
A self-hosted personal finance web application. Track income, expenses, investments, budgets, and savings goals. AI-powered financial assistant and receipt OCR built in. Sync bank accounts via Teller, Plaid, or Schwab.
|
||
|
||
**Live at:** https://pfm.ngodanguyen.tech
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [Features Overview](#features-overview)
|
||
2. [Getting Started](#getting-started)
|
||
3. [Dashboard](#dashboard)
|
||
4. [Transactions](#transactions)
|
||
5. [Accounts](#accounts)
|
||
6. [Categories](#categories)
|
||
7. [Budgets](#budgets)
|
||
8. [Goals & Savings](#goals--savings)
|
||
9. [Investments](#investments)
|
||
10. [AI Assistant](#ai-assistant)
|
||
11. [Reports & Export](#reports--export)
|
||
12. [Settings](#settings)
|
||
13. [Security & 2FA](#security--2fa)
|
||
14. [Recurring Transactions](#recurring-transactions)
|
||
15. [Bank Statement Import](#bank-statement-import)
|
||
16. [Receipt OCR](#receipt-ocr)
|
||
17. [Teller Bank Sync](#teller-bank-sync)
|
||
18. [Schwab Bank Sync](#schwab-bank-sync)
|
||
19. [Plaid Bank Sync](#plaid-bank-sync)
|
||
20. [USD → VND Rate Widget](#usd--vnd-rate-widget)
|
||
21. [System Logs](#system-logs)
|
||
22. [Keyboard Shortcuts & Tips](#keyboard-shortcuts--tips)
|
||
|
||
---
|
||
|
||
## Features Overview
|
||
|
||
| Module | What it does |
|
||
|--------|-------------|
|
||
| **Dashboard** | Net worth, savings rate, cash flow chart, budget gauges, upcoming bills, reconcile, AI insight, USD/VND rate |
|
||
| **Transactions** | Income/expense entry, transfer, inline category, bulk actions, quick date filters, duplicate detection, split transaction, filtered export |
|
||
| **Accounts** | Multiple account types, auto-calculated or provider-synced balances (Teller / Plaid / Schwab) |
|
||
| **Categories** | Custom expense + income categories with color and icon |
|
||
| **Budgets** | Monthly spending limits with progress bars, budget vs actual chart, rollover support |
|
||
| **Goals** | Savings goals with contribution tracking, projected completion, emergency fund tracker |
|
||
| **Investments** | Stock/ETF/crypto portfolio, per-account view, price alerts, price history chart, live price fetch |
|
||
| **AI Assistant** | Chat with your finances via Groq (free), daily auto-insight, streaming responses |
|
||
| **Receipt OCR** | Drag-drop a receipt image — AI extracts and fills the form |
|
||
| **Reports** | Monthly/quarterly/yearly summaries, net worth history, category spending trends, PDF/CSV/Excel export |
|
||
| **Teller** | Live US bank sync (mTLS), balance refresh, transaction import, webhook |
|
||
| **Schwab** | Schwab brokerage sync — balance, stock/ETF positions, transaction import, daily auto-sync |
|
||
| **Plaid** | 12,000+ US banks/credit unions via Plaid — cursor sync, credit card billing, webhook auto-import |
|
||
| **Bank Import** | Upload PDF/OFX/QFX/CSV bank statements — auto-categorizes, preview before import |
|
||
| **Security** | TOTP 2FA, session idle timeout, rate limiting, audit log, at-rest encryption for bank tokens |
|
||
| **System Logs** | DB-backed application log viewer with colour-coded levels, search, module filter, and purge |
|
||
|
||
---
|
||
|
||
## Getting Started
|
||
|
||
### First Login
|
||
|
||
1. Navigate to `https://pfm.ngodanguyen.tech`
|
||
2. Enter the username and password created during setup (`python scripts/init_db.py`)
|
||
3. Check "Remember me" to stay logged in across browser sessions
|
||
|
||
### Recommended Setup Order
|
||
|
||
1. **Add accounts** — add your bank accounts, cash wallet, and credit cards first
|
||
2. **Review categories** — 21 default categories are seeded; add custom ones if needed
|
||
3. **Set your currency** — go to Settings → Profile and pick from 8 currency options
|
||
4. **Connect bank sync** — connect Teller (US banks), Plaid (12,000+ institutions), or Schwab for automatic data
|
||
5. **Add transactions** — enter income/expenses manually, import a bank statement, or sync from a provider
|
||
6. **Set budgets** — once you have spending data, set monthly limits per category
|
||
7. **Create goals** — add savings goals and start contributing
|
||
8. **Add investments** — manually or via Schwab sync
|
||
9. **Enable 2FA** — recommended: Settings → Security → Two-Factor Authentication
|
||
|
||
---
|
||
|
||
## Dashboard
|
||
|
||
The dashboard is the home screen — accessible from the sidebar or by clicking the PFM logo.
|
||
|
||
### Period Selector
|
||
Three buttons in the top-right: **This Month**, **Last Month**, **Custom** (date range picker). All summary cards update for the chosen period.
|
||
|
||
### Summary Cards
|
||
- **Income** — total income for the selected period
|
||
- **Expenses** — total expenses for the selected period
|
||
- **Net Cash Flow** — income minus expenses
|
||
- **Savings Rate** — net cash flow ÷ income (green ≥ 20%, blue > 0%, red negative)
|
||
- **Net Worth** — total assets minus liabilities
|
||
- **Checking & Savings** — sum of checking, savings, and cash account balances
|
||
- **Investments** — sum of investment and crypto account balances
|
||
|
||
### Reconcile Button
|
||
Click **Reconcile** (next to period selector) to recalculate income, expenses, net cash flow, and savings rate while **excluding internal transfers**. This shows your true external cash flow. A notice shows the excluded transfer amounts and which categories were excluded. Click again to toggle back to the original totals.
|
||
|
||
### Cash Flow Chart
|
||
Bar chart showing the last 6 months of income (green) vs expenses (red).
|
||
|
||
### Upcoming Bills
|
||
Table of recurring rules due within the next 14 days — category icon, rule name, due date (color-coded: today/overdue in red, within 3 days in amber), amount, and account. Links to the Recurring page.
|
||
|
||
### Accounts Panel
|
||
Lists all active accounts with current balances. Credit cards show **Amount Owed** (positive) instead of a raw negative balance.
|
||
|
||
### AI Daily Insight
|
||
Auto-generated summary of your finances at midnight. Click **Generate Now** for an on-demand insight. Click **Open AI →** for the full chat interface.
|
||
|
||
### USD → VND Widget
|
||
Reference-only exchange rate. Click ↻ to refresh without reloading. Click the widget to expand a 30-day trend chart. A ⚠ stale indicator appears if the rate is older than one day.
|
||
|
||
### Schwab Expiry Warning
|
||
A banner appears on the dashboard when your Schwab refresh token expires within 2 days. Click the link to reconnect.
|
||
|
||
---
|
||
|
||
## Transactions
|
||
|
||
### Viewing Transactions
|
||
Navigate via **Transactions** in the sidebar. Two tabs: **Expenses** and **Income** (with total counts).
|
||
|
||
### Filtering
|
||
- **Search** — matches description and notes fields
|
||
- **Category** dropdown
|
||
- **Account** dropdown
|
||
- **Date range** — from/to pickers
|
||
- **Amount range** — min/max amount
|
||
- **Quick date filters** — "This Month" and "Last Month" buttons above the filter bar; active button is highlighted; ✕ clears the quick filter
|
||
- **Saved filter presets** — save the current filter combination under a name; reload it from the dropdown in one click
|
||
|
||
### Plaid Review Banner
|
||
When transactions are imported via Plaid webhook without a category, a purple banner at the top of the Transactions page shows the count and a link to review and categorize them. The sidebar Transactions link also shows a badge with the count.
|
||
|
||
### Adding a Transaction
|
||
Use the topbar **Income** / **Expense** buttons, or use the sidebar links. The form includes:
|
||
- Type toggle (Income / Expense) — switches available categories
|
||
- Description, amount, date, account, category, notes
|
||
- **Duplicate detection** — if the same amount on the same date already exists, a yellow warning banner appears before you save
|
||
|
||
### Inline Category Change
|
||
Click the **category dropdown** on any transaction row in the table to change the category. The change saves via AJAX — no page reload.
|
||
|
||
### Editing and Deleting
|
||
Click **Edit** to open the full form. Click **Del** to delete permanently.
|
||
|
||
### Split Transaction
|
||
Click the ✂ (scissors) icon on any transaction row to split it into multiple parts:
|
||
- A split page shows the original transaction details and two default rows
|
||
- Assign a different **category**, **description**, and **amount** to each part
|
||
- A live **Remaining** counter shows how much is left to allocate
|
||
- Add or remove rows as needed; the total must equal the original amount
|
||
- On confirm, the original transaction is replaced by the individual split transactions
|
||
|
||
### Bulk Actions
|
||
Check one or more transaction rows (or use the **select all** header checkbox) to reveal the bulk action toolbar:
|
||
- **Set category** — apply a category to all selected rows at once; dropdowns update in the table without reload
|
||
- **Delete** — delete all selected transactions after a confirmation dialog
|
||
|
||
### Export Filtered View
|
||
In the filter bar, **CSV** and **Excel** buttons export the current filtered view (respects all active filters — search, category, account, date range, amount range). Exports are streamed for memory efficiency — no row limit.
|
||
|
||
### Transfers
|
||
Click **Transfer** in the topbar. Creates a single transfer record between two accounts. Transfers are excluded from income/expense totals.
|
||
|
||
---
|
||
|
||
## Accounts
|
||
|
||
### Account Types
|
||
`checking` / `savings` / `cash` / `credit_card` / `crypto` / `investment` / `other`
|
||
|
||
### Balance Sources
|
||
- **Manually managed** — balance is computed from transactions (income − expenses ± transfers). Updates after every transaction.
|
||
- **Teller-linked** — live balance from Teller API. Blue **Teller** badge. Updated after sync or Refresh click.
|
||
- **Schwab-linked** — balance from Schwab snapshot (liquidation value). Green **Schwab** badge. Updated after Balance & Positions click or daily auto-sync.
|
||
- **Plaid-linked** — live balance from Plaid API. Purple **Plaid** badge. Updated after sync or Refresh click.
|
||
|
||
### Teller Account Actions
|
||
| Button | What it does |
|
||
|--------|-------------|
|
||
| **Refresh** | Pulls live balance from Teller API (AJAX) |
|
||
| **Sync** | Opens transaction preview — import new transactions |
|
||
| **Reset** | Clears sync cursor — next Sync re-fetches full 90-day history |
|
||
|
||
### Schwab Account Actions
|
||
| Button | What it does |
|
||
|--------|-------------|
|
||
| **Balance & Positions** | Fetches live balance + investment holdings from Schwab |
|
||
| **Transactions** | Opens transaction import preview |
|
||
|
||
### Plaid Account Actions
|
||
| Button | What it does |
|
||
|--------|-------------|
|
||
| **Refresh** | Pulls live balance from Plaid API (AJAX) |
|
||
| **Sync** | Opens transaction preview — import new transactions |
|
||
| **Billing** | Fetches credit card due date, minimum payment, and statement balance |
|
||
|
||
### Plaid Credit Card Billing Card
|
||
For Plaid-linked credit cards, a billing card on the account shows: due date, days remaining, minimum payment, and last statement balance. Updated by clicking **Billing**.
|
||
|
||
### Credit Cards
|
||
Credit cards show two values:
|
||
- **Amount Owed** — how much you currently owe (positive number)
|
||
- **This Month** — expenses charged to the card this calendar month
|
||
|
||
### Opening Balance
|
||
When creating a new account, enter the current balance in the **Opening Balance** field. For credit cards, enter a **negative number** to indicate existing debt (e.g. `-500` if you owe $500).
|
||
|
||
---
|
||
|
||
## Categories
|
||
|
||
Navigate via the sidebar footer → **Categories**.
|
||
|
||
**Default Expense (14):** Housing, Food & Dining, Transport, Utilities, Health, Entertainment, Shopping, Education, Insurance, Personal Care, Travel, Subscriptions, Gifts, Other
|
||
|
||
**Default Income (7):** Salary, Freelance, Business, Investment, Rental, Gift Received, Other Income
|
||
|
||
System categories (grey badge) cannot be deleted — color and icon can still be changed. Custom categories can be fully edited and deleted.
|
||
|
||
---
|
||
|
||
## Budgets
|
||
|
||
Navigate via **Budgets** in the sidebar. Use ◀ ▶ to navigate months.
|
||
|
||
### Setting Budgets
|
||
Click **Add Budget** in the topbar to set a monthly limit for a category. Click **Edit** on an existing row to adjust.
|
||
|
||
### Budget vs Actual Chart
|
||
A horizontal bar chart at the top of the page shows **Spent** (color-coded green/amber/red) vs **Budget limit** per category — for all categories that have a budget set this month.
|
||
|
||
### Progress Bars
|
||
Each row shows a progress bar: green (< 80%) → amber (80–99%) → red (≥ 100%). Rows that exceed the limit have a red background tint.
|
||
|
||
### Rollover
|
||
Enable rollover on a budget to carry unused amounts forward to the next month. A blue **+rollover** badge shows the carried-over amount on the row.
|
||
|
||
### Copy from Previous Month
|
||
Click **Copy from [month]** at the top right to duplicate last month's budgets to the current month in one click. Also available on the empty-state screen.
|
||
|
||
---
|
||
|
||
## Goals & Savings
|
||
|
||
Navigate via **Goals** in the sidebar.
|
||
|
||
- Create goals with target amount, target date, color, and icon
|
||
- Add contributions with dates and notes; view contribution history
|
||
- Progress bar + projected completion date (based on average monthly contribution)
|
||
- Auto-completes when 100% is reached
|
||
- **Emergency Fund Tracker** — shows how many months your liquid assets (checking + savings + cash accounts) cover at your current monthly spending rate, with 3-month and 6-month targets
|
||
|
||
---
|
||
|
||
## Investments
|
||
|
||
Navigate via **Investments** in the sidebar.
|
||
|
||
### Portfolio Overview
|
||
Summary cards: **Total Value**, **Total Cost**, **Unrealized P&L**, **Return %**. Allocation doughnut chart by asset type. Sidebar "By Account" breakdown.
|
||
|
||
### Price Alerts
|
||
A yellow banner at the top of the Investments page appears when any holding moves ≥ 5% intraday. The banner lists each mover with its ticker and change percentage. Dismiss with ×. Alerts are recalculated daily when prices update.
|
||
|
||
### Investment Detail Page
|
||
Click any holding to see the detail page:
|
||
- Current price, day change, P&L
|
||
- **Price history chart** — 1W / 1M / 3M / 6M / 1Y timeframes; fetched from Yahoo Finance
|
||
- Full buy/sell/dividend/split transaction log
|
||
|
||
### Per-Account View
|
||
If investments span multiple accounts (e.g. Schwab Individual + Schwab Roth IRA), holdings are grouped into separate sections — one per account. Each section shows the account name, total value, and its own holdings table. Same ticker in different accounts stays as separate rows.
|
||
|
||
### Syncing from Schwab
|
||
Click **Sync Schwab** in the topbar to pull the latest holdings and balances for all mapped Schwab accounts at once.
|
||
|
||
### Adding a Holding Manually
|
||
Click **Add Holding** in the topbar. After saving, go to the detail page to record buy transactions.
|
||
|
||
### Ticker Format
|
||
- US Stocks/ETFs: `AAPL`, `VOO`, `QQQ`
|
||
- Crypto: `BTC-USD`, `ETH-USD`
|
||
- International: Yahoo Finance suffix (e.g. `VIC.VN`)
|
||
|
||
### Refreshing Prices
|
||
Click **Refresh Prices** in the topbar. Prices also auto-update daily at 4 PM weekdays via cron.
|
||
|
||
---
|
||
|
||
## AI Assistant
|
||
|
||
Navigate via **AI Assistant** in the sidebar.
|
||
|
||
The AI has access to the last 90 days of transactions, budget status, goals, investments, and net worth. No personal names or identifiers are sent — only aggregated financial figures.
|
||
|
||
- Type a message and press **Enter** to send; **Shift+Enter** for a new line
|
||
- Responses stream word-by-word (SSE)
|
||
- Eight quick-question suggestion buttons
|
||
- **Daily Insight** — auto-generated at midnight; click **Generate Now** to create on demand
|
||
- **Chat History** — all past responses with timestamps
|
||
|
||
### AI Model
|
||
Change in Settings → Profile → AI Model:
|
||
- `llama-3.3-70b-versatile` — best quality (default)
|
||
- `llama-3.1-8b-instant` — faster, slightly lower quality
|
||
|
||
---
|
||
|
||
## Reports & Export
|
||
|
||
Navigate via **Reports** in the sidebar.
|
||
|
||
Four tabs: **Monthly**, **Quarterly**, **Yearly**, **Tax Year**.
|
||
|
||
Export buttons in the topbar:
|
||
- **CSV** — plain text, streamed (no row limit)
|
||
- **Excel** — color-coded (green = income, red = expense), formatted, streamed
|
||
- **PDF** — printable report via WeasyPrint
|
||
|
||
**Net Worth History** — line chart from monthly snapshots. **Snapshot Now** saves today's values immediately.
|
||
|
||
**Category Spending Trends** — top 6 categories over the last 6 months.
|
||
|
||
---
|
||
|
||
## Settings
|
||
|
||
Navigate via the gear icon at the bottom of the sidebar.
|
||
|
||
| Section | What you can change |
|
||
|---------|-------------------|
|
||
| **Profile** | Display name, email, timezone, currency (8 options), AI model |
|
||
| **Password** | Change password (requires current password) |
|
||
| **Security** | Enable/disable TOTP 2FA; view Audit Log |
|
||
| **Recurring** | Create/edit/pause recurring transaction rules |
|
||
| **Import** | Upload CSV or bank statement for bulk import |
|
||
| **System Logs** | View, search, and purge application logs |
|
||
|
||
All Settings sub-pages have a **← Settings** back button in the topbar.
|
||
|
||
---
|
||
|
||
## Security & 2FA
|
||
|
||
### Two-Factor Authentication (TOTP)
|
||
1. Go to Settings → **Security** section
|
||
2. Click **Enable Two-Factor Authentication**
|
||
3. Scan the QR code with an authenticator app (Google Authenticator, Authy, etc.) or enter the manual key
|
||
4. Enter the 6-digit code to confirm setup
|
||
5. On future logins, you will be prompted for a 6-digit code after password entry
|
||
|
||
To disable 2FA: Settings → Security → **Disable** (requires password confirmation).
|
||
|
||
The TOTP verify endpoint is rate-limited (10/min, 30/hr). After 5 failed attempts in one session, the login is invalidated and you must start over.
|
||
|
||
### Session Idle Timeout
|
||
Sessions expire after 60 minutes of inactivity (configurable via `SESSION_IDLE_MINUTES` in `.env`).
|
||
|
||
### Audit Log
|
||
Settings → **Audit Log** shows a paginated, filterable log of security events with IP addresses and timestamps:
|
||
- Login success / failure (with and without 2FA)
|
||
- 2FA enabled / disabled
|
||
- Password changed
|
||
- Schwab connected / disconnected
|
||
|
||
Filter by event type. **Purge** dropdown removes entries older than 7, 30, or 90 days.
|
||
|
||
### At-Rest Encryption
|
||
Teller, Schwab, and Plaid OAuth tokens are encrypted in the database using AES-128 (Fernet). Changing `SECRET_KEY` in `.env` invalidates stored tokens — all providers would need to reconnect.
|
||
|
||
---
|
||
|
||
## Recurring Transactions
|
||
|
||
Navigate via Settings → **Recurring**.
|
||
|
||
Rules auto-create transactions on a schedule. Frequencies: `daily`, `weekly`, `biweekly`, `monthly`, `quarterly`, `yearly`.
|
||
|
||
- Set start date, optional end date, account, category, and amount
|
||
- Pause/enable individual rules without deleting them
|
||
- **Run Now** button processes all overdue rules immediately
|
||
- **Upcoming (30 days)** panel shows next-due dates for all active rules
|
||
- Rules also appear on the **Dashboard upcoming bills widget** when due within 14 days
|
||
|
||
---
|
||
|
||
## Bank Statement Import
|
||
|
||
Navigate via Settings → **Import Statement** (sidebar) or Settings → Import.
|
||
|
||
### Supported Formats
|
||
| Format | Notes |
|
||
|--------|-------|
|
||
| **PDF** | Digital (text-based) PDFs only — scanned/image PDFs are rejected. Uses table extraction first; falls back to AI parsing via Groq if no structured table is found |
|
||
| **OFX / QFX** | Standard Open Financial Exchange format (most US banks) |
|
||
| **CSV** | Chase, BofA, Citi, Capital One, Discover, Amex, USAA, Wells Fargo, and Generic CSV |
|
||
| **Custom CSV** | Map your own column headers when the bank format isn't recognized |
|
||
|
||
### Import Flow
|
||
1. Upload the file
|
||
2. **Preview table** — per-row checkboxes, editable category dropdowns, bulk category apply, bulk type toggle
|
||
3. Click **Confirm Import** to write to the database
|
||
|
||
### Duplicate Detection
|
||
- OFX/QFX: uses the `FITID` field
|
||
- CSV/PDF: matches on date + amount + description + account
|
||
|
||
### Auto-Categorization
|
||
200+ keyword rules automatically assign categories to imported transactions. Override any row in the preview before confirming.
|
||
|
||
---
|
||
|
||
## Receipt OCR
|
||
|
||
On the **new expense form**: drag-drop or click the purple **AI Receipt Scanner** panel to upload a receipt image (JPG/PNG/GIF/WEBP, max 10MB). The AI extracts amount, date, merchant name, and category suggestion, then fills the form fields with a green flash animation. Always review before saving.
|
||
|
||
On the **edit form**:
|
||
- **Re-extract** button re-runs OCR on the already-attached receipt
|
||
- OCR also runs automatically when you select a new image file in the upload field
|
||
|
||
---
|
||
|
||
## Teller Bank Sync
|
||
|
||
Teller connects US bank accounts using a secure mTLS connection. Accessible via **Settings** → Bank Connections.
|
||
|
||
### Connecting
|
||
1. Go to Settings → **Bank Connections**
|
||
2. Click **Connect a Bank** — the Teller Connect modal opens
|
||
3. Select your bank and log in
|
||
4. After connecting, use **Map Account** on any unmapped accounts to link them to PFM accounts
|
||
|
||
### Syncing Transactions
|
||
On the **Accounts** page, find a Teller-linked account (blue **Teller** badge) and click **Sync**. Review the transaction preview and confirm to import. After import, the live balance is fetched from Teller automatically.
|
||
|
||
### Webhook
|
||
Teller can push transaction updates to PFM automatically. The webhook endpoint verifies the `Teller-Signature` header (HMAC-SHA256) and has a 5-minute replay window.
|
||
|
||
### Disconnecting
|
||
Settings → Bank Connections → **Disconnect**. Imported transactions are kept.
|
||
|
||
---
|
||
|
||
## Schwab Bank Sync
|
||
|
||
Schwab integration uses OAuth 2.0 to sync brokerage and IRA accounts. Accessible via **Settings**.
|
||
|
||
### Connecting
|
||
1. Set `SCHWAB_CLIENT_ID`, `SCHWAB_CLIENT_SECRET`, `SCHWAB_REDIRECT_URI` in `.env`
|
||
2. Register the redirect URI in the Schwab developer portal (exact match required)
|
||
3. Settings → **Schwab** → **Connect Schwab Account**
|
||
4. Authorize on Schwab's login page
|
||
5. On the **Map Accounts** page, link each Schwab account to a PFM account (or create new ones)
|
||
|
||
### Syncing Balance & Investment Positions
|
||
On the **Accounts** page, click **Balance & Positions** on a Schwab account (green badge). This:
|
||
- Updates the account balance to Schwab's total portfolio liquidation value
|
||
- Upserts stock/ETF/bond/fund holdings into the Investments section
|
||
- Associates each holding with the specific account (Individual vs Roth IRA stay separate)
|
||
|
||
Also click **Sync Schwab** in the Investments page topbar to update all Schwab accounts at once.
|
||
|
||
### Syncing Transactions
|
||
Click **Transactions** on a Schwab account card. Review the preview and confirm to import.
|
||
|
||
### Token Expiry
|
||
Schwab access tokens expire after 30 minutes (auto-refreshed). Refresh tokens last 7 days — a dashboard warning appears when ≤ 2 days remain. Reconnect via Settings → Schwab to reset the expiry.
|
||
|
||
### Daily Auto-Sync
|
||
A cron job runs at 7 AM daily (`scripts/sync_schwab.py`) — updates balances, positions, and transactions for all mapped Schwab accounts automatically.
|
||
|
||
### Disconnecting
|
||
Settings → Schwab → **Disconnect**. Imported transactions and holdings are kept.
|
||
|
||
---
|
||
|
||
## Plaid Bank Sync
|
||
|
||
Plaid connects to 12,000+ US banks and credit unions. Accessible via **Settings**.
|
||
|
||
### Connecting
|
||
1. Set `PLAID_CLIENT_ID`, `PLAID_SECRET`, `PLAID_ENV` (`sandbox` or `production`) in `.env`
|
||
2. Settings → **Plaid** → **Connect Bank Account**
|
||
3. The Plaid Link widget opens — search for your institution and log in
|
||
4. On the **Map Accounts** page, link each Plaid account to a PFM account (or create new ones)
|
||
|
||
### Syncing Transactions
|
||
On the **Accounts** page, click **Sync** on a Plaid-linked account (purple badge). This uses cursor-based sync (`/transactions/sync`) — only new transactions since the last sync are fetched. Review the preview and confirm.
|
||
|
||
**Reset Sync** — click **Reset** to clear the sync cursor. The next sync re-fetches the full available history; duplicates are automatically skipped via the `Plaid:<transaction_id>` marker in notes.
|
||
|
||
### Live Balance Refresh
|
||
Click **Refresh** on a Plaid account card to fetch the latest balance from Plaid's `/accounts/balance/get` endpoint.
|
||
|
||
### Credit Card Billing
|
||
For Plaid-linked credit cards, click **Billing** on the account card to fetch:
|
||
- Next payment due date
|
||
- Minimum payment amount
|
||
- Last statement balance
|
||
- Overdue indicator
|
||
|
||
This information also appears in the billing card on the Accounts page.
|
||
|
||
### Webhook Auto-Import
|
||
Plaid can push new transactions to PFM via webhook (`POST /plaid/webhook`). When a `TRANSACTIONS/SYNC` event arrives, new transactions are imported silently (no preview step). Transactions imported this way without a category appear in the **Plaid review** banner on the Transactions page and the sidebar badge — review and categorize them from there.
|
||
|
||
The webhook is verified using Plaid's JWT signature (ES256). Configure the webhook URL in Settings → Plaid → **Apply to Existing Items**.
|
||
|
||
### Disconnecting
|
||
Settings → Plaid → **Disconnect** on a connection. Imported transactions are kept.
|
||
|
||
---
|
||
|
||
## USD → VND Rate Widget
|
||
|
||
Reference-only exchange rate on the dashboard. Does not affect any app calculations.
|
||
|
||
- Click ↻ to force-refresh without reloading the page
|
||
- Click the widget to expand a 30-day trend chart
|
||
- Source label shown (yfinance / exchangerate-api)
|
||
- ⚠ stale indicator appears if the cached rate is more than one day old
|
||
|
||
---
|
||
|
||
## System Logs
|
||
|
||
Navigate via Settings → **System Logs** (or sidebar → Settings → System Logs card).
|
||
|
||
Application log entries are stored in the database and shown in a colour-coded viewer:
|
||
- Filter by level (INFO / WARNING / ERROR / DEBUG) or free-text search
|
||
- Filter by module name (e.g. `app.teller`, `app.plaid`)
|
||
- **Auto-refresh** toggle for live monitoring
|
||
- **Download** — downloads the raw log file (`app.log`)
|
||
- **Purge** dropdown — delete DB entries older than 7, 30, or 90 days
|
||
- **Clear All** — truncates both the DB log table and the log file
|
||
- DB entry count shown in the page header
|
||
|
||
---
|
||
|
||
## Keyboard Shortcuts & Tips
|
||
|
||
### Navigation
|
||
- Sidebar collapses on desktop — click ☰ to toggle (state saved in localStorage)
|
||
- On mobile, tap outside the sidebar to close it; tables scroll horizontally
|
||
|
||
### Transactions
|
||
- **Enter** sends in AI chat; **Shift+Enter** adds a new line
|
||
- Change category directly in the transactions table — no form needed
|
||
- Date defaults to today — change it for past transactions
|
||
- Use the **✂ Split** button on a row to divide a transaction across multiple categories
|
||
- Export the current filtered view with the **CSV** / **Excel** buttons in the filter bar
|
||
|
||
### Budgets
|
||
- **Copy from previous month** at the start of each month saves re-entering all budgets
|
||
- The **Budget vs Actual** chart gives a quick visual of where you stand each month
|
||
- Rollover amounts appear as a blue **+rollover** badge on the row
|
||
|
||
### Investments
|
||
- Click any holding row to go to the detail page with P&L and price history chart
|
||
- **↓** button on the new transaction price field fetches the live price for that ticker
|
||
- Ticker symbols are auto-uppercased on save
|
||
- Price alerts banner appears automatically when any holding moves ≥ 5% intraday
|
||
|
||
### Reports
|
||
- **Snapshot Now** saves today's net worth to the history chart immediately
|
||
- CSV and Excel exports from the Reports page use the selected period
|
||
- From the Transactions page, use the filter bar export buttons to export any filtered view
|
||
|
||
### Security
|
||
- Enable **2FA** in Settings → Security for additional login protection
|
||
- The **Audit Log** (Settings → Security → Audit Log) records every login attempt and security event with IP address
|
||
- Sessions time out after 60 minutes of inactivity
|