| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 0 | 15 | 0% |
| Commands | 0 | 0 | 2 | 0% |
| Section tags | 1 | 1 | 10 | 8% |
What each file covers
Sections
0 shared · 0 only in A · 15 only in B- + Repository Guidelines
- + Project Structure & Module Organization
- + Build, Test, and Development Commands
- + Coding Style & Naming Conventions
- + Testing Guidelines
- + Commit & Pull Request Guidelines
- + Security & Configuration Tips
- + API Development Guidelines
- + OpenAPI Documentation (MANDATORY)
- + Post-commit API consistency (LLM checklist)
- + Design System Hygiene (UI PRs)
- + Securities Providers
- + Debug Logging for Provider Syncs
- + Providers: Pending Transactions and FX Metadata (SimpleFIN/Plaid/Lunchflow)
- + Provider support notes
Commands
0 shared · 0 only in A · 2 only in B- + npm run lint
- + npm run format
Section tags
1 shared · 1 only in A · 10 only in B- − testing-strategy
- + build
- + test
- + lint-format
- + architecture
- + git-pr
- + security
- + api
- + ui
- + do-not
- + docs
- code-style
Line diff
we-promise/sure · .cursor/rules/testing.mdc
@@ −1 @@
1---
2description:
3globs: test/**
4alwaysApply: false
5---
6Use this rule to learn how to write tests for the codebase.
7
8Due to the open-source nature of this project, we have chosen Minitest + Fixtures for testing to maximize familiarity and predictability.
9
10- **General testing rules**
11 - Always use Minitest and fixtures for testing, NEVER rspec or factories
12 - Keep fixtures to a minimum. Most models should have 2-3 fixtures maximum that represent the "base cases" for that model. "Edge cases" should be created on the fly, within the context of the test which it is needed.
13 - For tests that require a large number of fixture records to be created, use Rails helpers to help create the records needed for the test, then inline the creation. For example, [entries_test_helper.rb](mdc:test/support/entries_test_helper.rb) provides helpers to easily do this.
14
15- **Write minimal, effective tests**
16 - Use system tests sparingly as they increase the time to complete the test suite
17 - Only write tests for critical and important code paths
18 - Write tests as you go, when required
19 - Take a practical approach to testing. Tests are effective when their presence _significantly increases confidence in the codebase_.
20
21 Below are examples of necessary vs. unnecessary tests:
22
23 ```rb
24 # GOOD!!
25 # Necessary test - in this case, we're testing critical domain business logic
26 test "syncs balances" do
27 Holding::Syncer.any_instance.expects(:sync_holdings).returns([]).once
28
29 @account.expects(:start_date).returns(2.days.ago.to_date)
30
31 Balance::ForwardCalculator.any_instance.expects(:calculate).returns(
32 [
33 Balance.new(date: 1.day.ago.to_date, balance: 1000, cash_balance: 1000, currency: "USD"),
34 Balance.new(date: Date.current, balance: 1000, cash_balance: 1000, currency: "USD")
35 ]
36 )
37
38 assert_difference "@account.balances.count", 2 do
39 Balance::Syncer.new(@account, strategy: :forward).sync_balances
40 end
41 end
42
43 # BAD!!
44 # Unnecessary test - in this case, this is simply testing ActiveRecord's functionality
45 test "saves balance" do
46 balance_record = Balance.new(balance: 100, currency: "USD")
47
48 assert balance_record.save
49 end
50 ```
51
52- **Test boundaries correctly**
53 - Distinguish between commands and query methods. Test output of query methods; test that commands were called with the correct params. See an example below:
54
55 ```rb
56 class ExampleClass
57 def do_something
58 result = 2 + 2
59
60 CustomEventProcessor.process_result(result)
61
62 result
63 end
64 end
65
66 class ExampleClass < ActiveSupport::TestCase
67 test "boundaries are tested correctly" do
68 result = ExampleClass.new.do_something
69
70 # GOOD - we're only testing that the command was received, not internal implementation details
71 # The actual tests for CustomEventProcessor belong in a different test suite!
72 CustomEventProcessor.expects(:process_result).with(4).once
73
74 # GOOD - we're testing the implementation of ExampleClass inside its own test suite
75 assert_equal 4, result
76 end
77 end
78 ```
79
80 - Never test the implementation details of one class in another classes test suite
81
82- **Stubs and mocks**
83 - Use `mocha` gem
84 - Always prefer `OpenStruct` when creating mock instances, or in complex cases, a mock class
85 - Only mock what's necessary. If you're not testing return values, don't mock a return value.
86
87
we-promise/sure · AGENTS.md
@@ +1 @@
1# Repository Guidelines
2
3## Project Structure & Module Organization
4- Code: `app/` (Rails MVC, services, jobs, mailers, components), JS in `app/javascript/`, styles/assets in `app/assets/` (Tailwind, images, fonts).
5- Config: `config/`, environment examples in `.env.local.example` and `.env.test.example`.
6- Data: `db/` (migrations, seeds), fixtures in `test/fixtures/`.
7- Tests: `test/` mirroring `app/` (e.g., `test/models/*_test.rb`).
8- Tooling: `bin/` (project scripts), `docs/` (guides), `public/` (static), `lib/` (shared libs).
9
10## Build, Test, and Development Commands
11- Setup: `cp .env.local.example .env.local && bin/setup` — install deps, set DB, prepare app.
12- Run app: `bin/dev` — starts Rails server and asset/watchers via `Procfile.dev`.
13- Test suite: `bin/rails test` — run all Minitest tests; add `TEST=test/models/user_test.rb` to target a file.
14- Lint Ruby: `bin/rubocop` — style checks; add `-A` to auto-correct safe cops.
15- Lint/format JS/CSS: `npm run lint` and `npm run format` — uses Biome.
16- Security scan: `bin/brakeman` — static analysis for common Rails issues.
17
18## Coding Style & Naming Conventions
19- Ruby: 2-space indent, `snake_case` for methods/vars, `CamelCase` for classes/modules. Follow Rails conventions for folders and file names.
20- Views: ERB checked by `erb-lint` (see `.erb_lint.yml`). Avoid heavy logic in views; prefer helpers/components.
21- JavaScript: `lowerCamelCase` for vars/functions, `PascalCase` for classes/components. Let Biome format code.
22- Commit small, cohesive changes; keep diffs focused.
23
24## Testing Guidelines
25- Framework: Minitest (Rails). Name files `*_test.rb` and mirror `app/` structure.
26- Run: `bin/rails test` locally and ensure green before pushing.
27- Fixtures/VCR: Use `test/fixtures` and existing VCR cassettes for HTTP. Prefer unit tests plus focused integration tests.
28
29## Commit & Pull Request Guidelines
30- Commits: Imperative subject ≤ 72 chars (e.g., "Add account balance validation"). Include rationale in body and reference issues (`#123`).
31- PRs: Clear description, linked issues, screenshots for UI changes, and migration notes if applicable. Ensure CI passes, tests added/updated, and `rubocop`/Biome are clean.
32
33## Security & Configuration Tips
34- Never commit secrets. Start from `.env.local.example`; use `.env.local` for development only.
35- Run `bin/brakeman` before major PRs. Prefer environment variables over hard-coded values.
36
37## API Development Guidelines
38
39### OpenAPI Documentation (MANDATORY)
40When adding or modifying API endpoints in `app/controllers/api/v1/`, you **MUST** create or update corresponding OpenAPI request specs for **DOCUMENTATION ONLY**:
41
421. **Location**: `spec/requests/api/v1/{resource}_spec.rb`
432. **Framework**: RSpec with rswag for OpenAPI generation
443. **Schemas**: Define reusable schemas in `spec/swagger_helper.rb`
454. **Generated Docs**: `docs/api/openapi.yaml`
465. **Regenerate**: Run `RAILS_ENV=test bundle exec rake rswag:specs:swaggerize` after changes
47
48### Post-commit API consistency (LLM checklist)
49After every API endpoint commit, ensure: (1) **Minitest** behavioral coverage in `test/controllers/api/v1/{resource}_controller_test.rb` (no behavioral assertions in rswag); (2) **rswag** remains docs-only (no `expect`/`assert_*` in `spec/requests/api/v1/`); (3) **rswag auth** uses the same API key pattern everywhere (`X-Api-Key`, not OAuth/Bearer). Full checklist: [.cursor/rules/api-endpoint-consistency.mdc](.cursor/rules/api-endpoint-consistency.mdc).
50
51## Design System Hygiene (UI PRs)
52
53When a PR touches `.erb`, view components, or `.css`:
54
551. **Tokens, not palette.** Use functional tokens from `app/assets/tailwind/sure-design-system.css` (`bg-warning/10`, `text-destructive`, `bg-container`, `text-primary`, `border-primary`). No raw Tailwind palette (`bg-blue-50`, `text-red-500`, hex literals).
562. **Reach for `DS::*` first.** Check `app/components/DS/` (`DS::Alert`, `DS::Button`, `DS::Disclosure`, `DS::Dialog`, `DS::Menu`, etc.) before writing an alert, badge, button, disclosure, dialog, or input shape.
573. **Two copies → lift to DS.** Same hand-rolled shape ≥2× in a diff with no DS equivalent → propose a new `DS::*` primitive before the second copy lands.
584. **Conventions.** Use the `icon` helper (never `lucide_icon` directly), no raw SVG outside DS primitives, user-facing strings via `t()`, avoid arbitrary `*-[Npx]` values when a scale token fits.
59
60Reviewers escalate violations of (2)–(3) to close/rewrite; (1) and (4) are request-changes.
61
62## Securities Providers
63
64If you need to add a new securities price provider (Tiingo, EODHD, Binance-style crypto, etc.), see [adding-a-securities-provider.md](./docs/llm-guides/adding-a-securities-provider.md) for the full walkthrough — provider class, registry wiring, MIC handling, settings UI, locales, and tests.
65
66## Debug Logging for Provider Syncs
67
68When a provider sync/import path hits a recoverable error or suspicious partial response that support may need to inspect later, prefer `DebugLogEntry.capture(...)` over `Rails.logger.*`.
69
70- Record support-relevant diagnostics in the debug log so they surface in the super-admin-friendly `/settings/debug` UI.
71- Include `category`, `level`, `message`, `source`, `provider_key`, and useful structured `metadata`.
72- Attach `family` and `account_provider` when available so support can filter and trace the affected connection.
73- Reserve raw Rails logging for low-value local noise; anything operators may need should go to the debug log.
74
75## Providers: Pending Transactions and FX Metadata (SimpleFIN/Plaid/Lunchflow)
76
77- Pending detection
78 - SimpleFIN: pending when provider sends `pending: true`, or when `posted` is blank/0 and `transacted_at` is present.
79 - Plaid: pending when Plaid sends `pending: true` (stored at `transaction.extra["plaid"]["pending"]` for bank/credit transactions imported via `PlaidEntry::Processor`).
80 - Lunchflow: pending when API returns `isPending: true` in transaction response (stored at `transaction.extra["lunchflow"]["pending"]`).
81- Storage (extras)
82 - Provider metadata lives on `Transaction#extra`, namespaced (e.g., `extra["simplefin"]["pending"]`).
83 - SimpleFIN FX: `extra["simplefin"]["fx_from"]`, `extra["simplefin"]["fx_date"]`.
84- UI
85 - Shows a small “Pending” badge when `transaction.pending?` is true.
86- Variability
87 - Some providers don’t expose pendings; in that case nothing is shown.
88- Configuration (default-off)
89 - SimpleFIN runtime toggles live in `config/initializers/simplefin.rb` via `Rails.configuration.x.simplefin.*`.
90 - Lunchflow runtime toggles live in `config/initializers/lunchflow.rb` via `Rails.configuration.x.lunchflow.*`.
91 - ENV-backed keys:
92 - `SIMPLEFIN_INCLUDE_PENDING=1` (forces `pending=1` on SimpleFIN fetches when caller didn’t specify a `pending:` arg)
93 - `SIMPLEFIN_DEBUG_RAW=1` (logs raw payload returned by SimpleFIN)
94 - `LUNCHFLOW_INCLUDE_PENDING=1` (forces `include_pending=true` on Lunchflow API requests)
95 - `LUNCHFLOW_DEBUG_RAW=1` (logs raw payload returned by Lunchflow)
96
97### Provider support notes
98
99- SimpleFIN: supports pending + FX metadata; stored under `extra["simplefin"]`.
100- Plaid: supports pending when the upstream Plaid payload includes `pending: true`; stored under `extra["plaid"]`.
101- Plaid investments: investment transactions currently do not store pending metadata.
102- Lunchflow: supports pending via `include_pending` query parameter; stored under `extra["lunchflow"]`.
103- Manual/CSV imports: no pending concept.
104
@@ −1 +1 @@
1−---
2−description:
3−globs: test/**
4−alwaysApply: false
5−---
6−Use this rule to learn how to write tests for the codebase.
1+# Repository Guidelines
72
8−Due to the open-source nature of this project, we have chosen Minitest + Fixtures for testing to maximize familiarity and predictability.
3+## Project Structure & Module Organization
4+- Code: `app/` (Rails MVC, services, jobs, mailers, components), JS in `app/javascript/`, styles/assets in `app/assets/` (Tailwind, images, fonts).
5+- Config: `config/`, environment examples in `.env.local.example` and `.env.test.example`.
6+- Data: `db/` (migrations, seeds), fixtures in `test/fixtures/`.
7+- Tests: `test/` mirroring `app/` (e.g., `test/models/*_test.rb`).
8+- Tooling: `bin/` (project scripts), `docs/` (guides), `public/` (static), `lib/` (shared libs).
99
10−- **General testing rules**
11− - Always use Minitest and fixtures for testing, NEVER rspec or factories
12− - Keep fixtures to a minimum. Most models should have 2-3 fixtures maximum that represent the "base cases" for that model. "Edge cases" should be created on the fly, within the context of the test which it is needed.
13− - For tests that require a large number of fixture records to be created, use Rails helpers to help create the records needed for the test, then inline the creation. For example, [entries_test_helper.rb](mdc:test/support/entries_test_helper.rb) provides helpers to easily do this.
10+## Build, Test, and Development Commands
11+- Setup: `cp .env.local.example .env.local && bin/setup` — install deps, set DB, prepare app.
12+- Run app: `bin/dev` — starts Rails server and asset/watchers via `Procfile.dev`.
13+- Test suite: `bin/rails test` — run all Minitest tests; add `TEST=test/models/user_test.rb` to target a file.
14+- Lint Ruby: `bin/rubocop` — style checks; add `-A` to auto-correct safe cops.
15+- Lint/format JS/CSS: `npm run lint` and `npm run format` — uses Biome.
16+- Security scan: `bin/brakeman` — static analysis for common Rails issues.
1417
15−- **Write minimal, effective tests**
16− - Use system tests sparingly as they increase the time to complete the test suite
17− - Only write tests for critical and important code paths
18− - Write tests as you go, when required
19− - Take a practical approach to testing. Tests are effective when their presence _significantly increases confidence in the codebase_.
18+## Coding Style & Naming Conventions
19+- Ruby: 2-space indent, `snake_case` for methods/vars, `CamelCase` for classes/modules. Follow Rails conventions for folders and file names.
20+- Views: ERB checked by `erb-lint` (see `.erb_lint.yml`). Avoid heavy logic in views; prefer helpers/components.
21+- JavaScript: `lowerCamelCase` for vars/functions, `PascalCase` for classes/components. Let Biome format code.
22+- Commit small, cohesive changes; keep diffs focused.
2023
21− Below are examples of necessary vs. unnecessary tests:
24+## Testing Guidelines
25+- Framework: Minitest (Rails). Name files `*_test.rb` and mirror `app/` structure.
26+- Run: `bin/rails test` locally and ensure green before pushing.
27+- Fixtures/VCR: Use `test/fixtures` and existing VCR cassettes for HTTP. Prefer unit tests plus focused integration tests.
2228
23− ```rb
24− # GOOD!!
25− # Necessary test - in this case, we're testing critical domain business logic
26− test "syncs balances" do
27− Holding::Syncer.any_instance.expects(:sync_holdings).returns([]).once
29+## Commit & Pull Request Guidelines
30+- Commits: Imperative subject ≤ 72 chars (e.g., "Add account balance validation"). Include rationale in body and reference issues (`#123`).
31+- PRs: Clear description, linked issues, screenshots for UI changes, and migration notes if applicable. Ensure CI passes, tests added/updated, and `rubocop`/Biome are clean.
2832
29− @account.expects(:start_date).returns(2.days.ago.to_date)
33+## Security & Configuration Tips
34+- Never commit secrets. Start from `.env.local.example`; use `.env.local` for development only.
35+- Run `bin/brakeman` before major PRs. Prefer environment variables over hard-coded values.
3036
31− Balance::ForwardCalculator.any_instance.expects(:calculate).returns(
32− [
33− Balance.new(date: 1.day.ago.to_date, balance: 1000, cash_balance: 1000, currency: "USD"),
34− Balance.new(date: Date.current, balance: 1000, cash_balance: 1000, currency: "USD")
35− ]
36− )
37+## API Development Guidelines
3738
38− assert_difference "@account.balances.count", 2 do
39− Balance::Syncer.new(@account, strategy: :forward).sync_balances
40− end
41− end
39+### OpenAPI Documentation (MANDATORY)
40+When adding or modifying API endpoints in `app/controllers/api/v1/`, you **MUST** create or update corresponding OpenAPI request specs for **DOCUMENTATION ONLY**:
4241
43− # BAD!!
44− # Unnecessary test - in this case, this is simply testing ActiveRecord's functionality
45− test "saves balance" do
46− balance_record = Balance.new(balance: 100, currency: "USD")
42+1. **Location**: `spec/requests/api/v1/{resource}_spec.rb`
43+2. **Framework**: RSpec with rswag for OpenAPI generation
44+3. **Schemas**: Define reusable schemas in `spec/swagger_helper.rb`
45+4. **Generated Docs**: `docs/api/openapi.yaml`
46+5. **Regenerate**: Run `RAILS_ENV=test bundle exec rake rswag:specs:swaggerize` after changes
4747
48− assert balance_record.save
49− end
50− ```
48+### Post-commit API consistency (LLM checklist)
49+After every API endpoint commit, ensure: (1) **Minitest** behavioral coverage in `test/controllers/api/v1/{resource}_controller_test.rb` (no behavioral assertions in rswag); (2) **rswag** remains docs-only (no `expect`/`assert_*` in `spec/requests/api/v1/`); (3) **rswag auth** uses the same API key pattern everywhere (`X-Api-Key`, not OAuth/Bearer). Full checklist: [.cursor/rules/api-endpoint-consistency.mdc](.cursor/rules/api-endpoint-consistency.mdc).
5150
52−- **Test boundaries correctly**
53− - Distinguish between commands and query methods. Test output of query methods; test that commands were called with the correct params. See an example below:
51+## Design System Hygiene (UI PRs)
5452
55− ```rb
56− class ExampleClass
57− def do_something
58− result = 2 + 2
53+When a PR touches `.erb`, view components, or `.css`:
5954
60− CustomEventProcessor.process_result(result)
55+1. **Tokens, not palette.** Use functional tokens from `app/assets/tailwind/sure-design-system.css` (`bg-warning/10`, `text-destructive`, `bg-container`, `text-primary`, `border-primary`). No raw Tailwind palette (`bg-blue-50`, `text-red-500`, hex literals).
56+2. **Reach for `DS::*` first.** Check `app/components/DS/` (`DS::Alert`, `DS::Button`, `DS::Disclosure`, `DS::Dialog`, `DS::Menu`, etc.) before writing an alert, badge, button, disclosure, dialog, or input shape.
57+3. **Two copies → lift to DS.** Same hand-rolled shape ≥2× in a diff with no DS equivalent → propose a new `DS::*` primitive before the second copy lands.
58+4. **Conventions.** Use the `icon` helper (never `lucide_icon` directly), no raw SVG outside DS primitives, user-facing strings via `t()`, avoid arbitrary `*-[Npx]` values when a scale token fits.
6159
62− result
63− end
64− end
60+Reviewers escalate violations of (2)–(3) to close/rewrite; (1) and (4) are request-changes.
6561
66− class ExampleClass < ActiveSupport::TestCase
67− test "boundaries are tested correctly" do
68− result = ExampleClass.new.do_something
62+## Securities Providers
6963
70− # GOOD - we're only testing that the command was received, not internal implementation details
71− # The actual tests for CustomEventProcessor belong in a different test suite!
72− CustomEventProcessor.expects(:process_result).with(4).once
64+If you need to add a new securities price provider (Tiingo, EODHD, Binance-style crypto, etc.), see [adding-a-securities-provider.md](./docs/llm-guides/adding-a-securities-provider.md) for the full walkthrough — provider class, registry wiring, MIC handling, settings UI, locales, and tests.
7365
74− # GOOD - we're testing the implementation of ExampleClass inside its own test suite
75− assert_equal 4, result
76− end
77− end
78− ```
66+## Debug Logging for Provider Syncs
7967
80− - Never test the implementation details of one class in another classes test suite
68+When a provider sync/import path hits a recoverable error or suspicious partial response that support may need to inspect later, prefer `DebugLogEntry.capture(...)` over `Rails.logger.*`.
8169
82−- **Stubs and mocks**
83− - Use `mocha` gem
84− - Always prefer `OpenStruct` when creating mock instances, or in complex cases, a mock class
85− - Only mock what's necessary. If you're not testing return values, don't mock a return value.
70+- Record support-relevant diagnostics in the debug log so they surface in the super-admin-friendly `/settings/debug` UI.
71+- Include `category`, `level`, `message`, `source`, `provider_key`, and useful structured `metadata`.
72+- Attach `family` and `account_provider` when available so support can filter and trace the affected connection.
73+- Reserve raw Rails logging for low-value local noise; anything operators may need should go to the debug log.
8674
75+## Providers: Pending Transactions and FX Metadata (SimpleFIN/Plaid/Lunchflow)
76+
77+- Pending detection
78+ - SimpleFIN: pending when provider sends `pending: true`, or when `posted` is blank/0 and `transacted_at` is present.
79+ - Plaid: pending when Plaid sends `pending: true` (stored at `transaction.extra["plaid"]["pending"]` for bank/credit transactions imported via `PlaidEntry::Processor`).
80+ - Lunchflow: pending when API returns `isPending: true` in transaction response (stored at `transaction.extra["lunchflow"]["pending"]`).
81+- Storage (extras)
82+ - Provider metadata lives on `Transaction#extra`, namespaced (e.g., `extra["simplefin"]["pending"]`).
83+ - SimpleFIN FX: `extra["simplefin"]["fx_from"]`, `extra["simplefin"]["fx_date"]`.
84+- UI
85+ - Shows a small “Pending” badge when `transaction.pending?` is true.
86+- Variability
87+ - Some providers don’t expose pendings; in that case nothing is shown.
88+- Configuration (default-off)
89+ - SimpleFIN runtime toggles live in `config/initializers/simplefin.rb` via `Rails.configuration.x.simplefin.*`.
90+ - Lunchflow runtime toggles live in `config/initializers/lunchflow.rb` via `Rails.configuration.x.lunchflow.*`.
91+ - ENV-backed keys:
92+ - `SIMPLEFIN_INCLUDE_PENDING=1` (forces `pending=1` on SimpleFIN fetches when caller didn’t specify a `pending:` arg)
93+ - `SIMPLEFIN_DEBUG_RAW=1` (logs raw payload returned by SimpleFIN)
94+ - `LUNCHFLOW_INCLUDE_PENDING=1` (forces `include_pending=true` on Lunchflow API requests)
95+ - `LUNCHFLOW_DEBUG_RAW=1` (logs raw payload returned by Lunchflow)
96+
97+### Provider support notes
98+
99+- SimpleFIN: supports pending + FX metadata; stored under `extra["simplefin"]`.
100+- Plaid: supports pending when the upstream Plaid payload includes `pending: true`; stored under `extra["plaid"]`.
101+- Plaid investments: investment transactions currently do not store pending metadata.
102+- Lunchflow: supports pending via `include_pending` query parameter; stored under `extra["lunchflow"]`.
103+- Manual/CSV imports: no pending concept.
87104
