feat(crewing): Phase 4b — leave & attendance (flagged) #70

Merged
shad0w merged 3 commits from feat/crewing-leave-attendance into feat/crewing-crew-records 2026-06-22 18:51:47 +00:00
Owner

Crewing — Phase 4b (Leave & attendance)

Second slice of Phase 4 (4a records → 4b leave/attendance → 4c sign-off). Stacks on #69 (4a crew records); base feat/crewing-crew-records, so nothing reaches master yet. Behind NEXT_PUBLIC_CREWING_ENABLED.

What's in

  • Schema: LeaveRequest (LeaveType/LeaveStatus) + Attendance (AttendanceStatus, unique per assignment+date) on CrewAssignment; VesselRankRequirement{vesselId,rankId,minStrength}; new CrewActionTypes.
  • Leave (R1): site staff apply on behalf (apply_leave); the Manager decides (decide_leave) → assignment ON_LEAVE; MPO has no leave role. Also in the central /approvals queue (§8.13 "Leave" kind, inline Approve/Decline). Notification LEAVE_FOR_APPROVAL.
  • Clash auto-backfill (R6, Option A): lib/leave-clash.ts flags a clash when approving a leave would drop active same-rank cover over the window below the configured VesselRankRequirement.minStrength (default 1 when unconfigured) → auto-raises a LEAVE requisition via the Phase-2 autoRaiseRequisition.
  • Attendance (R5): daily month calendar — site staff record (record_attendance), Manager views only (view_attendance), MPO neither. saveAttendance bulk-upserts dirty cells.
  • Screens: /crewing/leave + /crewing/attendance; Leave + Attendance added to the flag-gated nav (Manager + Site staff).

Tests & docs

  • Integration: leave-attendance.test.ts (8) — apply/decide, clash auto-raise (default + configured strength) and no-raise-when-cover-remains, MPO/Manager attendance lockout, permission gating.
  • type-check clean; full unit (240) + integration (183) green.
  • CLAUDE.md updated; wiki §12 status note bumped.

Follow-up (next PR)

The office UI to manage VesselRankRequirement, Manager direct crew placement (no requisition), and Admin crew CRUD land in a stacked crewing-admin PR behind a new manage_crew permission.

🤖 Generated with Claude Code


Closes Epic G — Leave & attendance (#81).

## Crewing — Phase 4b (Leave & attendance) Second slice of **Phase 4** (4a records → **4b leave/attendance** → 4c sign-off). Stacks on **#69** (4a crew records); base `feat/crewing-crew-records`, so nothing reaches `master` yet. Behind `NEXT_PUBLIC_CREWING_ENABLED`. ### What's in - **Schema:** `LeaveRequest` (`LeaveType`/`LeaveStatus`) + `Attendance` (`AttendanceStatus`, unique per assignment+date) on `CrewAssignment`; `VesselRankRequirement{vesselId,rankId,minStrength}`; new `CrewActionType`s. - **Leave (R1):** site staff **apply on behalf** (`apply_leave`); the **Manager decides** (`decide_leave`) → assignment `ON_LEAVE`; **MPO has no leave role**. Also in the central `/approvals` queue (§8.13 "Leave" kind, inline Approve/Decline). Notification `LEAVE_FOR_APPROVAL`. - **Clash auto-backfill (R6, Option A):** `lib/leave-clash.ts` flags a clash when approving a leave would drop active same-rank cover over the window **below the configured `VesselRankRequirement.minStrength`** (default **1** when unconfigured) → auto-raises a `LEAVE` requisition via the Phase-2 `autoRaiseRequisition`. - **Attendance (R5):** daily month calendar — **site staff record** (`record_attendance`), Manager **views only** (`view_attendance`), **MPO neither**. `saveAttendance` bulk-upserts dirty cells. - **Screens:** `/crewing/leave` + `/crewing/attendance`; **Leave** + **Attendance** added to the flag-gated nav (Manager + Site staff). ### Tests & docs - Integration: `leave-attendance.test.ts` (8) — apply/decide, **clash auto-raise (default + configured strength)** and no-raise-when-cover-remains, MPO/Manager attendance lockout, permission gating. - `type-check` clean; full unit (240) + integration (183) green. - `CLAUDE.md` updated; wiki §12 status note bumped. ### Follow-up (next PR) The office UI to manage `VesselRankRequirement`, **Manager direct crew placement** (no requisition), and **Admin crew CRUD** land in a stacked `crewing-admin` PR behind a new `manage_crew` permission. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- Closes **Epic G — Leave & attendance** (#81).
shad0w added 2 commits 2026-06-22 15:44:47 +00:00
Second slice of Phase 4 (stacked on 4a crew records). Leave (site-applied,
Manager-decided) with clash auto-backfill, and the daily attendance calendar,
per Crewing-Implementation-Spec §5.3/§8.9–8.10. Behind NEXT_PUBLIC_CREWING_ENABLED.

What's in
- Schema (crewing_leave_attendance migration): LeaveRequest (LeaveType,
  LeaveStatus) + Attendance (AttendanceStatus, unique per assignment+date) on
  CrewAssignment; CrewActionType += LEAVE_APPLIED/LEAVE_DECIDED/ATTENDANCE_RECORDED.
- Leave (R1): site staff apply on behalf (apply_leave); Manager decides
  (decide_leave) → assignment ON_LEAVE; MPO has no leave role. Leave approvals also
  surface in the central /approvals queue (§8.13 Leave kind). Notification
  LEAVE_FOR_APPROVAL.
- Clash auto-backfill (R6): lib/leave-clash.ts, required strength = 1 — approving a
  leave that leaves the vessel with zero active same-rank cover auto-raises a LEAVE
  requisition via the Phase-2 autoRaiseRequisition.
- Attendance (R5): daily month calendar; site staff record (record_attendance),
  Manager views (view_attendance) but cannot edit, MPO neither. saveAttendance
  bulk-upserts dirty cells.
- Screens: /crewing/leave (apply-on-behalf + Manager Approve/Decline) and
  /crewing/attendance (tap-to-cycle calendar + Save). Leave + Attendance added to
  the flag-gated nav (Manager + Site staff).

Tests & docs
- Integration: leave-attendance.test.ts (7) — apply/decide, clash auto-raise (and
  no-raise when cover remains), MPO/Manager attendance lockout, permission gating.
  type-check clean; full unit (240) + integration (182) green.
- CLAUDE.md updated with the Phase 4b surface.

Deferred: the 6-month leave-planner timeline (lightweight list for now); hours/
overtime attendance (A7).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(crewing): clash detection by required strength (Option A)
All checks were successful
PR checks / checks (pull_request) Successful in 38s
PR checks / integration (pull_request) Successful in 28s
040a66488d
Replace the implicit "strength = 1" clash rule with a configurable per-vessel,
per-rank requirement (director decision). Adds VesselRankRequirement
{vesselId, rankId, minStrength} (migration crewing_vessel_rank_requirement) and
reworks lib/leave-clash.ts → leaveCausesClash: a leave approval clashes when the
remaining active same-rank cover over the window would fall below minStrength
(default 1 when unconfigured), auto-raising a LEAVE requisition. The requirement
is managed by the office (manage_crew, admin UI in the follow-up).

- Integration: leave-attendance.test.ts gains a configured-strength case
  (minStrength 2, one remaining → clash). Full unit (240) + integration (183) green.
- CLAUDE.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shad0w added 1 commit 2026-06-22 18:50:50 +00:00
shad0w force-pushed feat/crewing-leave-attendance from b31cfc6ab8 to 040a66488d 2026-06-22 18:50:59 +00:00 Compare
shad0w added 1 commit 2026-06-22 18:51:28 +00:00
Merge branch 'feat/crewing-crew-records' into feat/crewing-leave-attendance
All checks were successful
PR checks / checks (pull_request) Successful in 38s
PR checks / integration (pull_request) Successful in 28s
b0caa9a2dd
shad0w merged commit 33cfc29a35 into feat/crewing-crew-records 2026-06-22 18:51:47 +00:00
Sign in to join this conversation.
No description provided.