ファイル
btrc-hub/backend/AGENTS.md
T
2026-06-07 00:14:36 +09:00

7.9 KiB

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:

bin/setup
bin/dev
bin/rails
bin/rake
bin/rubocop
bin/brakeman
bundle exec rspec

Common checks:

bundle exec rspec
bin/rubocop
bin/brakeman

Common Rails commands:

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:

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.
  • Never put a line break immediately before ) in Ruby.
  • Do not use %w or %i in new Ruby code.
  • Never write a Ruby line longer than 99 characters.
  • Aim to keep Ruby lines within 79 characters where practical.
  • For small Ruby method definitions that take keyword arguments, match the local no-parentheses style when nearby code uses it.
  • Treat Ruby hash { ... } style and Ruby block { ... } style as separate rules.
  • Do not format Ruby hashes like Ruby blocks.
  • For Ruby hashes, keep the closing } on the same line as the final pair.
  • Keep the first pair on the same line as { by default.
  • If the hash would exceed the line limit, break after { and indent pairs by 4 spaces.
  • Put one logical pair per line when the expression would otherwise become dense.
  • For Ruby blocks, use 2-space indentation for the block body.
  • 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.
  • For diagnostic or internal helper JSON, prefer a deliberately light response shape over full representation classes when callers only need identifiers, labels, URLs, or weights.

Active Record performance

  • When a controller action serializes nested associations, preload the associations it will touch instead of allowing N+1 queries.
  • Be sensitive to N+1 queries in all backend work.
  • Avoid introducing N+1 queries, and proactively fix existing N+1 issues when you find them in the code path you are editing.
  • When an association may already be preloaded, prefer loaded-association checks that reuse the preloaded data without losing the efficient database path.

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.