37ade2a988
Reviewed-on: #362 Co-authored-by: miteruzo <miteruzo@naver.com> Co-committed-by: miteruzo <miteruzo@naver.com>
220 行
8.4 KiB
Markdown
220 行
8.4 KiB
Markdown
# 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.
|
|
|
|
Do not create, modify, or run tests unless the user explicitly asks for test
|
|
work. When the user asks for tests, keep working and rerun them until they
|
|
pass or the remaining failure is clearly blocked.
|
|
|
|
## 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 arrays, never put whitespace or a line break immediately before `]`.
|
|
- Keep the first element on the same line as `[` by default.
|
|
- If an array would exceed the line limit, break after `[` and indent
|
|
elements by 4 spaces.
|
|
- 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 only when
|
|
the user explicitly asks for tests.
|
|
|
|
## 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 only when the user
|
|
explicitly asks for tests, 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. Cover conflicts in request specs only when the user
|
|
explicitly asks for tests.
|
|
|
|
## 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.
|