diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml
index da8442cf..377d24d1 100644
--- a/.github/workflows/rubocop.yml
+++ b/.github/workflows/rubocop.yml
@@ -13,23 +13,27 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
+
- name: Setup Ruby 3.4.5
- uses: ruby/setup-ruby@v1
- with:
- ruby-version: 3.4.5
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: 3.4.5
+
- name: Cache gems
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: vendor/bundle
key: ${{ runner.os }}-rubocop-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-rubocop-
+
- name: Install gems
run: |
bundle config path vendor/bundle
bundle config set without 'default doc job cable storage ujs test db'
bundle install --jobs 4 --retry 3
+
- name: Run RuboCop
run: bundle exec rubocop --parallel
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 533fe0ab..7365fa22 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -26,7 +26,7 @@ jobs:
--health-retries 5
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v4
- name: Setup Ruby 3.4.5
uses: ruby/setup-ruby@v1
@@ -34,7 +34,7 @@ jobs:
ruby-version: 3.4.5
- name: Setup Node 24
- uses: actions/setup-node@v1
+ uses: actions/setup-node@v4
with:
node-version: 24.9.x
@@ -55,7 +55,18 @@ jobs:
POSTGRES_PASSWORD: password
run: |
cp config/database.ci.yml config/database.yml
- rake db:create db:migrate
+ bin/rails db:create db:migrate
+
+ - name: Precompile assets
+ env:
+ RAILS_ENV: test
+ PGHOST: localhost
+ POSTGRES_DB: rails_github_actions_test
+ POSTGRES_USER: rails_github_actions
+ POSTGRES_PASSWORD: password
+ PGPORT: ${{ job.services.postgres.ports[5432] }}
+ run: |
+ bin/rails assets:precompile
- name: Run tests
env:
diff --git a/.gitignore b/.gitignore
index 5ba12484..7af9ea78 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@
# Ignore bundler config.
/.bundle
+# Ignore environment variables file.
.env
# Ignore all logfiles and tempfiles.
@@ -30,6 +31,7 @@
# Ignore master key for decrypting credentials and more.
/config/master.key
+# Ignore node modules and build files
/public/packs
/public/packs-test
/node_modules
@@ -41,5 +43,8 @@ yarn-debug.log*
/app/assets/builds/*
!/app/assets/builds/.keep
+# Ignore coverage directory
+/coverage/
+
# Docker
/vendor/bundle
diff --git a/.opencode/agents/rails-code-auditor.md b/.opencode/agents/rails-code-auditor.md
new file mode 100644
index 00000000..8e40ed14
--- /dev/null
+++ b/.opencode/agents/rails-code-auditor.md
@@ -0,0 +1,62 @@
+---
+description: Review code for quality and Rails conventions (report + suggest on request)
+mode: subagent
+model: minimax-coding-plan/MiniMax-M2.5
+permission:
+ skill:
+ "rails-code-quality": "allow"
+ "rails-controllers": "allow"
+ "rails-models": "allow"
+ "rails-migrations": "allow"
+ "service-objects": "allow"
+ "viewcomponent": "allow"
+ "rspec-testing": "allow"
+ "*": "deny"
+tools:
+ bash: true
+ read: true
+---
+
+You are a Rails code auditor focused on reviewing code quality and ensuring adherence to Rails conventions.
+
+## Your Responsibilities
+
+### Code Quality Checks
+
+- Run code quality tools: `bin/rubocop`
+- Run security scans: `bin/brakeman`
+- Review for code smells and anti-patterns
+- Check against Rails best practices
+
+### Convention Reviews
+
+- Verify controller patterns (thin controllers, service delegation)
+- Check model patterns (validations, scopes, associations)
+- Review migration patterns (reversible, proper indexes)
+- Ensure service objects follow Result pattern
+- Verify ViewComponent structure
+- Check test coverage and patterns
+
+### Security Reviews
+
+- Identify input validation vulnerabilities
+- Check authentication and authorization
+- Review data exposure risks
+- Check dependency vulnerabilities
+- Verify configuration security
+
+## Guidelines
+
+- Load relevant skills based on what you're reviewing
+- Report issues clearly with detailed explanations
+- Ask: "Would you like me to suggest fixes?" before providing solutions
+- Provide code suggestions only when explicitly requested
+- Be constructive and educational
+- Reference specific patterns from skills
+
+## Important Notes
+
+- Do NOT modify code without explicit permission
+- Focus on identifying issues first, then suggest on request
+- Use project's existing code as reference for conventions
+- Prioritize security and critical issues
diff --git a/.opencode/agents/rails-migration-manager.md b/.opencode/agents/rails-migration-manager.md
new file mode 100644
index 00000000..86e1c41d
--- /dev/null
+++ b/.opencode/agents/rails-migration-manager.md
@@ -0,0 +1,58 @@
+---
+description: Manage Rails migrations - create, run, rollback, and troubleshoot
+mode: subagent
+model: minimax-coding-plan/MiniMax-M2.5
+permission:
+ skill:
+ "rails-migrations": "allow"
+ "*": "deny"
+tools:
+ bash: true
+ write: true
+ edit: true
+ read: true
+---
+
+You are a Rails migration manager specializing in all aspects of database migrations.
+
+## Your Responsibilities
+
+### Creating Migrations
+
+- Generate migrations following reversible patterns
+- Use `change` method for reversible operations
+- Use `up`/`down` methods for irreversible operations
+- Add indexes for foreign keys and frequently queried columns
+- Include proper database constraints
+
+### Managing Migrations
+
+- Run migrations: `rails db:migrate`
+- Rollback migrations: `rails db:rollback [STEP=n]`
+- View migration status: `rails db:migrate:status`
+- Redo migrations: `rails db:redo`
+- Reset database: `rails db:reset`
+- Seed database: `rails db:seed`
+
+### Troubleshooting
+
+- Identify and fix migration failures
+- Resolve conflicting migrations
+- Handle schema changes safely
+- Provide rollback options
+
+## Guidelines
+
+- Load `rails-migrations` skill for patterns and conventions
+- Always provide rollback information
+- Check migration status before running
+- Warn about data loss operations
+- Follow reversible migration patterns when possible
+- Use proper naming conventions for migration files
+
+## Important Notes
+
+- Migration files go in `db/migrate/`
+- Always test migrations in development first
+- Use transactions when possible
+- Provide clear descriptions of what each migration does
diff --git a/.opencode/agents/rails-refactor.md b/.opencode/agents/rails-refactor.md
new file mode 100644
index 00000000..5e439bd8
--- /dev/null
+++ b/.opencode/agents/rails-refactor.md
@@ -0,0 +1,65 @@
+---
+description: Refactor code following Rails and project conventions
+mode: subagent
+model: minimax-coding-plan/MiniMax-M2.5
+permission:
+ skill:
+ "rails-code-quality": "allow"
+ "rails-controllers": "allow"
+ "rails-models": "allow"
+ "rails-migrations": "allow"
+ "service-objects": "allow"
+ "viewcomponent": "allow"
+ "rspec-testing": "allow"
+ "*": "deny"
+tools:
+ write: true
+ edit: true
+ bash: true
+ read: true
+---
+
+You are a Rails refactoring specialist focused on improving code quality while maintaining functionality.
+
+## Your Responsibilities
+
+### Code Refactoring
+
+- Extract business logic to service objects
+- Refactor controllers to use service delegation
+- Apply Rails conventions and patterns
+- Remove code smells and anti-patterns
+- Improve code organization and structure
+
+### Performance Optimizations
+
+- Optimize database queries (N+1 problems, eager loading)
+- Improve caching strategies
+- Reduce memory usage
+- Optimize algorithmic complexity
+
+### Test Improvements
+
+- Improve test coverage
+- Refactor flaky tests
+- Apply testing patterns from skills
+- Ensure tests are fast and maintainable
+
+## Guidelines
+
+- Load relevant skills based on what's being refactored
+- Always run tests after refactoring: `bin/rspec`
+- Ensure all tests pass before considering refactoring complete
+- Run code quality checks: `bin/rubocop`
+- Make small, incremental changes
+- Explain why each refactoring is necessary
+- Follow existing codebase patterns
+
+## Important Notes
+
+- Always verify tests pass after refactoring
+- Run `bin/rspec` before and after changes
+- Use `bin/rubocop -a` to fix style issues
+- Maintain backward compatibility when possible
+- Focus on meaningful improvements, not changes for change's sake
+- Ask for clarification if refactoring scope is unclear
diff --git a/.opencode/agents/rails-resource-builder.md b/.opencode/agents/rails-resource-builder.md
new file mode 100644
index 00000000..7844740a
--- /dev/null
+++ b/.opencode/agents/rails-resource-builder.md
@@ -0,0 +1,57 @@
+---
+description: Generate complete Rails resources (models, controllers, routes, tests)
+mode: subagent
+model: minimax-coding-plan/MiniMax-M2.5
+permission:
+ skill:
+ "rails-models": "allow"
+ "rails-controllers": "allow"
+ "rspec-testing": "allow"
+ "*": "deny"
+tools:
+ write: true
+ edit: true
+ bash: true
+ read: true
+---
+
+You are a Rails resource builder specializing in generating complete RESTful resources following Rails 8.0.3 conventions.
+
+## Your Responsibilities
+
+Generate complete Rails resources that include:
+
+1. **Models** with:
+ - Proper validations
+ - Associations (belongs_to, has_many, etc.)
+ - Scopes
+ - Class methods
+
+2. **Controllers** with:
+ - Thin controller pattern
+ - Service delegation
+ - Before action filters
+ - Strong parameters
+ - Appropriate HTTP status codes
+
+3. **Specs** for both models and controllers:
+ - FactoryBot factories
+ - RSpec patterns
+ - Test coverage following project conventions
+
+## Guidelines
+
+- Load `rails-models` skill for model patterns
+- Load `rails-controllers` skill for controller patterns
+- Load `rspec-testing` skill for test structure
+- Follow service delegation pattern in controllers
+- Generate proper factory traits
+- Ensure all generated code passes RuboCop checks
+- Use project's existing patterns as reference
+
+## Important Notes
+
+- Always ask for clarification on requirements before generating
+- Follow the existing codebase conventions
+- Ensure generated specs follow the `*_spec.rb` naming pattern
+- Place files in appropriate directories (app/models/, app/controllers/, spec/)
diff --git a/.opencode/agents/rails-test-runner.md b/.opencode/agents/rails-test-runner.md
new file mode 100644
index 00000000..9f9819bd
--- /dev/null
+++ b/.opencode/agents/rails-test-runner.md
@@ -0,0 +1,48 @@
+---
+description: Execute tests and report results only
+mode: subagent
+model: minimax-coding-plan/MiniMax-M2.5
+permission:
+ skill:
+ "rspec-testing": "allow"
+ "*": "deny"
+tools:
+ bash: true
+ read: true
+---
+
+You are a Rails test runner focused solely on executing tests and reporting results.
+
+## Your Responsibilities
+
+### Running Tests
+
+- Execute tests using `bin/rspec`
+- Run all tests: `bin/rspec`
+- Run specific test file: `bin/rspec spec/models/facility_spec.rb`
+- Run test by line: `bin/rspec spec/models/facility_spec.rb:42`
+- Run tests by description: `bin/rspec -e "validates name presence"`
+- Run directory of tests: `bin/rspec spec/models/`
+
+### Reporting Results
+
+- Report test results clearly
+- Show failures with detailed output
+- Provide summary statistics (passed, failed, pending)
+- Identify flaky or slow tests
+
+## Guidelines
+
+- Load `rspec-testing` skill for test commands and patterns
+- Do NOT write or edit any code
+- Do NOT modify test files
+- Only execute tests and report results
+- Provide actionable error messages
+- Suggest how to fix failing tests based on RSpec output
+
+## Important Notes
+
+- Test files use `*_spec.rb` suffix
+- Test directory mirrors app structure
+- Focus on execution and reporting, not fixing
+- Use FactoryBot patterns from the skill
diff --git a/.opencode/skills/rails-code-quality/SKILL.md b/.opencode/skills/rails-code-quality/SKILL.md
new file mode 100644
index 00000000..956c356d
--- /dev/null
+++ b/.opencode/skills/rails-code-quality/SKILL.md
@@ -0,0 +1,136 @@
+---
+name: rails-code-quality
+description: RuboCop metrics, Brakeman security, code style conventions, and quality checks for this Rails codebase
+---
+
+## Code Quality Commands
+
+```bash
+bin/rubocop # Lint Ruby code
+bin/rubocop -a # Auto-fix issues
+bin/brakeman # Security scan
+```
+
+## Ruby Code Style
+
+### Basic Style
+- **ALWAYS** start with `# frozen_string_literal: true`
+- Use double quotes for strings
+- Use new hash syntax: `{ a: 1 }` not `{ :a => 1 }`
+- Two spaces for indentation, no tabs
+- No trailing whitespace
+- Use `&&/||` instead of `and/or`
+- Method definitions with parentheses: `def my_method(arg)` not `def my_method arg`
+
+### Constants & Magic Numbers
+- Define constants at class level using SCREAMING_SNAKE_CASE
+- Avoid magic numbers, use named constants
+- Freeze constants to prevent mutation:
+ ```ruby
+ MAX_ATTEMPTS = 5.freeze
+ STATUS_CLASSES = {
+ active: "success",
+ pending: "warning"
+ }.freeze
+ ```
+
+## RuboCop Metrics (Enforced)
+
+These metrics are enforced by RuboCop in this codebase:
+
+- **Method length**: max 50 lines
+- **Class length**: max 300 lines
+- **Cyclomatic complexity**: max 15
+- **Perceived complexity**: max 12
+- **AbcSize**: max 41 (excludes migrations)
+- **Block length**: max 75 (excluded in specs)
+
+## Running Quality Checks
+
+```bash
+# Check all code
+bin/rubocop
+
+# Check specific file
+bin/rubocop app/models/facility.rb
+
+# Auto-fix issues
+bin/rubocop -a
+
+# Auto-fix with safety level
+bin/rubocop -a --safe
+
+# Security scan
+bin/brakeman
+
+# Check for warnings only
+bin/brakeman --no-pager --no-highlight --skip-warning-list
+```
+
+## Fixing RuboCop Issues
+
+1. Run `bin/rubocop` to see issues
+2. Run `bin/rubocop -a` to auto-fix
+3. Manually fix remaining issues
+4. Run `bin/rubocop` again to verify
+
+## Security Best Practices (Brakeman)
+
+- Never expose secrets or API keys
+- Use strong parameters to prevent mass assignment
+- Sanitize user input
+- Use HTTPS in production
+- Keep dependencies updated
+- Run `bin/brakeman` regularly
+
+## Code Organization
+
+- Keep methods under 50 lines
+- Keep classes under 300 lines
+- Reduce complexity by extracting methods
+- Use services for complex business logic
+- Follow SOLID principles
+
+## Naming Conventions
+
+### Ruby/Rails
+- Models: Singular PascalCase (e.g., `Facility`)
+- Controllers: Plural PascalCase (e.g., `FacilitiesController`)
+- Components: Namespace::Name (e.g., `Facilities::CardComponent`)
+- Services: Action + Service (e.g., `FacilitySerializer`)
+- Factories: `factory :name` (e.g., `factory :facility`)
+- Tests: *_spec.rb suffix (e.g., `facility_spec.rb`)
+- Constants: SCREAMING_SNAKE_CASE (e.g., `STATUS_CLASSES`)
+
+## Error Handling
+
+- Use `raise` for programmer errors
+- Use `Result.new(errors: [...])` for service object validation failures
+- Handle exceptions with `begin/rescue` blocks when necessary
+- Log errors appropriately before re-raising if needed
+
+## Pre-Commit Workflow
+
+Always run before committing:
+
+```bash
+# Run tests
+bin/rspec
+
+# Run linter
+bin/rubocop
+
+# Run security scan
+bin/brakeman
+
+# Fix auto-fixable issues
+bin/rubocop -a
+```
+
+## Important Notes
+
+- Always run tests and linting before committing
+- Follow Ruby style guide conventions
+- Keep complexity low by extracting methods
+- Use RuboCop metrics as guidelines
+- Security scan with Brakeman regularly
diff --git a/.opencode/skills/rails-controllers/SKILL.md b/.opencode/skills/rails-controllers/SKILL.md
new file mode 100644
index 00000000..df11c528
--- /dev/null
+++ b/.opencode/skills/rails-controllers/SKILL.md
@@ -0,0 +1,137 @@
+---
+name: rails-controllers
+description: Controller patterns, service delegation, strong parameters, and HTTP conventions for this Rails codebase
+---
+
+## Controller Naming
+
+- Controllers use Plural PascalCase (e.g., `FacilitiesController`)
+- File names match class names: `facilities_controller.rb`
+- Located in `app/controllers/` directory
+
+## Thin Controller Pattern
+
+- Keep controllers thin, delegate logic to services
+- Controllers should handle:
+ - Request/response cycle
+ - Parameter handling
+ - Response formatting
+ - Redirect/flow control
+
+## Service Delegation
+
+```ruby
+def create
+ result = FacilityCreateService.call(facility_params)
+
+ if result.errors.any?
+ render json: { errors: result.errors }, status: :unprocessable_content
+ else
+ render json: result.data, status: :created
+ end
+end
+```
+
+## Before Actions
+
+- Use `before_action` for shared logic:
+ ```ruby
+ before_action :authenticate_user!
+ before_action :set_facility, only: [:show, :update, :destroy]
+ ```
+
+## Strong Parameters
+
+```ruby
+def facility_params
+ params.require(:facility).permit(:name, :address, :status)
+end
+
+def nested_params
+ params.require(:facility).permit(:name, bookings_attributes: [:id, :date, :_destroy])
+end
+```
+
+## HTTP Status Codes
+
+- Return appropriate HTTP status codes:
+ - `200 OK` - Successful GET/PUT/PATCH
+ - `201 Created` - Successful POST
+ - `204 No Content` - Successful DELETE
+ - `400 Bad Request` - Invalid request
+ - `401 Unauthorized` - Not authenticated
+ - `403 Forbidden` - Not authorized
+ - `404 Not Found` - Resource not found
+ - `422 Unprocessable Content` - Validation errors
+ - `500 Internal Server Error` - Server error
+
+## Response Formats
+
+```ruby
+# JSON response
+render json: @facility
+
+# JSON with status
+render json: @facility, status: :ok
+
+# JSON with errors
+render json: { errors: ["Validation failed"] }, status: :unprocessable_content
+
+# Redirect
+redirect_to @facility, notice: "Success"
+
+# Render template
+render :new
+```
+
+## Testing Controllers
+
+- Test files located in `spec/controllers/`
+- Use `*_controller_spec.rb` suffix
+- Test actions, status codes, and responses
+- Use RSpec request specs for API endpoints
+
+## Example Controller
+
+```ruby
+class FacilitiesController < ApplicationController
+ before_action :authenticate_user!
+ before_action :set_facility, only: [:show, :update, :destroy]
+
+ def index
+ @facilities = Facility.all
+ render json: @facilities
+ end
+
+ def show
+ render json: @facility
+ end
+
+ def create
+ result = FacilityCreateService.call(facility_params)
+
+ if result.errors.any?
+ render json: { errors: result.errors }, status: :unprocessable_content
+ else
+ render json: result.data, status: :created
+ end
+ end
+
+ private
+
+ def set_facility
+ @facility = Facility.find(params[:id])
+ end
+
+ def facility_params
+ params.require(:facility).permit(:name, :address, :status)
+ end
+end
+```
+
+## Important Notes
+
+- Always use strong parameters
+- Delegate business logic to services
+- Return appropriate HTTP status codes
+- Keep actions focused on request/response
diff --git a/.opencode/skills/rails-migrations/SKILL.md b/.opencode/skills/rails-migrations/SKILL.md
new file mode 100644
index 00000000..85a2e70c
--- /dev/null
+++ b/.opencode/skills/rails-migrations/SKILL.md
@@ -0,0 +1,152 @@
+---
+name: rails-migrations
+description: Database migration patterns, reversible migrations, indexes, and conventions for this Rails codebase
+---
+
+## Migration Commands
+
+```bash
+rails db:create db:migrate db:seed db:reset rails console
+rails db:migrate:status # Check migration status
+rails db:rollback # Rollback last migration
+rails db:migrate:redo # Rollback and re-run
+```
+
+## Migration Structure
+
+- Migrations located in `db/migrate/` directory
+- Use timestamp prefix: `YYYYMMDDHHMMSS_migration_name.rb`
+- Name migrations descriptively: `add_email_to_users.rb`
+
+## Reversible Migrations
+
+- Use `change` method instead of `up/down` when possible:
+ ```ruby
+ class AddEmailToUsers < ActiveRecord::Migration[8.0]
+ def change
+ add_column :users, :email, :string
+ end
+ end
+ ```
+
+## Creating Migrations
+
+```bash
+rails generate migration AddFieldToTable field:type
+rails generate migration RemoveFieldFromTable field:type
+rails generate migration CreateTableName field1:type field2:type
+```
+
+## Common Migration Patterns
+
+### Add Column
+```ruby
+def change
+ add_column :users, :email, :string, null: false
+end
+```
+
+### Remove Column
+```ruby
+def change
+ remove_column :users, :email, :string
+end
+```
+
+### Add Index
+```ruby
+def change
+ add_index :users, :email, unique: true
+end
+```
+
+### Add Reference
+```ruby
+def change
+ add_reference :bookings, :facility, foreign_key: true
+end
+```
+
+### Add Foreign Key Constraint
+```ruby
+def change
+ add_foreign_key :bookings, :facilities
+end
+```
+
+### Create Table
+```ruby
+def change
+ create_table :facilities do |t|
+ t.string :name, null: false
+ t.text :address
+ t.timestamps
+ end
+end
+```
+
+## Best Practices
+
+- Keep migrations reversible
+- Use `change` method instead of `up/down`
+- Add indexes for foreign keys and frequently queried columns
+- Use `null: false` and foreign key constraints
+- Use appropriate data types
+- Include defaults when appropriate
+
+## Adding Indexes
+
+```ruby
+# Single column index
+add_index :users, :email
+
+# Composite index
+add_index :bookings, [:user_id, :facility_id]
+
+# Unique index
+add_index :users, :email, unique: true
+
+# Index with name
+add_index :users, :email, name: 'index_users_on_email_lower'
+```
+
+## Foreign Keys
+
+```ruby
+# Add reference with foreign key
+add_reference :bookings, :facility, foreign_key: true
+
+# Add foreign key constraint
+add_foreign_key :bookings, :facilities
+
+# Add foreign key with options
+add_foreign_key :bookings, :facilities, on_delete: :cascade
+```
+
+## When to Use Up/Down
+
+Use `up/down` when `change` doesn't support the operation:
+
+```ruby
+class ChangeUserEmailFormat < ActiveRecord::Migration[8.0]
+ def up
+ execute <<-SQL
+ UPDATE users SET email = LOWER(email)
+ SQL
+ end
+
+ def down
+ # Cannot automatically rollback
+ raise ActiveRecord::IrreversibleMigration
+ end
+end
+```
+
+## Important Notes
+
+- Always test migrations in development
+- Keep migrations small and focused
+- Use `rails db:migrate:status` to check status
+- Never modify existing migrations after deployment
+- Use `null: false` for required fields
+- Add indexes for performance
diff --git a/.opencode/skills/rails-models/SKILL.md b/.opencode/skills/rails-models/SKILL.md
new file mode 100644
index 00000000..c7adc076
--- /dev/null
+++ b/.opencode/skills/rails-models/SKILL.md
@@ -0,0 +1,85 @@
+---
+name: rails-models
+description: ActiveRecord model patterns, validations, scopes, and conventions for this Rails codebase
+---
+
+## Model Naming
+
+- Models use Singular PascalCase (e.g., `Facility`)
+- File names match class names: `facility.rb`
+- Located in `app/models/` directory
+
+## Validations
+
+- Use ActiveRecord validations for model-level validation:
+ ```ruby
+ validates :name, presence: true
+ validates :email, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
+ ```
+
+## Scopes
+
+- Use scopes for complex queries:
+ ```ruby
+ scope :active, -> { where(active: true) }
+ scope :recent, -> { order(created_at: :desc) }
+ ```
+
+## Enums
+
+- Use enum for fixed state fields:
+ ```ruby
+ enum status: { pending: 0, active: 1, archived: 2 }
+ ```
+
+## Callbacks
+
+- Use callbacks sparingly
+- Prefer explicit methods over callbacks
+- Keep callback logic simple and focused
+
+## Associations
+
+- Define standard ActiveRecord associations
+- Use proper foreign key conventions
+- Consider inverse_of for better performance
+
+## Model Methods
+
+- Define business logic as instance methods
+- Use class methods for collection operations
+- Keep methods small and focused
+
+## Testing Models
+
+- Test files located in `spec/models/`
+- Use `*_spec.rb` suffix (e.g., `facility_spec.rb`)
+- Test validations, scopes, and custom methods
+- Use factories for test data
+
+## Example Model
+
+```ruby
+class Facility < ApplicationRecord
+ has_many :bookings
+
+ validates :name, presence: true
+ validates :status, presence: true
+
+ scope :active, -> { where(active: true) }
+ scope :recent, -> { order(created_at: :desc) }
+
+ enum status: { pending: 0, active: 1, archived: 2 }
+
+ def active?
+ status == 'active'
+ end
+end
+```
+
+## Important Notes
+
+- Keep database logic in models
+- Avoid complex business logic in models (use services)
+- Use factories for test fixtures
+- Always run model tests after changes
diff --git a/.opencode/skills/rspec-testing/SKILL.md b/.opencode/skills/rspec-testing/SKILL.md
new file mode 100644
index 00000000..cc9af8e6
--- /dev/null
+++ b/.opencode/skills/rspec-testing/SKILL.md
@@ -0,0 +1,59 @@
+---
+name: rspec-testing
+description: RSpec testing patterns, conventions, and test commands for this Rails codebase
+---
+
+## Testing Commands
+
+```bash
+bin/rspec # Run all tests
+bin/rspec spec/models/facility_spec.rb # Run single test file
+bin/rspec spec/models/facility_spec.rb:42 # Run specific test by line
+bin/rspec spec/models/facility_spec.rb -e "validates name presence" # Run by description
+bin/rspec spec/models/ # All model specs
+bin/rspec spec/services/facility_serializer_spec.rb # Specific service spec
+```
+
+## Testing Patterns
+
+- Use RSpec's `describe` for context and `it` for examples
+- Prefer `expect(x).to eq(y)` over `expect(x) == y`
+- Use `let` for lazy evaluation, `let!` for immediate
+- Use `subject` for the main object being tested
+- Use shared contexts with `it_behaves_like` for repeated patterns
+
+## Testing Structure
+
+- Test files use `*_spec.rb` suffix (e.g., `facility_spec.rb`)
+- Test directory mirrors app structure:
+ - `spec/models/` - Model tests
+ - `spec/services/` - Service tests
+ - `spec/controllers/` - Controller tests
+- ViewComponent tests use `type: :component`
+- System specs use Capybara and Puma
+
+## Example Test Pattern
+
+```ruby
+RSpec.describe Facility do
+ subject(:facility) { create(:facility, :with_verified) }
+
+ describe "#managed_by?" do
+ it "returns true for admin users" do
+ expect(facility.managed_by?(admin_user)).to be true
+ end
+ end
+end
+```
+
+## Factory Usage
+
+- Use FactoryBot for test data
+- Define factories with `factory :name` (e.g., `factory :facility`)
+- Use traits with `:trait_name` syntax (e.g., `:with_verified`)
+
+## Important Notes
+
+- Always run tests before committing: `bin/rspec`
+- Use factory-bot gem for test fixtures
+- Test coverage should mirror application structure
diff --git a/.opencode/skills/service-objects/SKILL.md b/.opencode/skills/service-objects/SKILL.md
new file mode 100644
index 00000000..4c0a25fa
--- /dev/null
+++ b/.opencode/skills/service-objects/SKILL.md
@@ -0,0 +1,83 @@
+---
+name: service-objects
+description: Service object patterns, Result objects, and validation conventions for this Rails codebase
+---
+
+## Service Object Pattern
+
+All services inherit from `ApplicationService` and follow this structure:
+
+```ruby
+class MyService < ApplicationService
+ def initialize(arg1, arg2)
+ super()
+ @arg1 = arg1
+ @arg2 = arg2
+ end
+
+ def call
+ return Result.new(errors: ["validation error"]) unless valid?
+ Result.new(data: result_data)
+ end
+
+ private
+
+ def validate
+ add_error("Invalid input") if invalid_condition?
+ end
+end
+```
+
+## Usage Pattern
+
+```ruby
+# Call service directly
+result = MyService.call(arg1, arg2)
+
+# Check for errors
+if result.errors.any?
+ # Handle errors
+else
+ # Use result.data
+end
+```
+
+## Naming Convention
+
+- Services use "Action + Service" pattern (e.g., `FacilitySerializer`)
+- File names match class names: `facility_serializer.rb`
+- Located in `app/services/` directory
+
+## Result Pattern
+
+- Services return `Result` objects
+- `Result.new(errors: [...])` for validation failures
+- `Result.new(data: ...)` for successful operations
+- Check `result.errors.any?` to determine success/failure
+
+## Validation in Services
+
+- Use private `validate` methods for validation logic
+- Use `add_error(message)` to collect validation errors
+- Return early with error Result if validation fails
+- Keep validation logic separate from business logic
+
+## Error Handling
+
+- Use `raise` for programmer errors
+- Use `Result.new(errors: [...])` for service object validation failures
+- Handle exceptions with `begin/rescue` blocks when necessary
+- Log errors appropriately before re-raising if needed
+
+## Testing Services
+
+- Test files located in `spec/services/`
+- Use `*_service_spec.rb` suffix (e.g., `facility_serializer_spec.rb`)
+- Test both success and error paths
+- Verify Result objects structure
+
+## Important Notes
+
+- Keep services focused on single responsibilities
+- Avoid complex nested logic in services
+- Use services to keep controllers thin
diff --git a/.opencode/skills/viewcomponent/SKILL.md b/.opencode/skills/viewcomponent/SKILL.md
new file mode 100644
index 00000000..61246522
--- /dev/null
+++ b/.opencode/skills/viewcomponent/SKILL.md
@@ -0,0 +1,82 @@
+---
+name: viewcomponent
+description: ViewComponent patterns, naming conventions, and structure for this Rails codebase
+---
+
+## ViewComponent Pattern
+
+All components inherit from `ViewComponent::Base`:
+
+```ruby
+class Features::CardComponent < ViewComponent::Base
+ def initialize(feature:)
+ super()
+ @feature = feature
+ end
+
+ def private_method
+ # Helper methods
+ end
+end
+```
+
+## Naming Convention
+
+- Components use `Namespace::Name` pattern (e.g., `Facilities::CardComponent`)
+- File names match class names: `features/card_component.rb`
+- Located in `app/components/` directory (namespaced)
+
+## Component Structure
+
+- Always call `super()` in `initialize`
+- Use keyword arguments in `initialize` (e.g., `feature:`)
+- Store arguments in instance variables with `@` prefix
+- Define helper methods for complex logic in templates
+
+## Directory Structure
+
+```
+app/components/
+├── facilities/
+│ └── card_component.rb
+└── features/
+ └── card_component.rb
+```
+
+## Testing Components
+
+- Test files located in `spec/components/`
+- Use `type: :component` in RSpec specs
+- Test rendering output and state
+- Test helper methods individually
+
+## Usage in Views
+
+```ruby
+# Render component with arguments
+<%= render Features::CardComponent.new(feature: @feature) %>
+
+# Or with shorthand
+<%= render Features::CardComponent.new(@feature) %>
+```
+
+## Best Practices
+
+- Keep components small and focused
+- Use helper methods for complex logic in views
+- Avoid embedding business logic in components
+- Components should receive data, not fetch it
+- Use components to reduce partial duplication
+
+## Component Patterns
+
+- Card components for displaying items
+- List components for collections
+- Form components for reusable form fields
+- Button components for UI actions
+
+## Important Notes
+
+- ViewComponent is used for UI components in this codebase
+- Components are namespaced by domain (e.g., `Features::`, `Facilities::`)
+- Test components using `type: :component` in RSpec
diff --git a/.rubocop.yml b/.rubocop.yml
index 9488804e..b84bc1ff 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,8 +1,13 @@
-require:
+plugins:
- rubocop-packaging
- rubocop-performance
- - rubocop-ast
- rubocop-rails
+ - rubocop-rspec
+
+require:
+ - rubocop-ast
+
+
AllCops:
TargetRubyVersion: 3.1
@@ -29,7 +34,7 @@ Performance:
- '**/spec/**/*'
Rails:
- StyleGuideBaseURL: https://rails.rubystyle.guide
+ DocumentationBaseURL: https://rails.rubystyle.guide
Rails/BulkChangeTable:
Exclude:
@@ -59,6 +64,11 @@ Rails/FilePath:
Enabled: true
EnforcedStyle: arguments
+Rails/I18nLocaleTexts:
+ Enabled: false
+
+
+
# Prefer &&/|| over and/or.
Style/AndOr:
Enabled: true
@@ -89,10 +99,6 @@ Layout/EndAlignment:
Layout/EmptyLineAfterMagicComment:
Enabled: true
-Layout/EmptyLinesAroundAccessModifier:
- Enabled: false
- EnforcedStyle: only_before
-
Layout/EmptyLinesAroundBlockBody:
Enabled: true
@@ -129,6 +135,11 @@ Layout/IndentationConsistency:
Enabled: true
EnforcedStyle: normal #indented_internal_methods
+Layout/MultilineMethodCallIndentation:
+ EnforcedStyle: indented
+ Include:
+ - '**/spec/**/*'
+
# Two spaces, no tabs (for indentation).
Layout/IndentationWidth:
Enabled: true
@@ -323,6 +334,22 @@ Performance/DeletePrefix:
Performance/DeleteSuffix:
Enabled: true
+# Disable RSpec/MultipleExpectations cop to reduce noise (443 instances)
+# Note: Despite correct syntax, this configuration appears to not be properly
+# respected by rubocop-rspec 3.7.0. Use --except RSpec/MultipleExpectations
+# command-line flag to disable when needed.
+RSpec/MultipleExpectations:
+ Enabled: false
+
+RSpec/ExampleLength:
+ Enabled: false
+
+RSpec/MultipleMemoizedHelpers:
+ Enabled: false
+
+RSpec/NestedGroups:
+ Enabled: false
+
##########
# Metrics
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 00000000..97e245ee
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,15 @@
+# AGENTS.md - Linkvan API
+
+## Git Policy
+
+**CRITICAL: Agents must never modify git history.**
+
+- Prohibited: `git add`, `git commit`, `git rebase`, `git push`, etc.
+- If git operations are needed, ask the user to perform them.
+
+## Conventions
+
+- Active development branch: `develop`
+- Admin interface: `/admin/dashboard`
+- ViewComponent tests: `type: :component`
+- System specs: Capybara + Puma
diff --git a/Gemfile b/Gemfile
index b2d45f16..6998400d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -4,7 +4,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "3.4.5"
# Bundle edge Rails instead: gem "rails", github: "rails/rails"
-gem "rails", "~> 8.0.3"
+gem "rails", "~> 8.1.0"
# Use postgresql as the database for Active Record
gem "pg", "~> 1.6.2"
# Use Puma as the app server
@@ -48,13 +48,16 @@ gem 'rack-cors'
group :development, :test do
gem 'dotenv-rails'
- gem "rspec-rails", "~> 7.1.1"
+ gem "rspec-rails", "~> 8.0"
gem "shoulda-matchers", ">= 6.2.0"
gem "capybara"
+ gem "rails-controller-testing"
- gem "factory_bot_rails", "~> 6.4.3"
-
- # Call "byebug" anywhere in the code to stop execution and get a debugger console
+ gem "factory_bot_rails", "~> 6.4.3"
+
+ gem 'simplecov', require: false
+
+ # Call "byebug" anywhere in the code to stop execution and get a debugger console
gem "byebug", platforms: [:mri, :windows]
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 6befeed4..f7e6329c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -7,29 +7,31 @@ GIT
GEM
remote: https://rubygems.org/
specs:
- actioncable (8.0.3)
- actionpack (= 8.0.3)
- activesupport (= 8.0.3)
+ action_text-trix (2.1.17)
+ railties
+ actioncable (8.1.2)
+ actionpack (= 8.1.2)
+ activesupport (= 8.1.2)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
- actionmailbox (8.0.3)
- actionpack (= 8.0.3)
- activejob (= 8.0.3)
- activerecord (= 8.0.3)
- activestorage (= 8.0.3)
- activesupport (= 8.0.3)
+ actionmailbox (8.1.2)
+ actionpack (= 8.1.2)
+ activejob (= 8.1.2)
+ activerecord (= 8.1.2)
+ activestorage (= 8.1.2)
+ activesupport (= 8.1.2)
mail (>= 2.8.0)
- actionmailer (8.0.3)
- actionpack (= 8.0.3)
- actionview (= 8.0.3)
- activejob (= 8.0.3)
- activesupport (= 8.0.3)
+ actionmailer (8.1.2)
+ actionpack (= 8.1.2)
+ actionview (= 8.1.2)
+ activejob (= 8.1.2)
+ activesupport (= 8.1.2)
mail (>= 2.8.0)
rails-dom-testing (~> 2.2)
- actionpack (8.0.3)
- actionview (= 8.0.3)
- activesupport (= 8.0.3)
+ actionpack (8.1.2)
+ actionview (= 8.1.2)
+ activesupport (= 8.1.2)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
@@ -37,42 +39,43 @@ GEM
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
useragent (~> 0.16)
- actiontext (8.0.3)
- actionpack (= 8.0.3)
- activerecord (= 8.0.3)
- activestorage (= 8.0.3)
- activesupport (= 8.0.3)
+ actiontext (8.1.2)
+ action_text-trix (~> 2.1.15)
+ actionpack (= 8.1.2)
+ activerecord (= 8.1.2)
+ activestorage (= 8.1.2)
+ activesupport (= 8.1.2)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
- actionview (8.0.3)
- activesupport (= 8.0.3)
+ actionview (8.1.2)
+ activesupport (= 8.1.2)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
- activejob (8.0.3)
- activesupport (= 8.0.3)
+ activejob (8.1.2)
+ activesupport (= 8.1.2)
globalid (>= 0.3.6)
- activemodel (8.0.3)
- activesupport (= 8.0.3)
- activerecord (8.0.3)
- activemodel (= 8.0.3)
- activesupport (= 8.0.3)
+ activemodel (8.1.2)
+ activesupport (= 8.1.2)
+ activerecord (8.1.2)
+ activemodel (= 8.1.2)
+ activesupport (= 8.1.2)
timeout (>= 0.4.0)
- activestorage (8.0.3)
- actionpack (= 8.0.3)
- activejob (= 8.0.3)
- activerecord (= 8.0.3)
- activesupport (= 8.0.3)
+ activestorage (8.1.2)
+ actionpack (= 8.1.2)
+ activejob (= 8.1.2)
+ activerecord (= 8.1.2)
+ activesupport (= 8.1.2)
marcel (~> 1.0)
- activesupport (8.0.3)
+ activesupport (8.1.2)
base64
- benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
+ json
logger (>= 1.4.2)
minitest (>= 5.1)
securerandom (>= 0.3)
@@ -83,12 +86,11 @@ GEM
ast (2.4.3)
base64 (0.3.0)
bcrypt (3.1.20)
- benchmark (0.4.1)
better_errors (2.10.1)
erubi (>= 1.0.0)
rack (>= 0.9.0)
rouge (>= 1.0.0)
- bigdecimal (3.2.3)
+ bigdecimal (4.0.1)
bindex (0.8.1)
binding_of_caller (1.0.1)
debug_inspector (>= 1.2.0)
@@ -109,14 +111,14 @@ GEM
xpath (~> 3.2)
coderay (1.1.3)
colorize (1.1.0)
- concurrent-ruby (1.3.5)
- connection_pool (2.5.4)
+ concurrent-ruby (1.3.6)
+ connection_pool (3.0.2)
crass (1.0.6)
csv (3.3.5)
dartsass-rails (0.5.1)
railties (>= 6.0.0)
sass-embedded (~> 1.63)
- date (3.4.1)
+ date (3.5.1)
debug_inspector (1.2.0)
devise (4.9.4)
bcrypt (~> 3.0)
@@ -125,12 +127,13 @@ GEM
responders
warden (~> 1.2.3)
diff-lcs (1.6.2)
+ docile (1.4.1)
dotenv (3.1.8)
dotenv-rails (3.1.8)
dotenv (= 3.1.8)
railties (>= 6.1)
drb (2.2.3)
- erb (5.0.2)
+ erb (6.0.2)
erubi (1.13.1)
factory_bot (6.5.5)
activesupport (>= 6.1.0)
@@ -184,7 +187,7 @@ GEM
rails (>= 6.0.0)
stimulus-rails
turbo-rails
- i18n (1.14.7)
+ i18n (1.14.8)
concurrent-ruby (~> 1.0)
importmap-rails (2.2.2)
actionpack (>= 6.0.0)
@@ -193,9 +196,10 @@ GEM
inline_svg (1.10.0)
activesupport (>= 3.0)
nokogiri (>= 1.6)
- io-console (0.8.1)
- irb (1.15.2)
+ io-console (0.8.2)
+ irb (1.17.0)
pp (>= 0.6.0)
+ prism (>= 1.3.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
json (2.15.0)
@@ -207,10 +211,11 @@ GEM
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.7.0)
- loofah (2.24.1)
+ loofah (2.25.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
- mail (2.8.1)
+ mail (2.9.0)
+ logger
mini_mime (>= 0.1.1)
net-imap
net-pop
@@ -220,11 +225,13 @@ GEM
memory_profiler (1.1.0)
method_source (1.1.0)
mini_mime (1.1.5)
- minitest (5.25.5)
+ minitest (6.0.2)
+ drb (~> 2.0)
+ prism (~> 1.5)
msgpack (1.8.0)
net-http (0.6.0)
uri
- net-imap (0.5.11)
+ net-imap (0.6.3)
date
net-protocol
net-pop (0.1.2)
@@ -233,22 +240,22 @@ GEM
timeout
net-smtp (0.5.1)
net-protocol
- nio4r (2.7.4)
- nokogiri (1.18.10-aarch64-linux-gnu)
+ nio4r (2.7.5)
+ nokogiri (1.19.1-aarch64-linux-gnu)
racc (~> 1.4)
- nokogiri (1.18.10-aarch64-linux-musl)
+ nokogiri (1.19.1-aarch64-linux-musl)
racc (~> 1.4)
- nokogiri (1.18.10-arm-linux-gnu)
+ nokogiri (1.19.1-arm-linux-gnu)
racc (~> 1.4)
- nokogiri (1.18.10-arm-linux-musl)
+ nokogiri (1.19.1-arm-linux-musl)
racc (~> 1.4)
- nokogiri (1.18.10-arm64-darwin)
+ nokogiri (1.19.1-arm64-darwin)
racc (~> 1.4)
- nokogiri (1.18.10-x86_64-darwin)
+ nokogiri (1.19.1-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.18.10-x86_64-linux-gnu)
+ nokogiri (1.19.1-x86_64-linux-gnu)
racc (~> 1.4)
- nokogiri (1.18.10-x86_64-linux-musl)
+ nokogiri (1.19.1-x86_64-linux-musl)
racc (~> 1.4)
orm_adapter (0.5.0)
ostruct (0.6.3)
@@ -264,7 +271,7 @@ GEM
pg (1.6.2-x86_64-darwin)
pg (1.6.2-x86_64-linux)
pg (1.6.2-x86_64-linux-musl)
- pp (0.6.2)
+ pp (0.6.3)
prettyprint
prettyprint (0.2.0)
prism (1.5.1)
@@ -286,14 +293,14 @@ GEM
pry-stack_explorer (0.6.1)
binding_of_caller (~> 1.0)
pry (~> 0.13)
- psych (5.2.6)
+ psych (5.3.1)
date
stringio
public_suffix (6.0.2)
puma (6.4.3)
nio4r (~> 2.0)
racc (1.8.1)
- rack (3.2.3)
+ rack (3.2.5)
rack-cors (3.0.0)
logger
rack (>= 3.0.14)
@@ -304,32 +311,36 @@ GEM
rack (>= 3.0.0)
rack-test (2.2.0)
rack (>= 1.3)
- rackup (2.2.1)
+ rackup (2.3.1)
rack (>= 3)
- rails (8.0.3)
- actioncable (= 8.0.3)
- actionmailbox (= 8.0.3)
- actionmailer (= 8.0.3)
- actionpack (= 8.0.3)
- actiontext (= 8.0.3)
- actionview (= 8.0.3)
- activejob (= 8.0.3)
- activemodel (= 8.0.3)
- activerecord (= 8.0.3)
- activestorage (= 8.0.3)
- activesupport (= 8.0.3)
+ rails (8.1.2)
+ actioncable (= 8.1.2)
+ actionmailbox (= 8.1.2)
+ actionmailer (= 8.1.2)
+ actionpack (= 8.1.2)
+ actiontext (= 8.1.2)
+ actionview (= 8.1.2)
+ activejob (= 8.1.2)
+ activemodel (= 8.1.2)
+ activerecord (= 8.1.2)
+ activestorage (= 8.1.2)
+ activesupport (= 8.1.2)
bundler (>= 1.15.0)
- railties (= 8.0.3)
+ railties (= 8.1.2)
+ rails-controller-testing (1.0.5)
+ actionpack (>= 5.0.1.rc1)
+ actionview (>= 5.0.1.rc1)
+ activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.3.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
- rails-html-sanitizer (1.6.2)
- loofah (~> 2.21)
+ rails-html-sanitizer (1.7.0)
+ loofah (~> 2.25)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
- railties (8.0.3)
- actionpack (= 8.0.3)
- activesupport (= 8.0.3)
+ railties (8.1.2)
+ actionpack (= 8.1.2)
+ activesupport (= 8.1.2)
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
@@ -337,11 +348,11 @@ GEM
tsort (>= 0.2)
zeitwerk (~> 2.6)
rainbow (3.1.1)
- rake (13.3.0)
+ rake (13.3.1)
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
- rdoc (6.15.0)
+ rdoc (7.2.0)
erb
psych (>= 4.0.0)
tsort
@@ -350,7 +361,7 @@ GEM
redis-client (0.26.1)
connection_pool
regexp_parser (2.11.3)
- reline (0.6.2)
+ reline (0.6.3)
io-console (~> 0.5)
requestjs-rails (0.0.13)
railties (>= 7.1.0)
@@ -366,10 +377,10 @@ GEM
rspec-mocks (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
- rspec-rails (7.1.1)
- actionpack (>= 7.0)
- activesupport (>= 7.0)
- railties (>= 7.0)
+ rspec-rails (8.0.2)
+ actionpack (>= 7.2)
+ activesupport (>= 7.2)
+ railties (>= 7.2)
rspec-core (~> 3.13)
rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13)
@@ -425,13 +436,19 @@ GEM
securerandom (0.4.1)
shoulda-matchers (6.5.0)
activesupport (>= 5.2.0)
+ simplecov (0.22.0)
+ docile (~> 1.1)
+ simplecov-html (~> 0.11)
+ simplecov_json_formatter (~> 0.1)
+ simplecov-html (0.13.2)
+ simplecov_json_formatter (0.1.4)
slop (3.6.0)
stackprof (0.2.27)
stimulus-rails (1.3.4)
railties (>= 6.0.0)
- stringio (3.1.7)
- thor (1.4.0)
- timeout (0.4.3)
+ stringio (3.2.0)
+ thor (1.5.0)
+ timeout (0.6.1)
tsort (0.2.0)
turbo-rails (2.0.17)
actionpack (>= 7.1.0)
@@ -443,10 +460,11 @@ GEM
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.1.0)
- uri (1.0.3)
+ uri (1.1.1)
useragent (0.16.11)
- view_component (4.0.2)
- activesupport (>= 7.1.0, < 8.1)
+ view_component (4.5.0)
+ actionview (>= 7.1.0)
+ activesupport (>= 7.1.0)
concurrent-ruby (~> 1)
warden (1.2.9)
rack (>= 2.0.9)
@@ -461,7 +479,7 @@ GEM
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
- zeitwerk (2.7.3)
+ zeitwerk (2.7.5)
PLATFORMS
aarch64-linux-gnu
@@ -510,16 +528,18 @@ DEPENDENCIES
puma (~> 6.4.2)
rack-cors
rack-mini-profiler (~> 3.3.1)
- rails (~> 8.0.3)
+ rails (~> 8.1.0)
+ rails-controller-testing
redis (~> 5.4.1)
requestjs-rails
- rspec-rails (~> 7.1.1)
+ rspec-rails (~> 8.0)
rubocop (>= 1.81.1)
rubocop-packaging
rubocop-performance
rubocop-rails
rubocop-rspec
shoulda-matchers (>= 6.2.0)
+ simplecov
stackprof
turbo-rails
tzinfo-data
diff --git a/app/components/alerts/table_component.rb b/app/components/alerts/table_component.rb
index 1d81c169..a7780ea0 100644
--- a/app/components/alerts/table_component.rb
+++ b/app/components/alerts/table_component.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Alerts::TableComponent < ViewComponent::Base
attr_reader :alerts
diff --git a/app/components/facilities/card_component.html.erb b/app/components/facilities/card_component.html.erb
index 47e08d30..c88489e9 100644
--- a/app/components/facilities/card_component.html.erb
+++ b/app/components/facilities/card_component.html.erb
@@ -1,4 +1,4 @@
-