feat(crewing): Phase 3a — candidates / talent pool (flagged) #66

Merged
shad0w merged 2 commits from feat/crewing-candidates into feat/crewing-requisitions 2026-06-22 18:48:34 +00:00
Owner

Crewing — Phase 3a (Candidates / talent pool)

First slice of Phase 3 (Candidate intake + 7-stage pipeline + onboarding), which ships as stacked sub-PRs — 3a candidates → 3b pipeline → 3c onboarding. Stacks on #65 (Phase 2 requisitions); base branch is feat/crewing-requisitions, so nothing reaches master yet. Behind NEXT_PUBLIC_CREWING_ENABLED (off by default).

What's in

  • Schema (crewing_candidates migration): CrewMember — the talent-pool spine, one row per person kept through CANDIDATE → EMPLOYEE → EX_HAND (CrewStatus); employeeId is assigned only at onboarding (3c), so it's nullable here. CandidateType / CandidateSource enums; currentRankId (rank held) + appliedRankId. CrewAction gains a nullable crewMemberId; CrewActionType += CANDIDATE_ADDED/UPDATED.
  • Actions (crewing/candidates/actions.ts): addCandidate / updateCandidate — guard flag + manage_candidates, write a CrewAction, optional CV upload via buildStorageKey("cv", …) + uploadBuffer. EX_HAND source ⇒ type/status = EX_HAND; an edit never downgrades an EMPLOYEE.
  • Screens: /crewing/candidates (master list — search / source / rank-applied / min-experience filters as removable chips + match count + Clear all; Add-candidate modal) and /crewing/candidates/[id] (profile; the 7-stage pipeline/stepper is 3b). Candidates added to the flag-gated Crewing nav (Manager + MPO).

Tests & docs

  • Integration: candidates.test.ts (7) — add/update, ex-hand derivation, employee no-downgrade, permission gating.
  • type-check clean; full unit (225) + integration (153) suites green.
  • CLAUDE.md "Crewing" section updated with the Phase 3a surface.

Deferred

  • Public careers intake API (A2, §13 open question) — 3a uses the internal Add-candidate modal only; CVs are stored but not parsed.

🤖 Generated with Claude Code


Closes Epic B — Candidate intake (#76).

## Crewing — Phase 3a (Candidates / talent pool) First slice of **Phase 3** (Candidate intake + 7-stage pipeline + onboarding), which ships as **stacked sub-PRs** — 3a candidates → 3b pipeline → 3c onboarding. Stacks on **#65** (Phase 2 requisitions); base branch is `feat/crewing-requisitions`, so nothing reaches `master` yet. Behind `NEXT_PUBLIC_CREWING_ENABLED` (off by default). ### What's in - **Schema** (`crewing_candidates` migration): `CrewMember` — the talent-pool spine, one row per person kept through `CANDIDATE → EMPLOYEE → EX_HAND` (`CrewStatus`); `employeeId` is assigned only at onboarding (3c), so it's nullable here. `CandidateType` / `CandidateSource` enums; `currentRankId` (rank held) + `appliedRankId`. `CrewAction` gains a nullable `crewMemberId`; `CrewActionType += CANDIDATE_ADDED/UPDATED`. - **Actions** (`crewing/candidates/actions.ts`): `addCandidate` / `updateCandidate` — guard flag + `manage_candidates`, write a `CrewAction`, optional CV upload via `buildStorageKey("cv", …)` + `uploadBuffer`. EX_HAND source ⇒ `type/status = EX_HAND`; an edit never downgrades an `EMPLOYEE`. - **Screens**: `/crewing/candidates` (master list — search / source / rank-applied / min-experience filters as removable chips + match count + Clear all; Add-candidate modal) and `/crewing/candidates/[id]` (profile; the 7-stage pipeline/stepper is 3b). **Candidates** added to the flag-gated Crewing nav (Manager + MPO). ### Tests & docs - Integration: `candidates.test.ts` (7) — add/update, ex-hand derivation, employee no-downgrade, permission gating. - `type-check` clean; full unit (225) + integration (153) suites green. - `CLAUDE.md` "Crewing" section updated with the Phase 3a surface. ### Deferred - Public careers intake API (A2, §13 open question) — 3a uses the internal Add-candidate modal only; CVs are stored but not parsed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- Closes **Epic B — Candidate intake** (#76).
shad0w added 1 commit 2026-06-22 12:21:24 +00:00
First slice of Phase 3 (Epics B/C/D shipped as stacked sub-PRs). Adds the
CrewMember talent-pool spine and the Candidates screens. Behind
NEXT_PUBLIC_CREWING_ENABLED; production unchanged. Stacks on the requisitions
branch (Phase 2).

What's in
- Schema (crewing_candidates migration): CrewMember (spine) + CrewStatus,
  CandidateType, CandidateSource enums; CrewAction gains a nullable crewMemberId;
  CrewActionType += CANDIDATE_ADDED/UPDATED. employeeId is assigned at onboarding
  (3c), so it's nullable here.
- Actions (crewing/candidates/actions.ts): addCandidate / updateCandidate —
  guard flag + manage_candidates, write a CrewAction, optional CV upload via
  buildStorageKey("cv", …) + uploadBuffer (no parsing — A2 deferred). EX_HAND
  source ⇒ type/status EX_HAND; edits never downgrade an EMPLOYEE.
- Screens: /crewing/candidates (master list with search/source/rank-applied/
  min-experience filters as removable chips + match count + Clear all; Add-candidate
  modal) and /crewing/candidates/[id] (profile; pipeline stepper is 3b). Candidates
  added to the flag-gated Crewing nav (Manager + MPO).

Tests & docs
- Integration: candidates.test.ts (7) — add/update, ex-hand derivation, employee
  no-downgrade, permission gating. type-check clean; full unit (225) + integration
  (153) suites green.
- CLAUDE.md "Crewing" section updated with the Phase 3a surface.

Deferred: public careers intake API (A2, §13 open question); CV parsing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shad0w force-pushed feat/crewing-candidates from f3ce2d5da2 to be6db075dc 2026-06-22 12:53:04 +00:00 Compare
shad0w added 1 commit 2026-06-22 18:48:15 +00:00
Merge branch 'feat/crewing-requisitions' into feat/crewing-candidates
All checks were successful
PR checks / checks (pull_request) Successful in 37s
PR checks / integration (pull_request) Successful in 27s
136cb798f5
shad0w force-pushed feat/crewing-candidates from 136cb798f5 to be6db075dc 2026-06-22 18:48:25 +00:00 Compare
shad0w merged commit a89440d6dd into feat/crewing-requisitions 2026-06-22 18:48:34 +00:00
Sign in to join this conversation.
No description provided.