Skip to content

Latest commit

 

History

History
298 lines (213 loc) · 15.9 KB

File metadata and controls

298 lines (213 loc) · 15.9 KB

CLAUDE.md

このファイルはClaude Codeがこのリポジトリで作業する際に参照する指示書です。 作業開始前に必ず本書全体を確認してください。


プロジェクト概要

tecnova-platform は、長崎市と長崎大学による共同事業として開催される子ども向けファブリケーション活動 tec-nova Nagasaki(テクノバながさき) の運営基盤プラットフォームです。 モノレポ構成で、APIサーバ(Hono on Cloudflare Workers)と複数のフロントエンド(Next.js)を含みます。

詳細な要件・設計は以下を参照してください。実装前に必ず読むこと

💡 開発を再開するときは、まず docs/handoff.md で進捗・既知の罠・残作業を確認してください。


作業前の必須チェックリスト

タスクに着手する前に:

  1. docs/mvp.md の関連セクションを読んだか
  2. ✅ 該当する実装が「Phase 1(MVP)」のスコープに含まれるか確認したか
  3. ✅ 既存コードのパターンを確認したか
  4. ✅ 「重要な制約」セクション(後述)を理解したか

ディレクトリ規約

tecnova-platform/
├── apps/                # エンドユーザー向けアプリ
│   ├── api/             # Hono on Cloudflare Workers
│   ├── checkin/         # Next.js iPad PWA(受付端末)
│   ├── admin/           # Next.js 管理画面(PC・モバイル / PWA)
│   └── signage/         # Next.js 会場サイネージ(大型モニター・キオスク)
├── packages/            # アプリ間で共有するライブラリ
│   ├── db/              # Drizzle schema・migrations
│   ├── shared/          # 共通型・Zodスキーマ・Sheets連携
│   └── ui/              # 共通UIコンポーネント (shadcn/ui)・APIクライアント・共通フォーマッタ
└── docs/                # 設計ドキュメント

apps/mentor(メンタースマホPWA)は Phase 1.5 でスコープ化されるが現時点では未実装。 Better Auth の設定は packages/auth ではなく apps/api/src/lib/auth.ts に集約している (リクエスト毎に instance を作る制約上、Workers の Env を直接受け取れる場所に置くのが自然なため)。

フロント3アプリ(checkin / admin / signage)はいずれも Next.js 16 / React 19。各 apps/*/CLAUDE.md は冒頭で @AGENTS.md を読み込み、App Router の API がトレーニングデータと 乖離しているため実装前に node_modules/next/dist/docs/ を確認するよう指示している。 ポート・env・PWA 設定などアプリ固有の制約は各アプリの CLAUDE.md を参照すること。

新しい機能の追加先を判断する基準:

  • 単一アプリ固有 → 該当 apps/*
  • 複数アプリで使う → packages/* のいずれか
  • DB関連 → packages/db
  • 型定義・Zodスキーマ・外部API連携 → packages/shared
  • フロント共通の UI / apiFetch / JST フォーマッタ / MeProviderpackages/ui

コーディング規約

TypeScript

  • TypeScript strict mode を有効に
  • any 型の使用は禁止(やむを得ない場合は unknown + 型ガード)
  • 関数は arrow function で統一(クラスメソッド・ジェネレータを除く)
  • import文はファイルの先頭にまとめる
  • 型定義(type/interface)は使用箇所の近くに配置するか、packages/shared/src/types/ に集約

ファイル命名

  • ファイル名: kebab-case.ts(コンポーネントは PascalCase.tsx
  • React component: 1ファイル1コンポーネント
  • ディレクトリ: kebab-case

コメント

  • 日本語コメントOK(チーム言語が日本語)
  • 「なぜそうするか」を書く。「何をしているか」はコードで表現する
  • TODO/FIXMEには必ず文脈を残す(例: // TODO(activate-flow): スプシ書き戻し失敗時のリトライキュー対応

スタイル

  • Biome で lint + format
  • インデント: スペース2つ
  • セミコロン: 使用する
  • クォート: シングルクォート
  • 行末の余分な空白なし

Git コミット

  • コミットメッセージは英語推奨(OSS化を意識)
  • 形式: <type>: <subject> (例: feat: add checkin endpoint
  • type: feat / fix / chore / docs / refactor / test / style

重要な制約(必ず守ること)

1. Cloudflare Workers環境の制約

APIサーバ(apps/api)は Cloudflare Workers で動作します。以下を厳守:

  • Node.js 専用APIを使わないfs, path, child_process, process.env の直接参照)
  • googleapis パッケージを使わない(Node.js依存のためWorkers非対応)
  • Web Standard APIを使うfetch, crypto.subtle, URL, TextEncoder など)
  • ✅ 環境変数は c.env.<NAME> でアクセス(Hono context経由)
  • ✅ 重い処理は c.executionCtx.waitUntil() でバックグラウンド実行

2. Better Auth on Workers の落とし穴

  • ✅ リクエスト毎に auth instance を生成する(middleware内で)
  • ⚠️ ctx.waitUntil() は「レスポンス送信後にバックグラウンド処理を走らせる場合」に使う。現状の auth 経路(routes/auth.ts / middleware/auth.ts)は Better Auth の DB 書き込みを await で完結させているため未配線。今後カスタム非同期フックや secondary storage などで遅延処理を足すときは、必ず c.executionCtx.waitUntil() を通すこと
  • ❌ グローバルスコープに auth instance を保持しない(接続ロックの問題)

詳細: docs/mvp.md 10.1節

3. Google Sheets API の実装方針

  • ✅ Web Crypto API で自前JWT生成 + fetch直叩き
  • ✅ アクセストークンは1時間有効、モジュールスコープでキャッシュ
  • ✅ サービスアカウント鍵は base64 エンコードしてから Secrets / .dev.vars に格納(GOOGLE_SERVICE_ACCOUNT_KEY
  • GOOGLE_SHEETS_ID も Secrets / .dev.vars で管理(学生側スプシIDの秘匿)
  • ❌ サービスアカウント鍵を生 JSON のまま .dev.vars に置かない(dotenv パーサが \n を実改行に変換し JSON.parse が失敗する)
  • googleapis パッケージは使わない

実装サンプル: docs/mvp.md 5.4節packages/shared/src/google-sheets.ts

4. データ整合性(D1 saga パターン)

DBは Cloudflare D1(SQLite)。インタラクティブ・トランザクションが使えないため、アクティベート処理は補償処理ベースで実装:

  1. ID採番(SELECT で直近IDを取得 → 計算)
  2. event_id を get-or-create
  3. db.batch([...]) で原子的に: INSERT participants + INSERT sessions
  4. スプシ書き戻し
  5. 失敗時の補償: db.batch([...])DELETE sessionsDELETE participants を実行
  6. PK 衝突時のリトライは現行未実装(apps/api/src/lib/checkin.ts の TODO)。当面は運用上の手動再試行で回復する

詳細: docs/mvp.md 6.1節/checkin/activate 処理順

5. 個人情報の取り扱い

  • 内製DBに保持するのは 氏名(本名)・ニックネーム・学年 のみ
  • 氏名はメンターの呼びかけや救急時の本人確認のために必要なので学生側でも持つが、メイン識別子はニックネーム(QR・検索・一覧の主表示はニックネーム)
  • 住所・年齢・保護者連絡先・学校名は 保持しない。これらは教員側の管理スプシで完結する設計

6. タイムゾーン

  • DBはUTCで保存(D1/SQLite では integer({ mode: 'timestamp_ms' }) = Unix epoch ms)
  • 「今日」を判定する場合は明示的にJST変換: Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Tokyo' })
  • フロント表示時は Asia/Tokyo で表示

7. Public リポジトリ運用

このリポジトリはPublicです。以下を絶対にコミットしないでください:

  • .env, .env.local, .dev.vars, .dev.vars.production
  • ❌ サービスアカウントJSON鍵
  • ❌ OAuth Client Secret
  • ❌ Better Auth Secret
  • ❌ D1 database_id(wrangler.toml にコミットされる場合は public でも閲覧可能だが、念のため。本番デプロイ用は別管理推奨)
  • ❌ 学生側スプシのID(公開しても直接アクセスはできないが念のため秘匿)
  • ❌ 実在する子ども・保護者・メンターの個人情報(テストデータも含めない)
  • ❌ 本番ドメイン名

シークレット情報は wrangler secret put または Vercel環境変数で管理します。 .env.example には変数名のみ記載してください。


subagent / skill の活用方針

このプロジェクトでは subagent と skill を積極的に活用する。 以下のタスクでは、ユーザーに明示的に頼まれなくても該当ツールを使うこと。

タスク 使うもの
3クエリ以上の横断的なコード探索・調査 Explore subagent
既存機能の深掘り(実行経路・依存の把握) feature-dev:code-explorer subagent
新機能の着手前(要件・設計の整理) superpowers:brainstormingfeature-dev:code-architect
実装(機能追加・バグ修正) superpowers:test-driven-development
バグ・テスト失敗・想定外挙動の調査 superpowers:systematic-debugging
多段タスクの計画作成・実行 superpowers:writing-plans / executing-plans
2つ以上の独立した調査・作業(並列化可能) superpowers:dispatching-parallel-agents
計画を分割して順次実装 superpowers:subagent-driven-development
コードレビュー / PR レビュー feature-dev:code-reviewer / code-review:code-review
マージ前の成果物レビュー依頼 superpowers:requesting-code-review
レビュー指摘を受け取って対応 superpowers:receiving-code-review
完了・修正完了を宣言する前 superpowers:verification-before-completion
フロントの UI 構築(checkin / admin / signage) frontend-design / vercel:shadcn
Next.js の設計・デバッグ vercel:nextjs
ライブラリ・SDK の最新ドキュメント確認 context7 (MCP)

ガードレール(積極化しても守ること):

  • subagent は「並列化できる独立タスク」か「メインのコンテキストを汚さず大量の結果を処理したい」場合に使う。同じ調査をメインと subagent で二重にやらない。
  • skill は該当タスクの着手前に呼ぶ(process 系 brainstorming/debugging が先、implementation 系が後)。
  • 「常にミニマム・シンプルから始める」原則は維持する。ツールの起動自体が目的化しないよう、効果が薄い場面では無理に使わない。

Agent-Driven な標準フロー(大きめのタスク):

  1. 着手前に superpowers:brainstorming で要件・設計を詰める
  2. 多段なら superpowers:writing-plans で計画化 → executing-plans / subagent-driven-development で実行
  3. 独立した調査・作業が並んだら superpowers:dispatching-parallel-agents でまとめて並列ディスパッチ
  4. 実装は superpowers:test-driven-development、詰まったら superpowers:systematic-debugging
  5. 完了宣言の前に superpowers:verification-before-completion、必要に応じて requesting-code-review

実装フローの推奨順序

新機能を実装する際の推奨順序:

  1. docs/mvp.md の該当セクションを読む
  2. 型を定義するpackages/shared/src/types/ または該当アプリ内)
  3. Zodスキーマを定義するpackages/shared/src/schemas/
  4. DB操作が必要ならpackages/db のスキーマを確認・更新
  5. APIエンドポイントを実装apps/apiroutes/ 配下にモジュール単位で)
  6. フロント側で呼び出し@tecnova/ui/lib/api-clientapiFetch を使い、レスポンスは packages/shared/src/schemas の型でアサート)
  7. 動作確認してから次へ

よく使うコマンド

# 開発サーバ起動(全アプリ)
pnpm dev

# 特定アプリのみ起動
# 注: workspace 名は package.json の "name" を使う。フロント3つは
# @tecnova/ プレフィックスを付けていない(checkin / admin / signage)。
pnpm --filter @tecnova/api dev   # :8787
pnpm --filter checkin dev        # :3000
pnpm --filter admin dev          # :3001
pnpm --filter signage dev        # :3002

# Lint & format
pnpm biome check --write .

# 型チェック
pnpm type-check

# DB マイグレーション生成(drizzle-kit が SQL を packages/db/drizzle/ に出力)
pnpm --filter @tecnova/db db:generate

# DB マイグレーション適用(ローカル D1 / 本番 D1)
pnpm --filter @tecnova/api db:apply:local
pnpm --filter @tecnova/api db:apply:remote

# Cloudflare Workers デプロイ
pnpm --filter @tecnova/api deploy

# シークレット設定
cd apps/api
npx wrangler secret put <SECRET_NAME>

設計判断時の参照先

実装中に「これってどう設計するんだっけ?」となったら:

疑問 参照先
全体システム構成・拡張ロードマップ docs/architecture.md
なぜこの技術スタックなのか docs/requirements.md 10章
なぜこのデータモデルなのか docs/requirements.md 5章 + 付録A
APIのリクエスト/レスポンス形式 docs/mvp.md 6章
画面遷移・UI仕様 docs/mvp.md 7章
既知のリスク・対策 docs/requirements.md 12章
トラブルシュート docs/mvp.md 10章
設計判断の根拠 docs/requirements.md 付録A

判断に迷うことがあれば、まず上記を確認してから提案・実装してください。


このドキュメントの更新

仕様変更や新しい制約が判明した場合:

  1. まず docs/requirements.md または docs/mvp.md を更新
  2. 必要に応じて本書(CLAUDE.md)を更新
  3. その後にコード変更を行う

ドキュメント先行の原則を守ることで、後から見たときに「なぜこの実装なのか」が辿れる状態を保ちます。