# 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, return `NextResponse.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.tsx` exports ``)
**`migrations/`:**
- Purpose: Database schema versioning
- Contains: Numbered SQL files (001–089), applied in alphabetical order on Postgres init
- Patterns: `IF NOT EXISTS` for idempotence, `ON CONFLICT DO NOTHING` for 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 entry
- `app/dashboard/page.tsx` — KPI home
**Configuration:**
- `lib/auth.ts` — Better Auth config (magic link, 2FA, Microsoft OAuth)
- `lib/permissions.ts` — Role → resource → action matrix
- `next.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 orchestration
- `lib/services/analyzer/worker.ts` — 2s polling loop (auto-starts in production)
- `lib/services/rmm/executor.ts` — Script validation + rate limiting
- `lib/services/rmm/worker.ts` — 5s polling loop for RMM executions
**Authentication & Authorization:**
- `lib/auth.ts` — Better Auth instance + session type
- `lib/auth-utils.ts` — `requireAuth()`, `requireAdmin()`, `requirePermission()`
- `lib/bootstrap.ts` — Admin user creation from `DEFAULT_ADMIN_EMAIL`
- `middleware.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 + PageHeader
- `components/navigation/page-header.tsx` — Title + breadcrumbs + action slot
- `components/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 shapes
- `lib/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.tsx` exports ``
- Wrapper types: `*Modal`, `*Panel`, `*Dialog`, `*Card` (e.g., `DetailModal`, `related-tickets-panel`)
**Functions & Variables:**
- camelCase: `requireAuth()`, `postgresClient.query()`, `getAutotaskClient()`
- Factories: `getClient()`, `isConfigured()` (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/-client.ts` + `lib/services/-factory.ts` + `lib/services/-sync-service.ts`
- Types: `lib/types/.ts`
- API routes: `app/api//route.ts`
- Pages: `app//page.tsx`
- Components: `components//*.tsx`
- Tests: `lib/services//*.test.ts` (if logic is testable)
**New Component/Module:**
- Implementation: `components//.tsx` (or `components/ui/` if it's a primitive)
- Usage: Import via `@/components//`
**New Page:**
- File: `app//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/.ts` (e.g., `lib/utils/env.ts` for type-safe env access)
- Service-local helpers: Inline in `lib/services/.ts` if not reused
**Migrations:**
- File: `migrations/NNN_*.sql` (next number in sequence)
- Pattern: `IF NOT EXISTS` for idempotence, `ON CONFLICT DO NOTHING` for seed data
- Audit columns: Include `created_at`, `updated_at`, `is_deleted`, `deleted_at` where applicable
- Important: Never edit a committed migration; create a new one instead
**Tests:**
- Location: `__tests__/` sibling to source file or `.test.ts` / `.spec.ts` suffix
- Framework: `vitest` (import from `vitest`, not `jest`)
- 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-codebase` with focus areas (tech, arch, quality, concerns)
- Committed: Yes (consumed by `/gsd-plan-phase` and `/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 `.env` contents; don't add `.env.local` to 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*