.github/copilot-instructions.md: update
This commit is contained in:
parent
a708d89b2e
commit
987f3c08cc
1 changed files with 178 additions and 54 deletions
232
.github/copilot-instructions.md
vendored
232
.github/copilot-instructions.md
vendored
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
description: 'L4D Tools - Rails 8.1 application with Solid Queue, Hotwire stack'
|
||||
description: 'L4D Tools - Early-stage Rails 8.1 app with Solid Queue, Hotwire, Kamal deployment'
|
||||
applyTo: '**/*.rb'
|
||||
---
|
||||
|
||||
|
|
@ -7,70 +7,99 @@ applyTo: '**/*.rb'
|
|||
|
||||
## 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)
|
||||
**l4d_tools** is a fresh Rails 8.1 application in early development stage. No domain models exist yet—focus is on establishing clean patterns for future features.
|
||||
|
||||
**Core Stack:**
|
||||
- **Framework**: Rails 8.1 (modern defaults: modern browser support, Propshaft asset pipeline)
|
||||
- **Database**: SQLite with WAL mode (development); production supports Kamal/Docker deployment
|
||||
- **Jobs**: Solid Queue (embedded in Puma via `plugin :solid_queue` when `SOLID_QUEUE_IN_PUMA=true`)
|
||||
- **Frontend**: Hotwire (Turbo + Stimulus) + importmap-rails (no build step)
|
||||
- **Testing**: Minitest + Capybara with parallel workers
|
||||
- **Deployment**: Kamal (Docker/container-based) with private registry at `localhost:5555`
|
||||
- **Security**: Brakeman, Rubocop-rails-omakase, Bundler-audit
|
||||
|
||||
## Critical Developer Workflows
|
||||
|
||||
### Initial Setup
|
||||
### Setup & Running
|
||||
```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
|
||||
bin/setup # Install gems, prepare SQLite DB, start server on :3000
|
||||
bin/dev # Start Rails dev server (invokes bin/rails server)
|
||||
bin/rails console # Interactive REPL with full app context
|
||||
```
|
||||
|
||||
### Development Commands
|
||||
### Testing
|
||||
```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
|
||||
bin/rails test # Full test suite (auto-parallelized by CPU cores)
|
||||
bin/rails test test/models/post_test.rb # Single test file
|
||||
bin/rails test test/models/post_test.rb:42 # Specific test by line number
|
||||
```
|
||||
|
||||
### Database Management
|
||||
### Code Quality
|
||||
```bash
|
||||
bundle exec brakeman # Security scanning; fix ALL warnings before merge
|
||||
bundle exec rubocop -a # Auto-fix style issues (rails-omakase rules)
|
||||
bundle exec bundler-audit # Check gem vulnerabilities; update outdated gems
|
||||
```
|
||||
|
||||
### Database (SQLite WAL mode)
|
||||
```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
|
||||
bin/rails db:rollback # Revert last migration step
|
||||
bin/rails db:reset # Wipe dev DB and re-run schema + seeds
|
||||
```
|
||||
|
||||
### 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
|
||||
### Deployment (Kamal)
|
||||
- **Config**: `config/deploy.yml` (servers, registry endpoint, environment variables)
|
||||
- **Build**: Auto-built by Kamal; Dockerfile uses multi-stage build
|
||||
- **Registry**: Private Docker registry at `localhost:5555` (configured in deploy.yml)
|
||||
- **Secrets**: Set `RAILS_MASTER_KEY` env var via Kamal secrets or system env
|
||||
- **Job Queue**: `SOLID_QUEUE_IN_PUMA=true` embeds queue supervisor in Puma (single-server deployments only)
|
||||
|
||||
## 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
|
||||
### Job Processing (Solid Queue - no separate Redis/Sidekiq)
|
||||
- **Store**: Database-backed; data lives in Solid Queue tables (queue_schema.rb)
|
||||
- **Location**: `app/jobs/` - inherit from `ApplicationJob < ActiveJob::Base`
|
||||
- **Configuration**: `config/queue.yml` defines:
|
||||
- `threads: 3` - worker threads per process
|
||||
- `processes: JOB_CONCURRENCY` env var - defaults to 1 (scale via env)
|
||||
- `polling_interval: 0.1` - how frequently workers check for jobs
|
||||
- **Enqueue**: `MyJob.perform_later(args)` for async; `MyJob.perform_now(args)` for testing/immediate
|
||||
- **Puma Integration**: `plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"]` in `config/puma.rb` runs supervisor in same process (single-server deployments only)
|
||||
- **In Tests**: Jobs run synchronously (development mode behavior)
|
||||
- **Important**: No Sidekiq/Redis—Solid Queue is database-backed and built into Puma
|
||||
|
||||
### 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`
|
||||
### Frontend (Hotwire + Importmap, no build step)
|
||||
- **Turbo**: Handles navigation via AJAX (replaces full page loads); auto-loads from `data-turbo=true`
|
||||
- **Stimulus**: Zero-config JavaScript binding via `data-controller="name"` → `NameController` in `app/javascript/controllers/name_controller.js`
|
||||
- **Asset Pipeline**: Propshaft (modern successor to Sprockets) + importmap-rails
|
||||
- CSS: All files in `app/assets/stylesheets/` auto-loaded via `stylesheet_link_tag :app`
|
||||
- JS: Controllers auto-discovered; no webpack/bundler required
|
||||
- Entry point: `app/javascript/application.js` imports controllers and libraries
|
||||
- **Example Stimulus binding**:
|
||||
```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
|
||||
<!-- In view: -->
|
||||
<div data-controller="search">
|
||||
<input data-search-target="input" data-action="input->search#search">
|
||||
</div>
|
||||
```
|
||||
|
||||
### 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
|
||||
### Database & Migrations (SQLite WAL)
|
||||
- **Schema**: `db/schema.rb` auto-generated; commit to git (tracks schema evolution)
|
||||
- **Migrations**: Generate via `bin/rails generate migration DescriptiveNameHere`
|
||||
- Use `change` method for reversible migrations (preferred)
|
||||
- Always add indexes for foreign keys
|
||||
- Test rollback: `bin/rails db:rollback` verifies reversibility
|
||||
- **SQLite Limits**: AUTOINCREMENT primary keys, pragma constraints, no ALTER COLUMN
|
||||
- **Models**: No domain models exist yet; structure will be pattern-driven once first models are created
|
||||
|
||||
### Testing Structure
|
||||
- **Unit Tests**: `test/models/`, `test/helpers/`, `test/controllers/`
|
||||
|
|
@ -81,18 +110,70 @@ bin/rails db:rollback # Revert last migration
|
|||
|
||||
## Project-Specific Guidelines
|
||||
|
||||
- Follow RuboCop-rails-omakase style guide strictly; run `rubocop -a` to auto-fix
|
||||
### Early Stage Patterns (No Domain Models Yet)
|
||||
- **Start with migrations**: Define database schema first; models follow naturally
|
||||
- **Keep ApplicationRecord/ApplicationJob clean**: These are templates for future models/jobs
|
||||
- **Use concerns sparingly**: Extract concerns only after 2+ models need the same behavior
|
||||
- **Establish directory structure early**: Create `app/services/`, `app/presenters/` if needed for future patterns
|
||||
|
||||
### Code Quality & Style
|
||||
- Follow RuboCop-rails-omakase style guide strictly; run `bundle exec 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
|
||||
- Keep `config/routes.rb` simple; add routes only when adding controller actions
|
||||
- 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
|
||||
### Performance & Background Jobs
|
||||
- Use Solid Queue `perform_later` for background work; never block HTTP requests
|
||||
- Set `JOB_CONCURRENCY` env var to scale job processing beyond default (1 process × 3 threads)
|
||||
- Test jobs with `MyJob.perform_now` in test env; they run synchronously
|
||||
- Monitor job failures in `bin/rails console`: `SolidQueue::Job.where(status: :failed)`
|
||||
|
||||
### Frontend & UI
|
||||
- Prefer Turbo Frames (`<turbo-frame>`) for dynamic UI updates over full page reloads
|
||||
- Always set `data-turbo="false"` on forms that should NOT use Turbo (e.g., file uploads, legacy forms)
|
||||
- Stimulus controllers are zero-config; name them kebab-case, file them snake_case
|
||||
- Test JavaScript with system tests; Capybara + Selenium support Turbo navigation
|
||||
|
||||
### Secrets & Credentials
|
||||
- Store all secrets in `Rails.application.credentials` (encrypted via `master.key`)
|
||||
- Never commit `config/master.key`; set `RAILS_MASTER_KEY` env var in production
|
||||
- Use `bin/rails credentials:edit` to add new secrets
|
||||
- Development uses `.key` file automatically; test/production use env variable
|
||||
|
||||
### Debugging
|
||||
- Debug with `byebug` or Rails logger; avoid `puts` for production debugging
|
||||
- Use `Rails.logger.info("...")` for production-safe logging
|
||||
- Inspect Solid Queue tables directly: `bin/rails console` → `SolidQueue::Job.last(10)`
|
||||
|
||||
## Integration Points & Data Flows
|
||||
|
||||
### HTTP Request Lifecycle
|
||||
1. **Routing**: `config/routes.rb` → Controller action
|
||||
2. **Parameter Validation**: Use `strong_parameters` in ApplicationController (already configured)
|
||||
3. **Business Logic**: Execute in service objects or job queues, not controllers
|
||||
4. **Response**: Render ERB template (with Turbo) or JSON (if API)
|
||||
5. **Browser**: Turbo replaces page or frame; Stimulus controllers initialize
|
||||
|
||||
### Database Access Patterns
|
||||
- **Queries**: Use model scopes and class methods (not raw SQL)
|
||||
- **Write Operations**: Controller delegates to service → model (transaction boundaries)
|
||||
- **Background Jobs**: Solid Queue tables store jobs; accessed via ActiveJob interface
|
||||
- **Migrations**: Always reversible; schema changes are version-controlled in `db/schema.rb`
|
||||
|
||||
### Job Queue Integration
|
||||
1. **Enqueue**: `MyJob.perform_later(id)` in controller/service
|
||||
2. **Polling**: Solid Queue supervisor (in Puma) polls for jobs every 0.1s
|
||||
3. **Execution**: Worker thread picks job, calls `perform(id)`
|
||||
4. **Persistence**: Results/errors logged in job records; failures retryable
|
||||
5. **Monitoring**: Check status via `SolidQueue::Job` model in console
|
||||
|
||||
### Asset & Static File Pipeline
|
||||
- **CSS**: All files in `app/assets/stylesheets/` auto-included via `stylesheet_link_tag :app`
|
||||
- **JS**: Controllers auto-discovered from `app/javascript/controllers/`; no bundling required
|
||||
- **Images**: Reference via `image_tag "name"` (fingerprinted in production)
|
||||
- **PWA**: Service worker template available in `app/views/pwa/` (commented out in routes)
|
||||
|
||||
### Job Enqueue (Solid Queue)
|
||||
```ruby
|
||||
|
|
@ -164,3 +245,46 @@ end
|
|||
- 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
|
||||
|
||||
## Key Directory Structure
|
||||
|
||||
- `app/controllers/` - HTTP request handlers; keep thin (validate + delegate to services)
|
||||
- `app/models/` - ActiveRecord models; use scopes for queries, keep business logic minimal
|
||||
- `app/views/` - ERB templates with Turbo/Stimulus integration
|
||||
- `app/javascript/controllers/` - Stimulus controllers for DOM interactivity
|
||||
- `app/jobs/` - Solid Queue background jobs; use for time-consuming operations
|
||||
- `config/` - Application configuration; routes, database, queue, deployment settings
|
||||
- `test/` - Test suite mirroring app structure; fixtures auto-loaded
|
||||
- `db/migrations/` - Version-controlled database schema changes
|
||||
|
||||
## Common Pitfalls to Avoid
|
||||
|
||||
### Early-Stage Mistakes
|
||||
- **Don't skip migrations**: Always create reversible migrations with `change` blocks (or up/down)
|
||||
- **Don't hard-code job names**: Reference jobs via constants/classes, not strings
|
||||
- **Don't mix concerns in models**: Business logic belongs in services; models are data containers
|
||||
- **Don't create routes without controllers**: Routes must map to actual controller actions
|
||||
|
||||
### Solid Queue Specifics
|
||||
- **No Sidekiq/Redis**: Job data is stored in SQLite; don't assume Redis-style operations
|
||||
- **Single-server default**: `JOB_CONCURRENCY=1` by default; set env var to scale
|
||||
- **Test mode synchronous**: Jobs run immediately in tests; use `perform_now` explicitly if needed
|
||||
- **Monitor job failures**: Failed jobs remain in DB; check `SolidQueue::Job.where(status: :failed)`
|
||||
|
||||
### Hotwire/Frontend Gotchas
|
||||
- **Set data-turbo="false" for file uploads**: Turbo doesn't handle multipart forms well
|
||||
- **Use `data-turbo-method="delete"` for non-GET actions**: Turbo expects method hints
|
||||
- **Stimulus controllers auto-initialize**: No manual instantiation needed; just use HTML attributes
|
||||
- **CSS conflicts with Turbo**: Use scoped styles; avoid global `.active` or `.selected` classes
|
||||
|
||||
### SQLite Development
|
||||
- **No concurrent migrations**: SQLite locks during schema changes; don't run multiple devs simultaneously
|
||||
- **WAL mode enabled**: Provides better concurrency; don't disable without reason
|
||||
- **No ALTER COLUMN**: Use temporary tables pattern for complex migrations
|
||||
- **Indexes matter**: SQLite can't optimize without them; always index foreign keys
|
||||
|
||||
### Deployment & Secrets
|
||||
- **RAILS_MASTER_KEY required**: Set env var before Docker startup; app won't boot without it
|
||||
- **Registry authentication**: Docker registry at localhost:5555 must be running for Kamal builds
|
||||
- **Single-server assumption**: `SOLID_QUEUE_IN_PUMA=true` only works with one web server
|
||||
- **Database file location**: SQLite database is in `storage/` directory; ensure volume mounts in Docker
|
||||
|
|
|
|||
Loading…
Reference in a new issue