このファイルはClaude Codeがこのリポジトリで作業する際に参照する指示書です。 作業開始前に必ず本書全体を確認してください。
tecnova-platform は、長崎市と長崎大学による共同事業として開催される子ども向けファブリケーション活動 tec-nova Nagasaki(テクノバながさき) の運営基盤プラットフォームです。 モノレポ構成で、APIサーバ(Hono on Cloudflare Workers)と複数のフロントエンド(Next.js)を含みます。
詳細な要件・設計は以下を参照してください。実装前に必ず読むこと:
- 📘
docs/requirements.md— 全体構想・設計判断の根拠 - 📗
docs/mvp.md— 実装ガイド(実装に直結する詳細仕様) - 📐
docs/architecture.md— 全体システム構成・拡張ロードマップ
💡 開発を再開するときは、まず
docs/handoff.mdで進捗・既知の罠・残作業を確認してください。
タスクに着手する前に:
- ✅
docs/mvp.mdの関連セクションを読んだか - ✅ 該当する実装が「Phase 1(MVP)」のスコープに含まれるか確認したか
- ✅ 既存コードのパターンを確認したか
- ✅ 「重要な制約」セクション(後述)を理解したか
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 フォーマッタ /MeProvider→packages/ui
- 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つ
- セミコロン: 使用する
- クォート: シングルクォート
- 行末の余分な空白なし
- コミットメッセージは英語推奨(OSS化を意識)
- 形式:
<type>: <subject>(例:feat: add checkin endpoint) - type:
feat/fix/chore/docs/refactor/test/style
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()でバックグラウンド実行
- ✅ リクエスト毎に auth instance を生成する(middleware内で)
⚠️ ctx.waitUntil()は「レスポンス送信後にバックグラウンド処理を走らせる場合」に使う。現状の auth 経路(routes/auth.ts/middleware/auth.ts)は Better Auth の DB 書き込みをawaitで完結させているため未配線。今後カスタム非同期フックや secondary storage などで遅延処理を足すときは、必ずc.executionCtx.waitUntil()を通すこと- ❌ グローバルスコープに auth instance を保持しない(接続ロックの問題)
- ✅ 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
DBは Cloudflare D1(SQLite)。インタラクティブ・トランザクションが使えないため、アクティベート処理は補償処理ベースで実装:
- ID採番(
SELECTで直近IDを取得 → 計算) - event_id を get-or-create
db.batch([...])で原子的に:INSERT participants+INSERT sessions- スプシ書き戻し
- 失敗時の補償:
db.batch([...])でDELETE sessions→DELETE participantsを実行 - PK 衝突時のリトライは現行未実装(
apps/api/src/lib/checkin.tsの TODO)。当面は運用上の手動再試行で回復する
詳細: docs/mvp.md 6.1節 の /checkin/activate 処理順
- 内製DBに保持するのは 氏名(本名)・ニックネーム・学年 のみ
- 氏名はメンターの呼びかけや救急時の本人確認のために必要なので学生側でも持つが、メイン識別子はニックネーム(QR・検索・一覧の主表示はニックネーム)
- 住所・年齢・保護者連絡先・学校名は 保持しない。これらは教員側の管理スプシで完結する設計
- DBはUTCで保存(D1/SQLite では
integer({ mode: 'timestamp_ms' })= Unix epoch ms) - 「今日」を判定する場合は明示的にJST変換:
Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Tokyo' }) - フロント表示時は
Asia/Tokyoで表示
このリポジトリは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 を積極的に活用する。 以下のタスクでは、ユーザーに明示的に頼まれなくても該当ツールを使うこと。
| タスク | 使うもの |
|---|---|
| 3クエリ以上の横断的なコード探索・調査 | Explore subagent |
| 既存機能の深掘り(実行経路・依存の把握) | feature-dev:code-explorer subagent |
| 新機能の着手前(要件・設計の整理) | superpowers:brainstorming → feature-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 な標準フロー(大きめのタスク):
- 着手前に
superpowers:brainstormingで要件・設計を詰める - 多段なら
superpowers:writing-plansで計画化 →executing-plans/subagent-driven-developmentで実行 - 独立した調査・作業が並んだら
superpowers:dispatching-parallel-agentsでまとめて並列ディスパッチ - 実装は
superpowers:test-driven-development、詰まったらsuperpowers:systematic-debugging - 完了宣言の前に
superpowers:verification-before-completion、必要に応じてrequesting-code-review
新機能を実装する際の推奨順序:
docs/mvp.mdの該当セクションを読む- 型を定義する(
packages/shared/src/types/または該当アプリ内) - Zodスキーマを定義する(
packages/shared/src/schemas/) - DB操作が必要なら、
packages/dbのスキーマを確認・更新 - APIエンドポイントを実装(
apps/api、routes/配下にモジュール単位で) - フロント側で呼び出し(
@tecnova/ui/lib/api-clientのapiFetchを使い、レスポンスはpackages/shared/src/schemasの型でアサート) - 動作確認してから次へ
# 開発サーバ起動(全アプリ)
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 |
判断に迷うことがあれば、まず上記を確認してから提案・実装してください。
仕様変更や新しい制約が判明した場合:
- まず
docs/requirements.mdまたはdocs/mvp.mdを更新 - 必要に応じて本書(
CLAUDE.md)を更新 - その後にコード変更を行う
ドキュメント先行の原則を守ることで、後から見たときに「なぜこの実装なのか」が辿れる状態を保ちます。