mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-18 20:59:39 +02:00
* Use Redis for ActiveJob and ActionCable * Fix alwaysApply setting * Update queue names and weights * Tweak weights * Update job queues * Update docker setup guide * Remove deprecated upgrade columns from users table * Refactor Redis configuration for Sidekiq and caching in production environment * Add Sidekiq Sentry monitoring * queue naming fix * Clean up schema
85 lines
No EOL
5.1 KiB
Text
85 lines
No EOL
5.1 KiB
Text
---
|
|
description:
|
|
globs:
|
|
alwaysApply: true
|
|
---
|
|
This rule serves as high-level documentation for how the Maybe codebase is structured.
|
|
|
|
## Rules for AI
|
|
|
|
- Use this file to understand how the codebase works
|
|
- Treat this rule/file as your "source of truth" when making code recommendations
|
|
- When creating migrations, always use `rails g migration` instead of creating the file yourself
|
|
|
|
## Project Tech Stack
|
|
|
|
- Web framework: Ruby on Rails
|
|
- Minitest + fixtures for testing
|
|
- Propshaft for asset pipeline
|
|
- Hotwire Turbo/Stimulus for SPA-like UI/UX
|
|
- TailwindCSS for styles
|
|
- Lucide Icons for icons
|
|
- Database: PostgreSQL
|
|
- Jobs: Sidekiq + Redis
|
|
- External
|
|
- Payments: Stripe
|
|
- User bank data syncing: Plaid
|
|
- Market data: Synth (our custom API)
|
|
|
|
## Project conventions
|
|
|
|
These conventions should be used when writing code for Maybe.
|
|
|
|
### Convention 1: Minimize dependencies, vanilla Rails is plenty
|
|
|
|
Dependencies are a natural part of building software, but we aim to minimize them when possible to keep this open-source codebase easy to understand, maintain, and contribute to.
|
|
|
|
- Push Rails to its limits before adding new dependencies
|
|
- When a new dependency is added, there must be a strong technical or business reason to add it
|
|
- When adding dependencies, you should favor old and reliable over new and flashy
|
|
|
|
### Convention 2: Leverage POROs and concerns over "service objects"
|
|
|
|
This codebase adopts a "skinny controller, fat models" convention. Furthermore, we put almost _everything_ directly in the `app/models/` folder and avoid separate folders for business logic such as `app/services/`.
|
|
|
|
- Organize large pieces of business logic into Rails concerns and POROs (Plain ole' Ruby Objects)
|
|
- While a Rails concern _may_ offer shared functionality (i.e. "duck types"), it can also be a "one-off" concern that is only included in one place for better organization and readability.
|
|
- When concerns are used for code organization, they should be organized around the "traits" of a model; not for simply moving code to another spot in the codebase.
|
|
- When possible, models should answer questions about themselves—for example, we might have a method, `account.balance_series` that returns a time-series of the account's most recent balances. We prefer this over something more service-like such as `AccountSeries.new(account).call`.
|
|
|
|
### Convention 3: Prefer server-side solutions over client-side solutions
|
|
|
|
- When possible, leverage Turbo frames over complex, JS-driven client-side solutions
|
|
- When writing a client-side solution, use Stimulus controllers and keep it simple!
|
|
- Especially when dealing with money and currencies, calculate + format server-side and then pass that to the client to display
|
|
- Keep client-side code for where it truly shines. For example, [bulk_select_controller.js](mdc:app/javascript/controllers/bulk_select_controller.js) is a case where server-side solutions would degrade the user experience significantly. When bulk-selecting entries, client-side solutions are the way to go and Stimulus provides the right toolset to achieve this.
|
|
|
|
### Convention 4: Sacrifice performance, optimize for simplicitly and clarity
|
|
|
|
This codebase is still young. We are still rapidly iterating on domain designs and features. Because of this, code should be optimized for simplicitly and clarity over performance.
|
|
|
|
- Focus on good OOP design first, performance second
|
|
- Be mindful of large performance bottlenecks, but don't sweat the small stuff
|
|
|
|
### Convention 5: Prefer semantic, native HTML features
|
|
|
|
The HTML spec has improved tremendously over the years and offers a ton of functionality out of the box. We prefer semantic, native HTML solutions over JS-based ones. A few examples of this include:
|
|
|
|
- Using the `dialog` element for modals
|
|
- Using `summary` / `details` elements for disclosures (or `popover` attribute)
|
|
|
|
The Hotwire suite (Turbo/Stimulus) works very well with these native elements and we optimize for this.
|
|
|
|
### Convention 6: Use Minitest + Fixtures for testing, minimize fixtures
|
|
|
|
Due to the open-source nature of this project, we have chosen Minitest + Fixtures for testing to maximize familiarity and predictability.
|
|
|
|
- Always use Minitest and fixtures for testing.
|
|
- 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.
|
|
- For tests that require a large number of fixture records to be created, use Rails helpers such as [entries_test_helper.rb](mdc:test/support/account/entries_test_helper.rb) to act as a "factory" for creating these. For a great example of this, check out [balance_calculator_test.rb](mdc:test/models/account/balance_calculator_test.rb)
|
|
|
|
### Convention 7: Use ActiveRecord for complex validations, DB for simple ones, keep business logic out of DB
|
|
|
|
- Enforce `null` checks, unique indexes, and other simple validations in the DB
|
|
- ActiveRecord validations _may_ mirror the DB level ones, but not 100% necessary. These are for convenience when error handling in forms. Always prefer client-side form validation when possible.
|
|
- Complex validations and business logic should remain in ActiveRecord |