diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md
index b839871..27e170d 100644
--- a/.planning/REQUIREMENTS.md
+++ b/.planning/REQUIREMENTS.md
@@ -51,7 +51,24 @@ Requirements for this milestone. Each maps to a roadmap phase.
## Traceability
-
+| Requirement | Phase | Status |
+|-------------|-------|--------|
+| PAX8-01 | Phase 10 | Pending |
+| PAX8-02 | Phase 10 | Pending |
+| PAX8-03 | Phase 11 | Pending |
+| PAX8-04 | Phase 11 | Pending |
+| PAX8-05 | Phase 11 | Pending |
+| PAX8-08 | Phase 11 | Pending |
+| PAX8-06 | Phase 12 | Pending |
+| PAX8-10 | Phase 12 | Pending |
+| PAX8-11 | Phase 12 | Pending |
+| PAX8-07 | Phase 13 | Pending |
+| PAX8-09 | Phase 13 | Pending |
+| PAX8-12 | Phase 14 | Pending |
+| PAX8-13 | Phase 14 | Pending |
+| PAX8-14 | Phase 14 | Pending |
+
+**Coverage:** 14/14 v2.0 requirements mapped ✓
---
*Requirements defined: 2026-07-10*
diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
index ab9f0d4..b9f31a6 100644
--- a/.planning/ROADMAP.md
+++ b/.planning/ROADMAP.md
@@ -1,17 +1,9 @@
-# Roadmap: Pulse Mobile Shell Redesign
+# Roadmap: Pulse
-## Overview
+## Milestones
-Eight phases mirror the deliberate build order in the source spec
-(`docs/superpowers/specs/2026-05-03-mobile-shell-design.md` §8). Each phase
-ships independently to `master` — no big-bang merge. Phase 1 lays PWA
-metadata and safe-area utilities. Phase 2 rebuilds `app/mobile/layout.tsx`
-with the new header, 5-cell bottom nav, and More drawer (deleting
-`/mobile/nav` in the same change). Once the shell lands, Phases 3–7 are
-independent restyles/new pages and may be executed in parallel; Phase 8
-follows Phase 7 because the user profile is reached from the Engagement
-overview. All work happens in place under `/mobile/*` — no `/mobile-v2`,
-no parallel routes.
+- ✅ **v1.0 Mobile Shell Redesign** — Phases 1-9.1 (shipped 2026-07-10)
+- 📋 **v2.0 PAX8 Integration** — Phases 10-14 (planned)
## Phases
@@ -21,19 +13,30 @@ no parallel routes.
Decimal phases appear between their surrounding integers in numeric order.
-- [ ] **Phase 1: PWA Scaffolding** — Manifest, viewport meta, and safe-area utilities so the shell installs and paints under the home indicator
-- [ ] **Phase 2: Mobile Shell + More Drawer** — New `app/mobile/layout.tsx` (header + 5-cell bottom nav) and Sheet drawer that replaces `/mobile/nav`
-- [ ] **Phase 3: Dashboard Restyle** — 2×2 KPI grid, Needs Attention strip, worker/backup status row (no charts)
-- [ ] **Phase 4: Tickets Restyle** — Collapsible URL-synced filters, priority-bar rows, cursor-based infinite scroll, detail header reskin
-- [x] **Phase 5: Finance Restyle** — Adopt new Card + typography scale, swap wide tables for stacked lists (completed 2026-05-03)
-- [ ] **Phase 6: Analyzer Feed (NEW)** — `/mobile/analyzer` read-only stream + `/api/mobile/analyzer/feed`
-- [ ] **Phase 7: Engagement Overview (NEW)** — `/mobile/engagement` phone-first overview reachable from the More drawer
-- [ ] **Phase 7.1: User Timezone Fix (INSERTED — urgent)** — Per-user IANA timezone column + viewer-tz date math so dashboards and filters render the right "today"
-- [ ] **Phase 8: Engagement User Profile (NEW)** — `/mobile/engagement/[userId]` real-page profile that replaces the desktop modal pattern
-- [ ] **Phase 9: User Profile & Preferences (NEW)** — `/mobile/profile` settings page (timezone chooser, theme, mobile push, Teams + ntfy channels)
-- [ ] **Phase 9.1: ntfy Backend Fix (INSERTED — urgent)** — Personal ntfy channels target the company ntfy server with bearer auth + `pulse-me-` prefix (UAT gap closure)
+
+✅ v1.0 Mobile Shell Redesign (Phases 1-9.1) - SHIPPED 2026-07-10
-## Phase Details
+Eight phases mirror the deliberate build order in the source spec
+(`docs/superpowers/specs/2026-05-03-mobile-shell-design.md` §8). Each phase
+shipped independently to `master` — no big-bang merge. Phase 1 laid PWA
+metadata and safe-area utilities. Phase 2 rebuilt `app/mobile/layout.tsx`
+with the new header, 5-cell bottom nav, and More drawer (deleting
+`/mobile/nav` in the same change). Once the shell landed, Phases 3–7 were
+independent restyles/new pages; Phase 8 followed Phase 7 because the user
+profile is reached from the Engagement overview. All work happened in place
+under `/mobile/*` — no `/mobile-v2`, no parallel routes.
+
+- [x] **Phase 1: PWA Scaffolding** — Manifest, viewport meta, and safe-area utilities so the shell installs and paints under the home indicator
+- [x] **Phase 2: Mobile Shell + More Drawer** — New `app/mobile/layout.tsx` (header + 5-cell bottom nav) and Sheet drawer that replaces `/mobile/nav`
+- [x] **Phase 3: Dashboard Restyle** — 2×2 KPI grid, Needs Attention strip, worker/backup status row (no charts)
+- [x] **Phase 4: Tickets Restyle** — Collapsible URL-synced filters, priority-bar rows, cursor-based infinite scroll, detail header reskin
+- [x] **Phase 5: Finance Restyle** — Adopt new Card + typography scale, swap wide tables for stacked lists (completed 2026-05-03)
+- [x] **Phase 6: Analyzer Feed (NEW)** — `/mobile/analyzer` read-only stream + `/api/mobile/analyzer/feed`
+- [x] **Phase 7: Engagement Overview (NEW)** — `/mobile/engagement` phone-first overview reachable from the More drawer
+- [x] **Phase 7.1: User Timezone Fix (INSERTED — urgent)** — Per-user IANA timezone column + viewer-tz date math so dashboards and filters render the right "today"
+- [x] **Phase 8: Engagement User Profile (NEW)** — `/mobile/engagement/[userId]` real-page profile that replaces the desktop modal pattern
+- [x] **Phase 9: User Profile & Preferences (NEW)** — `/mobile/profile` settings page (timezone chooser, theme, mobile push, Teams + ntfy channels)
+- [x] **Phase 9.1: ntfy Backend Fix (INSERTED — urgent)** — Personal ntfy channels target the company ntfy server with bearer auth + `pulse-me-` prefix (UAT gap closure)
### Phase 1: PWA Scaffolding
**Goal**: A manager who taps "Add to Home Screen" gets a standalone Pulse icon that opens to the mobile shell with content respecting the device safe areas.
@@ -213,27 +216,122 @@ Decimal phases appear between their surrounding integers in numeric order.
- [x] 09.1-01-PLAN.md — Personal-channels regex/prefix/bearer + propagate to notify/approval/digest send paths + ProfileChannelsSection QR & copy
**UI hint**: no (backend-heavy; one component edit for QR/link target)
+
+
+### 📋 v2.0 PAX8 Integration (Planned)
+
+**Milestone Goal:** Sync PAX8 licensing/subscription data into Pulse, read-only,
+mapped to Autotask companies, so managers can see subscription costs and seat
+counts alongside existing company data.
+
+This milestone follows the codebase's existing external-integration pattern
+(`-client.ts` + `-factory.ts` + numbered migration + sync service +
+scheduler entry + admin toggle). Phase 10 stands up auth + schema in isolation
+so the OAuth2 client-credentials flow is proven before anything is built on
+top of it. Phase 11 syncs the "current state" entities (companies, catalog,
+subscriptions). Phase 12 adds historical cost data (orders/invoices) and the
+fuzzy-name company-matching pass, since matching needs companies to already
+exist. Phase 13 wires the combined sync into the daily scheduler and the
+`/admin/integrations` toggle — deliberately last among the backend phases so
+it schedules the *complete* sync, not a partial one. Phase 14 ships the
+`/pax8` page, which needs Phase 12's data and match state to have something to
+render, including the manual-resolution workflow for flagged companies.
+
+- [ ] **Phase 10: PAX8 Client & Auth Foundation** — OAuth2 client-credentials auth, `isPax8Configured()`, and the PAX8 schema migration
+- [ ] **Phase 11: Company, Catalog & Subscription Sync** — Read-only sync of current-state companies, product catalog, and subscriptions into Postgres
+- [ ] **Phase 12: Orders/Invoices & Company Matching** — Historical cost sync plus fuzzy-name auto-matching (with flagging) of PAX8 companies to Autotask companies
+- [ ] **Phase 13: Scheduler & Admin Toggle** — Daily `pax8-daily` cron entry and an on/off switch in `/admin/integrations`
+- [ ] **Phase 14: /pax8 UI Surface** — New page listing companies/subscriptions/cost breakdown, plus manual resolution of flagged company matches
+
+## Phase Details
+
+### Phase 10: PAX8 Client & Auth Foundation
+**Goal**: Pulse can authenticate to the PAX8 API via OAuth2 client-credentials, and the Postgres schema for all four PAX8 entities exists — proving the integration pattern before any sync logic is built on top of it.
+**Depends on**: Nothing (first phase of v2.0)
+**Requirements**: PAX8-01, PAX8-02
+**Success Criteria** (what must be TRUE):
+ 1. `lib/services/pax8-factory.ts` exports `isPax8Configured()`, returning `true` only when the PAX8 client ID and secret env vars are both set, `false` otherwise
+ 2. `getPax8Client()` performs an OAuth2 client-credentials token exchange against `api.pax8.com/v1` and successfully calls a read-only endpoint (e.g., list companies) using the resulting bearer token
+ 3. Calling the client with missing/invalid credentials throws a clear, typed error rather than failing silently or crashing the process — matching the existing `isConfigured()` + throw-if-missing pattern used by other integrations
+ 4. A new numbered migration creates the PAX8 tables (companies, subscriptions, products/catalog, orders, and a company-match/review table) using `IF NOT EXISTS`, ready for Phase 11+ to populate
+**Plans**: TBD
+**UI hint**: no
+
+### Phase 11: Company, Catalog & Subscription Sync
+**Goal**: PAX8 companies, the product catalog, and current subscriptions are synced into Postgres and are human-readable (not raw SKU IDs) — the "current state" half of the integration.
+**Depends on**: Phase 10
+**Requirements**: PAX8-03, PAX8-04, PAX8-05, PAX8-08
+**Success Criteria** (what must be TRUE):
+ 1. Running the sync populates a companies table with every PAX8 company (PAX8 ID, name, and other identifying fields)
+ 2. Running the sync populates a product/catalog table (SKUs, categories) and a subscriptions table (product, seat count, billing term) per company
+ 3. A synced subscription row displays a readable product name and category by joining to the catalog table — not a bare SKU/product ID
+ 4. No code path in the PAX8 client or this sync service issues a write (POST/PUT/PATCH/DELETE) to the PAX8 API — every call is a read, verified by inspection of the client's exposed methods
+**Plans**: TBD
+**UI hint**: no
+
+### Phase 12: Orders/Invoices & Company Matching
+**Goal**: Pulse has historical PAX8 cost data for reconciliation over time, and every PAX8 company is automatically linked to its Autotask counterpart or explicitly flagged for review — never silently guessed.
+**Depends on**: Phase 11
+**Requirements**: PAX8-06, PAX8-10, PAX8-11
+**Success Criteria** (what must be TRUE):
+ 1. Running the sync populates an orders/invoices table with historical line items (not just current-state seat counts), enabling cost-over-time comparisons
+ 2. At sync time, each PAX8 company is automatically matched to an Autotask company by fuzzy name similarity when a sufficiently confident match exists, and the match is persisted
+ 3. A PAX8 company with no match, or with multiple similarly-scored Autotask candidates, is persisted with a flagged/needs-review status instead of being auto-assigned
+ 4. Re-running the sync does not overwrite a match that has already been manually confirmed/resolved (idempotent with respect to human decisions)
+**Plans**: TBD
+**UI hint**: no
+
+### Phase 13: Scheduler & Admin Toggle
+**Goal**: PAX8 sync runs automatically once a day like every other Pulse integration, and can be turned on or off from `/admin/integrations` without a container restart.
+**Depends on**: Phase 12
+**Requirements**: PAX8-07, PAX8-09
+**Success Criteria** (what must be TRUE):
+ 1. A `pax8-daily` (or equivalently named) entry exists in the sync scheduler and fires once per day, running the full companies + catalog + subscriptions + orders sync in sequence
+ 2. PAX8 appears as a toggleable row on `/admin/integrations`, backed by the `integration_settings` table like every other integration
+ 3. Disabling PAX8 from that UI stops future scheduled sync runs (respecting the existing health-cache window, or immediately per the PATCH-clears-cache convention) and records `disabled_by`, `disabled_at`, and an optional `disabled_reason`
+ 4. Re-enabling PAX8 resumes scheduled sync at the next cron tick with no code deploy or container restart required
+**Plans**: TBD
+**UI hint**: no
+
+### Phase 14: /pax8 UI Surface
+**Goal**: A manager can open `/pax8` and see PAX8 companies with their subscriptions and a cost breakdown, and an admin can resolve any flagged/ambiguous company match directly from that page — no psql required.
+**Depends on**: Phase 12
+**Requirements**: PAX8-12, PAX8-13, PAX8-14
+**Success Criteria** (what must be TRUE):
+ 1. `/pax8` lists PAX8 companies together with their current subscriptions
+ 2. Each company shows a cost breakdown (e.g., by subscription/product) built from the synced subscription and order/invoice data
+ 3. Flagged/ambiguous company matches appear in a distinct, clearly-labeled review section on `/pax8` rather than being mixed silently into the main list
+ 4. From that review section, an admin can pick the correct Autotask company for a flagged PAX8 company; the resolution persists and is respected (not overwritten) by future syncs
+**Plans**: TBD
+**UI hint**: yes
+
## Progress
**Execution Order:**
-Phases execute in numeric order. Phase 2 unblocks Phases 3–7 (any order, parallelizable). Phase 8 follows Phase 7.
+Phases execute in numeric order. v1.0 (Phases 1-9.1) shipped 2026-07-10. v2.0 phases run 10 → 11 → 12 → 13 → 14 — each is a hard dependency on the previous within this milestone (no parallelization: auth → current-state sync → historical sync + matching → scheduling → UI, in that order).
-| Phase | Plans Complete | Status | Completed |
-|-------|----------------|--------|-----------|
-| 1. PWA Scaffolding | 1/2 | Executing | - |
-| 2. Mobile Shell + More Drawer | 0/TBD | Not started | - |
-| 3. Dashboard Restyle | 0/2 | Not started | - |
-| 4. Tickets Restyle | 0/3 | Not started | - |
-| 5. Finance Restyle | 2/2 | Complete | 2026-05-03 |
-| 6. Analyzer Feed | 0/3 | Not started | - |
-| 7. Engagement Overview | 0/3 | Not started | - |
-| 7.1. User Timezone Fix | 0/5 | Not started | - |
-| 8. Engagement User Profile | 0/2 | Not started | - |
-| 9. User Profile & Preferences | 0/5 | Not started | - |
-| 9.1. ntfy Backend Fix | 0/1 | Not started | - |
+| Phase | Milestone | Plans Complete | Status | Completed |
+|-------|-----------|----------------|--------|-----------|
+| 1. PWA Scaffolding | v1.0 | 2/2 | Complete | 2026-07-10 |
+| 2. Mobile Shell + More Drawer | v1.0 | 2/2 | Complete | 2026-07-10 |
+| 3. Dashboard Restyle | v1.0 | 2/2 | Complete | 2026-07-10 |
+| 4. Tickets Restyle | v1.0 | 3/3 | Complete | 2026-07-10 |
+| 5. Finance Restyle | v1.0 | 2/2 | Complete | 2026-05-03 |
+| 6. Analyzer Feed | v1.0 | 3/3 | Complete | 2026-07-10 |
+| 7. Engagement Overview | v1.0 | 3/3 | Complete | 2026-07-10 |
+| 7.1. User Timezone Fix | v1.0 | 5/5 | Complete | 2026-07-10 |
+| 8. Engagement User Profile | v1.0 | 2/2 | Complete | 2026-07-10 |
+| 9. User Profile & Preferences | v1.0 | 6/6 | Complete | 2026-07-10 |
+| 9.1. ntfy Backend Fix | v1.0 | 1/1 | Complete | 2026-07-10 |
+| 10. PAX8 Client & Auth Foundation | v2.0 | 0/TBD | Not started | - |
+| 11. Company, Catalog & Subscription Sync | v2.0 | 0/TBD | Not started | - |
+| 12. Orders/Invoices & Company Matching | v2.0 | 0/TBD | Not started | - |
+| 13. Scheduler & Admin Toggle | v2.0 | 0/TBD | Not started | - |
+| 14. /pax8 UI Surface | v2.0 | 0/TBD | Not started | - |
---
*Roadmap created: 2026-05-03*
-*Source spec: `docs/superpowers/specs/2026-05-03-mobile-shell-design.md`*
+*v2.0 phases added: 2026-07-10*
+*Source spec (v1.0): `docs/superpowers/specs/2026-05-03-mobile-shell-design.md`*
+*Source seed (v2.0): `.planning/seeds/SEED-002-pax8-integration.md`*
-
\ No newline at end of file
diff --git a/.planning/STATE.md b/.planning/STATE.md
index aacb014..36eaeab 100644
--- a/.planning/STATE.md
+++ b/.planning/STATE.md
@@ -6,7 +6,7 @@ status: planning
last_updated: "2026-07-10T15:53:23.273Z"
last_activity: 2026-07-10
progress:
- total_phases: 0
+ total_phases: 5
completed_phases: 0
total_plans: 0
completed_plans: 0
@@ -17,25 +17,27 @@ progress:
## Project Reference
-See: .planning/PROJECT.md (updated 2026-05-03)
+See: .planning/PROJECT.md (updated 2026-07-10)
-**Core value:** A manager can open Pulse on their phone and, in under 30 seconds, see the state of the business and triage tickets — without ever needing to switch to desktop for read-only awareness.
-**Current focus:** Phase 09.1 — ntfy-backend-fix
+**Core value:** Managers can see PAX8 subscription costs and seat counts alongside existing Autotask company data in Pulse, without manually cross-referencing PAX8's own portal.
+**Current focus:** Phase 10 — PAX8 Client & Auth Foundation
## Current Position
-Phase: Not started (defining requirements)
-Plan: —
-Status: Defining requirements
-Last activity: 2026-07-10 — Milestone v2.0 started
+Phase: 10 of 14 (PAX8 Client & Auth Foundation)
+Plan: — (not yet planned)
+Status: Roadmap approved, ready to plan Phase 10
+Last activity: 2026-07-10 — v2.0 ROADMAP.md created, Phases 10-14 defined
+
+Progress: [░░░░░░░░░░] 0%
## Performance Metrics
**Velocity:**
-- Total plans completed: 30
+- Total plans completed: 30 (all from v1.0 Mobile Shell Redesign)
- Average duration: —
-- Total execution time: 0.0 hours
+- Total execution time: 0.0 hours (v2.0)
**By Phase:**
@@ -51,15 +53,19 @@ Last activity: 2026-07-10 — Milestone v2.0 started
| 07.1 | 5 | - | - |
| 08 | 2 | - | - |
| 09 | 6 | - | - |
+| 09.1 | 1 | - | - |
+| 10 | TBD | - | - |
+| 11 | TBD | - | - |
+| 12 | TBD | - | - |
+| 13 | TBD | - | - |
+| 14 | TBD | - | - |
**Recent Trend:**
-- Last 5 plans: —
+- Last 5 plans: — (v1.0 closed; v2.0 not yet executed)
- Trend: —
*Updated after each plan completion*
-| Phase 02-mobile-shell-more-drawer P02 | 8 | 4 tasks | 2 files |
-| Phase 05-finance-restyle P02 | 2 | 2 tasks | 1 files |
## Accumulated Context
@@ -68,15 +74,19 @@ Last activity: 2026-07-10 — Milestone v2.0 started
Decisions are logged in PROJECT.md Key Decisions table.
Recent decisions affecting current work:
-- Roadmap: Phases mirror the spec's 8-step build order so each step ships independently to `master` (spec §8)
-- Phase 2 unblocks Phases 3–7; Phases 3–7 are mutually independent and can be parallelized; Phase 8 depends on Phase 7
-- All work happens in place under `/mobile/*` — no `/mobile-v2`, no parallel routes (spec §2)
-- [Phase 02-mobile-shell-more-drawer]: Single useState in mobile layout.tsx for drawer open state — no Zustand/Context per CLAUDE.md constraint
-- [Phase 02-mobile-shell-more-drawer]: Tailwind 4 pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))] arbitrary value works without inline-style fallback
-- [Phase 02-mobile-shell-more-drawer]: No redirect on /mobile/nav deletion — standard 404 per DRAWER-06 spec
-- [Phase 05-finance-restyle]: D-09: Monthly revenue renders as stacked list, not recharts bar chart (DASH-04 precedent — no charts on mobile)
-- [Phase 05-finance-restyle]: D-02: Revenue YTD folded into Paid MTD caption; separate Revenue YTD card removed
-- [Phase 05-finance-restyle]: D-08: Aging bucket palette locked: amber/orange/destructive token — no raw red/yellow Tailwind classes
+- v2.0 roadmap: 5 phases (10-14), strictly sequential — auth foundation →
+ current-state sync → historical sync + company matching → scheduler/admin
+ toggle → UI — each phase is a hard dependency on the previous, no
+ parallelization within this milestone
+- Phase 10 isolates OAuth2 client-credentials auth + the full PAX8 schema
+ migration before any sync logic is written, to de-risk the new external
+ integration early
+- PAX8-08 (read-only guarantee) and PAX8-11 (flag don't guess) are treated as
+ constraints verified within their natural sync phase (11 and 12
+ respectively), not standalone phases
+- PAX8-12 (admin resolves flagged matches) is delivered on the `/pax8` page
+ itself (Phase 14) rather than a separate `/admin` surface — `/pax8` is the
+ dedicated home for this integration's data and review workflow
### Pending Todos
@@ -86,16 +96,19 @@ None yet.
None yet.
-### Quick Tasks Completed
+## Deferred Items
-| # | Description | Date | Commit | Directory |
-|---|-------------|------|--------|-----------|
-| 260519-0oz | Add QBO createPayment + createDeposit + .FH reconciliation script | 2026-05-19 | 5497458 | [260519-0oz-add-qbo-createpayment-createdeposit-fh-r](./quick/260519-0oz-add-qbo-createpayment-createdeposit-fh-r/) |
-| 260521-fci | Stopgap nightly reconciliation for stale open tickets in postgres mirror | 2026-05-21 | badd718 | [260521-fci-stopgap-nightly-reconciliation-for-stale](./quick/260521-fci-stopgap-nightly-reconciliation-for-stale/) |
-| 260521-foj | Fix weekly-full FK error: widen Companies filter + defensive ticket company_id validation | 2026-05-21 | 62c529f | [260521-foj-fix-weekly-full-fk-error-widen-companies](./quick/260521-foj-fix-weekly-full-fk-error-widen-companies/) |
+Items acknowledged and carried forward from previous milestone close:
+
+| Category | Item | Status | Deferred At |
+|----------|------|--------|-------------|
+| Follow-up | Tablet breakpoint (`md:max-w-2xl`) on mobile shell | Deferred | v1.0 close |
+| Follow-up | Real notification list behind Bell icon | Deferred | v1.0 close |
+| Follow-up | Scroll restoration on Engagement profile back navigation (partial fix only) | Deferred | v1.0 close |
## Session Continuity
-Last session: 2026-05-10T02:09:48.834Z
-Stopped at: Phase 9 UI-SPEC approved
-Resume file: .planning/phases/09-user-profile-preferences-new/09-UI-SPEC.md
+Last session: 2026-07-10T15:53:23.273Z
+Stopped at: v2.0 ROADMAP.md and REQUIREMENTS.md traceability written; awaiting `/gsd:plan-phase 10`
+Resume file: None
+