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
22 KiB
22 KiB
Codebase Structure
Analysis Date: 2026-05-03
Directory Layout
pulse/
├── app/ # Next.js App Router pages + API routes
│ ├── api/ # API route handlers (GET/POST/PATCH/DELETE)
│ │ ├── admin/ # Admin settings, users, roles, integrations
│ │ ├── analyzer/ # Ticket analysis, aggregate reports, IT Glue
│ │ ├── auth/ # Better Auth endpoints
│ │ ├── webhooks/ # Autotask webhook endpoint (public)
│ │ ├── sync/ # Sync trigger endpoints (public, called by scheduler)
│ │ ├── health # Health check (public)
│ │ ├── integrations/ # Integration status (public)
│ │ └── …/ # Other feature APIs (companies, tickets, etc.)
│ ├── admin/ # /admin landing page + sub-pages (sync, workflow, RMM, IT Glue)
│ ├── analyzer/ # /analyzer/* pages (tickets, reports, queue)
│ ├── dashboard/ # /dashboard — KPI home
│ ├── status/ # /status — integration + worker health
│ ├── configuration-items/ # /configuration-items — CI browser
│ ├── engagement/ # /engagement/* — MS Graph employee data
│ ├── backup-status/ # /backup-status — Veeam RPO dashboard
│ ├── veeam-*/ # Veeam comparison + ticket analysis pages
│ ├── auth/ # /auth/sign-in, /auth/2fa — magic link flow
│ ├── settings/ # /settings, /settings/security — user profile
│ ├── kiosk/ # /kiosk/* — public field app (no nav)
│ ├── mobile/ # /mobile/* — mobile API endpoints (no nav)
│ ├── styles/ # CSS modules (brand.css, globals.css)
│ ├── layout.tsx # Root layout (AppNavigation, CommandPalette, Toaster)
│ └── page.tsx # Redirect to /dashboard
│
├── lib/ # Shared utilities, services, types
│ ├── services/ # Integration clients + sync/worker logic (~50 files)
│ │ ├── autotask-*.ts # Autotask API client + sync
│ │ ├── datto-rmm-*.ts # Datto RMM client + sync
│ │ ├── itglue-*.ts # IT Glue client + sync
│ │ ├── veeam-*.ts # Veeam VSPC client + sync
│ │ ├── msgraph-*.ts # MS Graph client + engagement sync
│ │ ├── engagement-*.ts # Engagement dashboard data
│ │ ├── analyzer/ # Analyzer pipeline (8 subdirs + 20 files)
│ │ │ ├── pipeline.ts # 7-stage orchestration
│ │ │ ├── worker.ts # 2s polling loop (auto-starts in production)
│ │ │ ├── persistence.ts # Read/write analyzer_analyses
│ │ │ ├── link-discovery.ts # Find related tickets
│ │ │ ├── itglue-search.ts # Redacted IT Glue lookups
│ │ │ ├── asset-audit/ # IT Glue write-back audits
│ │ │ ├── stages/ # 7 pipeline stages
│ │ │ └── fixtures/ # Test data
│ │ ├── rmm/ # RMM executor + Overshell
│ │ │ ├── executor.ts # Validate + enqueue
│ │ │ ├── worker.ts # 5s polling loop
│ │ │ ├── scripts/ # Script registry (code-defined)
│ │ │ ├── target-resolver.ts
│ │ │ └── …/
│ │ ├── llm/ # LLM dispatch + cost tracking
│ │ │ ├── call.ts # Claude + OpenRouter routing
│ │ │ ├── models.ts # Stage → model mapping
│ │ │ └── pricing.ts # Cost estimation
│ │ ├── b2/ # Backblaze B2 object storage
│ │ ├── sync-scheduler.ts # node-cron singleton (auto-starts)
│ │ ├── sync-service.ts # Incremental sync orchestration
│ │ ├── entity-sync.ts # Per-entity Autotask → Postgres
│ │ ├── postgres-client.ts # DB singleton (query/transaction/upsert)
│ │ ├── integration-health.ts # Health check orchestration
│ │ ├── email.ts # Email service (magic link)
│ │ ├── webhook-service.ts # HMAC verification
│ │ ├── redis-client.ts # Redis cache (optional)
│ │ ├── rate-limiter.ts # RMM execute limits
│ │ ├── audit.ts # Audit log writes
│ │ └── (25+ other services for Zoom, Duo, Mimecast, S1, etc.)
│ │
│ ├── types/ # TypeScript type definitions
│ │ ├── autotask.ts # Autotask API shapes
│ │ ├── analyzer.ts # Analysis, stage execution, aggregate report shapes
│ │ ├── database.ts # DB row types (tickets, companies, etc.)
│ │ ├── sync.ts # Sync schedule + progress shapes
│ │ ├── veeam.ts # Veeam shapes
│ │ ├── workflow.ts # Workflow engine shapes
│ │ ├── datto-rmm.ts # RMM types
│ │ └── …/
│ │
│ ├── auth.ts # Better Auth config + session type
│ ├── auth-utils.ts # requireAuth(), requireAdmin(), requirePermission()
│ ├── auth-client.ts # Client-side Better Auth SDK
│ ├── permissions.ts # Role → resource → action matrix
│ ├── bootstrap.ts # DEFAULT_ADMIN_EMAIL user creation
│ ├── status-registry.ts # Priority/status color maps (shared UI state)
│ ├── utils.ts # Misc helpers
│ │
│ └── utils/ # Utility modules
│ ├── env.ts # Type-safe env var access
│ └── …/
│
├── components/ # React components
│ ├── ui/ # shadcn/ui primitives (50+ files)
│ │ ├── button.tsx # Base button component
│ │ ├── card.tsx # Card + CardHeader/CardTitle/CardContent
│ │ ├── dialog.tsx # Modal + trigger + close
│ │ ├── table.tsx # HTML table wrapper with Tailwind classes
│ │ ├── input.tsx, select.tsx, checkbox.tsx, etc.
│ │ ├── skeleton.tsx # Loading placeholder
│ │ ├── skeleton-helpers.tsx # SkeletonRow, SkeletonCard, etc.
│ │ ├── empty-state.tsx # Zero-data UI
│ │ ├── status-badge.tsx # Status pill driven by status-registry
│ │ ├── status-light.tsx # Status indicator dot
│ │ ├── form.tsx # react-hook-form bridge
│ │ └── …/
│ │
│ ├── navigation/ # Top bar + page structure
│ │ ├── app-navigation.tsx # NavigationMenu + UserMenu + ThemeToggle
│ │ ├── page-header.tsx # Title + breadcrumbs + action slot
│ │ ├── command-palette.tsx # Cmd+K launcher
│ │ ├── mobile-nav.tsx # Mobile hamburger menu
│ │ ├── user-menu.tsx # User profile dropdown
│ │ └── status-indicator.tsx # Top-bar integration health
│ │
│ ├── admin/ # Admin-specific components
│ │ ├── DataTable.tsx # Paginated/sortable/searchable table (@tanstack/react-table)
│ │ ├── DetailModal.tsx # Ticket deep-dive (tabs: status, priority maps)
│ │ ├── SyncScheduler.tsx # Edit sync schedules
│ │ └── …/
│ │
│ ├── analyzer/ # Analyzer-specific components
│ │ ├── analyze-button.tsx # Trigger analysis from ticket
│ │ ├── share-modal.tsx # Email share dialog
│ │ ├── provider-toggle.tsx # Anthropic/OpenRouter switch
│ │ ├── related-tickets-panel.tsx
│ │ ├── itglue-suggestions-panel.tsx
│ │ └── …/
│ │
│ ├── rmm/ # RMM components
│ │ ├── rmm-dispatch-dialog.tsx # Pick + execute script
│ │ ├── rmm-script-picker.tsx # Script browser
│ │ ├── rmm-execution-stream.tsx # Live output tail
│ │ └── …/
│ │
│ ├── dashboard/ # Dashboard-specific components
│ │ ├── kpi-card.tsx # KPI with delta
│ │ ├── volume-trend.tsx # 30-day ticket volume chart
│ │ ├── resolution-trend.tsx # Resolution time chart
│ │ ├── queue-heatmap.tsx # Queue × priority heatmap
│ │ ├── active-engineers.tsx # Today's hours logged
│ │ └── …/
│ │
│ ├── configuration-items/ # CI browser components
│ │ └── config-item-modal.tsx # CI detail shell
│ │
│ ├── branding/ # Wulf branding
│ │ ├── wulf-mark.tsx # W glyph or wordmark
│ │ └── tagline-footer.tsx # "Don't be afraid to cry" footer
│ │
│ ├── auth/ # Auth flow components
│ │ └── auth-provider.tsx # Better Auth session context
│ │
│ ├── status/ # Status page components
│ │ ├── worker-pulse.tsx # Analyzer/RMM/sync heartbeats
│ │ ├── activity-sparkline.tsx # 24h per-worker activity
│ │ └── …/
│ │
│ └── (other feature dirs: backup, settings, tickets, tasks, etc.)
│
├── migrations/ # Numbered SQL migrations (001–089)
│ ├── 001_initial_schema.sql # Core schema, audit columns
│ ├── 012_create_auth_tables.sql # Better Auth tables
│ ├── 030_create_workflow_engine_tables.sql
│ ├── 041_create_engagement_tables.sql
│ ├── 069_create_analyzer_tables.sql
│ ├── 077_create_rmm_overshell_tables.sql
│ └── …/
│
├── scripts/ # One-off operations scripts
│ ├── apply-migrations # Manual migration runner for existing DB
│ └── …/
│
├── docs/ # Long-form guides (linked from CLAUDE.md)
│ ├── AUTOTASK_API_GUIDE.md
│ ├── POSTGRES_SYNC_SETUP.md
│ ├── ANALYZER_RUNBOOK.md
│ ├── RMM_OVERSHELL_SPEC.md
│ ├── LOGLIFT_SPEC.md
│ ├── IT_GLUE_AUDIT_SPEC.md
│ └── …/
│
├── public/ # Static assets (favicon, logos, branding)
│ ├── favicon.png
│ ├── wulff-logo.png
│ └── branding/
│
├── hooks/ # React hooks (useSearchParams, fetch helpers, etc.)
├── tasks/ # (Reserved for background tasks; unused today)
├── .planning/ # GSD planning documents (generated)
├── .env # Committed env vars (treat as potentially real secrets)
├── next.config.js # Turbopack, React compiler, output: standalone
├── tsconfig.json # Path alias @/*, strict mode
├── package.json # Next 16, React 19, Tailwind 4, shadcn/ui, etc.
├── Dockerfile # Standalone build, port 3100
├── docker-compose.yml # Postgres 16, Redis 7, app
├── CLAUDE.md # Repo guide for Claude (read first)
├── ARCHITECTURE.md # Runtime topology, data flow, workers (read before touching workers)
└── DESIGN.md # UI tokens, nav IA, component conventions
Directory Purposes
app/:
- Purpose: Next.js App Router pages + API routes
- Contains: Page components (
'use client'with fetch), route handlers (GET/POST/PATCH/DELETE), layout shells - Key files:
layout.tsx(root shell),page.tsx(redirect to /dashboard)
app/api/:
- Purpose: HTTP API endpoints called by client or external systems
- Contains: Route handlers exporting GET/POST/PATCH/DELETE
- Patterns: Auth check via
requireAuth(), delegate to service layer, returnNextResponse.json() - Subdirs mirror resources:
admin/,analyzer/,sync/,webhooks/, etc.
lib/services/:
- Purpose: Business logic, integration clients, sync orchestration, background workers
- Contains: ~50 files including factories, sync services, analyzer pipeline, RMM executor, integration health checks
- Patterns: Factory pattern for clients, incremental sync via
lastTrackedModificationDateTime, side-effect import auto-start for workers
lib/types/:
- Purpose: TypeScript type definitions (no runtime code)
- Contains: Entity shapes (ticket, company, analysis, rmm_execution, etc.), API request/response envelopes
- Organized: By domain (autotask, analyzer, database, sync, workflow, etc.)
lib/auth.ts, lib/auth-utils.ts, lib/permissions.ts:
- Purpose: Session management, role-based authorization, permission matrix
- Contains: Better Auth config,
requireAuth()/requireAdmin()/requirePermission(), resource → action matrix - Used by: Every API route handler for access control
components/ui/:
- Purpose: shadcn/ui primitives (Button, Card, Dialog, Input, Select, Table, etc.)
- Contains: Radix-based components with Tailwind styling
- Pattern: One component per file (e.g.,
button.tsx), default export is the component
components/navigation/:
- Purpose: Top bar, page headers, breadcrumbs, command palette, mobile menu
- Contains:
app-navigation.tsx(sticky top bar),page-header.tsx(title + actions),command-palette.tsx(Cmd+K) - Used by: Root layout + all pages
components/admin/, components/analyzer/, components/rmm/, etc.:
- Purpose: Feature-specific components
- Contains: Reusable UI for that domain (e.g., DataTable, DetailModal, analyze-button)
- Pattern: Exported from kebab-case files (e.g.,
analyze-button.tsxexports<AnalyzeButton />)
migrations/:
- Purpose: Database schema versioning
- Contains: Numbered SQL files (001–089), applied in alphabetical order on Postgres init
- Patterns:
IF NOT EXISTSfor idempotence,ON CONFLICT DO NOTHINGfor seed data, audit columns (created_at,updated_at,is_deleted) - Important: Never edit a committed migration; add a new one instead. Duplicate numbers exist (002, 004, 009) — apply order is filesystem-alphabetical.
scripts/:
- Purpose: One-off operations and utilities
- Contains:
apply-migrations(manual migration runner for existing DB) - Important: Not tests; not part of the build
docs/:
- Purpose: Long-form integration and feature guides
- Contains: Setup guides for Autotask, sync architecture, analyzer runbook, RMM/LogLift specs, IT Glue audit spec
- Pattern: One file per major system; referenced from CLAUDE.md, not duplicated in code
public/:
- Purpose: Static web assets (favicon, logos, branding images)
- Contains: PNG/SVG files served at
/favicon.png,/wulff-logo.png, etc.
Key File Locations
Entry Points:
app/page.tsx— Root page (redirect to /dashboard)app/layout.tsx— Root layout (AppNavigation, CommandPalette, Toaster, theme provider)app/auth/sign-in/page.tsx— Magic link entryapp/dashboard/page.tsx— KPI home
Configuration:
lib/auth.ts— Better Auth config (magic link, 2FA, Microsoft OAuth)lib/permissions.ts— Role → resource → action matrixnext.config.js— Turbopack, React compiler,output: 'standalone'tsconfig.json— Path aliases (@/*), strict mode.env— Committed env vars (API keys, secrets — treat as real)
Core Logic:
lib/services/postgres-client.ts— DB singleton (query, transaction, upsert)lib/services/sync-scheduler.ts— node-cron scheduler (auto-starts, self-initializes)lib/services/entity-sync.ts— Per-entity incremental sync (Autotask, etc.)lib/services/analyzer/pipeline.ts— 7-stage LLM analysis orchestrationlib/services/analyzer/worker.ts— 2s polling loop (auto-starts in production)lib/services/rmm/executor.ts— Script validation + rate limitinglib/services/rmm/worker.ts— 5s polling loop for RMM executions
Authentication & Authorization:
lib/auth.ts— Better Auth instance + session typelib/auth-utils.ts—requireAuth(),requireAdmin(),requirePermission()lib/bootstrap.ts— Admin user creation fromDEFAULT_ADMIN_EMAILmiddleware.ts— Session cookie verification (no role checks here)
Testing:
lib/services/analyzer/*.test.ts— Unit tests for analyzer (preprocessor, pipeline, link-discovery, itglue-search, itglue-redact)lib/services/rmm/executor.test.ts— RMM executor tests (rate limiting, script validation)lib/services/b2/client.test.ts— B2 client tests
UI & Components:
components/ui/— shadcn primitives (50+ files)components/navigation/app-navigation.tsx— Top bar + PageHeadercomponents/navigation/page-header.tsx— Title + breadcrumbs + action slotcomponents/admin/DataTable.tsx— Paginated/sortable table (@tanstack/react-table)components/admin/DetailModal.tsx— Ticket detail tabs
Types & Schemas:
lib/types/autotask.ts— Autotask API shapes (ticket, company, contact, etc.)lib/types/analyzer.ts— Analysis, stage execution, aggregate report shapeslib/types/database.ts— DB row types (all tables)lib/types/sync.ts— Sync schedule + progress shapes
Status Registry (Shared State):
lib/status-registry.ts— Priority/status color maps, state labels- Used by: DetailModal, StatusBadge, all pages that display ticket status/priority
Naming Conventions
Files:
- kebab-case:
auth-utils.ts,sync-scheduler.ts,app-navigation.tsx - Pattern: service/factory files end in
-service.ts,-factory.ts,-client.ts - Example:
autotask-client.ts,datto-rmm-sync-service.ts,msgraph-factory.ts
Directories:
- kebab-case:
api/,lib/,services/,rmm/,admin/ - Resource-based:
app/api/analyzer/,app/api/admin/,app/analyzer/ - Subdomain grouping:
lib/services/analyzer/(pipeline stages + persistence),lib/services/rmm/(executor + scripts + worker)
Components:
- PascalCase exports from kebab-case files:
analyze-button.tsxexports<AnalyzeButton /> - Wrapper types:
*Modal,*Panel,*Dialog,*Card(e.g.,DetailModal,related-tickets-panel)
Functions & Variables:
- camelCase:
requireAuth(),postgresClient.query(),getAutotaskClient() - Factories:
get<Name>Client(),is<Name>Configured()(e.g.,getDattoRmmClient(),isAutotaskConfigured()) - Hooks:
useSearchParams(),useEffect(),useState()
Database:
- snake_case columns:
ticket_id,company_id,created_at,updated_at,is_deleted - Audit columns:
created_at,updated_at,synced_at,is_deleted,deleted_at - Tables named for entity plurals:
tickets,companies,resources,contacts,analyst_analyses
API Responses:
- camelCase keys (transformed from DB snake_case in route handlers)
- Example:
{ ticketId, companyId, createdAt, updatedAt, isDeleted } - Transformation happens in route handler, not ORM-based
Where to Add New Code
New Feature (e.g., new integration):
- Primary code:
lib/services/<integration>-client.ts+lib/services/<integration>-factory.ts+lib/services/<integration>-sync-service.ts - Types:
lib/types/<integration>.ts - API routes:
app/api/<resource>/route.ts - Pages:
app/<resource>/page.tsx - Components:
components/<resource>/*.tsx - Tests:
lib/services/<integration>/*.test.ts(if logic is testable)
New Component/Module:
- Implementation:
components/<feature>/<kebab-case-name>.tsx(orcomponents/ui/if it's a primitive) - Usage: Import via
@/components/<feature>/<kebab-case-name>
New Page:
- File:
app/<route>/page.tsx - Layout: Use
PageHeader+container mx-auto px-6 py-6(standard padding) - Components: Import shared components from
components/
Utilities:
- Shared helpers:
lib/utils/<name>.ts(e.g.,lib/utils/env.tsfor type-safe env access) - Service-local helpers: Inline in
lib/services/<name>.tsif not reused
Migrations:
- File:
migrations/NNN_*.sql(next number in sequence) - Pattern:
IF NOT EXISTSfor idempotence,ON CONFLICT DO NOTHINGfor seed data - Audit columns: Include
created_at,updated_at,is_deleted,deleted_atwhere applicable - Important: Never edit a committed migration; create a new one instead
Tests:
- Location:
__tests__/sibling to source file or.test.ts/.spec.tssuffix - Framework:
vitest(import fromvitest, notjest) - Patterns: Unit tests for analyzer, RMM, B2; other areas are type-checked only
Special Directories
.planning/:
- Purpose: Generated GSD (Goal, Scope, Definition) planning documents
- Generated: By
/gsd-map-codebasewith focus areas (tech, arch, quality, concerns) - Committed: Yes (consumed by
/gsd-plan-phaseand/gsd-execute-phase) - Contains: STACK.md, INTEGRATIONS.md, ARCHITECTURE.md, STRUCTURE.md, CONVENTIONS.md, TESTING.md, CONCERNS.md
.env:
- Purpose: Environment variables (API keys, secrets, connection strings)
- Committed: Yes (treat values as potentially real production secrets)
- Secrets: DATABASE_URL, REDIS_URL, AUTOTASK_API_URL, BETTER_AUTH_SECRET, LLM keys, etc.
- Important: Never echo or log
.envcontents; don't add.env.localto version control
node_modules/, .next/, .git/:
- Purpose: Generated directories
- Committed: No (git-ignored)
- Cleaned:
rm -rf node_modules && npm install,npm run build && rm -rf .next
public/:
- Purpose: Static web assets
- Served: At
/path(e.g.,/favicon.png) - Committed: Yes
docs/:
- Purpose: Long-form guides
- Committed: Yes
- Pattern: One file per major system (Autotask, Postgres, Analyzer, RMM, etc.)
- Updated: As integration behavior changes; link from CLAUDE.md, don't duplicate in inline comments
Structure analysis: 2026-05-03