Skip to content

実装指示書

転職エージェント業務管理システム - Claude Code向け


プロジェクト概要

転職エージェント業務における複数ツール(スプレッドシート、社内システム、Matchingood)を統合し、業務効率化・登録漏れ防止を実現するWebアプリケーション。

対象ユーザー

  • エージェント: 2名(面談・企業紹介担当)
  • アシスタント: 1名(エントリー・企業調整担当)
  • 計3名、権限分けなし

スケジュール

  • MVP: 2025年2月末
  • フェーズ2: 2025年3月以降

技術スタック

レイヤー技術
フロントエンドReact 19 + TypeScript + Vite 6
スタイリングTailwind CSS 4 + shadcn/ui
データ取得TanStack React Query 5
状態管理Zustand
バックエンドHono 4 + Node.js 22
データベースSupabase (PostgreSQL)
認証Cloudflare Access (Google IdP)
フロントホスティングCloudflare Pages
APIホスティングCloud Run

実装時の注意事項

認証について

重要: 認証はCloudflare Accessがインフラレベルで処理する。

  • フロントエンドにログイン画面は不要
  • フロントエンドに認証ライブラリ(Auth0等)は不要
  • APIリクエスト時、CF-Access-JWT-Assertionヘッダーが自動付与される
  • バックエンドではこのJWTを検証してユーザー情報を取得
typescript
// フロントエンド: API呼び出し
const apiClient = axios.create({
  baseURL: import.meta.env.VITE_API_ROOT_URL,
  withCredentials: true, // Cookie送信でJWTが自動付与される
})

// バックエンド: JWT検証
const cfToken = c.req.header('CF-Access-JWT-Assertion')
const { payload } = await jose.jwtVerify(cfToken, jwks, { audience: CF_ACCESS_AUD })
c.set('user', { email: payload.email })

データベース接続

Supabaseへの接続は2つの方法がある:

  1. Supabase Client(推奨): REST API経由、セットアップが簡単
  2. Direct Connection: PostgreSQL直接接続、パフォーマンス重視

今回はSupabase Clientを使用。

typescript
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!)

クリーンアーキテクチャ

バックエンドは4層構造:

  1. interfaces層: ルーティング、ミドルウェア、コントローラー
  2. application層: ユースケース(サービス)
  3. domain層: エンティティ、リポジトリインターフェース、ドメインサービス
  4. infrastructure層: リポジトリ実装(Supabase)

依存性注入を使い、domain層がinfrastructure層に依存しないようにする。


主要機能の実装ポイント

1. ダッシュボード

エンドポイント: /api/v1/dashboard/*

表示項目:

  • 未完了タスク一覧
  • 今日の面接予定
  • 今週の面接予定
  • 選考結果待ち一覧
  • 実績サマリ(前月比較付き)

実装ポイント:

  • 面接予定はapplicationsテーブルとselection_statusesから取得
  • 実績サマリは集計クエリで計算
  • 前月比較は2つの期間の集計を比較

2. 求職者管理

エンドポイント: /api/v1/candidates/*

実装ポイント:

  • 一覧取得はページネーション必須
  • フィルタは複数条件のAND検索
  • 詳細画面には選考一覧と面談メモを含める
  • 年齢は生年月日から自動計算

3. 選考管理

エンドポイント: /api/v1/applications/*

実装ポイント:

  • ステータス更新時は必ず履歴テーブルにも追加
  • 同じ求職者×企業の重複登録はエラー
  • 横断一覧は複数フィルタ対応

4. ASP出金日計算

ドメインサービス: AspPaymentCalculator

typescript
function calculatePaymentDate(
  applicationDate: Date, // 申込日
  cutoffDay: number, // ASPの締め日
  paymentMonthOffset: number // 出金月オフセット
): Date {
  const day = applicationDate.getDate()

  if (day > cutoffDay) {
    // 締め日を過ぎている → オフセット+1ヶ月後の月末
    return endOfMonth(addMonths(applicationDate, paymentMonthOffset + 1))
  } else {
    // 締め日以前 → オフセット月後の月末
    return endOfMonth(addMonths(applicationDate, paymentMonthOffset))
  }
}

5. ASP承認判定

ドメインサービス: AspApprovalJudge

typescript
function getApprovalStatus(candidate: Candidate): 'approved' | 'rejected' | 'pending' {
  // Zoom面談日が入っている = 承認
  if (candidate.zoomInterviewDate) return 'approved'

  // 終了理由がある = 否認
  if (candidate.terminationReason || candidate.phoneTerminationReason) return 'rejected'

  // それ以外 = 対応待ち
  return 'pending'
}

6. 売上計算

ドメインサービス: RevenueCalculator

typescript
function calculateRevenue(application: Application): Revenue {
  const finalSalary = application.finalSalary * 10000 // 万円→円
  const feeRate = application.candidate.channel.feeRate
  const aspCost = application.candidate.asp?.costPerAcquisition || 0

  if (feeRate > 0) {
    // スカウト媒体経由
    return {
      grossRevenue: finalSalary,
      cost: finalSalary * feeRate,
      netRevenue: finalSalary * (1 - feeRate),
    }
  } else {
    // 自社サイト経由
    return {
      grossRevenue: finalSalary,
      cost: aspCost,
      netRevenue: finalSalary - aspCost,
    }
  }
}

画面実装のポイント

OOUIの原則

このシステムはオブジェクト指向UI設計に基づいている:

  1. オブジェクト(名詞)が主役: 求職者、企業、選考
  2. 一覧 → 詳細 → アクションの流れ
  3. 詳細画面から関連オブジェクトへ遷移可能

画面遷移パターン

求職者一覧 → 求職者詳細 → 選考詳細 / 面談メモ
企業一覧 → 企業詳細 → 選考詳細
選考一覧 → 選考詳細 → 求職者詳細 / 企業詳細
ダッシュボード → 各詳細画面(直接遷移)

コンポーネント設計

  • 一覧画面: フィルタ + テーブル + ページネーション
  • 詳細画面: 基本情報 + サブコレクション(タブまたはセクション)
  • 登録・編集: モーダルダイアログ
  • ステータス更新: 専用モーダル(履歴追加機能付き)

ファイル一覧(このプロジェクトで提供するドキュメント)

ファイル名内容
要件定義書.docx機能要件、非機能要件、業務フロー
テーブル定義書.docx全12テーブルの詳細定義
ER図.mermaidテーブル間のリレーション
画面定義書.docx全14画面の詳細定義
API_DESIGN.mdAPIエンドポイント設計
INFRASTRUCTURE.mdインフラ構成ガイド
ENVIRONMENT_VARIABLES.md環境変数一覧
DIRECTORY_STRUCTURE.mdディレクトリ構成
database_schema.sqlSupabase用テーブル作成SQL
DockerfileCloud Run用Dockerfile
deploy-api.ymlバックエンドCI/CDワークフロー
deploy-cloudflare.ymlフロントエンドCI/CDワークフロー

実装の進め方(推奨)

Phase 1: 基盤構築

  1. プロジェクト初期化

    • フロントエンド: npm create vite@latest frontend -- --template react-ts
    • バックエンド: mkdir api && npm init -y
  2. データベース構築

    • Supabaseプロジェクト作成
    • database_schema.sql を実行
  3. バックエンド基盤

    • Honoアプリケーション設定
    • Cloudflare Access JWT検証ミドルウェア
    • Supabase接続設定
    • ヘルスチェックエンドポイント
  4. フロントエンド基盤

    • Vite + React設定
    • Tailwind CSS + shadcn/ui設定
    • React Query設定
    • APIクライアント設定
    • ルーティング設定

Phase 2: マスタ機能

  1. バックエンド: マスタCRUD API
  2. フロントエンド: マスタ管理画面

Phase 3: 求職者機能

  1. バックエンド: 求職者CRUD API、面談メモAPI
  2. フロントエンド: 求職者一覧、詳細、登録・編集画面

Phase 4: 企業機能

  1. バックエンド: 企業CRUD API
  2. フロントエンド: 企業一覧、詳細、登録・編集画面

Phase 5: 選考機能

  1. バックエンド: 選考CRUD API、ステータス更新API、履歴API
  2. フロントエンド: 選考一覧、詳細、ステータス更新画面

Phase 6: ダッシュボード

  1. バックエンド: ダッシュボード集計API
  2. フロントエンド: ダッシュボード画面

Phase 7: 集計・レポート

  1. バックエンド: 各種集計API(日次、月次、媒体別、ASP別、担当者別)
  2. フロントエンド: レポート画面

Phase 8: 仕上げ

  1. テスト: ユニットテスト、E2Eテスト
  2. CI/CD: GitHub Actions設定
  3. デプロイ: Cloud Run、Cloudflare Pages

開発フロー(Issue駆動開発)

基本ルール

  1. 実装前にIssueを作成する
  2. 1つのIssueは1つの小さなタスク
  3. Issueに紐づくブランチで作業
  4. コミットメッセージにIssue番号を含める
  5. 完了したらIssueをクローズ

Issueの粒度

1つのIssueは1〜4時間で完了できるサイズに分割する。

良い例:

  • [API] 求職者一覧取得エンドポイント実装
  • [Frontend] 求職者一覧テーブルコンポーネント作成
  • [API] Cloudflare Access JWT検証ミドルウェア実装

悪い例:

  • 求職者機能を実装する ← 大きすぎる
  • バグ修正 ← 具体性がない

Issue テンプレート

markdown
## 概要

<!-- 何を実装するか -->

## 完了条件

- [ ] 条件1
- [ ] 条件2
- [ ] 条件3

## 関連ドキュメント

<!-- 参照すべきドキュメントがあれば -->

## 備考

<!-- 補足事項があれば -->

ブランチ命名規則

feature/#{Issue番号}-{簡潔な説明}

例:

  • feature/#1-setup-project
  • feature/#5-candidate-list-api
  • feature/#12-dashboard-ui

コミットメッセージ規則

{type}: {説明} #{Issue番号}

type一覧:

  • feat: 新機能
  • fix: バグ修正
  • docs: ドキュメント
  • style: フォーマット(コードの動作に影響なし)
  • refactor: リファクタリング
  • test: テスト
  • chore: ビルド、ツール設定等

例:

feat: 求職者一覧APIを実装 #5
fix: ページネーションのオフセット計算を修正 #8
docs: API設計書を更新 #10

ワークフロー

1. Issueを作成

2. ブランチを作成(feature/#XX-xxx)

3. 実装・コミット(コミットメッセージに#XX)

4. Push

5. PRを作成(またはmainに直接マージ)

6. Issueをクローズ(PRマージ時に自動クローズ or 手動)

PRでIssueを自動クローズ

PRの説明に以下を含めると、マージ時にIssueが自動クローズされる:

Closes #5

推奨Issueラベル

ラベル説明
apiバックエンド関連
frontendフロントエンド関連
infraインフラ関連
bugバグ
enhancement水色機能改善
documentationドキュメント

初期Issue一覧(参考)

以下の順序でIssueを作成し、実装を進めることを推奨する。

Phase 1: 基盤構築

  1. [Infra] プロジェクト初期化(モノレポ構成)
  2. [Infra] Husky + lint-staged セットアップ
  3. [Infra] Supabaseプロジェクト作成・テーブル構築
  4. [API] Honoアプリケーション基盤構築
  5. [API] Cloudflare Access JWT検証ミドルウェア実装
  6. [API] Supabase接続設定
  7. [API] ヘルスチェックエンドポイント実装
  8. [Frontend] Vite + React プロジェクト初期化
  9. [Frontend] Tailwind CSS + shadcn/ui セットアップ
  10. [Frontend] React Query + APIクライアント設定
  11. [Frontend] ルーティング設定
  12. [Frontend] レイアウトコンポーネント作成

Phase 2: マスタ機能

  1. [API] マスタ取得API実装(channels, asps, statuses等)
  2. [API] マスタ更新API実装
  3. [Frontend] マスタ管理画面実装

Phase 3: 求職者機能

  1. [API] 求職者一覧API実装
  2. [API] 求職者詳細API実装
  3. [API] 求職者登録・更新API実装
  4. [API] 面談メモCRUD API実装
  5. [Frontend] 求職者一覧画面実装
  6. [Frontend] 求職者詳細画面実装
  7. [Frontend] 求職者登録・編集モーダル実装
  8. [Frontend] 面談メモ機能実装

Phase 4: 企業機能

  1. [API] 企業CRUD API実装
  2. [Frontend] 企業一覧画面実装
  3. [Frontend] 企業詳細画面実装
  4. [Frontend] 企業登録・編集モーダル実装

Phase 5: 選考機能

  1. [API] 選考一覧API実装
  2. [API] 選考詳細・履歴API実装
  3. [API] 選考登録・更新API実装
  4. [API] ステータス更新API実装(履歴追加)
  5. [Frontend] 選考一覧画面実装
  6. [Frontend] 選考詳細画面実装
  7. [Frontend] 選考登録・編集モーダル実装
  8. [Frontend] ステータス更新モーダル実装

Phase 6: ダッシュボード

  1. [API] ダッシュボード集計API実装
  2. [Frontend] ダッシュボード画面実装

Phase 7: 集計・レポート

  1. [API] 日次・月次実績API実装
  2. [API] 媒体別・ASP別集計API実装
  3. [API] 担当者別集計API実装
  4. [Frontend] レポート画面実装

Phase 8: 仕上げ

  1. [Test] ドメインサービスユニットテスト
  2. [Test] API統合テスト
  3. [Infra] CI/CD設定(GitHub Actions)
  4. [Infra] 本番デプロイ

コード品質の指針

Husky + lint-staged(必須)

コミット前にESLint/Prettierを自動実行する。プロジェクトルートで以下をセットアップすること。

セットアップ手順:

bash
# ルートディレクトリで実行
npm install -D husky lint-staged eslint prettier

# Husky初期化
npx husky init

package.json(ルート)に追加:

json
{
  "devDependencies": {
    "husky": "^9.0.0",
    "lint-staged": "^15.0.0",
    "eslint": "^9.0.0",
    "prettier": "^3.0.0"
  },
  "scripts": {
    "prepare": "husky"
  },
  "lint-staged": {
    "frontend/**/*.{ts,tsx}": ["eslint --fix", "prettier --write"],
    "api/**/*.ts": ["eslint --fix", "prettier --write"],
    "*.{json,md,yml,yaml}": ["prettier --write"]
  }
}

.husky/pre-commit:

bash
npx lint-staged

.prettierrc:

json
{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100
}

eslint.config.js(ESLint v9 flat config):

javascript
import js from '@eslint/js'
import typescript from '@typescript-eslint/eslint-plugin'
import typescriptParser from '@typescript-eslint/parser'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'

export default [
  js.configs.recommended,
  {
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      parser: typescriptParser,
      parserOptions: {
        ecmaVersion: 'latest',
        sourceType: 'module',
      },
    },
    plugins: {
      '@typescript-eslint': typescript,
      react,
      'react-hooks': reactHooks,
    },
    rules: {
      '@typescript-eslint/no-unused-vars': 'error',
      '@typescript-eslint/no-explicit-any': 'warn',
      'react-hooks/rules-of-hooks': 'error',
      'react-hooks/exhaustive-deps': 'warn',
    },
  },
]

TypeScript

  • strict: true を有効化
  • any 型は極力使わない
  • 型定義は types/ ディレクトリに集約

React

  • 関数コンポーネントのみ使用
  • カスタムフックで状態ロジックを分離
  • コンポーネントは単一責任原則

API

  • RESTful設計
  • 適切なHTTPステータスコード
  • エラーレスポンスは統一フォーマット

テスト

  • ドメインサービスはユニットテスト必須
  • APIはインテグレーションテスト推奨

よくある質問(FAQ)

Q: ログイン画面は必要?

A: 不要。Cloudflare Accessがインフラレベルで認証を行う。

Q: ユーザー登録機能は必要?

A: マスタ管理画面でユーザー(エージェント/アシスタント)を登録できるようにする。ただし、実際のログイン認証はCloudflare Access + Google Workspaceで行うため、メールアドレスが一致している必要がある。

Q: データ移行はどうする?

A: 既存データ(約1,000人分)はCSV/Excelでエクスポートし、Supabaseにインポートする。移行スクリプトは別途作成。

Q: メール機能は?

A: フェーズ2で実装予定。MVPには含まない。

Q: モバイル対応は?

A: レスポンシブデザインで対応。専用モバイルアプリは作らない。


連絡事項

  • 不明点があれば、このドキュメントと一緒に提供される他のドキュメント(要件定義書、画面定義書など)を参照
  • 仕様の判断に迷う場合は、シンプルな方を選択
  • パフォーマンスより可読性・保守性を優先