Skip to main content

19. Overage approval (facility magic link)

Date: 2026-06-06

Status

Accepted

Context

When a contractor's week exceeds contracted hours, the entries are flagged pending_approval (Step 7). The facility must authorize the overage before those hours can be invoiced. Facility contacts have no login — approval is a single-use magic link (token, 14-day expiry, single-use), reusing the Step-3 token primitives.

Decision

  • Generate (admin): requestOverageApproval recomputes authoritative worked/contracted/overage for the week, stores an approval_requests row with only the token hash (256-bit CSPRNG), 14-day expiry, and supersedes any prior pending request for the same week. Returns the /approve/<token> path to share (Gmail delivery to facility admin contacts is Step 12). Surfaced from /admin/overage, which groups pending_approval time entries by contractor+assignment+week.
  • Approve (public, no login): /approve/[token] validates the token (hash, pending, not expired) and shows the week summary; approveOverage re-validates, marks the request approved (capturing IP), and flips that week's pending_approval entries to approved. Both the page and action use the service role (the token is the authorization); the route is intentionally outside the proxy gate.

Consequences

  • Closes the loop opened in Step 7: overage hours move pending → approved and become invoiceable. Approved hours feed the same pay/invoice path.
  • Security: only the hash is stored; links are single-use, expiring, and superseded on regenerate; approval captures the approver IP. The public action is gated solely by the unguessable token (by design for no-login facility contacts).
  • One real Hubstaff/email nicety deferred: the magic link is shared manually until Gmail (Step 12). No reject button by design — facility contacts decline by contacting Nightingale (per spec).
  • Nullable FK columns on approval_requests are guarded before use.