Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 3 additions & 13 deletions .claude/rules/backend/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ backend/app/
│ │ ├── scorer.py
│ │ ├── sync_service.py
│ │ └── tech_keywords.json
│ ├── intelligence/ # GitHub 連携パイプラインと LLM 連携
│ ├── intelligence/ # GitHub 連携パイプライン(決定論的・ルールベース)
│ │ ├── pipeline.py
│ │ ├── github_collector.py
│ │ ├── github_link_service.py
Expand All @@ -67,14 +67,7 @@ backend/app/
│ │ │ └── repo_analyzer.py
│ │ ├── response_mapper.py
│ │ ├── skill_extractor.py
│ │ ├── skill_taxonomy/ # スキル分類(言語・トピック・キーワードマップ)
│ │ └── llm/ # LLM クライアント実装(休眠インフラ・温存)
│ │ ├── base.py
│ │ ├── factory.py
│ │ ├── ollama_client.py
│ │ └── vertex_client.py
│ ├── llm/ # LLM 入出力サニタイザ(intelligence/llm とは別・休眠)
│ │ └── sanitizer.py
│ │ └── skill_taxonomy/ # スキル分類(言語・トピック・キーワードマップ)
│ ├── tasks/ # 非同期タスク基盤(Cloud Tasks / ローカル)
│ │ ├── base.py # TaskType 定義(現状 GITHUB_LINK のみ)
│ │ ├── exceptions.py # RetryableError / NonRetryableError
Expand All @@ -92,15 +85,12 @@ backend/app/
│ └── shared/ # ドメイン横断の service util
│ ├── resume_format.py # レジュメ整形の共通ロジック(md/pdf 共有)
│ └── sort_utils.py
├── prompts/ # LLM プロンプトテンプレート(MD)
├── fonts/ # PDF 生成用フォント
└── utils/
└── prompt_loader.py # プロンプトファイルローダ
```

## 主要モジュールのポイント

- **routers/auth/ と routers/blog/**: いずれもパッケージ化されている。auth は `endpoints` / `github_auth` / `oauth_flow` / `token_manager`、blog は `accounts` / `score` / `sync` に責務分割
- **services/tasks/**: Cloud Tasks(本番)と BackgroundTasks(ローカル)を共通の `execute_task` でディスパッチ。状態遷移(`processing` / `completed` / `dead_letter` / `retrying`)は worker が担う。現在登録されているタスクは `GITHUB_LINK` の 1 種類のみだが、`AsyncTaskCacheService` / `TaskHandler` は新規タスク追加の拡張ポイントとして汎用化してある(インライン化しない)
- **services/intelligence/**: GitHub 連携 → スキル集計パイプライン。`github_link_service` → `pipeline` → `github_collector` → `skill_extractor` が live 経路
- **services/llm/ と services/intelligence/llm/**: 別物。前者は入出力サニタイザ等の横断 util、後者は LLM プロバイダクライアント(Ollama / Vertex AI を `LLMClient` 抽象で切替)の実装。**両者とも現状どの live エンドポイントからも到達しない休眠インフラ**で、将来用に温存している。デッドコードとして削除しないこと
- **services/intelligence/**: GitHub 連携 → スキル集計パイプライン。`github_link_service` → `pipeline` → `github_collector` → `skill_extractor` が live 経路。LLM は使わず決定論的(ルールベース)に処理する(LLM プロバイダ抽象化は ADR-0008 で撤去済み)
2 changes: 1 addition & 1 deletion .claude/rules/backend/auth-security.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ paths:

## セキュリティ

- 外部 API 呼び出しや LLM 実行のような**高コスト endpoint**には rate limit を付けること(`slowapi`)
- 外部 API 呼び出しのような**高コスト endpoint**には rate limit を付けること(`slowapi`)
- OAuth 開始 URL は backend で発行し、許可された `CORS_ORIGINS` のみをリダイレクト先に使うこと
- Cookie 認証を使う変更では `Secure` / `SameSite` / CORS の整合を必ず確認すること
- Cloudflare Pages → Cloud Run 間は `INTERNAL_SECRET` ヘッダで認証する(local 環境では省略可)
11 changes: 0 additions & 11 deletions .claude/rules/backend/llm.md

This file was deleted.

2 changes: 1 addition & 1 deletion .claude/rules/backend/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ nix develop --command bash -c "cd backend && .venv/bin/python -m pytest tests/te
- 新規サービス関数 → 主要分岐ごとに 1 ケース
- タスクハンドラ → 成功 / `NonRetryableError` / `RetryableError` の 3 パス
3. **失敗パスを明示的に検証している**: 例外を `pytest.raises(ExpectedError)` で必ず assert する。silent return を許容するテスト(過去の `test_no_cache_returns_early` のようなもの)は書かない
4. **モックは最小限**: DB はモックしない(実 SQLite セッションを使う)。外部サービス(GitHub API / LLM / Cloud Tasks / Redis)はモックする
4. **モックは最小限**: DB はモックしない(実 SQLite セッションを使う)。外部サービス(GitHub API / Cloud Tasks / Redis)はモックする
5. **lint が pass**: `make lint-backend` も同時に通ること

## アンチパターン
Expand Down
3 changes: 1 addition & 2 deletions .claude/rules/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ backend 内で文字列リテラル `os.getenv("XXX")` を使うことは禁止

- **Pydantic バリデーション必須**: API エンドポイントへの入力はすべて `app/schemas/` の Pydantic モデルで型・制約を検証する。`Any` 型や `dict` 型の素通しは避ける
- **SQL インジェクション防止**: SQLAlchemy ORM / Core のパラメータバインドを使う。文字列連結でクエリを組み立てることは禁止
- **LLM プロンプトへのユーザー入力**: ユーザー由来の文字列を LLM プロンプトに埋め込む場合は `backend/app/services/llm/sanitizer.py` を通す

### Frontend

Expand Down Expand Up @@ -125,6 +124,6 @@ AI エージェントがコードを変更した後に確認する項目:
- [ ] `dangerouslySetInnerHTML` / `innerHTML` の新規使用がないか
- [ ] ログに個人情報・認証情報が出力されないか
- [ ] 新規エンドポイントに認証ガード(`get_current_user` 依存)が付いているか
- [ ] 高コスト処理(外部 API 呼び出し・LLM 実行)に rate limit があるか(`slowapi`)
- [ ] 高コスト処理(外部 API 呼び出し等)に rate limit があるか(`slowapi`)
- [ ] `target="_blank"` に `rel="noopener noreferrer"` が付いているか
- [ ] 新規 IAM ロール付与に最小権限の原則を守っているか
7 changes: 3 additions & 4 deletions .claude/skills/BE_refacter/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ description: Use when reviewing or planning refactors for the DevForge FastAPI b
- `.claude/rules/backend/database.md`
- `.claude/rules/backend/auth-security.md`
- `.claude/rules/common/duplication.md`(DRY / 重複検知ポリシー)
- LLM やブログ AI 分析を含む場合だけ `.claude/rules/backend/llm.md`
- `report/dupe/jscpd-report.json` が存在すれば最新を読み込み、backend に該当する clone を抽出して Duplication Findings の素材にする

## 対象
Expand Down Expand Up @@ -62,7 +61,7 @@ description: Use when reviewing or planning refactors for the DevForge FastAPI b
- 大きいファイルを洗う: `rg --files backend/app backend/tests | xargs wc -l | sort -nr | head -n 30`
- まず以下の境界で構造を把握する
- router: HTTP 入出力、認証、rate limit、エラー変換
- service: ビジネスロジック、外部 API、LLM、PDF/Markdown 生成
- service: ビジネスロジック、外部 API、PDF/Markdown 生成
- repository: 永続化と問い合わせ
- schema/model: API 契約、DB 契約
- tests: ルータ、サービス、純粋関数、外部依存のモック
Expand Down Expand Up @@ -105,7 +104,7 @@ description: Use when reviewing or planning refactors for the DevForge FastAPI b
- 純粋関数の分岐、スコア計算、日付処理、マッピング
- router の認証、認可、validation、HTTP status、エラーメッセージ変換
- repository の upsert、一意制約、削除 cascade、ユーザー境界
- 外部 API や LLM の timeout / unavailable / partial failure
- 外部 API の timeout / unavailable / partial failure
- マイグレーション後の不変条件
- セキュリティ設定: cookie, CSRF, GitHub OAuth state, rate limit

Expand All @@ -118,7 +117,7 @@ description: Use when reviewing or planning refactors for the DevForge FastAPI b

- **本質的重複**(抽出すべき): ドメインロジック / バリデーション / スコア計算 / エラーマッピング / API パスや env 名リテラル / DTO 変換ロジック
- **偶発的重複**(抽出しない): SQLAlchemy の `created_at` / `updated_at` 定義などの boilerplate、Pydantic schema の field 列、pytest fixture の minimal scaffolding、import 文の塊
- **意味的重複**(jscpd では拾えない): 変数名やシグネチャは違うが「同じ判断・同じ整形・同じ I/O パターン」を行うコード。grep + 目視で別途探す。例: 似た Cloud Tasks エンキューロジック、似た LLM 呼び出しエラーハンドリング、似たエラー → HTTPException 変換
- **意味的重複**(jscpd では拾えない): 変数名やシグネチャは違うが「同じ判断・同じ整形・同じ I/O パターン」を行うコード。grep + 目視で別途探す。例: 似た Cloud Tasks エンキューロジック、似たエラー → HTTPException 変換

本質的重複は「3 回目で抽出(Rule of Three)」を守る。2 箇所だけの重複は **記録するが、抽出は次の重複出現時まで保留**。

Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/SEC_apply/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Missing Exploit Tests: 4
- 不審な新規依存(typosquatting / dependency confusion / postinstall)は導入を止め、代替を提案。
8. **Missing Exploit Tests(攻撃者視点の回帰テスト)**:
- レポートの「Missing Exploit Tests」と、今回直した設計穴を **攻撃が失敗することを assert** するテストで固定する。
- `.claude/rules/backend/test.md` 準拠: DB はモックせず実 SQLite セッション、外部 API(GitHub / LLM / Cloud Tasks / Redis)はモック。失敗パスは `pytest.raises` か HTTP status assert で必ず明示検証(silent return を許容しない)。
- `.claude/rules/backend/test.md` 準拠: DB はモックせず実 SQLite セッション、外部 API(GitHub / Cloud Tasks / Redis)はモック。失敗パスは `pytest.raises` か HTTP status assert で必ず明示検証(silent return を許容しない)。
- テスト名に守る仕様を書く(例: `test_他人のresumeはget_404` / `test_internal_secret欠落は拒否` / `test_state不一致のoauth_callbackは拒否`)。
- 配置先は既存方針: 認可/エンドポイントは `tests/test_<router>.py`、認証は `tests/test_auth.py` / `tests/test_oauth_flow.py`、タスクは `tests/test_worker_*.py`。

Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/SEC_review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ description: Use when running a security review / vulnerability check against th
- **OAuth フローの設計**: GitHub OAuth の `state` が backend Cookie で検証されているか(frontend のみ検証は不可)、`redirect_uri` が許可リスト内に固定されているか(オープンリダイレクト防止)。
- **トークンライフサイクル**: アクセス/リフレッシュトークンの失効・ローテーション、ログアウト時の Cookie 破棄、リフレッシュトークン再利用検知の有無。
- **マスアサインメント**: Pydantic スキーマが更新系で「ユーザーが書き換えてはいけないフィールド」(`user_id` / `role` / `is_admin` 相当 / タイムスタンプ)まで受け付けていないか。入力スキーマと DB モデルのフィールド差を確認。
- **ビジネスロジック濫用**: rate limit のない高コスト経路(LLM / 外部 API / PDF 生成)を繰り返し叩くコスト増幅、冪等性のない副作用の二重実行。
- **ビジネスロジック濫用**: rate limit のない高コスト経路(外部 API / PDF 生成)を繰り返し叩くコスト増幅、冪等性のない副作用の二重実行。
- **エラー / 例外からの情報漏洩**: スタックトレースや内部パス・SQL をユーザー向けレスポンスに返していないか(`detail` に生例外を載せていないか)。
- **暗号設計**: `FIELD_ENCRYPTION_KEY`(Fernet)で暗号化すべき機微フィールドが平文保存されていないか。鍵の取り違え・固定 IV 等。

Expand Down Expand Up @@ -113,7 +113,7 @@ description: Use when running a security review / vulnerability check against th

### 5. LLM プロンプトのサニタイズ

- ユーザー由来文字列を `services/llm/sanitizer.py` を通さずプロンプトに埋め込んでいないか: `rg -n 'prompt|messages=' backend/app/services` 周辺を目視
- 本プロジェクトは LLM 連携を廃止済み(ADR-0008)。現状この観点は該当なし。将来 LLM 連携を再導入する場合のみ、ユーザー由来文字列をプロンプトに埋め込む際のサニタイズ要否を検討する

### 6. Frontend XSS

Expand All @@ -132,7 +132,7 @@ description: Use when running a security review / vulnerability check against th

### 9. Rate limit

- 高コスト処理(外部 API / LLM 実行)に `slowapi` の `@limiter.limit` が付いているか
- 高コスト処理(外部 API 呼び出し等)に `slowapi` の `@limiter.limit` が付いているか

### 10. ファイルアップロード

Expand Down
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ Claude Code では対象パス編集時に自動ロードされる領域別ル
- [.claude/rules/backend/python.md](./.claude/rules/backend/python.md) — Python コーディング規約
- [.claude/rules/backend/database.md](./.claude/rules/backend/database.md) — DB / マイグレーション
- [.claude/rules/backend/auth-security.md](./.claude/rules/backend/auth-security.md) — 認証・認可
- [.claude/rules/backend/llm.md](./.claude/rules/backend/llm.md) — LLM 連携
- [.claude/rules/backend/test.md](./.claude/rules/backend/test.md) — テスト方針

### frontend(`frontend/` を触るとき)
Expand Down
3 changes: 2 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ docs/adr/XXXX-kebab-case-title.md
| [ADR-0001](docs/adr/0001-sqlite-gcs-backup.md) | SQLite + GCS バックアップ方式の採用 | Accepted |
| [ADR-0002](docs/adr/0002-jwt-cookie-auth.md) | JWT + Cookie 認証方式の採用 | Accepted |
| [ADR-0003](docs/adr/0003-redux-toolkit-persist.md) | Redux Toolkit + redux-persist の採用 | Accepted |
| [ADR-0004](docs/adr/0004-llm-provider-abstraction.md) | LLM プロバイダ抽象化(Ollama/Vertex AI) | Accepted |
| [ADR-0004](docs/adr/0004-llm-provider-abstraction.md) | LLM プロバイダ抽象化(Ollama/Vertex AI) | Superseded by ADR-0008 |
| [ADR-0005](docs/adr/0005-cloudrun-single-instance.md) | Cloud Run single instance 構成の採用 | Accepted |
| [ADR-0006](docs/adr/0006-tanstack-query.md) | TanStack Query 導入検討 | Proposed |
| [ADR-0008](docs/adr/0008-remove-llm-to-rule-based-design.md) | LLM プロバイダ抽象化の撤去とルールベース設計への統一 | Accepted |
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ help:
@echo " generate-keys JWT RSA 鍵ペアを生成"
@echo ""
@echo "ローカル開発"
@echo " dev docker-compose で API + Ollama を起動"
@echo " dev docker-compose で API を起動"
@echo " dev-build 再ビルドして起動"
@echo " dev-down docker-compose を停止"
@echo " dev-frontend Frontend 開発サーバーを起動 (Vite / localhost:5173)"
Expand Down
9 changes: 1 addition & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,9 @@ GitHub活動分析、ブログ連携による発信力を集計
- **Zenn** / **note** のアカウント連携・記事同期
- 記事メトリクス(タイトル、URL、公開日、いいね数、タグ)の一覧管理
- **ブログスコアリング**: 投稿頻度・反応数・技術記事比率等をもとにスコアを算出
- AIによるブログ活動要約(バックグラウンド非同期、ステータスポーリング方式)

### AIキャリアパス分析
- 職務経歴書データをもとに、LLMが希望ポジションへのキャリアパスを生成
- 分析履歴を複数バージョン保持・管理
- バックグラウンド非同期処理(202 Accepted → ステータスポーリング方式)

### 通知
- GitHub連携・ブログ要約・キャリア分析などのバックグラウンドタスクの成功/失敗をサイドバーの通知ベルで通知
- GitHub連携などのバックグラウンドタスクの成功/失敗をサイドバーの通知ベルで通知
- 未読バッジ表示(30秒ポーリング)・ドロップダウンパネルで一覧表示
- 「全て既読」ボタン・パネル外クリックで閉じる

Expand All @@ -53,7 +47,6 @@ GitHub活動分析、ブログ連携による発信力を集計
| 認証 | JWT Cookie (python-jose), bcrypt, GitHub OAuth |
| 暗号化 | Fernet(フィールド暗号化), bcrypt(パスワード) |
| PDF出力 | WeasyPrint(職務経歴書), ReportLab(分析レポート補助) |
| LLM | Ollama / Vertex AI(設定で切替、任意) |
| インフラ | GCP (Cloud Run, Artifact Registry, Secret Manager), Turso, Cloudflare Pages |
| IaC | OpenTofu(モジュール構成、マルチ環境) |
| CI/CD | GitHub Actions |
Expand Down
9 changes: 0 additions & 9 deletions backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ FIELD_ENCRYPTION_KEY=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=

# ---- LLM 設定 ----
LLM_PROVIDER=
OLLAMA_BASE_URL=
OLLAMA_MODEL=
OLLAMA_TIMEOUT=
VERTEX_PROJECT_ID=
VERTEX_LOCATION=
VERTEX_MODEL=

# ---- バックグラウンドタスク設定 ----
TASK_RUNNER=
# Cloud Tasks 用(TASK_RUNNER=cloud_tasks の場合のみ必要)
Expand Down
14 changes: 0 additions & 14 deletions backend/app/core/env_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,6 @@
APP_VERSION = "APP_VERSION"
ENVIRONMENT = "ENVIRONMENT"

# --- LLM ---

LLM_PROVIDER = "LLM_PROVIDER"
VERTEX_PROJECT_ID = "VERTEX_PROJECT_ID"
VERTEX_LOCATION = "VERTEX_LOCATION"
VERTEX_MODEL = "VERTEX_MODEL"
# Ollama プロバイダ(休眠インフラ・温存)。ローカル開発では docker-compose.yml の
# environment ブロックで注入する。本番(Cloud Run)には注入していない。
# なお `OLLAMA_KEEP_ALIVE`(docker-compose.yml の ollama サービス側)は
# Ollama サーバ自身の設定であり backend は参照しないため、ここには定義しない。
OLLAMA_BASE_URL = "OLLAMA_BASE_URL"
OLLAMA_MODEL = "OLLAMA_MODEL"
OLLAMA_TIMEOUT = "OLLAMA_TIMEOUT"

# --- 非同期タスク(Cloud Tasks / Local BackgroundTasks) ---

TASK_RUNNER = "TASK_RUNNER"
Expand Down
7 changes: 0 additions & 7 deletions backend/app/core/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ class ErrorCode(str, Enum):
# GitHub
GITHUB_RATE_LIMITED = "GITHUB_RATE_LIMITED"
GITHUB_USER_NOT_FOUND = "GITHUB_USER_NOT_FOUND"
# LLM
LLM_TIMEOUT = "LLM_TIMEOUT"
LLM_UNAVAILABLE = "LLM_UNAVAILABLE"
# バリデーション
VALIDATION_ERROR = "VALIDATION_ERROR"
# 外部 API
Expand Down Expand Up @@ -109,10 +106,6 @@ def infer_error_code(status_code: int, detail: Any = None) -> ErrorCode:

if "GitHubユーザーが見つかりません" in message:
return ErrorCode.GITHUB_USER_NOT_FOUND
if "タイムアウト" in message:
return ErrorCode.LLM_TIMEOUT
if ("LLM" in message or "AI " in message or "AI分析" in message) and "利用できません" in message:
return ErrorCode.LLM_UNAVAILABLE

if status_code == 401:
return ErrorCode.AUTH_REQUIRED
Expand Down
Loading
Loading