16. Calendar, hour entry, and contractor assignments
Date: 2026-06-06
Status
Accepted
Context
Outsourced contractors log daily hours on a calendar; the entries feed the corrected pay engine and the weekly facility invoice. Hours must show weekly progress against the contracted limit (colour-coded), accept but flag overage, flag implausible single-day totals, and become read-only once a period is locked. Logging requires an active contractor→facility assignment (rate + weekly hours), which had no creation path yet — so this step also adds the admin "assign contractor" flow (versioned assignments per §5.6).
Decision
- Pure calendar logic (
src/lib/calendar, unit-tested): a day cell is coloured by its week's progress (green < 85%, amber 85–<100%, red ≥ 100%/over), plus Monday-week grouping and a single-day anomaly check. Reusessrc/lib/datesUTC math. - Assignments:
createAssignment(admin, service role) writes a versionedcontractor_facility_assignmentsrow — money as integer minor units (hourly_rate_cents,bimonthly_rate_centavos) — and end-dates the prior active assignment for that contractor+facility so history is preserved. Managed from a new admin contractor-detail page (/admin/contractors/[id]). - Hour entry:
upsertTimeEntry(contractor, outsourced only — in-house hours come from Hubstaff) resolves the active assignment, recomputes the Monday–Sunday week total with the new value substituted in to detect overage (status →pending_approval), flags a single-day anomaly (threshold fromsettings, default 16h), and refuses to edit alockedentry. Writes go through the service-role action behind an ownership check (the magic-link overage approval itself is the next step). - UI:
/contractor/calendarrenders a month grid (CalendarBoard, client) with per-week progress, colour cells, anomaly/pending/locked badges, prev/next month navigation, and a single-column day modal with an inline overage warning before save. The board reuses the same pure helpers, so the colour a contractor sees matches the rule the server enforces.
Consequences
- The pay engine now has a real data source; logged hours flow straight into the period-fraction calculation built earlier.
- Overage is detected and marked here but the facility magic-link approval (creating
approval_requests, emailing admin contacts) is deferred to the overage-approval step; until then overage entries simply sit inpending_approval. - In-house admins see the calendar read-only; their hours arrive once the Hubstaff integration lands (still blocked on credentials).
- Live entry can be exercised once a contractor is active with an assignment; build/typecheck/lint and the pure week/anomaly logic are verified.