The soft reset to 77073ba inadvertently staged deletions of all phase 2
and 3 artifacts. This commit restores them from their source commits so
subsequent task commits build on the complete prior-phase foundation:
- components/mobile/{BottomNav,HeaderBar,KpiCardMobile,MoreDrawer,NeedsAttentionStrip,WorkerStatusRow}
- app/mobile/layout.tsx, dashboard/page.tsx, analyzer/page.tsx
- app/api/mobile/dashboard/route.ts
- All .planning/** files from phases 01-04
- CLAUDE.md, app/layout.tsx, app/styles/brand.css, public/manifest.json
4.6 KiB
Phase 4: Tickets Restyle - Discussion Log
Audit trail only. Do not use as input to planning, research, or execution agents. Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
Date: 2026-05-03 Phase: 04-tickets-restyle Mode: auto (--auto --chain) Areas discussed: Filter strip, URL sync, Pagination model, Infinite scroll trigger, List row presentation, Detail page header, Empty/loading states
Filter strip
| Option | Description | Selected |
|---|---|---|
| Always-expanded inline filters | All controls visible by default — more taps reachable | |
Collapsible from shadcn, default collapsed |
TICK-01 spec; phone-first density | ✓ |
| Drawer-based filter sheet | Filters open in a Sheet — feels heavier, more taps |
Auto choice rationale: TICK-01 explicitly says "default collapsed". Spec-locked.
Filter set
| Option | Description | Selected |
|---|---|---|
| Status + priority + queue + assigned-to-me | Spec set | ✓ |
| Add company filter | More flexibility; out of TICK-* scope | |
| Add date range | Could be useful; out of TICK-* scope |
Auto choice rationale: TICK-01 enumerates the four filters. Anything more is scope creep.
URL sync mechanism
| Option | Description | Selected |
|---|---|---|
router.push() on every filter change |
Each filter tweak adds a back-stack entry | |
router.replace() on every filter change |
Filter tweaks don't pollute back stack | ✓ |
Manual history.replaceState() |
Lower-level; loses Next.js rerouting integration |
Auto choice rationale: router.replace() is the App Router idiom for filter UIs. Back button should return to whatever surface the user came from, not 8 filter mutations ago.
Pagination model
| Option | Description | Selected |
|---|---|---|
Keep page-based ?page=N&limit=30 |
Simpler, current behavior | |
Cursor ?cursor=&limit=25 with last_activity_date+id |
Stable under writes; matches triage workflow | ✓ |
| Cursor on created_date+id | Stable but doesn't reflect "recent activity" priority |
Auto choice rationale: TICK-05 mandates cursor-based ~25/page. Choosing last_activity_date DESC, id DESC because managers triage by "what just changed" not "what was created".
Infinite scroll trigger
| Option | Description | Selected |
|---|---|---|
react-intersection-observer library |
Hook abstraction, extra dep | |
Browser-native IntersectionObserver |
No dep, ~20 lines | ✓ |
| Scroll-event listener with throttle | Less precise, more re-renders |
Auto choice rationale: CLAUDE.md prohibits adding new state libraries; native IntersectionObserver is sufficient.
"Load more" fallback
| Option | Description | Selected |
|---|---|---|
| Skip — sentinel handles it | Fails accessibility | |
| Always-rendered focusable button below sentinel | TICK-06 mandates accessibility | ✓ |
| Show only when keyboard navigation detected | Brittle, not robust |
Auto choice rationale: TICK-06 requires the fallback button. Always-rendered keeps it focusable and visible to screen readers.
List row priority indicator
| Option | Description | Selected |
|---|---|---|
| Existing dot (bg-color-N) | Smaller, less prominent | |
Left-edge stripe via border-l-4 |
TICK-03 spec | ✓ |
| Background tint of whole row | Too heavy on phone |
Auto choice rationale: TICK-03 explicitly specifies left-edge stripe.
Detail page header
| Option | Description | Selected |
|---|---|---|
| Refactor full detail page | Out of scope per TICK-07 | |
| Reskin in-page header only (back chevron + breadcrumb + ext link) | TICK-07 spec | ✓ |
Auto choice rationale: TICK-07 explicitly says "header reskinned... body kept largely as-is".
Empty/loading states
| Option | Description | Selected |
|---|---|---|
| Spinner only on load | Janky, no skeleton | |
| Skeleton rows initial + inline spinner subsequent + empty-state messages | Polished, fits design tokens | ✓ |
Auto choice rationale: Standard mobile pattern; existing Skeleton shadcn primitive available.
Auto-resolved scope creep checks
- Bulk actions — flagged and deferred (read-tap-detail is the manager workflow)
- Saved presets — deferred to a future phase
- Detail body refactor — explicitly excluded by TICK-07
External research
None. Decisions were derivable from spec + existing code patterns.