l4d.tools/.github/copilot-instructions.md
CroneKorkN a708d89b2e
Some checks are pending
CI / scan_ruby (push) Waiting to run
CI / scan_js (push) Waiting to run
CI / lint (push) Waiting to run
CI / test (push) Waiting to run
CI / system-test (push) Waiting to run
.github/copilot-instructions.md: init
2026-01-18 12:41:33 +01:00

166 lines
6.2 KiB
Markdown

---
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
<!-- View: -->
<div data-controller="search">
<input type="text" data-search-target="input" data-action="input->search#search">
</div>
```
### 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