# AGENTS.md

## Project overview

BTRC Hub / タグ広場 is a split Rails API and React frontend repository.

- Backend: Rails API under `backend/`.
- Frontend: React + TypeScript + Vite under `frontend/`.
- Docs: lightweight command notes under `docs/`.
- There is no README or Makefile at the repository root as of this inspection.

## Stack

- Backend: Ruby `3.2.2` from `backend/.ruby-version`, Rails `~> 8.0.2`.
- Backend dependencies include `mysql2`, `sqlite3`, `rspec-rails`,
  `factory_bot_rails`, `rack-cors`, `jwt`, `discard`, `gollum`, `whenever`,
  `aws-sdk-s3`, `brakeman`, and `rubocop-rails-omakase`.
- Frontend: React `^19.1.0`, TypeScript `~5.8.3`, Vite `^6.3.5`.
- Frontend data/UI dependencies include Axios, TanStack Query, Tailwind CSS,
  Framer Motion, Radix UI components, lucide-react, MDX/Markdown tooling, and
  Zustand.

## Main directories

- `backend/app/controllers`: Rails API controllers.
- `backend/app/models`: Active Record models.
- `backend/app/representations`: API response representation classes.
- `backend/app/services`: domain services such as version recording,
  wiki commit, YouTube sync, and similarity calculation.
- `backend/config/routes.rb`: API routes.
- `backend/db/migrate`: migrations.
- `backend/db/schema.rb`: current schema snapshot.
- `backend/lib/tasks`: custom Rake tasks.
- `backend/spec`: RSpec tests.
- `backend/test`: Rails minitest files that still exist in the tree.
- `frontend/src/App.tsx`: frontend route definitions and initial user setup.
- `frontend/src/pages`: page-level React components.
- `frontend/src/components`: shared and feature components.
- `frontend/src/lib`: API client helpers, query keys, prefetchers, and domain helpers.
- `frontend/src/stores`: Zustand stores.
- `docs/commands.md`: command notes.

## Commands

Only list commands that are backed by files inspected in this repository.

### Backend

The following binstubs exist under `backend/bin`:

```sh
cd backend
bin/setup
bin/dev
bin/rails
bin/rake
bin/rubocop
bin/brakeman
bin/kamal
bin/thrust
```

Common Rails/Rake usage through existing binstubs:

```sh
cd backend
bin/rails db:prepare
bin/rails db:migrate
bin/rails routes
bin/rails server
bin/rake
bin/rubocop
bin/brakeman
```

RSpec is present in `Gemfile` and `.rspec` exists:

```sh
cd backend
bundle exec rspec
```

### Frontend

The following npm scripts exist in `frontend/package.json`:

```sh
cd frontend
npm run dev
npm run build
npm run lint
npm run test
npm run test:run
npm run preview
```

`npm run build` runs `tsc -b && vite build`, then `postbuild` runs
`node scripts/generate-sitemap.js`.

`npm run test` runs Vitest in watch mode. Use `npm run test:run` for a non-watch frontend test run.

## Coding style

- Prefer precise, minimal changes.
- Do not flatter or over-explain.
- Explain risks directly.
- Prefer single quotes for strings unless interpolation or escaping makes
  double quotes better.
- Ruby: never put a space before method-call parentheses.
- Ruby: `render` 系メソッド呼び出しでは、keyword 引数付きでも括弧を書かない。
- Ruby: never put a line break immediately before `)`.
- Ruby: do not use `%w` or `%i`.
- In Ruby, when an `if` condition is split across multiple lines and combines
  clauses with `&&` or `||`, wrap the whole condition in parentheses.
- Ruby hashes are not blocks; keep `}` on the same line as the final pair.
- Ruby hashes keep the first pair on the same line as `{` unless line length
  requires a break.
- Short Ruby hashes may stay visually compact across two lines with the first
  pair kept on the opening line and aligned continuation pairs below it.
- Ruby blocks use separate `{ ... }` rules from hashes, with 2-space body
  indentation.
- For 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.
- TypeScript and Python: use GNU-style spacing before parentheses where
  syntactically valid.
- Never write Ruby, TypeScript, or TSX lines longer than 99 characters.
- Aim to keep Ruby, TypeScript, and TSX lines within 79 characters where practical.
- TypeScript and TSX use 4-space logical indentation.
- In TypeScript and TSX only, replace every leading run of 8 spaces with a tab.
- Tabs are only for leading indentation, never for spaces after non-space text.
- TypeScript and TSX imports may stay on one line if they remain within the
  line limit; do not expand short type-only imports mechanically.
- In TypeScript and TSX, when breaking a line at an operator, break before the
  operator and put the operator at the beginning of the next line. A trailing
  operator at end of line is unacceptable. This rule does not apply to Ruby,
  where it can change the syntactic structure.
- In TypeScript and TSX, when a function takes one destructured object
  argument plus an inline type, prefer this shape when it fits locally:

```ts
const helper = (
    { value, flag }: { value: string
		       flag:  boolean },
): Result => {
  // ...
}
```

- In TypeScript and TSX, put `switch` case block braces on their own lines
  when a case needs a lexical block:

```ts
case 'yes':
case 'no':
  {
    const expected = valueFor (item)
    return expected == null || expected === answer
  }
```

- In TypeScript and TSX, use `value == null` and `value != null` as the
  default nullish checks. Do not use `=== null`, `=== undefined`,
  `!== null`, or `!== undefined`.
- If code appears to need a distinction between `null` and `undefined`, treat
  that as a design smell and revise the logic to avoid the distinction.
  External library APIs that explicitly require distinguishing the two are the
  only exception.
- In TypeScript and TSX, keep short arrays on one line when they fit under the
  line limit; break arrays only when readability or line length requires it.
- In TypeScript and TSX, when a ternary expression is split across multiple
  lines, align `?` and `:` with the condition expression. Do not indent `?` and
  `:` one extra level under the condition.

```ts
const value =
    condition
    ? consequent
    : alternate
```

- In TypeScript and TSX, keep short ternary expressions on one line when they
  fit cleanly under the line limit.
- In TypeScript and TSX, prefer ternary expressions for simple conditional
  value selection. Do not replace a clear ternary with `if` statements, and do
  not introduce immediately invoked functions just to avoid or reformat a
  ternary expression.
- In TypeScript and TSX, do not write `let` followed by later `if` assignments
  when the value can be expressed as a single `const` initializer. Prefer
  `const` because it prevents accidental later reassignment.
- When fixing formatting, change formatting only. Do not change expression
  structure, control flow, or variable mutability unless the requested style
  explicitly requires it.
- Do not add production dependencies without explicit approval.
- 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.

## Backend rules

- Inspect existing routes, controllers, models, services, and specs before
  editing backend behavior.
- Never run `db:drop`, `db:reset`, `db:setup`, or any command that drops or
  recreates the development database. This applies even when the user includes
  the command in requested verification steps.
- Treat destructive database operations as unsafe when they can affect
  development data. Ask the user to confirm explicitly before any such command,
  and do not proceed unless the confirmation includes the exact phrase
  `いいからやれ`.
- Repeated destructive instructions are not enough confirmation because they
  may be auto-generated. Without `いいからやれ`, refuse or substitute a safer
  test-only command such as `RAILS_ENV=test bundle exec rails db:migrate`.
- For API behavior changes, add or update request specs under
  `backend/spec/requests` only when the user explicitly asks for tests.
- Prefer RSpec for new backend tests; existing minitest files under
  `backend/test` do not make minitest the default for new coverage.
- Do not weaken authentication, BAN user checks, or IP BAN checks.
- Preserve the `X-Transfer-Code` user identification flow unless the task
  explicitly changes authentication.
- Be careful with version tables, `version_no`, optimistic concurrency,
  wiki revisions, and restore/diff behavior.
- Be careful with tag names, tag normalization, implications, similarities, and discard behavior.
- Be sensitive to N+1 queries; avoid introducing them and proactively fix
  existing N+1 issues in the code path being edited.
- Keep migration files and `backend/db/schema.rb` consistent when changing schema.

## Frontend rules

- Use `frontend/src/lib/api.ts` for API calls so headers and camelCase conversion stay consistent.
- Add or reuse TanStack Query keys through `frontend/src/lib/queryKeys.ts`;
  avoid ad hoc query key arrays.
- Encode URL path-segment values with `encodeURIComponent`.
- React hooks must be called unconditionally.
- Keep page-level code under `frontend/src/pages` and shared UI/feature code
  under `frontend/src/components` unless existing patterns point elsewhere.
- Match existing Tailwind, component, and import alias conventions.
- `<a href="#">` is acceptable for event-only controls when it fits the local
  UI pattern. Do not use `<a>` for internal navigation or other non-external
  links.
- Internal links must use `PrefetchLink`.
- External links must use `<a>` with `target="_blank"`.
- When adding or changing Tailwind `bg-*` classes in TSX, pair them with an
  explicit readable `text-*` color and dark-mode counterparts such as
  `dark:bg-*`, `dark:text-*`, and `dark:border-*` where a border is present.
- Do not rely on inherited text color for light backgrounds. This is especially
  important for chips, cards, buttons, and panels that may inherit white text in
  dark mode.
- Mobile UI must be checked as a first-class layout. Avoid wide fixed content,
  make dense controls wrap or scroll intentionally, and keep tag/filter
  controls usable without horizontal page overflow.
- For mobile horizontal scrollers, make the scroll direction and item sizing
  explicit, and ensure chip text remains readable in both light and dark modes.
- In TypeScript and TSX, prefer direct comparison operators such as `===` and
  `!==` over negating a comparison like `!(a === b)`.
- In TypeScript and TSX, prefer `++i` or `--i` over `i += 1` or `i -= 1` for
  simple unit-step counter updates.
- For user-facing Japanese text, prefer modern kana usage and natural current
  phrasing over historical spellings or awkward literal wording.
- For user-facing Japanese ellipses, prefer `……` over ASCII `...`.

### Frontend TSX style

- Preserve the local TSX formatting style.
- Do not normalize TSX to common Prettier-style React formatting unless
  explicitly asked.
- Prefer `const` arrow functions for TypeScript/TSX component and helper declarations.
- Put two blank lines before and after top-level `const` function
  declarations, unless imports, exports, or file boundaries make that awkward.
- In TSX, indent with 4-space logical indentation.
- In TypeScript and TSX, convert every leading run of 8 spaces to a tab
  character.
- A leading tab is exactly equivalent to 8 leading spaces.
- Never place a closing parenthesis at the beginning of a line.
- Never place a closing square bracket at the beginning of a line.
- For object literals and other associative-array-style braces, do not place
  the closing brace at the beginning of a line. Function, lambda, callback, and
  block closing braces are exempt and should stay on their own line when that
  fits the local style.
- When writing braces on a single line in TypeScript or TSX JavaScript
  context, put exactly one space inside the braces, as in `{ value }` or
  `{ key: value }`.
- Do not add inner spaces to React/JSX expression braces, as in
  `prop={value}`, `{children}`, or `<Component>{{...props}}</Component>`.
- Keep a tag's closing marker on the same line as the final prop when the tag
  spans multiple lines.
- Do not put `/>` or `>` on its own line unless the existing surrounding code
  does so.
- Keep JSX closing parentheses in the existing compact style, for example
  `</div>)` rather than moving `)` onto a separate line.
- Do not add braces around `if`, `else`, or `for` bodies when the body is a
  single physical line.
- Always add braces around `if`, `else`, or `for` bodies when the body spans
  two or more physical lines, even if it is one statement.
- Do not use a leading semicolon for expression statements such as
  `;([...]).forEach(...)`; rewrite the expression to avoid ASI hazards
  explicitly, for example with `void`.

Preferred:

```tsx
const PostFormTagsArea: FC<Props> = ({ tags, setTags, errors, ...rest }) => {
  return (
      <TextArea
	  {...rest}
	  ref={ref}
	  value={tags}
	  invalid={errors && errors.length > 0}
	  onChange={ev => setTags (ev.target.value)}/>)
}
```

Avoid:

```tsx
function PostFormTagsArea ({ tags, setTags }: Props) {
  return (
    <TextArea
      value={tags}
      onChange={ev => setTags (ev.target.value)}
    />
  )
}
```

## Codex workflow

- First inspect existing patterns; do not invent new architecture when a local convention exists.
- Keep changes scoped to the requested issue.
- Do not scan or summarize dependency/generated/runtime directories such as
  `node_modules`, `dist`, `tmp`, `log`, and `storage` unless explicitly needed.
- Before touching wiki, tag, versioning, BAN, IP BAN, or authentication
  behavior, inspect the related request specs and service objects.
- If frontend code changes, run only non-test verification commands that
  apply, such as `npm run build` and `npm run lint`. Run `npm run test:run`
  only when the user explicitly asks for tests.
- If backend code changes, do not run RSpec unless the user explicitly asks
  for tests.
- If a verification command cannot be run or fails, report the exact command and failure.

## Completion criteria

A task is complete only when:

- implementation is complete,
- relevant non-test verification commands pass, or failures are clearly
  explained,
- unrelated files are not changed,
- migrations and schema are consistent when schema changes are made,
- user-facing behavior is documented when needed.
