ファイル・フォルダ構成と役割
実装を進めるときの地図。2026-09-01 時点の実態を記録し、未着手のものは「予定」として区別している。
構成そのものの規約は CLAUDE.md §9.1 が正。この文書は各ディレクトリが何を担うかと 依存の向きを補足するもの。両者が食い違ったら CLAUDE.md に従い、この文書を直す。
1. 依存の向き(最重要)
app/ (画面・APIルート)
│ 呼ぶ
▼
lib/db lib/logger lib/settings ← 非純粋層(I/O・副作用あり)
│ 呼ぶ
▼
lib/judge lib/config lib/format ← 純粋層(副作用なし・テストで固定)
下の層が上の層を import してはいけない。 特に:
lib/judge/ は lib/logger/ を import しない(CLAUDE.md §9.4 の純粋関数規約)
- 判定結果のログは、判定関数の中ではなく呼び出し側(APIルート)で記録する
lib/judge/ は USE_FIXTURES の切替の外側。fixtures でも本番でも同じロジックが走る
2. ルート直下
| パス |
役割 |
状態 |
CLAUDE.md |
全ルールの正。 仕様・禁止事項・実装規約。Claude Code と Cursor の両方が自動で読む |
運用中 |
.cursorrules |
Cursor の legacy 形式。中身は CLAUDE.md へ統合済みのポインタ |
縮小済み |
d-watch-api.yaml |
API契約の正。 変更は実装より先に行う(CLAUDE.md §9) |
一部に旧記述が残存※ |
d-watch-mock.jsx |
画面レイアウト・文言・遷移の正。 フロント実装はこれを移植する |
参照専用 |
instrumentation.ts |
起動ログ(app.start)と捕捉漏れエラー(app.uncaught)の記録(D-047) |
実装済み |
proxy.ts |
相関IDの発行+認証+IP制限。1プロジェクトに1ファイルしか置けないので、中身は lib/proxy/ へ分割し本体は順序制御だけにしてある |
実装済み(指示書I / D-101) |
next.config.ts |
serverExternalPackages: ["pino"] を設定 |
実装済み |
eslint.config.mjs |
no-console を全体に適用。lib/logger/** のみ除外 |
実装済み |
vitest.config.ts |
テスト設定。lib/** と app/** の *.test.ts を対象 |
運用中 |
.claude/launch.json |
開発サーバーの起動設定。ブラウザ確認込みで npm run dev を回すために使う |
運用中 |
prisma/schema.prisma |
db pull 実施後は生成物を正とし手で書き換えない(D-056、CLAUDE.md §7)。実施前は定義書ベースで手書き |
TeamWorks 領域 |
※ d-watch-api.yaml の info.description は却下済みの Laravel 構成(D-001)の記述を 現行構成(Next.js の API ルート、D-046)に書き直し済み。servers.url も /api/v1 という 実態と異なる記載になっていたため /api(app/api/clean-logs 等の実ルートと一致)に修正済み (D-050)。securitySchemes も cookie 方式(type: apiKey / in: cookie / name: dwatch_session)へ 書き換え済み(指示書I 段階0 / D-101)。bearerAuth と Laravel Sanctum への言及は残っていない。 401(未認証)/ 403(IP拒否)を components/responses に定義し、/auth/login は security: [] で 認証不要にしてある。
3. app/ — 画面とAPI
画面
| パス |
役割 |
状態 |
app/layout.tsx |
全体のルートレイアウト |
実装済み |
app/(dashboard)/layout.tsx |
サイドバー付きの共通シェル |
実装済み |
app/(dashboard)/detail-log/ |
清掃詳細ログ(F-02) |
実装済み。他画面の見本 |
app/(dashboard)/dashboard/ |
ダッシュボード(F-01) |
実装済み。 components/features/dashboard/DashboardScreen を描画する |
app/(dashboard)/alerts/ |
アラート(F-03) |
実装済み |
app/(dashboard)/reports/ |
レポート(F-04) |
実装済み(指示書F) |
app/(dashboard)/inspections/ |
点検記録(F-05) |
プレースホルダ。★デモまで一時的にメニューから隠している(D-079 項3)。D-031 のP1スコープは変えていない★ |
app/(dashboard)/ds-logs/ ds-alerts/ |
D-Security 系(F-06 / F-07) |
実装済み |
app/(dashboard)/facilities/ schedules/ system/ |
施設・スケジュール・運用設定 |
実装済み(指示書L。systemは運用設定タブのみ・読み取り専用) |
app/login/ |
共有トークンの入力画面 |
実装済み(指示書I / D-101)。モックには無い画面(認証がモックの対象外だったため) |
画面は (dashboard) ルートグループの中に置く。 ログイン画面だけはシェルを出さないため外に置く。
APIルート
| パス |
役割 |
状態 |
app/api/clean-logs/route.ts |
一覧取得。「動く見本」。他の一覧APIはこれを真似る |
実装済み |
app/api/clean-logs/export/route.ts |
CSV等の書き出し |
実装済み |
app/api/clean-logs/[id]/advice/route.ts |
アドバイス取得 |
実装済み |
app/api/clean-logs/unscheduled/[report_id]/advice/route.ts |
予定なしの行のアドバイス取得 |
実装済み |
app/api/clean-logs/[id]/areas/route.ts |
清掃エリア内訳 |
実装済み |
app/api/dashboard/route.ts |
ダッシュボードの集計取得(failure_breakdown は D-048 により未返却) |
実装済み |
app/api/settings/advice/route.ts |
アドバイス規則の設定 |
実装済み |
app/api/auth/login logout |
cookie の発行・削除 |
実装済み(指示書I / D-101)。login のみ認証不要 |
app/api/prechecks/[id]/status 他 |
状態更新(PATCH系。M3) |
予定 |
全APIルートの共通形:
export async function GET(request: Request) {
return withRequestId(request, async () => {
// ... 本体
// catch 節では logApiError() を呼ぶ(console.error は禁止)
});
}
.cursorrules にあった app/api/v1/ という記載は実態と異なる(v1 は無い)。 ログの route フィールドにも実際のパスを入れること。
4. lib/ — ロジック層
純粋層(副作用なし。テストで固定する)
| パス |
役割 |
注意 |
lib/judge/ |
判定ロジック。 ◎○△×(grade.ts)、L1〜L3(escalation.ts)、アドバイス規則(advice.ts)、KPI計算(kpi.ts) |
変更時は期待値表のテストを先に書く。 ロガーを import しない。DBアクセスを混ぜない |
lib/dashboard/ |
ダッシュボード(F-01)の集計。 aggregate.ts。定義の正は D-049 |
lib/judge/kpi.ts とは別物。 kpi.ts は週次/月次の KPI 集計(完了率は1回ごとの完了率の単純平均。D-155)、こちらは日次の件数カウント。混同すると分母の意味が変わる。failure_breakdown は D-048 により未対応(M3送り) |
lib/config/ |
閾値の外出し。 完了率90/70/10、猶予30分、L2=2日/L3=3日、アドバイス規則の既定値 |
ハードコード禁止。 閾値は必ずここから読む |
lib/format/ |
表示整形(日付など)。丸めは表示層のみ |
ロジック層には生値を渡す |
lib/types/ |
d-watch-api.yaml から起こした型。ErrorCode の union もここ |
YAML と乖離させない |
lib/i18n.ts |
JP/EN 切替 |
器を壊さない |
lib/theme.ts theme-status.ts |
ダーク/ライト切替 |
器を壊さない |
非純粋層(I/O・副作用あり)
| パス |
役割 |
注意 |
lib/db/ |
USE_FIXTURES による切替の唯一の場所。 USE_FIXTURES を export しており、他所で process.env を再解釈しない |
画面側は切替を意識しない |
lib/fixtures/ |
サンプルデータ。境界値・異常系を含む |
DB接続後も削除しない(テスト・デモ用)。実在の店舗名・住所・電話番号を入れない。__tests__/schedules.test.ts が「有効スケジュールの曜日該当件数=当日の清掃ログ行数」という不変条件を守っている。この不変条件を壊すとダッシュボードの既定表示が異常系になる |
lib/logger/ |
動作ログ(D-047)。詳細は docs/logging-design.md |
lib/judge/ から import してはいけない |
lib/settings/ |
設定の永続化(アドバイス規則の上書き) |
メインDBには書かない |
lib/clean-logs/ |
清掃詳細ログのクエリ解析とフィルタ |
画面固有のロジック |
lib/auth/ |
認証の純粋関数(token.ts 定数時間比較 / client-ip.ts XFF解決とIP許可判定 / cookie.ts cookie属性 / next-path.ts 戻り先の検証) |
実装済み(指示書I / D-101)。DBもファイルも触らない |
lib/proxy/ |
proxy.ts から呼ぶ横断処理(request-id.ts 相関ID発行 / authenticate.ts IP制限と認証の判定) |
実装済み(指示書I / D-101)。判定だけを返し Response は組み立てない |
lib/api/client.ts |
フロントからの fetch 集約点。 実装済み |
apiFetch() と ApiFetchError を提供し、F-01(DashboardScreen)・F-02(DetailLogScreen)の両方が利用している |
lib/inspections/ |
点検記録の独自ストア(SQLite + オブジェクトストレージ) |
予定。 メインDBと完全分離 |
lib/logger/ の内訳
| ファイル |
役割 |
index.ts |
pino インスタンス。mixin() で request_id / data_source を自動付与。logEvent() |
events.ts |
イベント型(allowlist)。 許可フィールドのみで構成し、禁止キーは型で弾く |
redact.ts |
実行時の禁止キー検査。個人情報13キー+認証情報8キー。大文字小文字を無視 |
context.ts |
AsyncLocalStorage。withRequestId() / normalizeRequestId() |
timestamp.ts |
ISO 8601 JST(ミリ秒付き)。pino 既定の epoch ms を置き換える |
api.ts |
logApiError()。クライアントに返す ApiError をそのまま受け取ることで、レスポンスとログのズレを構造的に防ぐ |
5. components/
| パス |
役割 |
components/ui/ |
共通部品。 Pill / GradeBadge / FilterButton / StatCard / ProgressBar(ProgressBar はF-04のKPI4列でも再利用予定) |
components/features/{画面名}/ |
画面固有のコンポーネント。 現在は detail-log/ と dashboard/ の2つ |
components/layout/ |
AppShell(サイドバー)、PlaceholderScreen(未実装画面の仮表示) |
components/theme/ |
ThemeProvider(ダーク/ライト) |
判定結果(◎○△×、L1〜L3、ソート順)はAPIから受け取る。フロントで再計算しない。
6. docs/
| ファイル |
何の正か |
spec.md |
機能一覧と開発フェーズの正。 何をどの順で作るか |
decisions.md |
決定事項とその理由の正。 「なぜこの仕様か」を遡る時に読む |
fixtures.md |
サンプルデータの正。 用意すべき境界値・異常系の一覧 |
logging-design.md |
ログ機構の実装の正。 マスキング規約・イベント定義・実装ステップ |
architecture.md |
この文書。構成と役割の地図 |
getting-started.md |
環境構築手順 |
7. 触ってはいけないもの
| 対象 |
理由 |
lib/judge/** とそのテスト |
純粋関数を維持する。判定を変えるときは期待値表を先に直す |
lib/dashboard/aggregate.ts とそのテスト |
lib/judge/** と同じ規律(D-041)で期待値表テストを先に直す。schedule_progress の定義は D-049 が正 |
lib/fixtures/schedules.ts の曜日設計 |
866fe4f で確定した曜日パターン(補完ペア+毎日)。__tests__/schedules.test.ts がこの不変条件を守っている。崩すと /dashboard の既定表示(当日・date省略)が異常系になる |
prisma/schema.prisma |
db pull 実施後は手で書き換えない(D-056)。TeamWorks の領域 |
d-watch-api.yaml |
API契約の正。変更は実装より先に、合意の上で |
CLAUDE.md の <!-- BEGIN:nextjs-agent-rules --> ブロック |
next dev が自動生成する |
| メインDBへの書き込み |
robot_error_reports / control_error_histories の4カラムのみ |
8. 未確定(決まり次第この文書を更新する)
| 項目 |
影響範囲 |
| ★アプリのポートが nginx からのみ到達可能か★ |
ネットワーク側の設定。★偽装 XFF を本当に塞ぐのはここ★(アプリでは防げない)。D-101 の申し送り |
| VM のプロセス管理方式 |
ログの出力先とローテーション(アプリ側の実装には影響しない) |
| グループ・会社マスタの階層構造 |
施設・会社・グループの関係が未定。group_id/customer_id は現在API側で受け取るが無視している |
PATCH /prechecks/{id}/status の memo と PrecheckItem.note |
同一物か別物か契約上判断できない。PATCH実装時に解消する |