wulf-pulse/docs/superpowers/specs/2026-05-03-mobile-shell-design.md
lorentz 672f17b7f9 chore: check in pending work — queue preferences, QBO AR diagnostics, mobile engagement fixes, ops scripts
Bundles several in-progress efforts that were sitting uncommitted:
- User queue-preferences (migration 087, API route, popover component)
- QBO invoice soft-delete (migration 088) and AR diagnostics route
- Dashboard/mobile engagement route and page adjustments
- Docker Compose log-rotation config
- One-off ticket/RMM investigation scripts (scripts/)
- Planning docs: phase verification/pattern notes, mobile shell design spec
- .gitignore: exclude local scratch financial/inventory data and Claude Code
  worktree/local-settings runtime state (never meant for version control)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W6RuWdiUiXrPK6FLBHjtpY
2026-07-18 06:34:57 -04:00

221 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Mobile Shell Redesign — Design Spec
**Date:** 2026-05-03
**Scope:** `/mobile/*` shell, navigation, and per-page layouts on Pulse.
## 1. Goal & audience
Pulse's mobile shell exists for **managers on the go** — quick status checks,
triage decisions, and read-only awareness. It is not a full replacement for the
desktop app; pages where mobile editing isn't justified should link out to the
desktop equivalent.
Success means a manager can:
- See the state of the business at a glance (Dashboard).
- Triage and inspect tickets (Tickets).
- Read AR / invoice / payment status (Finance).
- Skim recent AI ticket analyses (Analyzer).
- Reach Engagement and sign-out without clutter on the primary nav.
## 2. Approach
**Rebuild `/mobile` in place.** Keep all existing `/mobile/*` route paths
(`/mobile/dashboard`, `/mobile/tickets`, `/mobile/tickets/[id]`,
`/mobile/finance`). Replace `/mobile/layout.tsx`, the four page files, and
delete `/mobile/nav` (its content moves into a Sheet drawer — see §3).
No new top-level routes. No parallel `/mobile-v2` directory. The existing pages
stay their canonical URLs throughout the redesign.
## 3. Navigation
### 3.1 Bottom tab bar (primary)
Four tabs, equal-width, fixed to the bottom of the viewport:
| Tab | Icon (lucide) | Route |
|------------|-------------------|---------------------|
| Dashboard | `LayoutDashboard` | `/mobile/dashboard` |
| Tickets | `Ticket` | `/mobile/tickets` |
| Finance | `DollarSign` | `/mobile/finance` |
| Analyzer | `Sparkles` | `/mobile/analyzer` |
Active state: `text-primary`; inactive: `text-muted-foreground`. Active
detection via `pathname.startsWith(href)`.
### 3.2 "More" Sheet drawer (secondary)
A fifth control on the bottom bar — `Menu` icon labelled **More** — opens a
shadcn `Sheet` (side="right", or "bottom" on phones; pick one and stay
consistent). The drawer **replaces the standalone `/mobile/nav` page entirely**.
Drawer contents, top to bottom:
1. **Mobile sections** — Engagement (`/mobile/engagement`, see §6.5).
2. **Full site** — link list to desktop pages that have no mobile view yet
(Quotes, Configuration Items, Backup Status, Ticket Digest, Admin / Sync).
Each link uses the `ExternalLink` icon hint to signal "leaves mobile shell".
3. **Account** — current user (avatar + email, read-only), then **Sign out**
(calls `signOut()` then `router.push('/auth/sign-in')`).
Delete `app/mobile/nav/page.tsx` after the drawer is in place.
## 4. PWA setup
- `public/manifest.json` — name "Pulse", short_name "Pulse", `display: "standalone"`,
`start_url: "/mobile"`, theme/background colors matching the dark and light
shells. Reference it from `app/layout.tsx` via `<link rel="manifest">`.
- `viewport` meta in `app/layout.tsx` (or root metadata): include
`viewport-fit=cover` so the shell can paint behind the home indicator.
- **Safe-area insets** — both the sticky header and the bottom tab bar add
`env(safe-area-inset-top)` / `env(safe-area-inset-bottom)` padding. Use
Tailwind arbitrary values (`pt-[env(safe-area-inset-top)]`,
`pb-[env(safe-area-inset-bottom)]`) or a small utility class.
- **No service worker, no offline mode** in this iteration. Don't ship
`next-pwa` or a custom SW — deferred until a clear offline use-case lands.
- **Tablet** — `md:max-w-2xl mx-auto` wrapper is noted as a follow-up but is
**not** part of this spec's deliverable. Keep the current `max-w-lg`.
## 5. Shell (`app/mobile/layout.tsx`)
### 5.1 Header
Sticky top, `bg-background/95 backdrop-blur`, bottom border. Three slots:
- **Left:** Wulf mark (existing logo asset) + "Pulse" wordmark, linked to
`/mobile/dashboard`. Use the actual brand mark, not the text-only fallback.
- **Right (in order):**
- `Bell` icon button — **placeholder only**, no menu, no badge logic. Wire
to `aria-label="Notifications"` and an empty `onClick` so it's
keyboard-accessible. A future phase will turn this into a real list.
- Compact user avatar (`Avatar` from shadcn, size `h-7 w-7`). On tap,
opens the More drawer (so the avatar is the entry point alongside the
bottom-bar More button).
No page title in the header — pages render their own H1 in the content area.
### 5.2 Content area
`<main>` between header and bottom nav, scrollable. Add bottom padding equal to
the bottom-nav height + safe-area inset so content doesn't hide under the bar.
### 5.3 Bottom nav
Fixed, full-width, `border-t bg-background`. Wraps in `max-w-lg mx-auto` so
content and nav share the same gutter. Five cells: 4 tabs (§3.1) + More (§3.2).
## 6. Pages
### 6.1 Dashboard (`/mobile/dashboard`)
Sections, top to bottom:
1. **2×2 KPI grid** — four primary metric cards. KPIs to choose from the
desktop dashboard's hero stats; final selection during build, but the layout
is fixed at 2×2 on phone widths.
2. **"Needs Attention" strip** — horizontal scroll of compact cards
surfacing items that require manager action (overdue tickets, failed
backups, stalled workflows). Each card opens its detail view directly.
3. **Backup / worker status** — compact status row showing the analyzer
worker, RMM worker, and backup-success-rate at a glance. Read-only; tap
opens the desktop admin page.
No charts on the mobile Dashboard in this iteration — recharts on small widths
isn't earning its weight.
### 6.2 Tickets (`/mobile/tickets`)
- **Collapsible filter strip** at top (`Collapsible` from shadcn, default
collapsed). When expanded: status, priority, queue, assigned-to-me toggle.
Filter state syncs to the URL query string so deep-linking works.
- **Priority-bar rows** — list rows have a left-edge color stripe by priority
(Critical/High/Medium/Low → red/orange/amber/slate). Body shows ticket #,
title, company, age, assignee. Single-tap opens detail.
- **Infinite scroll** — replace the current pagination with cursor-based
infinite scroll. Fetch in pages of ~25; trigger next page when the last row
enters the viewport (IntersectionObserver). Keep a "Load more" fallback button
for accessibility.
- **Detail page** — keep `/mobile/tickets/[id]/page.tsx` largely as-is; only
reskin the header to match the new shell (Wulf mark, breadcrumb back).
### 6.3 Finance (`/mobile/finance`)
Restyle of the existing page only. No new data, no new sections. Adopt the new
Card and typography scale, fix any spacing that breaks on small phones. If a
section currently relies on a wide table, swap it for a stacked list on mobile.
### 6.4 Analyzer (`/mobile/analyzer`) — NEW
**Read-only feed of recent AI ticket analyses.**
- List view: most-recent-first stream of analyses. Each row shows ticket #,
title, the analyzer's one-line summary, confidence badge, and a stage
indicator (Triage → Analyze → Deep Review). Tap opens a mobile summary view.
- Mobile summary view: renders **Summary**, **Next Step**, **Next Step
Rationale** (all already produced by the analyzer pipeline). Includes a "View
full analysis" link out to the desktop analyzer page.
- No editing, no re-run, no prompt tuning on mobile.
- Source data: existing `analyzer_analyses` rows via a new
`/api/mobile/analyzer/feed` endpoint (or reuse an existing list endpoint if
one already returns the right shape).
### 6.5 Engagement (`/mobile/engagement`) — NEW, accessed via More drawer
Engagement gets a **real mobile refactor**, not a thin adaptation. The desktop
page (`app/engagement/page.tsx`, ~1300 lines) and profile page
(`app/engagement/profile/page.tsx`, ~650 lines) both rely on wide tables, dense
charts, and modal patterns that don't translate to phone widths. Build the
mobile views from the same data sources but with phone-first layouts.
**Overview (`/mobile/engagement`):**
- Period selector chip row (today / 7d / 30d) — sticky just below the page H1.
- Summary cards stacked single-column (active users, total Graph hours, total
Autotask hours, hours-per-active-user). No 4-up grid; reading numbers across
a 4-up row on a phone is a non-starter.
- Per-employee list as stacked rows (avatar / initials, name, role, hours
bar). Sortable via a small control above the list (sort by hours, name,
utilization). Search input above the list.
- Charts: replace the desktop's wide bar/line charts with one compact "hours
trend" sparkline at the top of the list, period-scoped. No multi-series
chart on mobile in this iteration.
**User profile (`/mobile/engagement/profile?userId=...` or
`/mobile/engagement/[userId]`):**
- Reuses the existing profile data endpoints. Layout is single-column:
identity header → period selector → key metrics (compact) → activity
breakdown list → recent items.
- This **replaces** the desktop user-detail modal pattern on mobile —
tapping a row navigates to a real page, not a modal, so the shell's back
gesture works correctly.
- Pick exactly one of the two route shapes above during build (prefer the
`[userId]` segment form for shareable URLs); don't ship both.
Engagement is **not** on the bottom bar — it lives in the More drawer because
managers don't check it as often as the four primary surfaces.
## 7. Out of scope (explicit non-goals)
- Service worker, offline cache, push notifications.
- Tablet breakpoint (md:max-w-2xl) — noted, deferred.
- Real notification list behind the bell.
- Mobile editing on Engagement (user detail) or Analyzer (re-run, prompt edits).
- Charts / recharts on mobile Dashboard.
- Replacing or restyling the desktop pages reachable from the More drawer.
## 8. Build order
1. PWA scaffolding — `manifest.json`, viewport meta, safe-area utility.
2. New `app/mobile/layout.tsx` — header, More drawer (Sheet), 5-cell bottom nav.
Delete `app/mobile/nav/page.tsx` in the same change.
3. Dashboard restyle (2×2 grid, Needs Attention, status row).
4. Tickets restyle (filter Collapsible, priority-bar rows, infinite scroll).
Detail page header reskin only.
5. Finance restyle.
6. Analyzer page + `/api/mobile/analyzer/feed` endpoint.
7. Engagement Overview (`/mobile/engagement`) — phone-first layout from existing data sources.
8. Engagement user profile (`/mobile/engagement/[userId]`) — replaces the desktop modal pattern with a real mobile page.
Each step ships independently — no big-bang merge.