You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
5. Support manual accounts with nullable Provider Item provenance and local source metadata.
480
-
6. Support a non-persistent demo store seeded with small, inspectable synthetic data for local testing and trial use without Provider credentials.
481
-
7. Implement store methods for listing accounts, creating manual accounts, listing/searching transactions, listing categories, listing tags, and listing recurring items against both real and demo stores.
-[x]5. Support manual accounts with nullable Provider Item provenance and local source metadata.
480
+
-[x]6. Support a non-persistent demo store seeded with small, inspectable synthetic data for local testing and trial use without Provider credentials.
481
+
-[x]7. Implement store methods for listing accounts, creating manual accounts, listing/searching transactions, listing categories, listing tags, and listing recurring items against both real and demo stores.
-[x]10. Add JSON contract tests for all first-milestone read commands, manual account dry-run/confirm behavior, and demo isolation/reset behavior.
485
+
-[x]11. Run `go test ./...`.
486
486
487
487
Acceptance:
488
488
@@ -546,16 +546,16 @@ Goal: prepare Plaid and Bridge as replaceable Provider adapters.
546
546
547
547
Steps:
548
548
549
-
1. Add official Go Plaid SDK.
550
-
2. Add Bridge HTTP client implementation.
551
-
3. Add Plaid config fields with `PLAID_` environment variable names.
552
-
4. Add Bridge config fields with `BRIDGE_` environment variable names.
553
-
5. Add provider registry with Plaid and Bridge adapters.
554
-
6. Define canonical provider records for Institution, ProviderItem, FinancialAccount, Transaction, and SyncResult.
555
-
7. Write fixture-based mapper tests before any live Provider calls, including canonical amount sign normalization and liability balance normalization.
556
-
8. Implement Plaid client construction without managed proxy behavior.
557
-
9. Implement Bridge client construction without managed proxy behavior.
558
-
10. Implement provider error classification.
549
+
-[x]1. Add official Go Plaid SDK.
550
+
-[x]2. Add Bridge HTTP client implementation.
551
+
-[x]3. Add Plaid config fields with `PLAID_` environment variable names.
552
+
-[x]4. Add Bridge config fields with `BRIDGE_` environment variable names.
553
+
-[x]5. Add provider registry with Plaid and Bridge adapters.
554
+
-[x]6. Define canonical provider records for Institution, ProviderItem, FinancialAccount, Transaction, and SyncResult.
555
+
-[x]7. Write fixture-based mapper tests before any live Provider calls, including canonical amount sign normalization and liability balance normalization.
556
+
-[x]8. Implement Plaid client construction without managed proxy behavior.
557
+
-[x]9. Implement Bridge client construction without managed proxy behavior.
558
+
-[x]10. Implement provider error classification.
559
559
560
560
Acceptance:
561
561
@@ -573,22 +573,22 @@ Goal: allow the user to create a Plaid item and store its access token inside th
573
573
574
574
Steps:
575
575
576
-
1. Implement `money link` for institution-first linking through Plaid when Plaid is the selected Provider.
577
-
2. Implement `money providers plaid link` for explicit Plaid linking.
578
-
3. Separate Provider support from Provider availability: list all Providers known to support the selected institution, mark locally unavailable Providers as missing credentials, and block selecting unavailable Providers with generated configure guidance.
579
-
4. Determine Provider availability from local config/env required fields, following Ray's configured-state pattern but using `money`'s explicit `env:` model.
580
-
5. Use Plaid `/institutions/search` with configured products and country codes for Plaid institution discovery.
581
-
6. Use a short-lived localhost Link page and callback server only for Plaid Link.
582
-
7. Create Plaid Link token with explicit products and country codes.
583
-
8. Serve a local page that loads Plaid Link with the link token and posts `public_token`, selected institution/account metadata, and random state back to the localhost helper on success.
584
-
9. Exchange public token for access token.
585
-
10. Store access token only after the encrypted store is open.
586
-
11. Store provider item, institution metadata, products, and initial cursor state.
587
-
12. Use random state/nonce values, timeout callback sessions, bind only for the active link flow, and shut down the helper after completion.
588
-
13. Follow GitHub CLI browser ergonomics in human mode: print the local Link URL, wait for Enter, then open the browser.
589
-
14. Support `--no-open` to print the URL without opening a browser for SSH, cron, and headless environments.
590
-
15. Do not automatically run the first sync after link; print help-derived guidance for running `money sync`.
591
-
16. Add tests for encrypted-store requirements and link exchange logic using fakes.
576
+
-[x]1. Implement `money link` for institution-first linking through Plaid when Plaid is the selected Provider.
577
+
-[x]2. Implement `money providers plaid link` for explicit Plaid linking.
578
+
-[x]3. Separate Provider support from Provider availability: list all Providers known to support the selected institution, mark locally unavailable Providers as missing credentials, and block selecting unavailable Providers with generated configure guidance.
579
+
-[x]4. Determine Provider availability from local config/env required fields, following Ray's configured-state pattern but using `money`'s explicit `env:` model.
580
+
-[x]5. Use Plaid `/institutions/search` with configured products and country codes for Plaid institution discovery.
581
+
-[x]6. Use a short-lived localhost Link page and callback server only for Plaid Link.
582
+
-[x]7. Create Plaid Link token with explicit products and country codes.
583
+
-[x]8. Serve a local page that loads Plaid Link with the link token and posts `public_token`, selected institution/account metadata, and random state back to the localhost helper on success.
584
+
-[x]9. Exchange public token for access token.
585
+
-[x]10. Store access token only after the encrypted store is open.
586
+
-[x]11. Store provider item, institution metadata, products, and initial cursor state.
587
+
-[x]12. Use random state/nonce values, timeout callback sessions, bind only for the active link flow, and shut down the helper after completion.
588
+
-[x]13. Follow GitHub CLI browser ergonomics in human mode: print the local Link URL, wait for Enter, then open the browser.
589
+
-[x]14. Support `--no-open` to print the URL without opening a browser for SSH, cron, and headless environments.
590
+
-[x]15. Do not automatically run the first sync after link; print help-derived guidance for running `money sync`.
591
+
-[x]16. Add tests for encrypted-store requirements and link exchange logic using fakes.
592
592
593
593
Acceptance:
594
594
@@ -608,17 +608,17 @@ Goal: allow the user to create or reconnect Bridge items.
608
608
609
609
Steps:
610
610
611
-
1.Extend `money link` to choose Bridge when Bridge supports the selected Institution.
612
-
2. Implement `money providers bridge link` for explicit Bridge linking.
613
-
3. Use the same supported-versus-available Provider selection rules as Plaid.
614
-
4. Create or reuse a Bridge external user ID.
615
-
5. Create a Bridge connect session.
616
-
6. Print the connect session URL, wait for Enter, then open the browser unless `--no-open` is set.
617
-
7. Poll Bridge items until a new or reconnected item is available.
618
-
8. Store provider item, institution metadata, status, and cursor state in the encrypted store.
619
-
9. Do not automatically run the first sync after link; print help-derived guidance for running `money sync`.
620
-
10. Add tests for Bridge connect/session/state logic using fakes.
621
-
11. If Bridge institution discovery cannot be implemented cleanly in the first adapter, keep `money providers bridge link` working and defer institution-first Bridge selection rather than inventing unsupported discovery.
611
+
-[x]1.Defer Bridge institution-first selection until Bridge institution discovery is implemented cleanly; explicit `money providers bridge link` remains supported.
612
+
-[x]2. Implement `money providers bridge link` for explicit Bridge linking.
613
+
-[x]3. Use the same supported-versus-available Provider selection rules as Plaid.
614
+
-[x]4. Create or reuse a Bridge external user ID.
615
+
-[x]5. Create a Bridge connect session.
616
+
-[x]6. Print the connect session URL, wait for Enter, then open the browser unless `--no-open` is set.
617
+
-[x]7. Poll Bridge items until a new or reconnected item is available.
618
+
-[x]8. Store provider item, institution metadata, status, and cursor state in the encrypted store.
619
+
-[x]9. Do not automatically run the first sync after link; print help-derived guidance for running `money sync`.
620
+
-[x]10. Add tests for Bridge connect/session/state logic using fakes.
621
+
-[x]11. If Bridge institution discovery cannot be implemented cleanly in the first adapter, keep `money providers bridge link` working and defer institution-first Bridge selection rather than inventing unsupported discovery.
622
622
623
623
Acceptance:
624
624
@@ -633,17 +633,17 @@ Goal: sync Plaid and Bridge accounts and transactions into canonical encrypted S
633
633
634
634
Steps:
635
635
636
-
1. Implement `money sync`.
637
-
2. Load linked provider items from the store.
638
-
3. Load provider access tokens from the encrypted store per item.
639
-
4. Sync accounts first.
640
-
5. Sync transactions using Plaid Transactions Sync cursors.
641
-
6. Sync Bridge transactions using Bridge updated-at cursor/state.
642
-
7. Upsert provider transactions by Provider Item plus provider-native transaction ID.
643
-
8. Handle added, modified, and removed transactions.
644
-
9. Store next cursor only after successful transaction processing.
645
-
10. Record a sync run with counts and status.
646
-
11. Add fixture-backed sync tests with fake Plaid client.
636
+
-[x]1. Implement `money sync`.
637
+
-[x]2. Load linked provider items from the store.
638
+
-[x]3. Load provider access tokens from the encrypted store per item.
639
+
-[x]4. Sync accounts first.
640
+
-[x]5. Sync transactions using Plaid Transactions Sync cursors.
641
+
-[x]6. Sync Bridge transactions using Bridge updated-at cursor/state.
642
+
-[x]7. Upsert provider transactions by Provider Item plus provider-native transaction ID.
643
+
-[x]8. Handle added, modified, and removed transactions.
644
+
-[x]9. Store next cursor only after successful transaction processing.
645
+
-[x]10. Record a sync run with counts and status.
646
+
-[x]11. Add fixture-backed sync tests with fake Plaid client.
647
647
648
648
Acceptance:
649
649
@@ -668,29 +668,29 @@ Goal: make the first-milestone read Command Contracts reliable enough for extern
668
668
669
669
Steps:
670
670
671
-
1. Document `accounts.list`, `transactions.list`, `transactions.search`, `categories.list`, `tags.list`, and `recurring.list` schemas.
672
-
2. Add pagination metadata.
673
-
3. Add stable error codes.
674
-
4. Add deterministic ordering:
671
+
-[x]1. Document `accounts.list`, `transactions.list`, `transactions.search`, `categories.list`, `tags.list`, and `recurring.list` schemas.
672
+
-[x]2. Add pagination metadata.
673
+
-[x]3. Add stable error codes.
674
+
-[x]4. Add deterministic ordering:
675
675
- Accounts: hidden flag, type, name, id.
676
676
- Transactions: date descending, pending status, id.
677
-
5. Add filters for account, category, merchant, tag, date range, needs-review, pending, recurring status, and limit.
678
-
6. Add command examples.
679
-
7. Add compatibility notes for Monarch migration.
677
+
-[x]5. Add filters for account, category, merchant, tag, date range, needs-review, pending, recurring status, and limit.
678
+
-[x]6. Add command examples.
679
+
-[x]7. Add compatibility notes for Monarch migration.
680
680
681
681
### Phase 6: Sync Contract Hardening
682
682
683
683
Goal: promote sync JSON from provisional to stable after real Provider behavior is understood.
684
684
685
685
Steps:
686
686
687
-
1. Document sync summary schema.
688
-
2. Define provider error taxonomy.
689
-
3. Define reconnect-required behavior.
690
-
4. Define removed transaction policy as soft delete plus explicit confirmed cleanup.
691
-
5. Define partial failure semantics and exit codes.
692
-
6. Add fixture tests for Plaid and Bridge partial failures.
693
-
7. Add command examples for cron usage.
687
+
-[x]1. Document sync summary schema.
688
+
-[x]2. Define provider error taxonomy.
689
+
-[x]3. Define reconnect-required behavior.
690
+
-[x]4. Define removed transaction policy as soft delete plus explicit confirmed cleanup.
691
+
-[x]5. Define partial failure semantics and exit codes.
692
+
-[x]6. Add fixture tests for Plaid and Bridge partial failures.
693
+
-[x]7. Add command examples for cron usage.
694
694
695
695
Acceptance:
696
696
@@ -710,17 +710,18 @@ Acceptance:
710
710
711
711
Goal: prove the Provider seam is real with a second adapter.
712
712
713
-
Choose one:
713
+
Selected path:
714
714
715
-
- Monarch import from `monarchmoney-cli --json`.
716
-
- CSV import.
717
-
- MX or Finicity provider adapter.
715
+
-[x] Bridge provider adapter as the second live Provider adapter alongside Plaid.
716
+
-[x] Monarch import from `monarchmoney-cli --json` deferred.
717
+
-[x] CSV import deferred.
718
+
-[x] MX or Finicity provider adapter deferred.
718
719
719
720
Acceptance:
720
721
721
-
- A second adapter can write the same canonical tables.
722
-
- Existing account and transaction contracts do not change.
723
-
- Source/provider-specific fields remain namespaced or internal.
722
+
-[x]A second adapter can write the same canonical tables.
723
+
-[x]Existing account and transaction contracts do not change.
724
+
-[x]Source/provider-specific fields remain namespaced or internal.
@@ -38,13 +38,10 @@ Existing personal finance tools either lock data behind a paid SaaS, embed opini
38
38
# Install
39
39
go install github.com/thedavidweng/money/cmd/money@latest
40
40
41
-
# Interactive setup — creates config, encryption key, and database
42
-
money setup
43
-
44
41
# Try it without real credentials
45
42
money demo accounts list --json
46
43
47
-
# After configuring a provider
44
+
# After creating ~/.money/config.yaml and ~/.money/.env
48
45
money link
49
46
money sync
50
47
money accounts list --json
@@ -62,13 +59,13 @@ money categories list List transaction categories
62
59
money tags list List transaction tags
63
60
money recurring list List recurring transactions
64
61
money link Link a financial institution
62
+
money providers plaid link Link a Plaid Provider Item
63
+
money providers bridge link Link a Bridge Provider Item
65
64
money sync Sync linked provider data
66
65
money demo <command> Run against non-persistent sample data
67
-
money doctor Check configuration health
68
-
money setup Guided first-time configuration
69
66
```
70
67
71
-
All commands support `--json` for machine-readable output. Write operations require `--dry-run` or `--confirm`.
68
+
Read commands and provisional sync diagnostics support `--json` for machine-readable output. Manual write operations require `--dry-run` or `--confirm`.
72
69
73
70
## Architecture
74
71
@@ -98,6 +95,7 @@ Read commands use local data only. Sync is the explicit boundary where outbound
Copy file name to clipboardExpand all lines: docs/ARCHITECTURE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -87,7 +87,7 @@ If a configured DB file already exists but cannot be opened, commands must repor
87
87
88
88
The concrete encrypted SQLite implementation is an engineering decision. Select the approach through a short spike using these criteria: single-binary feasibility on the target platforms, active maintenance, predictable Go driver behavior, compatibility with SQLite migrations and in-memory demo tests, no plaintext fallback, and clear handling of key material. If no mature single-binary encrypted SQLite option satisfies those constraints, document the trade-off before accepting an external native dependency.
89
89
90
-
The first implementation uses `github.com/ncruces/go-sqlite3` with its `database/sql` driver and the `github.com/ncruces/go-sqlite3/vfs/adiantum` encrypted VFS. This is the selected MVP path because it is cgo-free, supports app-managed 32-byte key material, keeps the CLI close to a single-binary distribution, works with normal SQLite migrations, and supports the in-memory demo path through the same SQLite implementation. Open encrypted databases with the encrypted VFS and set the key immediately after opening the connection using a PRAGMA rather than putting the key in the URI. Set `PRAGMA temp_store = memory` for encrypted real stores so temporary files do not become an accidental plaintext surface.
90
+
The first implementation uses `github.com/ncruces/go-sqlite3` with its `database/sql` driver and the `github.com/ncruces/go-sqlite3/vfs/adiantum` encrypted VFS. This is the selected MVP path because it is cgo-free, supports app-managed 32-byte key material, keeps the CLI close to a single-binary distribution, works with normal SQLite migrations, and supports the in-memory demo path through the same SQLite implementation. Open encrypted databases with the encrypted VFS, pass the configured 32-byte key as the VFS `hexkey`, and set `temp_store(memory)` on the encrypted connection so temporary files do not become an accidental plaintext surface.
91
91
92
92
This choice provides encryption at rest, not tamper-proof database authentication. The first version treats local tamper detection and signed backups as later hardening work, not a reason to add a custom encryption layer or ship plaintext fallback behavior. If the encrypted VFS fails the implementation spike on the target platforms, the next option is a SQLCipher-backed driver with the native dependency documented explicitly before adoption; do not replace whole-database encryption with ad hoc field encryption.
0 commit comments