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

10 KiB
Raw Blame History

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.
  • Tabletmd: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.