Test & follow-up checklist
A running list of things to verify, tests still to write, and tasks that need your input or credentials. Tick items off as you go. Grouped by priority: P1 = money/security correctness, P2 = core flows, P3 = nice-to-have / later.
Automated unit tests already pass: 93 tests across pay, money, dates, calendar, leave, hubstaff, crypto, payroll, invoice, performance, csv, and a real PDF render. Run them with
pnpm exec vitest run(note:pnpm testis watch mode — usevitest run).pnpm typecheck,pnpm lint, andpnpm buildare all green.
A. Manual end-to-end verification (run the app locally)
Run locally: fill api/root .env.local, then pnpm dev; admin signs in via Google SSO
(nightingalepm.com), contractors via the email invite flow.
P1 — Pay engine + period close (Step 10) — highest correctness priority
- Golden pay check: a full-time contractor who works their contracted hours every week of a period is paid exactly the bi-monthly rate — for 15-, 13-, 14-, and 16-day periods. (This is the headline bug-fix; covered by unit tests, but confirm once against a real payslip.)
- Reconcile a closed period against a known-good payslip/spreadsheet — match exact figures, call out any mismatch.
- Preview a closable period → totals are human-meaningful (N contractors × … = ₱total).
- Close the period → batch + per-contractor payments created; that period's entries become
locked;pending_approval(overage) entries are left unlocked; warnings shown. - Discard a prepared run → entries unlock to
submitted, payments + batch deleted, period can be re-closed. - Owner-only: a staff admin cannot preview/close/discard.
- Edit a time entry mid-close window → "hours changed since preview" aborts the close (no partial write).
P1 — Invoice generation (Step 11)
- Visual layout: generate an invoice, download the PDF, and compare side-by-side with
INV-0990/INV-0991— header, Billed-to/Issued-by, line table, totals, and the local + international Wise bank details should match. - Reproduce INV-0990 ($2,440) and INV-0991 ($600) exactly by entering the same contractors/hours/rates.
- Confirm the seeded issuer + Wise receiving details printed on the PDF are correct.
- Bills contracted hours; a line is variance-flagged when worked hours differ from contracted by more than the facility threshold.
- Numbering starts at INV-0992 and increments; a second invoice for the same facility+week is blocked; void frees the week to re-issue.
- Inactive facility and soft-deleted contractor are excluded.
- Download works (signed URL); if a PDF fails to render, Generate PDF recovers it.
- Decide: invoice logo + "Pay online" QR (both currently omitted — see §D).
P1 — Money & security rules
- No money-movement/funding endpoint exists anywhere (grep for
fundTransfer, Wisefund). - SSNs / bank accounts / tax IDs are masked to last-4 in the UI and never logged.
- All money is integer cents/centavos — no float drift (unit tests cover; spot-check totals).
- No secret lives in a
NEXT_PUBLIC_*var; secrets only in.env.local.
P2 — Auth & access
- Admin Google SSO rejects a non-nightingalepm.com account.
- Owner force-logout revokes a live session; per-role session timeout works.
- Contractor invite link is single-use (reuse fails), expires (14d), and is hashed at rest.
- Proxy/middleware blocks unauthenticated access to
/adminand/contractor.
P2 — Onboarding (Step 4)
- 4-step wizard saves; bank account stored as last-4 only; government ID uploads to Storage.
- Submit →
pending_activation; admin activate works only frompending_activation.
P2 — Facilities (Step 5)
- Create facility + contacts; upload a contract PDF; Claude extraction returns terms (redacted), admin confirms; a cross-tenant facility id is rejected.
- AI robustness: a code-fenced Claude response still parses + Zod-validates; a malformed response retries then fails safe.
P2 — Hubstaff (Step 6)
- Webhook with a bad/missing token → 401; valid token ingests.
- CSV import maps members → contractors; idempotent; does not clobber
locked/approved/manualentries; does not revert approved overage to submitted.
P2 — Calendar & hours (Step 7)
- Outsourced contractor logs hours; a week over contracted flips to
pending_approval. - Single-day anomaly (> 16h default) is flagged; a
lockedorapprovedday cannot be edited.
P2 — Leave & holiday (Step 8)
- Submit leave; admin approve/reject; holiday annual cap enforced; a year-spanning holiday request is rejected.
P2 — Overage approval (Step 9)
- Generate a facility magic link; facility approves with no login; link is single-use and
expiring; hours-changed-since-link is rejected; approval flips entries to
approved.
P3 — Dashboards (Steps 16, 17)
- Admin "needs attention" items are accurate (overage, overdue invoices, leave, activation, uninvoiced week, period-to-close); overview tiles correct.
- Contractor estimate matches a hand calculation; payslips + holiday balance correct.
P3 — Performance (Step 18) & Reports (Step 22)
- Traffic lights look right vs known data; recording a review saves a snapshot.
- Each report CSV opens cleanly in Excel/Sheets; amounts correct; variance report matches the invoices; owner-only full export is blocked for staff.
P3 — Timezone / DST
- Period and "closable week/period" boundaries are correct around a DST change and near month ends. (Note: the admin/contractor "today" currently uses UTC; operating tz is America/Denver — decide if the ~1-day edge near midnight matters.)
B. Automated tests still to write (integration lane — needs a local/test Supabase)
- RLS per role/tenant: a contractor cannot read another contractor's rows or another company's data; a contractor reads only invoices/payments they're on.
- Concurrency-safe invoice numbering under parallel
create_facility_invoicecalls (no dup, no skip). - Concurrency-safe payroll close (double-close blocked by the unique constraint + in-tx guard).
- Audit triggers fire on financial/PII writes; RPC paths attribute the actor via
app.actor_id. - Magic-link tokens (invite + overage approve): single-use, expiry, hashed, rate-limited.
- Double-payment guard: re-preparing a period trips it; discard → re-close works.
-
create_facility_invoicetotal-sum assertion rejects a mismatched header total. -
close_payroll_periodTOCTOU guard aborts when entries change after preview.
C. CI gates
- Grep gate failing on any Wise funding endpoint + a
NEXT_PUBLIC_*secret —pnpm guardrails(scripts/guardrails.mjs), wired into lefthook pre-push. -
testscript fixed tovitest run(was watch mode);test:watchadded. - Add a GitHub Actions workflow running
pnpm guardrails && pnpm typecheck && pnpm test && pnpm build(no.github/workflowsexists yet — pre-push covers local only).
D. Credentials & config (unblock the remaining steps)
- Gmail OAuth — Client ID / secret / refresh token / sender mailbox (see chat instructions); unblocks Step 12 + the email check-ingest half of Step 13.
- Wise — API token + business profile id + sandbox token/profile; unblocks Step 14 (draft-only).
- DocuSeal — host + API key + base URL; unblocks embedded signing (Step 4) + renewal re-sign (Step 20).
- OpenWeatherMap — API key; unblocks the contractor dashboard weather card (Step 16).
- Sample check image/PDF — to tune the Claude OCR for Step 13 (like the invoice samples).
- Raise the Anthropic monthly spend limit — re-enables the multi-agent review workflows (currently failing mid-run).
- Enable Supabase "Leaked password protection" (Dashboard → Authentication → settings) — the one outstanding security-advisor warning.
- Decide the invoice logo + pay-online QR target (Wise hosted-pay URL).
- Confirm contractor tax status (1099 / W-8BEN / PH AOR) with an accountant before payroll goes live — determines TIN/tax fields.
- Data-retention legal review (retention periods) before Step 24 policies are set.
E. Steps not yet built
- 12 Gmail (needs creds)
- 13 Check reconciliation (needs a sample check; OCR uses the Anthropic key already on file)
- 14 Wise draft-only payroll (needs creds)
- 15 Interest accrual (needs a manual invoice sent → overdue lifecycle added first)
- 19 Facility relationship (activity log, key dates, alerts) — no input needed
- 20 Contract renewals (alerts + version history; DocuSeal re-sign deferred)
- 21 Offboarding (termination checklists + auto-lock on end date) — no input needed
- 23 Automated jobs (
pg_cron→ route handlers; needs aCRON_SHARED_SECRET+ deploy) - 24 Data retention (soft-delete engine + policies) — no input needed
- 25 Staging & hardening (security review, grep gates, accessibility audit, historical import)
F. Known deferred limitations (documented in ADRs — revisit, not bugs)
- Payroll: a mid-period rate change uses the latest overlapping rate; a multi-facility contractor is paid only their primary assignment; the holiday-cap check has a TOCTOU under concurrent approvals (needs a DB transaction/RPC); tax/statutory deductions are not modeled (gross PHP only).
-
upsertTimeEntryattributes hours to the single newest active assignment (multi-facility contractors need a UI to choose). - Invoices are weekly only for now; logo + pay-online QR omitted until configured.