test(05): persist human verification items as UAT
This commit is contained in:
parent
3b582ace53
commit
a7759e3029
2 changed files with 281 additions and 0 deletions
74
.planning/phases/05-finance-restyle/05-HUMAN-UAT.md
Normal file
74
.planning/phases/05-finance-restyle/05-HUMAN-UAT.md
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
status: partial
|
||||
phase: 05-finance-restyle
|
||||
source: [05-VERIFICATION.md]
|
||||
started: 2026-05-03T00:00:00Z
|
||||
updated: 2026-05-03T00:00:00Z
|
||||
---
|
||||
|
||||
## Current Test
|
||||
|
||||
[awaiting human testing — needs Docker rebuild first to make new code live]
|
||||
|
||||
## Tests
|
||||
|
||||
### 1. Skeleton on initial load
|
||||
expected: |
|
||||
Open `/mobile/finance` on iPhone 15 Pro (393×852). Before data arrives, FinanceSkeleton shows: 2×2 grid of skeleton tiles + 3-cell aging row + skeleton rows. Animation visible.
|
||||
result: [pending]
|
||||
|
||||
### 2. KPI 2×2 grid + Overdue accent
|
||||
expected: |
|
||||
Four cards: Total AR / Current / Overdue / Paid MTD. Currency rendered with zero decimals via fmt$. Overdue card has destructive (red) left border when value > 0.
|
||||
result: [pending]
|
||||
|
||||
### 3. No horizontal overflow at 360px
|
||||
expected: |
|
||||
Resize viewport to exactly 360px wide. No content scrolls horizontally. Currency values truncate or wrap rather than push the layout.
|
||||
result: [pending]
|
||||
|
||||
### 4. Open Invoices collapsible + tab filter
|
||||
expected: |
|
||||
Tap "Open Invoices" — Collapsible expands. Tab toggle "Open / Overdue" filters the list. Each row uses FinanceRow with `text-destructive` amount tone for overdue.
|
||||
result: [pending]
|
||||
|
||||
### 5. Recent Payments empty state + positive tone
|
||||
expected: |
|
||||
Tap "Recent Payments" — Collapsible expands. Payment amounts use `text-emerald-600` (positive tone). When list is empty, "—" em-dash renders.
|
||||
result: [pending]
|
||||
|
||||
### 6. No charts on Monthly Revenue
|
||||
expected: |
|
||||
Monthly Revenue section renders as a stacked list (Month → revenue → count rows). No bars, no canvas, no chart anywhere on the page.
|
||||
result: [pending]
|
||||
|
||||
### 7. QBO sync banner + toast messages
|
||||
expected: |
|
||||
Tap "Sync QBO" button. Sync banner appears with progress copy. On success: `toast.success("QuickBooks sync complete")` fires. On failure: `toast.error("Sync failed — check QBO connection")` fires.
|
||||
result: [pending]
|
||||
|
||||
### 8. Bottom nav active tab still works
|
||||
expected: |
|
||||
Bottom nav "Finance" tab uses `text-primary` when on this page. Tapping other tabs navigates correctly. (Phase 2 regression check.)
|
||||
result: [pending]
|
||||
|
||||
### 9. Error retry card
|
||||
expected: |
|
||||
Force a fetch error (block network). Page renders destructive-tinted card with "Failed to load finance data" + Retry button. Tapping Retry re-fetches.
|
||||
result: [pending]
|
||||
|
||||
### 10. Empty state — no outstanding AR
|
||||
expected: |
|
||||
When `total_ar === 0`, "No outstanding AR" message renders in place of the AR cards. (Verify against test data or in dev QBO.)
|
||||
result: [pending]
|
||||
|
||||
## Summary
|
||||
|
||||
total: 10
|
||||
passed: 0
|
||||
issues: 0
|
||||
pending: 10
|
||||
skipped: 0
|
||||
blocked: 0
|
||||
|
||||
## Gaps
|
||||
207
.planning/phases/05-finance-restyle/05-VERIFICATION.md
Normal file
207
.planning/phases/05-finance-restyle/05-VERIFICATION.md
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
---
|
||||
phase: 05-finance-restyle
|
||||
verified: 2026-05-04T00:00:24Z
|
||||
status: human_needed
|
||||
score: 8/8 must-haves verified
|
||||
human_verification:
|
||||
- test: "Initial load skeleton — FinanceSkeleton renders for the loading window: 2x2 KPI tile skeletons + 3-cell aging row skeleton + two 3-row list skeletons. No flash of unstyled content. (D-17)"
|
||||
expected: "Skeleton layout visible before data loads, no unstyled flash"
|
||||
why_human: "Cannot observe skeleton timing or render order without a running browser"
|
||||
- test: "KPI grid — 2x2 tiles render: Total AR / Current / Overdue (destructive left border via tone=attention) / Paid MTD. Paid MTD caption shows 'YTD: $X,XXX'. Currency renders with zero decimals. (D-01, D-02, D-05)"
|
||||
expected: "Four tiles visible, Overdue has red left border, all amounts integer-formatted"
|
||||
why_human: "Visual appearance of Card borders and typography scale requires viewport"
|
||||
- test: "Aging row — visible only when overdue > 0. Three cells with amber/orange/destructive tones. No horizontal scroll at 360px. (D-08)"
|
||||
expected: "3-cell grid fits without overflow at 360px width"
|
||||
why_human: "Overflow at narrow viewport requires browser DevTools"
|
||||
- test: "Open Invoices Collapsible — collapsed by default. Tap chevron to open. Tab toggle switches between Overdue and Current without refetch. Overdue amounts in text-destructive. (D-06, D-15, D-16)"
|
||||
expected: "Collapsible opens/closes, tabs filter live, row amounts color correctly"
|
||||
why_human: "Interaction behavior and color rendering require browser"
|
||||
- test: "Recent Payments Collapsible — collapsed by default. Payment amounts in text-emerald-600. Empty payments body shows em-dash. (D-06, D-19)"
|
||||
expected: "Payments open/close, amounts green, empty state shows dash"
|
||||
why_human: "Interaction and color require browser"
|
||||
- test: "Monthly Revenue — stacked list, NO chart. Each row: month left, revenue + invoice count right. No bars. (D-09)"
|
||||
expected: "Divide-y list with no chart elements"
|
||||
why_human: "Absence of chart bars vs legitimate layout elements requires visual check"
|
||||
- test: "Sync flow — tap 'Sync QBO'. Banner appears with copy matching UI-SPEC ('Starting sync...' etc.). On success: sonner toast 'QuickBooks sync complete'. On failure: toast 'Sync failed — check QBO connection'. (D-14, D-17, D-18)"
|
||||
expected: "Banner text matches spec, toasts fire on completion/failure"
|
||||
why_human: "Live sync interaction with QBO requires running app"
|
||||
- test: "No horizontal overflow at 360px viewport width — drag DevTools to 360px. No section overflows. (D-12)"
|
||||
expected: "All sections fit within 360px; names truncate, grids wrap correctly"
|
||||
why_human: "Overflow behavior requires viewport at exact 360px width"
|
||||
- test: "No page H1 — shell HeaderBar (Wulf mark + Bell + avatar) is the only chrome above the KPI grid. (D-23)"
|
||||
expected: "No 'Finance' heading rendered in page body"
|
||||
why_human: "Absence of heading is best confirmed visually in context of full layout"
|
||||
- test: "Bottom nav Finance tab active state — Finance icon shows text-primary when on /mobile/finance. (pre-existing Phase 2 behavior)"
|
||||
expected: "Finance tab highlighted when on finance page"
|
||||
why_human: "Active state detection requires running routing"
|
||||
---
|
||||
|
||||
# Phase 5: Finance Restyle Verification Report
|
||||
|
||||
**Phase Goal:** A manager reading AR / invoice / payment status on a phone sees properly spaced cards and stacked lists instead of squished wide tables — same data, new shell.
|
||||
**Verified:** 2026-05-04T00:00:24Z
|
||||
**Status:** human_needed
|
||||
**Re-verification:** No — initial verification
|
||||
|
||||
## Goal Achievement
|
||||
|
||||
### Observable Truths
|
||||
|
||||
| # | Truth | Status | Evidence |
|
||||
|---|-------|--------|----------|
|
||||
| 1 | 2-line stacked FinanceRow component rendered by both invoice rows and payment rows | ✓ VERIFIED | `FinanceRow.tsx` exists, exports `FinanceRow` + `FinanceRowProps`; `<FinanceRow>` used 2x in page.tsx (invoices + payments collapsibles) |
|
||||
| 2 | FinanceSkeleton renders 4 KPI tile skeletons + 1 aging row + 2x 3-row list skeletons | ✓ VERIFIED | `FinanceSkeleton.tsx` confirmed: `grid-cols-2` (4x h-20), `grid-cols-3` (3x h-16), 2 sets of 3 h-4 row skeletons via local const |
|
||||
| 3 | `/mobile/finance` opens directly to 4 KPI tiles (2x2 grid) using KpiCardMobile — no Finance H1 | ✓ VERIFIED | 8 `<KpiCardMobile` usages (4 in normal branch + 4 in isEmpty branch); no `<h1` with Finance text; `tone="attention"` on Overdue tile |
|
||||
| 4 | Overdue Aging renders as 3-cell row with locked semantic colors — visible only when overdue_balance > 0 | ✓ VERIFIED | `text-amber-600`, `text-orange-600`, `text-destructive` present; gated on `summary.overdue_balance > 0` |
|
||||
| 5 | Open Invoices and Recent Payments use shadcn Collapsible with FinanceRow rows in 2-line stacked layout | ✓ VERIFIED | `<Collapsible>`, `<CollapsibleTrigger>`, `<CollapsibleContent>` present; `<FinanceRow` used in both sections |
|
||||
| 6 | Monthly revenue as stacked list (no chart) | ✓ VERIFIED | No `recharts` import; no `items-end`/`h-full group` bar-chart remnants; `divide-y` list with month/revenue/count rows |
|
||||
| 7 | Initial load shows FinanceSkeleton; failure shows destructive retry card; sync fires toast.success/toast.error | ✓ VERIFIED | `if (loading && !data) return <FinanceSkeleton />`; destructive retry card with "Failed to load finance data" + Retry button; `toast.success("QuickBooks sync complete")` and `toast.error(...)` both present |
|
||||
| 8 | Empty state renders when total_ar === 0 AND open_invoices.length === 0 | ✓ VERIFIED | `isEmpty` computed; renders "No outstanding AR" card; KPI grid still renders in isEmpty branch |
|
||||
|
||||
**Score:** 8/8 truths verified
|
||||
|
||||
### Required Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|----------|----------|--------|---------|
|
||||
| `components/mobile/FinanceRow.tsx` | Reusable 2-line stacked row (D-06) | ✓ VERIFIED | Exists; exports `FinanceRowProps` interface + `FinanceRow` function; `px-4 py-3`, `hover:bg-muted/50`, `text-sm font-semibold` line 1, `text-xs text-muted-foreground` line 2; `amountTone` supports destructive/positive/default; no priority stripe; no interactive handlers |
|
||||
| `components/mobile/FinanceSkeleton.tsx` | Initial-load skeleton matching final layout (D-17) | ✓ VERIFIED | Exists; no-prop export; imports `Skeleton` from `@/components/ui/skeleton` (not Card); outer `px-4 py-4 space-y-6`; `grid-cols-2 gap-3` with `h-20`; `grid-cols-3 gap-2` with `h-16`; two 3-row list blocks with `h-4` |
|
||||
| `app/mobile/finance/page.tsx` | Restyled mobile Finance page (FIN-01, FIN-02) | ✓ VERIFIED | Rewrote 309→391 lines; all 4 key imports present; KpiCardMobile (8x across both branches), FinanceRow (2x), FinanceSkeleton, Collapsible; no recharts; no raw red/yellow/green palette; no font-medium/font-bold; all locked decisions applied |
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
| From | To | Via | Status | Details |
|
||||
|------|----|-----|--------|---------|
|
||||
| `app/mobile/finance/page.tsx` | `components/mobile/KpiCardMobile.tsx` | `import { KpiCardMobile }` | ✓ WIRED | Import + 8 JSX usages confirmed |
|
||||
| `app/mobile/finance/page.tsx` | `components/mobile/FinanceRow.tsx` | `import { FinanceRow }` | ✓ WIRED | Import + 2 JSX usages (invoices + payments lists) |
|
||||
| `app/mobile/finance/page.tsx` | `components/mobile/FinanceSkeleton.tsx` | `import { FinanceSkeleton }` | ✓ WIRED | Import + usage in `if (loading && !data)` branch |
|
||||
| `app/mobile/finance/page.tsx` | `components/ui/collapsible.tsx` | `import { Collapsible, CollapsibleTrigger, CollapsibleContent }` | ✓ WIRED | Import + 2 Collapsible sections (invoices + payments) |
|
||||
| `app/mobile/finance/page.tsx` | `/api/mobile/finance` | `fetch('/api/mobile/finance')` in `load()` | ✓ WIRED | Fetch present; `setData(await r.json())` wires response to state |
|
||||
| `components/mobile/FinanceSkeleton.tsx` | `components/ui/skeleton.tsx` | `import { Skeleton }` | ✓ WIRED | Import confirmed; Skeleton used for all placeholder shapes |
|
||||
|
||||
### Data-Flow Trace (Level 4)
|
||||
|
||||
| Artifact | Data Variable | Source | Produces Real Data | Status |
|
||||
|----------|--------------|--------|-------------------|--------|
|
||||
| `app/mobile/finance/page.tsx` | `data` (FinanceData) | `fetch('/api/mobile/finance')` → `setData(await r.json())` | Yes — API route runs 6 parallel `postgresClient.query()` calls against `qbo_invoices`, `qbo_payments` | ✓ FLOWING |
|
||||
| `app/api/mobile/finance/route.ts` | DB queries | `postgresClient.query(...)` x6 | Yes — SUM/COUNT aggregates from `qbo_invoices`, JOIN with `qbo_payments`, returns parsed numeric values | ✓ FLOWING |
|
||||
|
||||
### Behavioral Spot-Checks
|
||||
|
||||
Step 7b SKIPPED for visual UI components — output is rendered DOM, not testable via CLI without a running server and browser.
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
| Requirement | Source Plan | Description | Status | Evidence |
|
||||
|-------------|------------|-------------|--------|----------|
|
||||
| FIN-01 | 05-01, 05-02 | Page restyled with new Card and typography scale; spacing fixed for small phones | ✓ SATISFIED | KpiCardMobile 2x2 grid adopted; `text-sm`/`text-xs`/`text-[10px]` typography scale; `px-4` sections; `truncate` on names; `overflow-hidden` on containers; no raw color palette violations |
|
||||
| FIN-02 | 05-01, 05-02 | Wide tables replaced with stacked lists; no new data, no new sections | ✓ SATISFIED | FinanceRow stacked rows (not `<table>`); Top Customers stacked list with proportion bar; Monthly Revenue `divide-y` list; no new API routes; no new data sources; same `FinanceData` interface |
|
||||
|
||||
### Anti-Patterns Found
|
||||
|
||||
| File | Line | Pattern | Severity | Impact |
|
||||
|------|------|---------|----------|--------|
|
||||
| `components/mobile/KpiCardMobile.tsx` | 34 | `font-bold` on KPI value `<p>` | ℹ️ Info | Pre-existing Phase 3 component — NOT modified in Phase 5. D-03 constraint applies to Phase 5 new/modified files. KpiCardMobile was explicitly locked as "reuse, do not modify" (D-01). No action required. |
|
||||
|
||||
No blockers found. The single informational note is a pre-existing Phase 3 pattern outside Phase 5 scope.
|
||||
|
||||
### Locked Decisions Coverage (D-01 through D-23)
|
||||
|
||||
| Decision | Honored | Evidence |
|
||||
|----------|---------|----------|
|
||||
| D-01: Card adoption for KPI tiles | ✓ | 4 `KpiCardMobile` tiles in 2x2 grid |
|
||||
| D-02: KPI scale + Revenue YTD → Paid MTD caption | ✓ | `caption={\`YTD: ${fmt$(summary.paid_ytd)}\`}` |
|
||||
| D-03: Two font weights only (semibold/normal) | ✓ | No `font-medium`, no `font-bold` in page.tsx, FinanceRow.tsx, FinanceSkeleton.tsx |
|
||||
| D-04: Three size tiers | ✓ | `text-sm`, `text-xs`, `text-[10px]` throughout |
|
||||
| D-05: fmt$() zero decimals | ✓ | `maximumFractionDigits: 0` preserved verbatim |
|
||||
| D-06: Stacked 2-line rows via FinanceRow | ✓ | FinanceRow used for invoices + payments |
|
||||
| D-07: Top customers stacked list | ✓ | Inline stacked list with proportion bar |
|
||||
| D-08: Aging 3-cell locked palette | ✓ | amber-600, orange-600, text-destructive; no raw red/yellow |
|
||||
| D-09: Monthly revenue as stacked list | ✓ | divide-y list; no recharts import |
|
||||
| D-10: Page container spacing | ✓ | `pb-4 space-y-6` outer; each section owns `px-4` |
|
||||
| D-11: Row internal spacing | ✓ | `gap-3`/`gap-2` in grids, `divide-y` between rows |
|
||||
| D-12: No overflow at 360px | ? | Requires human verification |
|
||||
| D-13: Section headers text-sm font-semibold | ✓ | `<h2 className="text-sm font-semibold mb-2">` on all section headers |
|
||||
| D-14: Header controls with aria-labels | ✓ | `aria-label="Refresh finance data"` + `aria-label="Sync from QuickBooks"` |
|
||||
| D-15: Tab default overdue, no URL sync | ✓ | `useState<'open' \| 'overdue'>('overdue')`; no URL interaction |
|
||||
| D-16: Collapsibles use shadcn Collapsible | ✓ | `<Collapsible>`, `<CollapsibleTrigger>`, `<CollapsibleContent>` for both sections |
|
||||
| D-17: Sync progress banner + FinanceSkeleton | ✓ | `if (loading && !data) return <FinanceSkeleton />`; syncMsg banner with animate-spin |
|
||||
| D-18: Error state destructive retry card | ✓ | Destructive-tinted card with "Failed to load finance data" + Retry button |
|
||||
| D-19: Empty state + empty payments em-dash | ✓ | `isEmpty` gate renders "No outstanding AR"; `"—"` in empty payments body |
|
||||
| D-20: API route unchanged | ✓ | `git diff --name-only HEAD app/api/mobile/finance/route.ts` returns 0 lines |
|
||||
| D-21: FinanceData interface unchanged | ✓ | Interface preserved verbatim; toast.error in load() + syncAndRefresh() catch blocks |
|
||||
| D-22: No new sections/sources | ✓ | Only `fetch('/api/mobile/finance')` and `fetch('/api/qbo/sync')` (pre-existing) |
|
||||
| D-23: No page H1; layout.tsx untouched | ✓ | No `<h1>Finance`; `git diff --name-only HEAD app/mobile/layout.tsx` returns 0 lines |
|
||||
|
||||
### Regression Checks
|
||||
|
||||
| Check | Status | Evidence |
|
||||
|-------|--------|----------|
|
||||
| `app/mobile/nav/` does NOT exist | ✓ PASS | `ls app/mobile/nav/` returns error (directory absent) |
|
||||
| CLAUDE.md ~499 lines | ✓ PASS | `wc -l CLAUDE.md` returns 499 |
|
||||
| Phase 1-4 components intact | ✓ PASS | BottomNav, HeaderBar, MoreDrawer, NeedsAttentionStrip, TicketFilterStrip, TicketRowSkeleton, WorkerStatusRow all present |
|
||||
| `app/mobile/layout.tsx` unchanged | ✓ PASS | 0 lines in `git diff --name-only HEAD app/mobile/layout.tsx` |
|
||||
| `components/mobile/KpiCardMobile.tsx` unchanged | ✓ PASS | Last commit on KpiCardMobile is Phase 4 restore (`9658640`) |
|
||||
|
||||
### Human Verification Required
|
||||
|
||||
The following items require a running browser at phone-width viewport to verify. All automated checks pass; these represent the visual/interactive contract that cannot be confirmed statically.
|
||||
|
||||
#### 1. Skeleton loading state visual
|
||||
|
||||
**Test:** Load `/mobile/finance` on a slow connection or with DB delayed.
|
||||
**Expected:** FinanceSkeleton renders — 2x2 KPI tiles + 3-cell aging row + two 3-row list blocks. No flash of unstyled content.
|
||||
**Why human:** Skeleton render timing and visual shape require browser observation.
|
||||
|
||||
#### 2. KPI grid appearance
|
||||
|
||||
**Test:** View the 4 KPI tiles on an iPhone 15 Pro (393px) and 360px width.
|
||||
**Expected:** 2x2 grid; Overdue tile has red left border (`border-l-destructive`); all amounts integer-formatted (no decimals); Paid MTD caption shows "YTD: $X,XXX".
|
||||
**Why human:** Card border color, grid layout, and caption formatting require viewport.
|
||||
|
||||
#### 3. No horizontal overflow at 360px
|
||||
|
||||
**Test:** Drag DevTools to 360px width. Scroll through all sections.
|
||||
**Expected:** All sections fit within viewport — aging 3-column grid, customer names truncate, list rows wrap.
|
||||
**Why human:** Overflow detection at exact 360px requires DevTools.
|
||||
|
||||
#### 4. Open Invoices Collapsible interaction
|
||||
|
||||
**Test:** Tap the Open Invoices collapsible header to open. Toggle between Overdue and Current tabs.
|
||||
**Expected:** Collapsible opens/closes; tabs filter the list in place without refetch; overdue amounts render in red (text-destructive); tab line-indicator animates.
|
||||
**Why human:** Interaction flow and color rendering require browser.
|
||||
|
||||
#### 5. Recent Payments Collapsible + empty state
|
||||
|
||||
**Test:** Tap the Recent Payments collapsible.
|
||||
**Expected:** Opens to list of payments with amounts in emerald-600 (green). If no payments, shows "—" row.
|
||||
**Why human:** emerald-600 vs other greens requires visual confirmation.
|
||||
|
||||
#### 6. Monthly Revenue — no chart
|
||||
|
||||
**Test:** Scroll to Monthly Revenue section.
|
||||
**Expected:** Plain stacked list rows (month / revenue / count). No bars, no chart elements.
|
||||
**Why human:** Absence of chart bars vs border-bottom dividers requires visual scan.
|
||||
|
||||
#### 7. Sync flow + toast messages
|
||||
|
||||
**Test:** Tap "Sync QBO" button.
|
||||
**Expected:** Banner shows progression ("Starting sync…" → "Syncing with QuickBooks…" → "Refreshing data…"). On success: sonner toast "QuickBooks sync complete". Break connection, retry: toast "Sync failed — check QBO connection".
|
||||
**Why human:** Live sync interaction requires running app + network manipulation.
|
||||
|
||||
#### 8. Bottom nav Finance active tab
|
||||
|
||||
**Test:** Navigate to `/mobile/finance`.
|
||||
**Expected:** Finance (DollarSign) icon in bottom nav uses `text-primary`; other tabs use `text-muted-foreground`.
|
||||
**Why human:** Active routing state and color rendering require browser.
|
||||
|
||||
### Gaps Summary
|
||||
|
||||
No gaps found. All 8 observable truths verified, all artifacts exist and are substantive, all key links are wired, data flows from DB through API to rendered components. The phase goal — "properly spaced cards and stacked lists instead of squished wide tables" — is fully implemented.
|
||||
|
||||
The 10 human verification items above are residual interactive/visual checks that cannot be confirmed statically. They do not indicate missing implementation but rather runtime behaviors that require a browser to confirm.
|
||||
|
||||
---
|
||||
|
||||
_Verified: 2026-05-04T00:00:24Z_
|
||||
_Verifier: Claude (gsd-verifier)_
|
||||
Loading…
Add table
Add a link
Reference in a new issue