Audit-trail & transaction consistency (spec §11 "one transition, one row"):
- Action types: returnSalary/returnSelection/declineInterviewWaiver no longer
mislabel a backward decision as its forward action. New CrewActionType members
SALARY_RETURNED / SELECTION_RETURNED / WAIVER_DECLINED; added RECORD_DELETED;
dropped the unused GATE_FAILED (migration recreates the enum).
- Deletions are audited: deleteDocument / deleteNextOfKin now write a
RECORD_DELETED CrewAction (PII removals are traceable).
- Atomicity: autoRaiseRequisition takes an optional tx so the leave-clash and
sign-off backfills are created INSIDE the approval/sign-off transaction; the
office notification (notifyAutoRaised) fires after commit. An approved leave or
a sign-off can no longer commit without its backfill requisition.
Tests assert the corrected action types (crewing-gates, crew-records) and the
existing clash/sign-off suites still pass with the in-transaction backfill.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- C5 (Epic C5 AC1): advanceStage("verify_competency") now requires ≥1
ReferenceCheck before leaving COMPETENCY_AND_REFERENCES.
- C3 (Epic C3 AC1): verifyDocuments blocks advancement when a mandatory document
for the seat's rank that the candidate holds is expired. Missing-document
presence stays enforced post-onboarding in the verification queue (seafarer
docs aren't collected pre-onboarding) — documented inline + in wiki Tech-Debt.
- C4 (experience): deferred with an inline note (Requisition has no
min-experience field yet — Epic A2 AC1).
applications.test.ts: reference-gate block/pass and expired-required-doc
block/renew-pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- D1: require a Manager-approved SalaryStructure before onboarding; a SELECTED
application with none is now blocked instead of silently binding zero salary
rows.
- D3 AC2: the CREW_ONBOARDED CrewAction records the created IDs
(assignmentId, employeeId, salaryStructureId) in metadata.
- Atomicity: the contract letter is uploaded before the transaction and its row
is created INSIDE it, so onboarding is one atomic write (no half-onboarded
crew member without a contract on failure).
onboarding.test.ts asserts the metadata and the new D1 block (no assignment, the
candidate stays a CANDIDATE).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Clears the self-contained deferrals tracked across phases. Stacks on 5b appraisal.
Behind NEXT_PUBLIC_CREWING_ENABLED.
- SITE_STAFF login on onboard/placement (Epic D follow-up): lib/crew-login.ts
maybeCreateSiteStaffLogin creates a passwordless SITE_STAFF User (sharing the
CRW- employee no., siteId = the assignment's site) when a grantsLogin rank is
onboarded (onboardCandidate) or placed (placeCrew) and the crew member has an
email. No-op otherwise.
- Own-site scoping (Epic E follow-up, §8.7): User.siteId added (migration
crewing_followups); the Crew directory filters a SITE_STAFF user with a home site
to crew whose active assignment is at that site (graceful when unset). The link is
set at login creation.
- PPE / next-of-kin verify gates (Epic F/I follow-up): PpeIssue/NextOfKin gained
verificationStatus + verifiedById; verifyPpe / verifyNextOfKin (verify_site_records,
MPO) + queue sections in /crewing/verification.
Tests & docs
- Integration: crewing-followups.test.ts (6) — login created/skipped by rank+email
(+ siteId set), PPE/NoK verify + reject-reason + already-decided guard + gating.
type-check clean; full unit (245) + integration (211) green (RESEND_API_KEY unset).
- CLAUDE.md updated.
Part of Epic D (#78), Epic E (#79), Epic F (#80), Epic I (#83).
Still deferred (not self-contained): public careers API (A2); Pay-status pay rows (Phase 6).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>