diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md
index a1494a6..905c3b8 100644
--- a/.planning/REQUIREMENTS.md
+++ b/.planning/REQUIREMENTS.md
@@ -128,21 +128,69 @@ Updated during roadmap creation.
| Requirement | Phase | Status |
|-------------|-------|--------|
-| PWA-01 to PWA-04 | TBD | Pending |
-| SHELL-01 to SHELL-06 | TBD | Pending |
-| NAV-01 to NAV-03 | TBD | Pending |
-| DRAWER-01 to DRAWER-06 | TBD | Pending |
-| DASH-01 to DASH-04 | TBD | Pending |
-| TICK-01 to TICK-07 | TBD | Pending |
-| FIN-01 to FIN-02 | TBD | Pending |
-| ANL-01 to ANL-06 | TBD | Pending |
-| ENG-01 to ENG-09 | TBD | Pending |
+| PWA-01 | Phase 1 | Pending |
+| PWA-02 | Phase 1 | Pending |
+| PWA-03 | Phase 1 | Pending |
+| PWA-04 | Phase 1 | Pending |
+| SHELL-01 | Phase 2 | Pending |
+| SHELL-02 | Phase 2 | Pending |
+| SHELL-03 | Phase 2 | Pending |
+| SHELL-04 | Phase 2 | Pending |
+| SHELL-05 | Phase 2 | Pending |
+| SHELL-06 | Phase 2 | Pending |
+| NAV-01 | Phase 2 | Pending |
+| NAV-02 | Phase 2 | Pending |
+| NAV-03 | Phase 2 | Pending |
+| DRAWER-01 | Phase 2 | Pending |
+| DRAWER-02 | Phase 2 | Pending |
+| DRAWER-03 | Phase 2 | Pending |
+| DRAWER-04 | Phase 2 | Pending |
+| DRAWER-05 | Phase 2 | Pending |
+| DRAWER-06 | Phase 2 | Pending |
+| DASH-01 | Phase 3 | Pending |
+| DASH-02 | Phase 3 | Pending |
+| DASH-03 | Phase 3 | Pending |
+| DASH-04 | Phase 3 | Pending |
+| TICK-01 | Phase 4 | Pending |
+| TICK-02 | Phase 4 | Pending |
+| TICK-03 | Phase 4 | Pending |
+| TICK-04 | Phase 4 | Pending |
+| TICK-05 | Phase 4 | Pending |
+| TICK-06 | Phase 4 | Pending |
+| TICK-07 | Phase 4 | Pending |
+| FIN-01 | Phase 5 | Pending |
+| FIN-02 | Phase 5 | Pending |
+| ANL-01 | Phase 6 | Pending |
+| ANL-02 | Phase 6 | Pending |
+| ANL-03 | Phase 6 | Pending |
+| ANL-04 | Phase 6 | Pending |
+| ANL-05 | Phase 6 | Pending |
+| ANL-06 | Phase 6 | Pending |
+| ENG-01 | Phase 7 | Pending |
+| ENG-02 | Phase 7 | Pending |
+| ENG-03 | Phase 7 | Pending |
+| ENG-04 | Phase 7 | Pending |
+| ENG-05 | Phase 7 | Pending |
+| ENG-09 | Phase 7 | Pending |
+| ENG-06 | Phase 8 | Pending |
+| ENG-07 | Phase 8 | Pending |
+| ENG-08 | Phase 8 | Pending |
**Coverage:**
- v1 requirements: 47 total
-- Mapped to phases: 0 (pending roadmap)
-- Unmapped: 47 ⚠️ (resolved by roadmapper)
+- Mapped to phases: 47
+- Unmapped: 0 ✓
+
+**Per-phase counts:**
+- Phase 1 (PWA Scaffolding): 4 requirements
+- Phase 2 (Mobile Shell + More Drawer): 15 requirements
+- Phase 3 (Dashboard Restyle): 4 requirements
+- Phase 4 (Tickets Restyle): 7 requirements
+- Phase 5 (Finance Restyle): 2 requirements
+- Phase 6 (Analyzer Feed): 6 requirements
+- Phase 7 (Engagement Overview): 6 requirements
+- Phase 8 (Engagement User Profile): 3 requirements
---
*Requirements defined: 2026-05-03*
-*Last updated: 2026-05-03 after initial definition*
+*Last updated: 2026-05-03 — traceability filled in at roadmap creation*
diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
new file mode 100644
index 0000000..bffa497
--- /dev/null
+++ b/.planning/ROADMAP.md
@@ -0,0 +1,151 @@
+# Roadmap: Pulse Mobile Shell Redesign
+
+## Overview
+
+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.
+
+## Phases
+
+**Phase Numbering:**
+- Integer phases (1, 2, 3): Planned milestone work
+- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
+
+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
+- [ ] **Phase 5: Finance Restyle** — Adopt new Card + typography scale, swap wide tables for stacked lists
+- [ ] **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 8: Engagement User Profile (NEW)** — `/mobile/engagement/[userId]` real-page profile that replaces the desktop modal pattern
+
+## Phase Details
+
+### 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.
+**Depends on**: Nothing (first phase)
+**Requirements**: PWA-01, PWA-02, PWA-03, PWA-04
+**Success Criteria** (what must be TRUE):
+ 1. Visiting `/manifest.json` returns valid JSON with `name: "Pulse"`, `display: "standalone"`, `start_url: "/mobile"`, and theme/background colors matching the app shells
+ 2. The root `app/layout.tsx` references the manifest via `` and the viewport meta includes `viewport-fit=cover`
+ 3. A safe-area utility (Tailwind arbitrary values or shared class) is available so any sticky top/bottom bar can opt into `env(safe-area-inset-top)` / `env(safe-area-inset-bottom)` padding
+ 4. Installing Pulse to a phone home screen launches a chromeless app pointed at `/mobile` (no service worker, no offline)
+**Plans**: TBD
+**UI hint**: no
+
+### Phase 2: Mobile Shell + More Drawer
+**Goal**: Every `/mobile/*` page renders inside a new layout — sticky header (Wulf mark + Bell placeholder + avatar), scrollable content, and a 5-cell bottom nav whose fifth control opens a Sheet drawer that fully replaces `/mobile/nav`.
+**Depends on**: Phase 1
+**Requirements**: SHELL-01, SHELL-02, SHELL-03, SHELL-04, SHELL-05, SHELL-06, NAV-01, NAV-02, NAV-03, DRAWER-01, DRAWER-02, DRAWER-03, DRAWER-04, DRAWER-05, DRAWER-06
+**Success Criteria** (what must be TRUE):
+ 1. On any `/mobile/*` route the user sees a sticky header with the Wulf wordmark linking to `/mobile/dashboard`, a Bell icon button (keyboard-focusable, no menu), and a compact avatar — no page title in the header
+ 2. A fixed bottom bar exposes four primary tabs (Dashboard, Tickets, Finance, Analyzer) plus a More cell; tapping a tab routes to its page and the active tab uses `text-primary` based on `pathname.startsWith(href)`
+ 3. Tapping More (or the header avatar) opens a single Sheet drawer with three sections — Mobile sections (Engagement), Full site (Quotes, Configuration Items, Backup Status, Ticket Digest, Admin/Sync — each with an `ExternalLink` hint), and Account (current user read-only + Sign out)
+ 4. Tapping Sign out in the drawer signs the user out and lands them on `/auth/sign-in`
+ 5. `app/mobile/nav/page.tsx` no longer exists; visiting `/mobile/nav` does not render the old standalone nav page
+ 6. Page content scrolls under the sticky header and is not hidden behind the bottom nav (bottom padding accounts for nav height + safe-area inset)
+**Plans**: TBD
+**UI hint**: yes
+
+### Phase 3: Dashboard Restyle
+**Goal**: A manager opening `/mobile/dashboard` sees the state of the business at a glance — four KPIs, items needing attention, and a worker/backup status row — with no charts.
+**Depends on**: Phase 2
+**Requirements**: DASH-01, DASH-02, DASH-03, DASH-04
+**Success Criteria** (what must be TRUE):
+ 1. Dashboard renders a 2×2 grid of four primary KPI cards drawn from desktop hero stats (no 1×4 row, no charts)
+ 2. Below the grid, a "Needs Attention" horizontally-scrollable strip surfaces overdue tickets, failed backups, and stalled workflows; tapping a card opens its detail view
+ 3. A compact status row shows analyzer worker, RMM worker, and backup-success-rate; tapping any element opens the corresponding desktop admin page
+ 4. The page contains no recharts/chart components on phone widths
+**Plans**: TBD
+**UI hint**: yes
+
+### Phase 4: Tickets Restyle
+**Goal**: A manager triages tickets on a phone with a collapsible filter bar that deep-links via URL, priority-coloured rows, and infinite scroll — and the detail page header matches the new shell.
+**Depends on**: Phase 2
+**Requirements**: TICK-01, TICK-02, TICK-03, TICK-04, TICK-05, TICK-06, TICK-07
+**Success Criteria** (what must be TRUE):
+ 1. The Tickets page opens with the filter strip collapsed; expanding it reveals status, priority, queue, and an assigned-to-me toggle, and changing any filter updates the URL query string (deep link works on reload)
+ 2. Each list row has a left-edge stripe matching priority (Critical/High/Medium/Low → red/orange/amber/slate) and shows ticket #, title, company, age, and assignee
+ 3. Single-tapping a row navigates to `/mobile/tickets/[id]`
+ 4. Scrolling to the bottom of the list automatically loads the next ~25 rows (no Next button); a "Load more" fallback button is also visible/focusable for accessibility
+ 5. The detail page header uses the new shell styling (Wulf mark, breadcrumb back) while the body remains largely unchanged
+**Plans**: TBD
+**UI hint**: yes
+
+### Phase 5: Finance Restyle
+**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.
+**Depends on**: Phase 2
+**Requirements**: FIN-01, FIN-02
+**Success Criteria** (what must be TRUE):
+ 1. `/mobile/finance` adopts the new Card and typography scale — no horizontal overflow, spacing legible on small phones
+ 2. Sections that previously rendered wide tables on phone widths now render as stacked lists (no new sections, no new data sources)
+**Plans**: TBD
+**UI hint**: yes
+
+### Phase 6: Analyzer Feed (NEW)
+**Goal**: A manager taps the Analyzer tab and skims a most-recent-first stream of AI ticket analyses, opening any one to a phone-friendly summary view that links out to desktop for full details.
+**Depends on**: Phase 2
+**Requirements**: ANL-01, ANL-02, ANL-03, ANL-04, ANL-05, ANL-06
+**Success Criteria** (what must be TRUE):
+ 1. Tapping the Analyzer tab in the bottom nav lands on `/mobile/analyzer` and shows a most-recent-first list of AI ticket analyses
+ 2. Each row shows ticket #, title, the analyzer's one-line summary, a confidence badge, and a stage indicator (Triage → Analyze → Deep Review)
+ 3. Tapping a row opens a mobile summary view rendering Summary, Next Step, and Next Step Rationale, with a "View full analysis" link out to the desktop analyzer page
+ 4. The mobile feed never exposes editing, re-run, or prompt-tuning controls (read-only by design)
+ 5. The list reads from `analyzer_analyses` via `/api/mobile/analyzer/feed` (or a reused list endpoint that already returns the right shape)
+**Plans**: TBD
+**UI hint**: yes
+
+### Phase 7: Engagement Overview (NEW)
+**Goal**: A manager reaches Engagement from the More drawer and sees a phone-first overview — period chips, stacked summary cards, a sortable per-employee list, and one compact sparkline.
+**Depends on**: Phase 2
+**Requirements**: ENG-01, ENG-02, ENG-03, ENG-04, ENG-05, ENG-09
+**Success Criteria** (what must be TRUE):
+ 1. The Mobile sections row in the More drawer links to `/mobile/engagement`; the Analyzer is on the bottom bar but Engagement is not
+ 2. The overview page shows a period selector (today / 7d / 30d) sticky just below the H1, with active period clearly indicated
+ 3. Summary cards (active users, total Graph hours, total Autotask hours, hours-per-active-user) render single-column stacked — no 4-up grid on phone widths
+ 4. The per-employee list renders as stacked rows (avatar/initials, name, role, hours bar) with a search input and a sort control above (sort by hours, name, utilization)
+ 5. A single compact "hours trend" sparkline renders at the top of the list, scoped to the selected period — no multi-series chart
+**Plans**: TBD
+**UI hint**: yes
+
+### Phase 8: Engagement User Profile (NEW)
+**Goal**: From the Engagement overview, a manager taps an employee row and arrives at a real, shareable profile page — single-column phone-first — and the device back gesture returns them to the overview.
+**Depends on**: Phase 7
+**Requirements**: ENG-06, ENG-07, ENG-08
+**Success Criteria** (what must be TRUE):
+ 1. Tapping a row in the per-employee list navigates to `/mobile/engagement/[userId]` (segment form, shareable URL)
+ 2. The profile is a real page (not a modal) — the device/browser back gesture returns to the overview at the same scroll position
+ 3. The profile renders single-column: identity header → period selector → key metrics (compact) → activity breakdown list → recent items, sourced from the existing engagement profile data endpoints (no new data)
+**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.
+
+| Phase | Plans Complete | Status | Completed |
+|-------|----------------|--------|-----------|
+| 1. PWA Scaffolding | 0/TBD | Not started | - |
+| 2. Mobile Shell + More Drawer | 0/TBD | Not started | - |
+| 3. Dashboard Restyle | 0/TBD | Not started | - |
+| 4. Tickets Restyle | 0/TBD | Not started | - |
+| 5. Finance Restyle | 0/TBD | Not started | - |
+| 6. Analyzer Feed | 0/TBD | Not started | - |
+| 7. Engagement Overview | 0/TBD | Not started | - |
+| 8. Engagement User Profile | 0/TBD | Not started | - |
+
+---
+*Roadmap created: 2026-05-03*
+*Source spec: `docs/superpowers/specs/2026-05-03-mobile-shell-design.md`*
diff --git a/.planning/STATE.md b/.planning/STATE.md
new file mode 100644
index 0000000..f4a7146
--- /dev/null
+++ b/.planning/STATE.md
@@ -0,0 +1,61 @@
+# Project State
+
+## Project Reference
+
+See: .planning/PROJECT.md (updated 2026-05-03)
+
+**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 1 — PWA Scaffolding
+
+## Current Position
+
+Phase: 1 of 8 (PWA Scaffolding)
+Plan: 0 of TBD in current phase
+Status: Ready to plan
+Last activity: 2026-05-03 — Roadmap created (8 phases, 47/47 v1 requirements mapped)
+
+Progress: [░░░░░░░░░░] 0%
+
+## Performance Metrics
+
+**Velocity:**
+- Total plans completed: 0
+- Average duration: —
+- Total execution time: 0.0 hours
+
+**By Phase:**
+
+| Phase | Plans | Total | Avg/Plan |
+|-------|-------|-------|----------|
+| - | - | - | - |
+
+**Recent Trend:**
+- Last 5 plans: —
+- Trend: —
+
+*Updated after each plan completion*
+
+## Accumulated Context
+
+### Decisions
+
+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)
+
+### Pending Todos
+
+None yet.
+
+### Blockers/Concerns
+
+None yet.
+
+## Session Continuity
+
+Last session: 2026-05-03
+Stopped at: Roadmap created — ready to plan Phase 1
+Resume file: None
diff --git a/CLAUDE.md b/CLAUDE.md
index 3c917a5..54d2bb3 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -161,3 +161,339 @@ Examples: `getAutotaskClient()`, `getMsgraphClient()`, `getDattoRmmClient()`,
- `PULSE_DATABASE_SKILL.md` — diagnostic queries
- `docs/` — sync behavior, webhook setup, workflow editor, analyzer runbook,
RMM Overshell + LogLift specs, IT Glue audit spec, per-integration guides
+
+
+## Project
+
+**Pulse Mobile Shell Redesign**
+
+A ground-up redesign of Pulse's `/mobile/*` shell — the manager-on-the-go view of
+the existing Pulse PSA dashboard. It replaces the current mobile layout, swaps
+the standalone `/mobile/nav` page for a Sheet drawer, restyles Dashboard /
+Tickets / Finance, and adds two new mobile surfaces (Analyzer feed,
+Engagement). Built on the existing Pulse codebase — same routes, same data,
+phone-first layouts.
+
+**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.
+
+### Constraints
+
+- **Tech stack**: Next.js 16 App Router, React 19, Tailwind 4, shadcn/ui — match
+ existing Pulse conventions (no new state libraries, no SWR/react-query, no
+ ORM, no Zod in API routes unless required)
+- **Routes**: Keep all existing `/mobile/*` paths. Replace files in place. No
+ new top-level routes outside `/mobile/`.
+- **Build order**: Each spec step ships independently — no big-bang merge.
+ Phase boundaries should let each step land on `master` cleanly.
+- **No service worker / no offline**: don't introduce `next-pwa` or a custom
+ SW in this iteration.
+- **Auth**: existing Better Auth + middleware handles `/mobile/*`. No new
+ auth surface.
+- **Data sources**: reuse existing endpoints where possible; add
+ `/api/mobile/*` only when an existing list endpoint doesn't return the
+ needed shape (e.g., analyzer feed).
+
+
+
+## Technology Stack
+
+## Languages
+- TypeScript 5 - Entire codebase, strict mode enabled
+- JavaScript/JSX - React components via TypeScript with JSX support
+- SQL - PostgreSQL migrations and queries
+- Bash - Build and deployment scripts
+## Runtime
+- Node.js (version inferred from package.json compatibility)
+- Next.js 16.1.1 running on port 3100
+- npm (lockfile: package-lock.json)
+## Frameworks
+- Next.js 16.1.1 - App Router with `output: 'standalone'` for Docker, React Compiler enabled
+- React 19.2.3 - Server and client components, React Compiler active
+- Better Auth 1.4.10 - Authentication with magic link, TOTP 2FA, Microsoft OAuth
+- Tailwind CSS 4.1.18 - Utility-first styling
+- shadcn/ui (via Radix UI primitives) - Component library: `components/ui/`
+- Recharts 3.7.0 - Charts and graphs (analytics/dashboards)
+- Lucide React 0.562.0 - Icon library
+- Sonner 2.0.7 - Toast notifications
+- cmdk 1.1.1 - Command palette component
+- react-hook-form 7.70.0 - Form state management (admin/auth only)
+- Zod 4.3.5 - Type-safe schema validation
+- @hookform/resolvers 5.2.2 - Form resolver for Zod
+- @tanstack/react-table 8.21.3 - Headless table library with sorting, pagination, search
+- react-markdown 10.1.0 - Markdown rendering
+- remark-gfm 4.0.1 - GitHub-flavored markdown support
+- date-fns 4.1.0 - Date manipulation and formatting
+- react-day-picker 9.13.0 - Calendar date picker
+- clsx 2.1.1 - Conditional className utility
+- tailwind-merge 3.4.0 - Merge Tailwind class conflicts
+- class-variance-authority 0.7.1 - CSS-in-JS variant management
+- next-themes 0.4.6 - Dark mode theme switching
+## Testing & Build
+- vitest 4.1.5 - Unit and integration testing runner
+- Run: `npm test` (run once), `npm run test:watch` (watch mode)
+- Test coverage for: `lib/services/analyzer/**`, `lib/services/rmm/**`, `lib/services/b2/**`, `lib/services/analyzer/link-discovery.test.ts`
+- Turbopack (via Next.js 16) - Fast bundler for development and production
+- ESLint 9.39.2 - Linting (with eslint-config-next 16.1.1)
+- TypeScript - Type checking via `npx tsc --noEmit --pretty`
+## Key Dependencies
+- pg 8.11.0 - PostgreSQL client (no ORM); queries via `postgresClient` singleton
+- ioredis 5.9.0 - Redis client for caching; optional (graceful fallback if REDIS_URL unset)
+- node-cron 4.2.1 - Job scheduler for sync tasks and workflows
+- @anthropic-ai/sdk 0.91.1 - Anthropic Claude API client for AI Ticket Analyzer pipeline
+- Better Auth ecosystem packages - OAuth, 2FA, session management
+- nodemailer 7.0.12 - Email delivery for magic link auth
+- babel-plugin-react-compiler 1.0.0 - React Compiler for optimized renders
+- shadcn 4.6.0 - CLI tool for adding shadcn/ui components
+- baseline-browser-mapping 2.10.8 - Browser compatibility mapping
+- tw-animate-css 1.4.0 - Tailwind animation utilities
+## Configuration
+- `BETTER_AUTH_URL` - Base URL for auth (e.g., `http://localhost:3100` or `https://pulse.wulfconsulting.cloud`)
+- `BETTER_AUTH_SECRET` - Secret key for session signing
+- `DATABASE_URL` or `POSTGRES_*` - PostgreSQL connection (host, port, db, user, password)
+- `REDIS_URL` - Redis connection (e.g., `redis://localhost:6380` in Docker compose)
+- `SESSION_TIMEOUT_SECONDS` - Session TTL (default: 86400 / 24 hours)
+- `MICROSOFT_CLIENT_ID`, `MICROSOFT_CLIENT_SECRET`, `MICROSOFT_TENANT_ID` - Microsoft OAuth for login (tenant is specific, not 'common')
+- `DEFAULT_ADMIN_EMAIL` - Bootstrap admin account email
+- Integration env vars: prefixed by service (e.g., `AUTOTASK_*`, `DATTO_RMM_*`, `MSGRAPH_*`, etc.) — see INTEGRATIONS.md
+- Path alias: `@/*` maps to project root for cleaner imports
+- Target: ES2017
+- Strict mode enabled
+- Config: `tsconfig.json`
+- File: `next.config.ts`
+- Standalone output for Docker deployment
+- React Compiler enabled
+- Image domains: configurable (currently empty)
+- `npm run build` → Next.js standalone app in `.next/`
+- `npm run start` → Starts production server on port 3100
+## Platform Requirements
+- Node.js 18+ (inferred from Next.js 16 compatibility)
+- npm 8+
+- PostgreSQL 16 (local or Docker)
+- Redis 7 (optional, enables caching)
+- Docker & Docker Compose (for full stack)
+- Docker with docker-compose.yml provided
+- Postgres 16 container (applies migrations on init)
+- Redis 7 container on port 6380 (custom, not 6379)
+- Next.js app container on port 3100
+- Traefik integration available (via labels in docker-compose.yml) for routing at `pulse.wulfconsulting.cloud`
+- Container-based: standalone Next.js image with migrations applied via Postgres init
+- Volume mounts for data persistence: `redis_data`, `postgres_data`
+- Environment configuration via `.env.local` file mounted read-only
+
+
+
+## Conventions
+
+## Naming Patterns
+- kebab-case for all files and directories (e.g., `postgres-client.ts`, `invite-user-form.tsx`, `entity-sync.ts`)
+- Nested directories use kebab-case (e.g., `lib/services/analyzer/`, `components/admin/users/`)
+- camelCase for all functions (e.g., `getAutotaskClient()`, `transformCompany()`, `extractExplicitFromText()`)
+- Factory functions prefixed with `get` (e.g., `getAutotaskClient()`, `getDattoRmmClient()`)
+- Helper functions suffixed with descriptive intent (e.g., `relTime()`, `deriveSigningKey()`)
+- Private/internal functions prefixed with underscore: `_INTERNALS` objects expose internals for test access
+- camelCase for all variables (e.g., `isLoading`, `setData`, `ticketNumber`)
+- Constants in UPPER_SNAKE_CASE (e.g., `MAX_EXPLICIT_LINKS`, `TICKET_NUMBER_REGEX`)
+- Database column names are always snake_case (e.g., `company_name`, `is_active`, `created_at`)
+- PascalCase for all type names (e.g., `ClassificationRule`, `WorkflowExecution`, `TicketData`)
+- Single-letter generics are acceptable (e.g., `queryEntity()`)
+- Union types as literal strings (e.g., `type RuleType = 'branch_routing' | 'ticket_type'`)
+- PascalCase exported from kebab-case files (e.g., export `InviteUserForm` from `invite-user-form.tsx`)
+- Page components: `export default function ComponentName()` at end of file
+- Form components: follow `[Resource]Form` naming (e.g., `InviteUserForm`, `SignInForm`, `UserForm`)
+## Code Style
+- TypeScript strict mode enabled (`"strict": true` in `tsconfig.json`)
+- No explicit formatter config (ESLint handles style)
+- Indentation: 2 spaces (inferred from existing code)
+- ESLint: `eslint.config.mjs` with Next.js config (`eslint-config-next/core-web-vitals`, `eslint-config-next/typescript`)
+- No additional custom rules beyond Next.js defaults
+- Type checking: `npx tsc --noEmit --pretty` (must pass before commit)
+## Import Organization
+- Configured as `"@/*": ["./*"]` in `tsconfig.json`
+- Use `@/lib/...`, `@/components/...`, `@/app/...` always
+- Never use relative paths like `../../../` for imports
+## Error Handling
+- All async functions use `try/catch` blocks
+- API routes: catch errors and return `NextResponse.json({ error, message }, { status })`
+- Standard status codes: `500` for runtime errors, `503` for missing/bad config, `401`/`403` from auth helpers
+- Error messages: include `error instanceof Error ? error.message : 'fallback message'`
+## Logging
+- `console.error()` for exceptions caught in try/catch (usually in API routes and services)
+- Include context: `console.error('Failed to fetch companies:', error)`
+- No `console.log()` for debugging (remove before commit per linter checks)
+## Comments
+- Explain *why*, not what (code shows the what)
+- Non-obvious logic or business rules
+- Performance-critical sections
+- Workarounds or hacks (mark with `// HACK:` or `// NOTE:`)
+- Used sparingly on complex functions
+- Example from `lib/services/analyzer/link-discovery.ts`:
+- Not required for simple getters/setters or obvious functions
+## Function Design
+- Keep functions focused: one responsibility per function
+- Aim for <50 lines for page components, <30 for utilities
+- Complex operations broken into smaller helpers
+- Prefer object parameters for >3 arguments
+- Don't use `any` — use specific types
+- Use `Partial` for optional object shapes
+- Async functions always return `Promise` explicitly
+- Prefer `null` over `undefined` for missing values
+- Use discriminated unions for success/error returns in critical paths (see analyzer pipeline)
+## Module Design
+- Prefer `export` at declaration point rather than grouped re-exports
+- One main export per file (exception: barrel files in `components/ui/`)
+- Internal utilities prefixed with underscore: `_INTERNALS` object for test access
+- `components/ui/index.ts` exports all shadcn primitives
+- `lib/types/` has domain-specific barrel files (e.g., `lib/types/workflow.ts`, `lib/types/autotask.ts`)
+- Avoid deep nesting — import from files, not directories unless barrel exists
+## Database Transformations
+## Shared Components & Libraries
+- shadcn primitives live in `components/ui/`
+- Feature-specific components in sibling directories (e.g., `components/dashboard/`, `components/admin/`)
+- Icons: Always use `lucide-react` (e.g., `import { Loader2, Send } from 'lucide-react'`)
+- Use `@tanstack/react-table` via `components/admin/DataTable.tsx` wrapper
+- Example: ``
+- Use `components/admin/DetailModal.tsx` for entity details
+- Follows card + tabs pattern (formatted/raw)
+- Use `components/navigation/app-navigation.tsx` (`NavigationMenu` from Radix)
+- Dropdowns prefer `@radix-ui/react-dropdown-menu` over submenus
+- Use `sonner` library: `import { toast } from 'sonner'`
+- Patterns: `toast.success()`, `toast.error()`, `toast.info()`
+- Use `react-hook-form` + Zod for validation
+- Only in admin/auth forms — NOT in every page
+- Pattern: `useForm()` with `zodResolver()`, then `