# 職務経歴書: 非IT経歴・休暇・資本金単位 + GitHubコントリビューション可視化#281
Conversation
# 職務経歴書: 非IT経歴・休暇・資本金単位 + GitHubコントリビューション可視化
|
Warning Review limit reached
More reviews will be available in 14 minutes and 54 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds capital_unit, non‑IT experiences, and vacation-client support across DB, backend, generators, and frontend; integrates GitHub contribution-calendar fetching, parsing, dashboard heatmap UI, and tests. ChangesResume Data Model & Generation
GitHub Contribution Calendar Integration
Frontend Core: types, payloads, hooks
Frontend UI & Heatmap
Other
Sequence Diagram(s) sequenceDiagram
participant Frontend
participant GitHubLinkService
participant fetch_contribution_calendar
participant GitHubGraphQL
participant CacheStore
Frontend->>GitHubLinkService: POST /api/github-link/run (includeForks, token)
GitHubLinkService->>fetch_contribution_calendar: fetch_contribution_calendar(username, token)
fetch_contribution_calendar->>GitHubGraphQL: GraphQL query (contributionsCollection)
GitHubGraphQL-->>fetch_contribution_calendar: JSON payload / errors
fetch_contribution_calendar-->>GitHubLinkService: ContributionCalendar | None
GitHubLinkService->>CacheStore: persist result with contribution_calendar / warning_message
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/app/services/intelligence/github_link_service.py`:
- Around line 99-103: The warning message is being set whenever calendar is None
even if no fetch was attempted; change the logic so you only set warning_message
when a fetch was actually attempted and failed (i.e., token is present but
fetch_contribution_calendar returned None). Update the block around
calendar/token/fetch_contribution_calendar to check token first and then, only
if token was provided and calendar is None, set warning_message; apply the same
token-presence check for the similar warning logic at the other occurrence (the
block around lines 127-129).
In `@backend/app/services/intelligence/github/contributions.py`:
- Around line 126-146: The call site that invokes _parse_calendar should be made
resilient: wrap the call to _parse_calendar(...) in a try/except Exception block
and return None if parsing fails to preserve the "on failure None" contract;
additionally make _parse_calendar itself defensive by replacing day["date"] with
day.get("date") (or skip days where date is missing/invalid), use .get for
contributionCount/contributionLevel, validate types before creating
ContributionDay, and ensure _parse_calendar never raises on malformed week/day
entries (instead skip bad entries or return an empty ContributionCalendar).
In `@backend/tests/test_endpoints.py`:
- Around line 242-244: The test currently reindexes experiences into a dict
(experiences = {exp["company"]: exp for exp in data["experiences"]}) which masks
the required sorting check; before that reindexing, add an explicit assertion on
data["experiences"] to verify the list order (e.g., check that each consecutive
item is not newer than the previous by comparing the relevant date fields
present on each exp) so the sort guarantee is validated prior to converting to a
dict.
In `@backend/tests/test_worker/test_github_link.py`:
- Around line 116-120: The test patch for
app.services.intelligence.github_link_service.fetch_contribution_calendar
currently uses return_value=MagicMock(), which can cause contribution_calendar
persistence and break the assertion; change the patch to use return_value=None
so the contribution calendar is not mutated and the assertion cache.result ==
sentinel_result remains valid—update the mock setup in the test where
fetch_contribution_calendar is patched accordingly.
In `@frontend/src/components/github-link/ContributionHeatmap.tsx`:
- Around line 24-31: The month extraction is timezone-dependent because monthOf
uses new Date(week[0].date).getMonth() on a "YYYY-MM-DD" string; fix it by
computing the month in UTC instead of local time — either call getUTCMonth() on
the created Date or parse the date into a UTC Date (e.g., via Date.UTC(year,
month-1, day)) and then use getUTCMonth(); update the monthOf function
(referenced as monthOf, week[0].date, and MONTH_NAMES) accordingly so month
labels are stable across timezones.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 651efafb-72ab-4644-ba3f-e843a10f81d8
📒 Files selected for processing (47)
backend/alembic_migrations/versions/0039_add_capital_unit.pybackend/alembic_migrations/versions/0040_add_resume_non_it_and_vacation.pybackend/app/messages.jsonbackend/app/models/resume.pybackend/app/repositories/resume.pybackend/app/schemas/github_link.pybackend/app/schemas/resume.pybackend/app/services/intelligence/github/contributions.pybackend/app/services/intelligence/github_link_service.pybackend/app/services/markdown/generators/resume_generator.pybackend/app/services/pdf/generators/resume_generator.pybackend/app/services/pdf/templates/resume.cssbackend/tests/test_contributions.pybackend/tests/test_endpoints.pybackend/tests/test_markdown_generator.pybackend/tests/test_pdf_generator.pybackend/tests/test_schemas.pybackend/tests/test_worker/test_github_link.pyfrontend/e2e/github-link.spec.tsfrontend/e2e/navigation.spec.tsfrontend/src/App.module.cssfrontend/src/api/githubLink.tsfrontend/src/components/AuthenticatedLayout.tsxfrontend/src/components/forms/CareerFormEditors/CareerExperienceEditor.tsxfrontend/src/components/forms/CareerResumeForm.module.cssfrontend/src/components/forms/sections/CareerExperienceSection.tsxfrontend/src/components/github-link/ContributionHeatmap.module.cssfrontend/src/components/github-link/ContributionHeatmap.test.tsxfrontend/src/components/github-link/ContributionHeatmap.tsxfrontend/src/components/github-link/GitHubLinkDashboard.module.cssfrontend/src/components/github-link/GitHubLinkDashboard.test.tsxfrontend/src/components/github-link/GitHubLinkDashboard.tsxfrontend/src/components/icons/ChevronDownIcon.tsxfrontend/src/constants.tsfrontend/src/constants/messages.tsfrontend/src/formMappers.tsfrontend/src/formTypes.tsfrontend/src/hooks/career/useCareerDirty.tsfrontend/src/hooks/career/useCareerExperienceMutators.test.tsfrontend/src/hooks/career/useCareerExperienceMutators.tsfrontend/src/payloadBuilders.test.tsfrontend/src/payloadBuilders.tsfrontend/src/styles.cssfrontend/src/test/handlers.tsfrontend/src/test/renderWithProviders.tsxfrontend/src/types.tsfrontend/tests/payloadBuilders.test.cjs
Cross-Realm Refactor PR Report
Summary
SSoT ConsolidationsHigh
Medium
Low
Documentation Consolidations
Skipped
Validation
Follow-ups
|
Infra Refactor PR Report / Backend Refactor PR Report / Frontend Refactor PR Report
INFRA Summary
Applied ChangesMedium
Low
Modules / Variable ChangesModules 化
Variable 抽出
Module 統合
Structure Changes
State Migration
Skipped
Validation
Follow-ups
|
BE Summary
Applied ChangesHigh
Medium
Low
Test ChangesRemoved
Added
Duplication Resolved
Structure Changes
Skipped元レポート自身が「現状維持/保留推奨」とした項目。CLAUDE.md「過剰な抽象化を避ける」「Rule of Three」に従い、機械的 DRY 化を見送り記録のみ:
Validation
Follow-ups
|
FE Summary
Applied ChangesHigh
Medium
Low
Test ChangesRemoved
Added / Updated
Duplication Resolved
Structure ChangesSkipped
Validation
Follow-ups
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
backend/tests/test_delete_documents.py (1)
8-8: ⚡ Quick winBuild a fresh resume payload in each test.
_RESUME_PAYLOADis a shared mutable dict for the whole module, so any future in-place tweak in one test can leak into the others. Callingmake_resume_payload()at each POST keeps the helper’s fresh-object guarantee intact.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/tests/test_delete_documents.py` at line 8, Replace the module-level shared dictionary _RESUME_PAYLOAD with fresh calls to make_resume_payload() inside each test that posts a resume; i.e., wherever _RESUME_PAYLOAD is used in test functions (tests that perform POSTs), call make_resume_payload() to obtain a new dict for that request so tests no longer share a mutable object and cannot leak state between tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/app/services/tasks/worker.py`:
- Around line 212-216: The current work() closure reuses the same SQLAlchemy
Session for both _mark_dead_letter and _notify_if_real_user which can fail
because _mark_dead_letter swallows DB errors and leaves the session in an
inactive state; change the flow so _mark_dead_letter runs in its own session and
the notification runs in a fresh session: call _run_in_new_session(lambda db:
_mark_dead_letter(db, task_type, payload, error=error)) first, then call
_run_in_new_session(lambda db: _notify_if_real_user(db, task_type, user_id,
"failed")) (or otherwise ensure you rollback/close the session returned from
_mark_dead_letter before creating the notification) so notification creation
never reuses a potentially tainted session.
In `@frontend/src/components/forms/CareerFormEditors/ClientEditor.tsx`:
- Around line 227-233: The delete button label should reflect the client's
vacation state; update the JSX in ClientEditor so the button text is conditional
on client.is_vacation (e.g. client.is_vacation ? '休業を削除' : '取引先を削除') while
keeping the existing onClick handler (onRemoveClient(expIndex, clientIndex)), so
users editing a vacation block see the appropriate label.
---
Nitpick comments:
In `@backend/tests/test_delete_documents.py`:
- Line 8: Replace the module-level shared dictionary _RESUME_PAYLOAD with fresh
calls to make_resume_payload() inside each test that posts a resume; i.e.,
wherever _RESUME_PAYLOAD is used in test functions (tests that perform POSTs),
call make_resume_payload() to obtain a new dict for that request so tests no
longer share a mutable object and cannot leak state between tests.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e032d8ec-19a5-4dda-ae3a-777d28193095
📒 Files selected for processing (32)
.jscpd.jsonbackend/app/repositories/blog.pybackend/app/routers/github_link.pybackend/app/services/tasks/worker.pybackend/tests/conftest.pybackend/tests/test_delete_documents.pybackend/tests/test_endpoints.pyfrontend/src/components/forms/CareerFormEditors/CareerExperienceEditor.tsxfrontend/src/components/forms/CareerFormEditors/ClientEditor.tsxfrontend/src/components/github-link/GitHubLinkDashboard.tsxfrontend/src/constants/messages.tsfrontend/src/hooks/blog/useBlogAccountManager.test.tsfrontend/src/hooks/blog/useBlogAccountManager.tsinfra/environments/dev/main.tfinfra/environments/dev/main.tfinfra/environments/dev/terraform.tfvarsinfra/environments/dev/versions.tfinfra/environments/dev/versions.tfinfra/environments/prod/main.tfinfra/environments/prod/main.tfinfra/environments/prod/terraform.tfvarsinfra/environments/prod/versions.tfinfra/environments/prod/versions.tfinfra/environments/shared/main.tfinfra/environments/shared/variables.tfinfra/environments/shared/versions.tfinfra/environments/stg/main.tfinfra/environments/stg/main.tfinfra/environments/stg/terraform.tfvarsinfra/environments/stg/versions.tfinfra/environments/stg/versions.tfscripts/lint-frontend-messages.sh
✅ Files skipped from review due to trivial changes (7)
- infra/environments/stg/terraform.tfvars
- infra/environments/prod/terraform.tfvars
- infra/environments/prod/versions.tf
- .jscpd.json
- infra/environments/stg/versions.tf
- infra/environments/prod/main.tf
- frontend/src/hooks/blog/useBlogAccountManager.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- backend/tests/test_endpoints.py
- frontend/src/components/github-link/GitHubLinkDashboard.tsx
概要
職務経歴書(Resume)を IT エンジニア以外の経歴にも対応させた。在籍企業を「非IT企業」としてマークすると取引先/プロジェクトの代わりに自由記述の「詳細」を入力でき、在籍中の「休暇」(育児/介護/留学等)を取引先と並べて期間・詳細付きで記述できる。あわせて資本金の単位を企業ごとに選択可能にした(従来は「千万円」固定)。
同コミットには GitHub 連携ダッシュボードのコントリビューション可視化(緑の四角ヒートマップ)と連携UI刷新も含まれる(詳細は
report/pr_github_contributions.md)。背景・目的
従来の職務経歴書は「IT企業の取引先 → プロジェクト」という構造に固定されており、次のケースを表現できなかった:
変更内容
Backend
models/resume.py)ResumeExperienceにcapital_unit(既定「千万円」)/is_it_company(既定 True)/description(非IT時の詳細)を追加ResumeClientにis_vacation/vacation_start_date/vacation_end_date/vacation_is_current/vacation_descriptionを追加。vacation_start_date/vacation_end_dateはformat_year_monthを通す read プロパティでYYYY-MM文字列化(NULL は"")alembic_migrations/versions/)0039_add_capital_unit:capital_unitを追加(既存行の後方互換としてserver_default="千万円")0040_add_resume_non_it_and_vacation: 非IT フラグ/詳細・休暇カラム群を追加(is_it_companyは既存行を IT 企業前提としてserver_default=1、is_vacationは0)op.add_column、downgrade の列削除は ALTER/DROP 非対応のためbatch_alter_table(テーブル再作成)schemas/resume.py)Experienceにcapital_unit: Literal["万円","百万円","千万円","億円"]/is_it_company/descriptionを追加Clientに休暇フィールド群を追加し、validate_vacation_dates(mode="after")で休暇時のみ開始年月必須・継続中なら end を""に正規化・end >= startを検証(Experience.validate_datesと同契約)repositories/resume.py): 新フィールドを payload から読み出して行を構築。休暇期間はparse_year_monthで日付化markdown/generators/resume_generator.py): 資本金は{cap}{capital_unit}を出力。非IT企業は取引先ループをスキップし「詳細」を出力。休暇エントリは「#### 休暇」+ 期間 + 詳細pdf/generators/resume_generator.py+templates/resume.css):_build_vacation_htmlを追加。非IT企業は.company-detailに詳細を表示、休暇は.vacationブロックで表示。資本金単位を反映Frontend
types.ts,formTypes.ts,constants.ts)CapitalUnit型(backendLiteralと手動同期)、CAPITAL_UNITS/DEFAULT_CAPITAL_UNITを追加CareerExperience/CareerClientに新フィールドを追加。blank テンプレートにも初期値を反映forms/CareerFormEditors/CareerExperienceEditor.tsx)CAPITAL_UNITS)を追加formMappers.ts: API レスポンスの新フィールドを?? デフォルトで吸収(後方互換)payloadBuilders.ts: 非IT企業はdescriptionのみ送信し clients を空に、休暇 client はvacation_*のみ送信。事前バリデーション(詳細必須・休暇期間必須・期間整合)を追加constants/messages.ts):EXPERIENCE_DESCRIPTION_REQUIRED/VACATION_START_DATE_REQUIRED/VACATION_END_DATE_REQUIREDをVALIDATION_MESSAGESに追加動作確認
make test-backend/make lint-backendtest_schemas.py(capital_unit / is_it_company / 休暇バリデーション)、test_markdown_generator.py・test_pdf_generator.py(非IT詳細・休暇・資本金単位の出力)、test_endpoints.py、test_contributions.py、test_worker/test_github_link.pymake lint-frontend/make lint-frontend-messages、unit tests(payloadBuilders.test.tsに非IT/休暇の送信・バリデーション、useCareerExperienceMutators.test.ts、ContributionHeatmap.test.tsx、GitHubLinkDashboard.test.tsx)npm run test:e2e(github-link.spec.ts/navigation.spec.ts更新)影響範囲・補足
make migrate)。既存行はserver_defaultで後方互換(全社 IT企業・資本金単位「千万円」・休暇なし扱い)schemas/resume.py↔ frontendtypes.tsの手動同期運用(codegen 未導入)。CapitalUnitの Literal を増減する場合は両方を更新するdescriptionのみ)になるSummary by CodeRabbit
New Features
UI Improvements
Messages