wulf-pulse/.planning/codebase/STRUCTURE.md
lorentz 9658640c04 fix(04-01): restore phase 2/3 work lost by worktree soft-reset
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
2026-05-03 18:01:14 -04:00

418 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 (001089)
│ ├── 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 `<AnalyzeButton />`)
**`migrations/`:**
- Purpose: Database schema versioning
- Contains: Numbered SQL files (001089), 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 `<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` (or `components/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.ts` for type-safe env access)
- Service-local helpers: Inline in `lib/services/<name>.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*