From d3f2b009bc325413d065410c72282142739b802f Mon Sep 17 00:00:00 2001 From: miteruzo Date: Mon, 11 May 2026 02:30:13 +0900 Subject: [PATCH] #346 --- .gitea/ISSUE_TEMPLATE/codex-task.md | 43 ++ AGENTS.md | 143 ++++++ backend/AGENTS.md | 147 +++++++ docs/codex-handoff.md | 646 ++++++++++++++++++++++++++++ docs/commands.md | 29 ++ docs/issue-workflow.md | 80 ++++ docs/release-checklist.md | 8 + docs/roadmap.md | 8 + frontend/AGENTS.md | 95 ++++ 9 files changed, 1199 insertions(+) create mode 100644 .gitea/ISSUE_TEMPLATE/codex-task.md create mode 100644 AGENTS.md create mode 100644 backend/AGENTS.md create mode 100644 docs/codex-handoff.md create mode 100644 docs/commands.md create mode 100644 docs/issue-workflow.md create mode 100644 docs/release-checklist.md create mode 100644 docs/roadmap.md create mode 100644 frontend/AGENTS.md diff --git a/.gitea/ISSUE_TEMPLATE/codex-task.md b/.gitea/ISSUE_TEMPLATE/codex-task.md new file mode 100644 index 0000000..1fad838 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/codex-task.md @@ -0,0 +1,43 @@ +--- +name: 'Codex task' +about: 'Codex に実装させるための課題' +title: '' +labels: + - codex-ready +--- + +## 背景 + +なぜ必要か。 + +## 対象範囲 + +- backend: +- frontend: +- docs: +- migration: + +## やること + +- [ ] + +## 受け入れ条件 + +- [ ] + +## 実行すべき確認 + +- [ ] `cd backend && bundle exec rspec` +- [ ] `cd frontend && npm run build` +- [ ] `cd frontend && npm run lint` + +## 禁止事項 + +- unrelated refactor はしない +- 既存 API response shape を壊さない +- 認証・認可・BAN を弱めない + +## Codex への指示 + +この issue を読んで実装してください。 +不明点があれば、実装前に調査結果と選択肢を提示してください。 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..168db54 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,143 @@ +# 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 preview +``` + +`npm run build` runs `tsc -b && vite build`, then `postbuild` runs `node scripts/generate-sitemap.js`. + +Do not write or report `npm test` as a repository command unless a `test` script is added to `frontend/package.json`. + +## 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: do not use `%w` or `%i`. +- TypeScript and Python: use GNU-style spacing before parentheses where syntactically valid. +- Do not add production dependencies without explicit approval. + +## Backend rules + +- Inspect existing routes, controllers, models, services, and specs before editing backend behavior. +- For API behavior changes, add or update request specs under `backend/spec/requests`. +- 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. +- 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. + +## 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 the existing frontend verification commands that apply: `npm run build` and `npm run lint`. +- If backend code changes, run the relevant RSpec command; for broad backend changes, run `bundle exec rspec`. +- 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 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. diff --git a/backend/AGENTS.md b/backend/AGENTS.md new file mode 100644 index 0000000..33d1b1f --- /dev/null +++ b/backend/AGENTS.md @@ -0,0 +1,147 @@ +# 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. diff --git a/docs/codex-handoff.md b/docs/codex-handoff.md new file mode 100644 index 0000000..fcb9f99 --- /dev/null +++ b/docs/codex-handoff.md @@ -0,0 +1,646 @@ +# Codex handoff for BTRC Hub / タグ広場 + +This document transfers project-specific context from prior ChatGPT-assisted design and review work to Codex. + +Use this file as project background. +Use `AGENTS.md`, `backend/AGENTS.md`, and `frontend/AGENTS.md` for concrete coding rules and verification commands. + +## Project identity + +BTRC Hub / タグ広場 is a collaborative knowledge base for collecting, tagging, explaining, and rediscovering Bocchi the Rock creature-related works. + +It is not a generic SNS. +It is not a comment board. +It is not a service for rehosting external content. +It is primarily a structured link, tag, wiki, material, and viewing-party system. + +Core domains: + +1. Posts +2. Tags +3. Wiki pages +4. Materials +5. Theatre / watch-party features + +The project is already publicly accessible and indexed by search engines, but it has not been broadly announced. Treat it as a small public production system, not a private prototype. + +## Current stack + +Backend: + +- Ruby 3.2.2 +- Rails 8.0.2 API +- MySQL 8 +- Active Storage +- Cloudflare R2 / S3-compatible storage is expected for uploaded files +- RSpec + +Frontend: + +- React 19.1 +- Vite 6.3 +- TypeScript 5.8 +- Axios +- TanStack Query +- Tailwind CSS +- Framer Motion +- shadcn-like local components +- react-markdown +- react-markdown-editor-lite +- remark-wiki-autolink + +Batch / background-like tasks: + +- Rake tasks +- Nico sync +- YouTube sync +- Similarity calculation tasks + +## Repository working principle + +Before editing, inspect the existing implementation. + +Do not invent a new architecture when the current repo already has an established convention. + +Keep changes scoped to the requested issue. + +Prefer small, reviewable changes over broad rewrites. + +Do not perform unrelated cleanup in the same patch. + +When a task has design ambiguity, first produce a short investigation and recommended plan. Do not silently choose a risky design. + +## User coding preferences + +General: + +- Prefer single quotes for strings unless interpolation, escaping, or framework convention makes double quotes better. +- Do not add production dependencies without explicit approval. +- Do not perform broad formatting churn. +- Do not convert unrelated files to a different style. + +Ruby: + +- Do not put a space before method-call parentheses. +- Do not use `%w`. +- Do not use `%i`. +- Keep Rails code idiomatic, but preserve the user's style where the repo already uses it. + +TypeScript / Python: + +- The user prefers GNU-style spacing before parentheses where syntactically valid. +- Preserve existing project formatting if a formatter or nearby code dictates otherwise. + +## Current authentication model + +The system does not use normal email/password authentication. + +Users are authenticated by inheritance code. + +Frontend: + +- Stores the code in `localStorage.user_code`. +- Sends it as the `X-Transfer-Code` header. + +Backend: + +- Looks up `users.inheritance_code`. +- Sets `current_user`. + +Roles: + +- `guest` +- `member` +- `admin` + +Important helper: + +- `User#gte_member?` returns true for `member` and `admin`. + +Never introduce a conventional login assumption unless the issue explicitly asks for it. + +## BAN / abuse-control model + +The backend currently enforces BAN at API level. + +The relevant before_action order is conceptually: + +1. Reject banned IP address. +2. Authenticate user if transfer code exists. +3. Reject banned user. + +Entities: + +- `users.banned_at` +- `ip_addresses.banned_at` +- `user_ips` + +IP addresses are stored as binary values using `IPAddr#hton`. + +Do not weaken BAN behavior. + +Do not move BAN checks behind optional authentication. + +Do not make preview, theatre, verify, user creation, or public-looking endpoints bypass BAN without an explicit design decision. + +## Public-operation assumptions + +Current practical operation: + +- A few editor accounts exist. +- Meaningful editing is mostly done by the owner. +- Read access is already public. +- Search engines have indexed the site. +- Future editor applications are expected through Discord. +- Prospective editors are likely people known in the Bocchi creature community. + +This means security and moderation issues matter even if traffic is still small. + +## Core domain summary + +### Posts + +Posts are external URL-based link records. + +Important properties: + +- `url` is required and unique. +- URLs are normalized. +- Only HTTP / HTTPS are allowed. +- Posts can have thumbnails through Active Storage. +- `uploaded_user_id` may be NULL for synced or bot-created posts. +- `original_created_from` and `original_created_before` represent a time range for original content creation. +- When both original time bounds exist, `from < before` is required. + +Parent/child posts: + +- Current implementation uses `post_implications`. +- It is many-to-many. +- Do not assume `posts.parent_id`. +- Frontend/API clients must send `parent_post_ids`, even when empty. +- `parent_post_ids` is parsed as a space-separated ID string. +- Self-parenting is invalid. +- Missing parent IDs are invalid. + +Versions: + +- `post_versions` stores snapshots. +- `version_no` is a per-post sequence. +- Snapshot includes title, URL, thumbnail base, tags, parent post IDs, original time bounds, event type, and actor. +- Optimistic locking for posts is planned / important, but do not assume it is fully implemented unless the code proves it. + +### Tags + +Tags are central. + +There is separation between tag names and tag entities: + +- `tag_names` +- `tags` + +Categories: + +- `deerjikist` +- `meme` +- `character` +- `general` +- `material` +- `nico` +- `meta` + +Alias model: + +- `tag_names.canonical_id` expresses aliases. +- `canonical_id = NULL` means canonical name. +- `canonical_id != NULL` means alias. +- An alias must not point to another alias. +- A tag name that already has a tag or wiki page generally must not be aliasified. + +Tag normalization: + +- User-entered tags are normalized through existing backend logic. +- Known aliases are canonicalized. +- Parent tags are expanded recursively. +- `nico:` is normally rejected for manual entry. +- Special tags such as tag-request / bot / unknown-deerjikist / video / niconico / youtube must be protected. + +Do not casually change tag normalization, alias resolution, or parent expansion. These affect search, wiki, sync, and historical data. + +### Nico tags + +Nico tags use the `nico` category and have separate versioning. + +Important relation: + +- `nico_tag_relations` maps external Nico tags to internal tags. +- `nico_tag_id` must be a Nico category tag. +- `tag_id` must not be Nico category. + +Do not allow ordinary manual tag editing to create or corrupt Nico tags. + +### Deerjikists + +Deerjikists map external platform identities to internal `deerjikist` tags. + +Known platforms include: + +- `nico` +- `youtube` + +YouTube handles may be normalized to `UC...` channel IDs. + +Do not treat user-facing handles and canonical channel IDs as interchangeable without checking existing code. + +### Wiki + +Wiki pages are a major knowledge layer. + +Important points: + +- Wiki pages are tied to tag-like titles. +- Title handling, aliases, and canonical tag names matter. +- There is line-level storage / revision-oriented behavior in the current implementation. +- There has been design tension between wiki revisions and wiki versions. +- Wiki conflict detection using `base_revision_id` exists on the backend side. +- Frontend support for conflict detection must be verified before assuming it is complete. + +Do not redesign Wiki storage casually. + +Do not add a second competing history system. + +Do not break existing wiki URLs. + +### Materials + +Materials connect files or reference URLs to `material` or `character` tags. + +Important properties: + +- A material has a `tag_id`. +- The tag must be `material` or `character`. +- A material requires either `url` or attached `file`. +- Active Storage is involved. +- Upload/security policy matters more than plain link posting. + +Important unresolved/risky area: + +- Material creation permissions have historically been risky because upload endpoints can be abused. +- Prefer `member` or higher for material creation unless the issue explicitly says otherwise. + +### Theatre + +Theatre is an experimental watch-party style feature. + +Known pieces include: + +- Display +- Presence +- Next post +- Comments +- Host-like control + +Do not assume theatre has complete CRUD/admin support unless the code proves it. + +Theatre may become expensive if next-item selection uses random DB ordering. + +## Current high-risk areas + +Treat these areas with extra care. + +### Security + +- Preview API SSRF protection. +- External iframe / embed CSP. +- Markdown link safety. +- BAN / IP BAN bypass. +- Transfer-code leakage. +- Guest write access. +- Upload endpoints. +- Admin-only tag operations. +- System tag mutation. + +### Data integrity + +- Tag alias canonicalization. +- Tag parent expansion. +- Post parent many-to-many relationships. +- Version tables. +- `version_no` synchronization. +- Schema drift from branch migration contamination. +- Wiki revision/version split. +- Material version recording. + +### Frontend correctness + +- React Hooks must not be called conditionally. +- Role guards are currently spread across components/pages. +- TanStack Query keys must not collide between ID/name or ID/title variants. +- URL path segments containing tag names or wiki titles must use `encodeURIComponent`. +- API response types may allow `null` users for bot or migration data. +- Tag autocomplete has had duplicated logic and stale state hazards. + +### Performance + +- Avoid unbounded `limit`. +- Avoid `order('RAND()')` for growing tables. +- Avoid loading full relations just to count. +- Avoid Ruby-side sorting/paging for large histories. +- Tag sidebar client-side aggregation can become expensive. +- Wiki full-text search needs deliberate indexing/design. + +## Current priority order + +Use this as the default priority unless an issue says otherwise. + +### P0: Safety before broad announcement + +1. Preview API SSRF hardening. +2. Material creation permission tightening. +3. System tag mutation holes. +4. `GET /users/me` transfer-code leakage through query params. +5. Limit caps for index/history/comment APIs. +6. CSP / iframe sandbox policy. +7. Confirm BAN enforcement remains global. + +### P1: Core correctness + +1. Post optimistic locking with `version_no`. +2. Wiki edit conflict handling. +3. Wiki history/revision model clarification. +4. Wiki search truthfulness: implement body search or remove false UI. +5. Tag alias/canonical/wiki interaction. +6. Tag URL encoding. +7. TanStack Query key separation. +8. Frontend null-user handling. +9. React Hooks rule fixes. +10. Material version policy. + +### P2: Operational/admin usability + +1. Admin screens for users, IPs, bans, aliases, and settings. +2. Settings table and user settings usage. +3. Better tag sidebar. +4. Better role guard helpers. +5. Better frontend tests. +6. Better issue triage and closure of already-implemented issues. + +### P3: Future features + +1. Theatre list/create/edit/admin flow. +2. Muted/hidden tags. +3. Tag category custom colors. +4. Responsive refinements. +5. Watch-party improvements. +6. Broader embed support. + +## Known issue triage notes + +Some existing issues may already be partially or mostly implemented. + +Before implementing an issue, check code first. + +Examples: + +- Tag search and OR/NOT search may already be mostly implemented. +- BAN enforcement may have been implemented after earlier issue drafts. +- YouTube sync exists and should not be treated as purely planned. +- Parent posts are many-to-many in current schema, even if older issues mention one-to-many. +- Some issues may reflect old schema or old branch state. + +When in doubt: + +1. Inspect current code. +2. Inspect schema. +3. Inspect routes. +4. Inspect frontend usage. +5. Report whether the issue is implemented, partially implemented, not implemented, or obsolete. +6. Only then edit. + +## Verification expectations + +Backend changes: + +- Run RSpec when possible. +- Add request specs for API behavior changes. +- Add model specs for validation / normalization changes. +- Check migrations and schema consistency. +- Do not silently ignore pending migrations. + +Frontend changes: + +- Run build. +- Run lint if configured. +- Run tests if configured. +- Add tests for important behavior when the test framework exists. +- If frontend tests are not yet installed, state that clearly. + +Full-stack changes: + +- Verify both backend and frontend compile/test paths where possible. +- Confirm API response shapes match TypeScript types. +- Confirm authorization behavior on both server and UI. + +If commands cannot be run because dependencies are missing, report that explicitly. Do not pretend verification passed. + +## Branch / migration caution + +The project has previously suffered from schema contamination caused by running migrations from another branch. + +Be careful when touching: + +- `db/schema.rb` +- migration files +- parent post schema +- banned / banned_at schema +- version_no migrations +- wiki asset schema + +Before changing migrations: + +1. Inspect current schema. +2. Inspect existing migrations. +3. Confirm whether the intended branch already includes related migrations. +4. Prefer additive migrations for shared branches. +5. Do not edit already-applied production migrations unless explicitly instructed. + +## API design principles + +Prefer explicit server-side authorization. + +Do not rely only on frontend hiding. + +Do not return sensitive codes unnecessarily. + +Use 403 for authorization failures. + +Use 422 for validation failures. + +Use 409 for edit conflicts. + +Do not expose internal exception messages to users. + +Clamp or reject abusive limits consistently. + +Keep response shape stable unless the issue explicitly includes a breaking API change. + +## Frontend design principles + +Use existing route and query-key conventions. + +Use TanStack Query `enabled` rather than conditional hook calls. + +Do not let role-based early returns change hook order. + +Centralize repeated tag autocomplete logic when touching it. + +Use `encodeURIComponent` for tag names and wiki titles in URL path segments. + +Prefer graceful fallback for nullable actors: + +- bot operation +- deleted user +- migration-created data +- external sync + +Do not assume all API user fields are non-null. + +## Testing priorities to add over time + +Frontend tests are especially important because the backend already has more mature RSpec coverage. + +Suggested first frontend tests: + +1. Tag autocomplete. +2. Post form tag editing. +3. Tag URL encoding. +4. Wiki edit conflict UI. +5. Role guard behavior. +6. Null-user history rendering. +7. Dialog behavior. +8. Top navigation responsive behavior. + +Backend test priorities: + +1. BAN enforcement across public-looking endpoints. +2. Material permissions. +3. Preview SSRF rejection. +4. System tag protection. +5. Post optimistic locking. +6. Wiki conflict detection. +7. Tag alias/canonical behavior. +8. Limit caps. +9. Parent post parsing. +10. Version recorder behavior. + +## What Codex should not do without explicit approval + +Do not: + +- Replace Rails. +- Replace React. +- Replace TanStack Query. +- Redesign the database. +- Rewrite Wiki storage. +- Remove version tables. +- Change authentication model. +- Change role names. +- Change tag category names. +- Add background job infrastructure. +- Add a new UI framework. +- Add a new test framework if one already exists. +- Add major dependencies. +- Change public URL design. +- Change production storage configuration. +- Remove historical data behavior. +- Simplify BAN/security checks. +- Treat the site as private-only. + +## Good first Codex tasks + +Start with investigation-only tasks. + +Example: + +```txt +Inspect the repository and summarize the Rails, React, TypeScript, and test setup. +Do not modify files. +List commands that actually exist in this repository. +List risks Codex should know before editing. +``` + +Then small safe patches: + +```txt +Fix a React Hooks rule violation in one file. +Keep behavior unchanged. +Run the relevant frontend verification commands. +``` + +```txt +Add encodeURIComponent around one tag-name URL path segment. +Add or update a test if the project has a frontend test setup. +Run build/lint. +``` + +```txt +Add a request spec for a known authorization rule. +Do not change implementation unless the spec fails for the expected reason. +``` + +Avoid starting with: + +- Wiki history redesign. +- Post versioning redesign. +- Full admin screen suite. +- Broad frontend refactor. +- Database cleanup. +- Authentication rewrite. + +## Relationship with ChatGPT + +ChatGPT has been used for: + +- Design review. +- Risk analysis. +- Prioritization. +- Specification reconstruction. +- Migration/locking discussions. +- Codex migration planning. + +Codex should be used mainly for: + +- Repository inspection. +- Localized implementation. +- Test addition. +- Running verification commands. +- Producing small reviewable diffs. + +For ambiguous architecture, Codex should stop and present options rather than implement a guessed design. + +## Current strategic stance + +The project should not be rewritten from scratch. + +The current Rails + React system is acceptable. + +The immediate goal is not elegance. +The immediate goal is safe public operation, data integrity, and maintainable incremental improvement. + +Priority is: + +1. Prevent abuse/security incidents. +2. Preserve data correctness. +3. Make editing safe for multiple users. +4. Add tests around fragile frontend behavior. +5. Improve admin/operation workflows. +6. Optimize performance after obvious dangerous patterns are removed. + +## Final rule + +When current code, old specs, issue drafts, and memory disagree, current code wins. + +When current code is unsafe, write that explicitly and propose a small safe fix. + +When the task is too broad, split it. + +When verification cannot be performed, say exactly what was not verified. diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 0000000..ea6c4aa --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,29 @@ +# Commands + +## Backend + +```sh +cd backend +bundle install +bundle exec rails db:migrate +bundle exec rspec +bundle exec rails routes +``` + +## Frontend + +```sh +cd frontend +npm install +npm run dev +npm run build +npm run lint +npm test +``` + +### Full verification + +```sh +cd backend && bundle exec rspec +cd ../frontend && npm run build && npm run lint +``` diff --git a/docs/issue-workflow.md b/docs/issue-workflow.md new file mode 100644 index 0000000..8e3a57e --- /dev/null +++ b/docs/issue-workflow.md @@ -0,0 +1,80 @@ +# Issue workflow + +## Source of truth + +Gitea Issues are the source of truth for tasks, discussions, labels, milestones, and status. + +Do not copy the full backlog into git. + +Repository documents may define: + +- issue templates +- triage rules +- Codex task format +- verification rules +- release checklist + +## Labels + +Recommended labels: + +- `P0` +- `P1` +- `P2` +- `P3` +- `security` +- `data-integrity` +- `backend` +- `frontend` +- `wiki` +- `tags` +- `materials` +- `theatre` +- `codex-ready` +- `needs-design` +- `blocked` +- `good-first-codex-task` + +## Codex-ready criteria + +An issue can be labeled `codex-ready` only when it has: + +- clear background +- target area +- concrete tasks +- acceptance criteria +- verification commands +- explicit non-goals +- no unresolved architecture decision + +## Workflow + +1. Create or refine the issue in Gitea. +2. Add labels and milestone. +3. If design is unclear, label `needs-design`. +4. Discuss design before implementation. +5. When scoped enough, label `codex-ready`. +6. Give Codex the issue URL or copied issue body. +7. Codex creates a branch. +8. Codex implements a small patch. +9. Codex runs verification commands. +10. Human reviews the diff. +11. Merge. +12. Close the issue from the PR/commit message. + +## Commit message + +Use issue references when possible: + +```txt +fix: prevent preview SSRF + +Refs: #123 +``` +or +``` +fix: prevent preview SSRF + +Closes: #123 +``` +depending on whether the change fully resolves the issue. diff --git a/docs/release-checklist.md b/docs/release-checklist.md new file mode 100644 index 0000000..8e6d525 --- /dev/null +++ b/docs/release-checklist.md @@ -0,0 +1,8 @@ +# Release checklist + +- [ ] Backend specs pass +- [ ] Frontend build passes +- [ ] No pending migrations +- [ ] Preview API SSRF checked +- [ ] BAN behavior checked +- [ ] CSP checked diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 0000000..8bb2ed9 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,8 @@ +# Roadmap + +## Public announcement readiness + +- Harden preview API +- Tighten material creation permission +- Add admin MVP +- Improve frontend tests diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md new file mode 100644 index 0000000..d24aaa2 --- /dev/null +++ b/frontend/AGENTS.md @@ -0,0 +1,95 @@ +# frontend/AGENTS.md + +## Scope + +These rules apply to work under `frontend/`. + +This is a Vite + React + TypeScript app using TanStack Query, Tailwind CSS, Framer Motion, Radix UI-style components, MDX, and Zustand. + +## Commands + +Use only scripts that exist in `package.json`: + +```sh +npm run dev +npm run build +npm run lint +npm run preview +``` + +`npm run build` runs `tsc -b && vite build`, and `postbuild` runs `node scripts/generate-sitemap.js`. + +There is currently no `test` script in `package.json`. Do not run or report `npm test` unless a test script is added. + +After frontend changes, run: + +```sh +npm run build +npm run lint +``` + +If either command cannot be run or fails, report the exact command and failure. + +## TypeScript + +- TypeScript is strict. `tsconfig.app.json` enables `strict`, `noUnusedLocals`, `noUnusedParameters`, `erasableSyntaxOnly`, `noFallthroughCasesInSwitch`, and `noUncheckedSideEffectImports`. +- Keep types explicit at module boundaries, API helpers, and exported utilities. +- Use `import type` for type-only imports. +- Prefer existing shared types from `src/types.ts` before adding local duplicate types. +- Preserve the repository's existing spacing style in TypeScript, including GNU-style spacing before call parentheses where it is already used. +- Prefer single quotes for strings unless interpolation or escaping makes double quotes better. + +## React + +- Use function components. +- Existing page components commonly export an anonymous function satisfying `FC`; match nearby file style when editing. +- React hooks must be called unconditionally and at the top level of components or custom hooks. +- Keep page-level components under `src/pages`. +- Keep shared and feature components under `src/components`. +- Use `react-router-dom` route params and navigation patterns already present in `src/App.tsx`. +- Encode URL path-segment values with `encodeURIComponent`. + +## TanStack Query + +- Use `@tanstack/react-query` for server state. +- Query keys should come from `src/lib/queryKeys.ts`; add key builders there instead of using ad hoc arrays in components. +- Fetch functions should live in domain helpers under `src/lib`, such as `posts.ts`, `tags.ts`, or `wiki.ts`. +- Use `useQueryClient().invalidateQueries` with the shared root keys when mutations affect cached lists or detail views. +- The app-wide `QueryClient` is configured in `src/main.tsx`; do not create additional clients in feature code. + +## API calls + +- Use `src/lib/api.ts` for HTTP calls. +- The API wrapper attaches `X-Transfer-Code` from `localStorage` and converts non-blob responses to camelCase. +- Send Rails snake_case params and request body keys where the backend expects them. +- Do not bypass the API wrapper unless there is a specific reason, such as a third-party request outside the Rails API. +- For blob responses, pass `responseType: 'blob'` so the wrapper does not camelCase the body. + +## Imports and aliases + +- The `@` alias points to `frontend/src`. +- Prefer `@/...` imports for app code instead of long relative paths. +- Keep type imports separate with `import type`. +- Match existing import grouping: external packages, app modules, then type imports. + +## Tailwind and UI + +- Tailwind scans `src/**/*.{html,js,ts,jsx,tsx,mdx}`. +- Use `cn` from `src/lib/utils.ts` for conditional class names and class merging. +- Reuse components from `src/components/common`, `src/components/layout`, and `src/components/ui` before adding new primitives. +- Keep Tailwind classes consistent with nearby components. +- When adding dynamic tag color classes, update `tailwind.config.js` safelist if the class cannot be statically detected. +- Do not introduce new UI libraries or production dependencies without approval. + +## Lint and build constraints + +- ESLint uses `@eslint/js`, `typescript-eslint`, `eslint-plugin-react-hooks`, and `eslint-plugin-react-refresh`. +- The hooks rules are enforced; fix hook ordering instead of disabling the rule. +- `react-refresh/only-export-components` is enabled as a warning with `allowConstantExport`. +- Build failures from unused locals or unused parameters are TypeScript errors, not lint-only issues. + +## Files to avoid in routine work + +- Do not edit `dist/` output directly. +- Do not inspect or modify `node_modules/` unless explicitly needed. +- Keep generated build artifacts out of source changes unless the user asks for them.