--- description: 'L4D Tools - Rails 8.1 application with Solid Queue, Hotwire stack' applyTo: '**/*.rb' --- # L4D Tools - AI Coding Guide ## Project Overview **l4d_tools** is a Rails 8.1 application using modern Rails conventions. Key architectural decisions: - **Database**: SQLite (development), supports production deployment via Kamal/Docker - **Job Processing**: Solid Queue (replaces Sidekiq) - background jobs embedded with app via `:solid_queue` plugin in Puma - **Frontend Stack**: Hotwire (Turbo + Stimulus) with importmap-rails and Propshaft - **Testing**: Minitest with Capybara for system tests (parallelized workers) - **Deployment**: Kamal-based Docker containerization with private registry support - **Security Scanning**: Brakeman (security), Rubocop-rails-omakase (style), Bundler-audit (gems) ## Critical Developer Workflows ### Initial Setup ```bash bin/setup # Installs gems, prepares DB, starts server bin/setup --reset # Full reset including DB wipe bin/setup --skip-server # Setup without starting server ``` ### Development Commands ```bash bin/dev # Start Rails server (port 3000) bin/rails console # REPL with app context bin/rails test # Full test suite (parallel workers) bin/rails test test/path # Specific test file/directory bundle exec brakeman # Security vulnerability scan bundle exec rubocop -a # Auto-fix style violations ``` ### Database Management ```bash bin/rails db:prepare # Create/migrate DB bin/rails db:reset # Wipe and re-seed bin/rails db:migrate # Apply pending migrations bin/rails db:rollback # Revert last migration ``` ### Deployment (Kamal/Docker) - **Config**: `config/deploy.yml` - registry, servers, environment variables - **Secrets**: `.kamal/secrets` file (contains RAILS_MASTER_KEY) - **Registry**: Private registry at localhost:5555 for deployment target - **Job Processing**: `SOLID_QUEUE_IN_PUMA=true` runs supervisor in web process (single-server only) - **Build**: `docker build -t l4d_tools .` builds production image ## Architecture & Key Components ### Job Processing (Solid Queue) - **Location**: `app/jobs/` - **Pattern**: Inherit from `ApplicationJob < ActiveJob::Base` - **Configuration**: `config/queue.yml` defines adapters and queues - **Execution**: Jobs run synchronously in test mode; async in development/production - **Puma Integration**: `plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"]` in `config/puma.rb` - **Usage**: `MyJob.perform_later(args)` for async; `MyJob.perform_now(args)` for testing ### Frontend (Hotwire) - **Turbo**: Rapid page transitions via AJAX without full reloads - **Stimulus**: Minimal DOM binding framework; controllers in `app/javascript/controllers/` - **Asset Pipeline**: Propshaft + importmap-rails; no build step needed - **Entry Point**: `app/javascript/application.js` loads all controllers - **Naming**: `data-controller="hello"` maps to `HelloController` in `app/javascript/controllers/hello_controller.js` ### Database & Models - **Schema**: `db/schema.rb` auto-generated from migrations (commit to VCS) - **Migrations**: Generate via `bin/rails generate migration CreateTableName` - **Patterns**: Use model scopes for complex queries; keep migrations simple and reversible - **Fixtures**: YAML files in `test/fixtures/*.yml` auto-loaded by Minitest ### Testing Structure - **Unit Tests**: `test/models/`, `test/helpers/`, `test/controllers/` - **Integration Tests**: `test/integration/` - **System Tests**: Full browser tests via Capybara/Selenium - **Parallelization**: Enabled by default; workers scale to CPU count - **Fixtures**: Auto-loaded and available as lowercase underscore-separated variables (e.g., `posts(:one)`) ## Project-Specific Guidelines - Follow RuboCop-rails-omakase style guide strictly; run `rubocop -a` to auto-fix - Use snake_case for variables/methods, CamelCase for classes - Extract reusable business logic into `app/services/` to keep models lean - Use Solid Queue `perform_later` for background work; never block HTTP requests - Prefer Turbo Frames for dynamic UI updates over full page reloads - Write tests using fixtures; auto-loaded into test instance variables - Use `bin/rails test` to run full suite with parallel workers - Keep `config/routes.rb` simple; add routes only when adding controller actions - Store secrets in `Rails.application.credentials` (encrypted via `master.key`) - Debug with `byebug` or Rails logger; avoid `puts` for production debugging ## Common Patterns ### Job Enqueue (Solid Queue) ```ruby # app/jobs/my_job.rb class MyJob < ApplicationJob queue_as :default def perform(arg1, arg2) # async work here end end # Trigger: MyJob.perform_later(arg1, arg2) # Test: MyJob.perform_now(arg1, arg2) ``` ### Model Scopes & Queries ```ruby # app/models/post.rb class Post < ApplicationRecord scope :published, -> { where(published: true) } scope :recent, -> { order(created_at: :desc) } def self.active; where(active: true); end end # Usage: Post.published.recent ``` ### Stimulus Controller ```javascript // app/javascript/controllers/search_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["input"] search() { console.log(this.inputTarget.value) } } ``` ```erb
``` ### Test Pattern (Minitest) ```ruby # test/models/post_test.rb class PostTest < ActiveSupport::TestCase fixtures :posts # Auto-loads test/fixtures/posts.yml test "post is valid" do assert posts(:one).valid? end end ``` ## Security & Production Readiness - Brakeman scans detect security issues; fix all warnings before merge - Bundler-audit tracks vulnerable gems; update versions regularly - Strong parameters required for all user input in controllers - RAILS_MASTER_KEY (from `config/master.key`) must be set in Docker via secrets - SQLite adequate for single-server; use PostgreSQL for multi-server scaling - Content Security Policy configured in `config/initializers/content_security_policy.rb` - Never commit `master.key` or `.kamal/secrets`; set RAILS_MASTER_KEY via environment