Jake wants no manual CSV exports. Wallets (Cash App/Venmo/PayPal) are now fed by parsed transaction-receipt emails as the primary path, with browser-automation statement fetch as reconciliation backstop and the CSV drop folder demoted to break-glass fallback. Finance inbox decided: finance@ordinatorlabs.com (IONOS IMAP; jbnel.dev has no MX). IMAP connector promoted from Phase 5 into Phase 2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uv7wnzF6Xv6fmaRjFTiMMq
156 lines
8.8 KiB
Markdown
156 lines
8.8 KiB
Markdown
# Personal Accounting Agent — Architecture Design
|
|
|
|
**Date:** 2026-08-23
|
|
**Status:** Approved (Jake, 2026-08-23)
|
|
**Scope:** Master architecture and phase decomposition. Each phase gets its own spec and implementation plan; this document is the frame they hang on.
|
|
|
|
## Purpose
|
|
|
|
Build a personal accounting agent around the existing Firefly III stack at
|
|
`https://firefly.jbnel.dev`. The agent:
|
|
|
|
1. Monitors account balances across all institutions.
|
|
2. Assesses spending trends, tracks budgets, and forecasts cashflow.
|
|
3. Prepares utility and other bill payments, executing only with Jake's explicit approval.
|
|
4. Alerts Jake to pertinent information through Telegram, ntfy, and email.
|
|
5. Maintains account records (statements, bill PDFs) in a structured local folder, with cloud sync later.
|
|
6. Keeps all record data queryable — ledger data in Firefly, everything else in a dedicated agent database.
|
|
|
|
## Decisions
|
|
|
|
These were settled in the design conversation and bind all phases:
|
|
|
|
| Decision | Choice |
|
|
|---|---|
|
|
| Primary bank feed | SimpleFIN Bridge (read-only, ~$1.50/mo) |
|
|
| Coverage strategy | Connector layer: SimpleFIN plus per-institution connectors until NFCU, TFCU, Cash App, Venmo, and PayPal are all covered. Verify real coverage per institution early; assume nothing. |
|
|
| Wallet feeds (Cash App, Venmo, PayPal) | *(Amended 2026-08-24 — Jake wants automation, no manual CSV.)* Primary: per-transaction email receipts parsed from the finance inbox (near-real-time; these apps support no aggregators). Backstop: browser automation fetches monthly statements/CSVs for reconciliation. Manual CSV drop folder is break-glass fallback only. PayPal may later upgrade to its Transaction Search API via business account. |
|
|
| Finance inbox | `finance@ordinatorlabs.com` — dedicated IONOS mailbox (ordinatorlabs.com already has IONOS MX; jbnel.dev has no mail hosting). Agent polls IONOS IMAP. Optional later: forward `finance@jbnel.dev` into it. |
|
|
| Bill-pay autonomy | Prep + approval. The agent tracks, verifies funding, and asks. Money never moves without an explicit approval from Jake. |
|
|
| Runtime | Hybrid. One Python worker container does deterministic work on schedules; scheduled Claude sessions do judgment work (analysis, forecast narrative, anomaly triage). |
|
|
| Notification channels | Telegram bot (interactive: alerts, approvals), ntfy (urgent push), email (digests, receipts). Routed by message class. |
|
|
| Document acquisition | Dedicated finance email inbox via IMAP first; browser-automation downloads later for billers that never email PDFs. |
|
|
| Business accounts | Separate Firefly instance when a venture opens. This instance stays purely personal. The connector layer is account-agnostic so it can serve both. |
|
|
| Agent state | `agentdb`: a separate database in the existing Postgres container. |
|
|
|
|
## Architecture
|
|
|
|
One new container, `agent`, joins the existing compose stack (Firefly III core,
|
|
Data Importer, Postgres 16, Redis, cron) behind Traefik. The worker is a Python
|
|
3.12 application under `agent/` in this repo, structured as modules with hard
|
|
boundaries so any module can become its own service during the planned k8s
|
|
migration:
|
|
|
|
- **Connectors** — pull data from sources on schedules. Each connector
|
|
implements one interface: fetch → emit canonical records. Initial set:
|
|
SimpleFIN poller, CSV drop-folder watcher, IMAP inbox poller. Later: browser
|
|
automation jobs.
|
|
- **Sync engine** — normalizes connector output into canonical models
|
|
(transaction, balance, document, bill), deduplicates, and pushes to Firefly
|
|
via its REST API using a personal access token.
|
|
- **Notifier** — one interface, three sinks (Telegram, ntfy, SMTP). Message
|
|
class determines routing: interactive requests and real-time alerts go to
|
|
Telegram, urgent one-way pushes to ntfy, digests and receipts to email.
|
|
- **Rules engine** — deterministic checks after each sync: low balance, large
|
|
or unusual transaction, failed sync, upcoming bill without positioned funds.
|
|
- **Bill module** — maintains the bill calendar in `agentdb` from Firefly
|
|
bills and parsed bill emails; runs the approval workflow.
|
|
- **Scheduler** — APScheduler; every job idempotent and individually
|
|
triggerable for testing.
|
|
|
|
Claude sessions run on schedules outside the container (Claude Code
|
|
routines/cron). They read the Firefly API and `agentdb`, write analysis and
|
|
narratives out through the notifier, and never write directly to the ledger.
|
|
The agent container exposes the notifier to them as one token-authenticated
|
|
HTTP endpoint (`POST /notify`), reachable only on the internal Docker network
|
|
or via SSH tunnel — never through Traefik.
|
|
|
|
### Data flow
|
|
|
|
```
|
|
SimpleFIN ─┐
|
|
CSV drop ─┼→ Connectors → canonical models → dedup → Firefly API (ledger)
|
|
IMAP ─┤ │
|
|
Browser ─┘ └→ agentdb (documents, bills,
|
|
sync runs, approvals)
|
|
Firefly API + agentdb → Claude sessions → Notifier → Telegram / ntfy / email
|
|
```
|
|
|
|
Deduplication: use the source's external ID where one exists (SimpleFIN
|
|
provides one); otherwise a content hash of date + amount + account + normalized
|
|
description. Firefly's own duplicate detection is the backstop, never the
|
|
primary mechanism.
|
|
|
|
### agentdb schema (v1)
|
|
|
|
- `sync_runs` — one row per connector execution: connector, started, finished, status, counts, error.
|
|
- `documents` — index of filed records: path, sha256, institution, account, doc type, period, source, received date.
|
|
- `bills` — calendar: payee, expected amount, due date, funding account, autopay flag, status.
|
|
- `approvals` — bill-pay approvals: bill, amount, requested at, approved/denied at, Telegram message ref, executed at.
|
|
|
|
## Safety and error handling
|
|
|
|
- **Idempotent imports.** Dedup keys make every retry safe.
|
|
- **Escalating failure alerts.** Every connector run logs to `sync_runs`; three
|
|
consecutive failures for a connector escalate to ntfy.
|
|
- **Secrets stay server-side.** `.env` on the host only, never in the repo.
|
|
Aggregator access is read-only.
|
|
- **Approval integrity.** An approval exists only as an `approvals` row created
|
|
by Jake's own Telegram interaction. The executor re-checks the approval
|
|
immediately before acting and refuses stale or amount-mismatched approvals.
|
|
- **Payment receipts.** Every browser-automation payment run captures
|
|
screenshots and files them as documents.
|
|
|
|
## Documents
|
|
|
|
Local folder structure (exact layout specified in the Phase 5 spec):
|
|
`records/<institution>/<account>/<year>/` with normalized filenames
|
|
(`2026-08-nfcu-checking-statement.pdf`). Every filed document gets a
|
|
`documents` row. Cloud sync via rclone; Jake picks the target during Phase 5.
|
|
|
|
## Testing
|
|
|
|
TDD throughout (superpowers test-driven-development skill). Connectors test
|
|
against recorded fixtures: captured SimpleFIN JSON, real Venmo/Cash App/PayPal
|
|
CSV exports, sample bill emails. The Firefly client tests against a throwaway
|
|
local Firefly via a compose test profile. One end-to-end smoke test proves
|
|
fixture → dedup → Firefly.
|
|
|
|
## Deployment
|
|
|
|
The stack runs on a remote host behind Traefik; this repo is the config source.
|
|
Assumed workflow: SSH to the host, `git pull`, `docker compose up -d`. Confirm
|
|
the exact workflow during Phase 1 planning and record it in the Phase 1 spec.
|
|
|
|
## Phases
|
|
|
|
Each phase is its own sub-project: spec → plan → implementation. Later phases
|
|
may not start until the prior phase runs in production.
|
|
|
|
1. **Foundation** — Firefly configured for API use (personal access token,
|
|
asset accounts created); `agent/` skeleton: Dockerfile, config loading,
|
|
scheduler with a heartbeat job, `agentdb` migrations, compose service,
|
|
deployed to the host.
|
|
2. **Ingestion** — SimpleFIN → Firefly sync with dedup; verified coverage for
|
|
NFCU and TFCU; IMAP receipt connector (promoted from Phase 5) parsing
|
|
Cash App/Venmo/PayPal transaction emails from the finance inbox; CSV
|
|
drop-folder connector kept as break-glass fallback.
|
|
3. **Alerts & monitoring** — notifier with all three sinks; rules engine:
|
|
low balance, large/unusual transaction, sync failure, negative trend.
|
|
4. **Analysis & forecasting** — scheduled Claude sessions: weekly spending
|
|
review, budget tracking, recurring-transaction detection, 30/60/90-day
|
|
cashflow forecast, monthly digest.
|
|
5. **Documents** — PDF extraction and filing from the finance inbox (IMAP
|
|
plumbing already live from Phase 2), browser-automation statement
|
|
downloads, document index, cloud sync target chosen and wired.
|
|
6. **Bills** — bill calendar, funding checks, Telegram approve/deny flow,
|
|
browser automation for approved payments and statement downloads.
|
|
7. **Later** — business Firefly instance when a venture opens; k8s migration
|
|
per `k8s/README.md`.
|
|
|
|
## Out of scope
|
|
|
|
- Investment portfolio management and tax preparation.
|
|
- Multi-user support; this system serves Jake alone.
|
|
- Modifying Firefly III itself; the agent is strictly an API consumer.
|