Browse Source

#346

pull/347/head
みてるぞ 2 weeks ago
parent
commit
d3f2b009bc
9 changed files with 1199 additions and 0 deletions
  1. +43
    -0
      .gitea/ISSUE_TEMPLATE/codex-task.md
  2. +143
    -0
      AGENTS.md
  3. +147
    -0
      backend/AGENTS.md
  4. +646
    -0
      docs/codex-handoff.md
  5. +29
    -0
      docs/commands.md
  6. +80
    -0
      docs/issue-workflow.md
  7. +8
    -0
      docs/release-checklist.md
  8. +8
    -0
      docs/roadmap.md
  9. +95
    -0
      frontend/AGENTS.md

+ 43
- 0
.gitea/ISSUE_TEMPLATE/codex-task.md View File

@@ -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 を読んで実装してください。
不明点があれば、実装前に調査結果と選択肢を提示してください。

+ 143
- 0
AGENTS.md View File

@@ -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.

+ 147
- 0
backend/AGENTS.md View File

@@ -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.

+ 646
- 0
docs/codex-handoff.md View File

@@ -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.

+ 29
- 0
docs/commands.md View File

@@ -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
```

+ 80
- 0
docs/issue-workflow.md View File

@@ -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.

+ 8
- 0
docs/release-checklist.md View File

@@ -0,0 +1,8 @@
# Release checklist

- [ ] Backend specs pass
- [ ] Frontend build passes
- [ ] No pending migrations
- [ ] Preview API SSRF checked
- [ ] BAN behavior checked
- [ ] CSP checked

+ 8
- 0
docs/roadmap.md View File

@@ -0,0 +1,8 @@
# Roadmap

## Public announcement readiness

- Harden preview API
- Tighten material creation permission
- Add admin MVP
- Improve frontend tests

+ 95
- 0
frontend/AGENTS.md View File

@@ -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.

Loading…
Cancel
Save