# backend/AGENTS.md ## Scope These rules apply to work under `backend/`. This is a Rails API app using Active Record, RSpec, request specs, service objects, representation classes, and version tables for post/tag/wiki history. ## Commands Use commands backed by files and dependencies in this directory: ```sh bin/setup bin/dev bin/rails bin/rake bin/rubocop bin/brakeman bundle exec rspec ``` Common checks: ```sh bundle exec rspec bin/rubocop bin/brakeman ``` Common Rails commands: ```sh bin/rails db:prepare bin/rails db:migrate bin/rails routes bin/rails server ``` After backend behavior changes, run the relevant RSpec files. For broad backend changes, run: ```sh bundle exec rspec ``` If a command cannot be run or fails, report the exact command and failure. ## Rails structure - `app/controllers`: API controllers. - `app/models`: Active Record models and concerns. - `app/representations`: JSON response shaping. - `app/services`: domain services such as version recorders, wiki commit, YouTube sync, and similarity calculation. - `config/routes.rb`: public API routes. - `db/migrate`: migrations. - `db/schema.rb`: schema snapshot. - `lib/tasks`: custom Rake tasks. - `spec`: RSpec tests. Before changing behavior, inspect the matching route, controller, model, service, representation, and spec. ## Ruby style - Prefer precise, minimal changes. - Use single quotes unless interpolation or escaping makes double quotes better. - Do not put a space before Ruby method-call parentheses. - Do not use `%w` or `%i` in new Ruby code. - Keep comments short and useful; avoid narrating obvious code. - Do not add production dependencies without approval. ## Authentication and authorization - Authentication is handled through the `X-Transfer-Code` header in `ApplicationController#authenticate_user`. - `current_user` is set by looking up `User.inheritance_code`. - Do not bypass or weaken the `X-Transfer-Code` flow unless the task explicitly changes authentication. - Unauthenticated write actions should return `:unauthorized` consistently with existing controllers. - Role checks use `User` enum roles: `guest`, `member`, and `admin`. - Use `current_user.gte_member?` for member-or-admin write permissions where existing controllers do so. - Use `current_user.admin?` only for admin-only paths, such as tag child relationship changes. - Do not replace role checks with looser presence checks. ## BAN and IP BAN - `ApplicationController` runs these before actions in order: - `reject_banned_ip_address!` - `authenticate_user` - `reject_banned_user!` - User and IP bans use `banned_at`, not a boolean `banned` column. - `User#banned?` and `IpAddress#banned?` check `banned_at.present?`. - Do not weaken BAN or IP BAN behavior. - If changing request authentication or controller before actions, add or update request specs covering banned users and banned IP addresses. ## RSpec - Prefer RSpec for new backend tests. - Put API behavior coverage under `spec/requests`. - Put model behavior under `spec/models`. - Put service behavior under `spec/services`. - Put Rake task coverage under `spec/tasks`. - `spec/rails_helper.rb` loads `spec/support/**/*.rb`. - Request specs include `AuthHelper` and `JsonHelper`. - `AuthHelper#sign_in_as(user)` stubs `ApplicationController#current_user`; use it when matching existing request spec style. - Add or update request specs for API behavior changes, especially status codes, permissions, response shape, and version conflict behavior. ## Migrations - Keep migrations and `db/schema.rb` consistent. - Use reversible migrations where practical; otherwise define explicit `up` and `down`. - For data backfills inside migrations, follow the existing pattern of defining migration-local `ActiveRecord::Base` classes with `self.table_name`. - Preserve existing indexes, foreign keys, check constraints, and null constraints. - Be careful with MySQL-specific options already present in migrations, such as `after:`. - Do not edit old migrations just to change current behavior unless explicitly requested; add a new migration. ## Version tables - Versioned records include posts, tags, nico tags, and wiki pages. - Current records have `version_no`; version tables have positive `version_no` with unique indexes scoped to the parent record. - Version event types are `create`, `update`, `discard`, and `restore`. - Version rows are readonly through the `VersionRecord` concern. - Use the existing recorder services instead of manually inserting version rows in application code: - `PostVersionRecorder` - `TagVersionRecorder` - `NicoTagVersionRecorder` - `WikiVersionRecorder` - `TagVersioning` - `VersionRecorder` locks the current record, validates sequence consistency, skips unchanged update snapshots, creates the next version row, and updates the record `version_no`. - Do not update versioned records without considering whether a version snapshot must be created. - For optimistic concurrency paths, preserve `base_version_no`, `force`, and `merge` semantics and cover conflicts in request specs. ## Domain cautions - Posts have tag snapshots, parent post implications, original-created ranges, viewed state, and version conflict behavior. - Tags have canonical names, aliases through `TagName`, categories, parent implications, discard behavior, and version snapshots. - Nico tags have separate relation/version behavior; do not treat them like normal editable tags without checking existing code. - Wiki pages involve page content, revisions/history, version rows, title/tag-name behavior, and diff/restore paths. - Materials, theatres, and comments have user and permission checks; inspect the controller before changing them. ## API responses - Use representation classes under `app/representations` when existing endpoints do. - Keep response keys consistent with existing JSON contracts; frontend code expects camelCase conversion client-side, while Rails params and JSON keys are generally snake_case. - Preserve existing HTTP status conventions: `:unauthorized` for no user, `:forbidden` for insufficient role or banned user, `:not_found` for missing records, and `:unprocessable_entity` for validation failures. ## Files to avoid in routine work - Do not inspect or edit `tmp/`, `log/`, `storage/`, `vendor/`, or dependency directories unless explicitly needed. - Do not modify generated schema or migration output without the corresponding migration when schema changes are made.