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):
requestOverageApprovalrecomputes authoritative worked/contracted/overage for the week, stores anapproval_requestsrow 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 groupspending_approvaltime entries by contractor+assignment+week. - Approve (public, no login):
/approve/[token]validates the token (hash, pending, not expired) and shows the week summary;approveOveragere-validates, marks the requestapproved(capturing IP), and flips that week'spending_approvalentries toapproved. 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_requestsare guarded before use.