# 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*