|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Commands |
| 6 | + |
| 7 | +```bash |
| 8 | +# Install all dependencies (root + workspaces) |
| 9 | +npm run install:all |
| 10 | + |
| 11 | +# Development |
| 12 | +npm run dev:backend # Backend on port 3000 (tsx watch) |
| 13 | +npm run dev:frontend # Frontend dev server on port 5173 |
| 14 | +npm run dev:fullstack # Build frontend + serve everything from backend |
| 15 | + |
| 16 | +# Build |
| 17 | +npm run build # Build both frontend and backend |
| 18 | + |
| 19 | +# Testing |
| 20 | +npm run test # Run all tests (backend + frontend, no-watch) |
| 21 | +npm run test --workspace=backend # Backend tests only |
| 22 | +npm run test --workspace=frontend # Frontend tests only |
| 23 | +npm run test:watch --workspace=backend # Backend watch mode |
| 24 | +npm run test:e2e # Playwright E2E tests |
| 25 | +npm run test:e2e:ui # Playwright with UI mode |
| 26 | + |
| 27 | +# Run a single test file |
| 28 | +cd backend && npx vitest run test/unit/SomeService.test.ts |
| 29 | + |
| 30 | +# Linting |
| 31 | +npm run lint # Lint both workspaces (0 warnings allowed) |
| 32 | +npm run lint:fix # Auto-fix lint issues |
| 33 | +``` |
| 34 | + |
| 35 | +Backend uses `tsx watch` for hot-reload during development. The frontend dev server proxies API calls to the backend. |
| 36 | + |
| 37 | +## Architecture Overview |
| 38 | + |
| 39 | +Pabawi is an infrastructure management web UI — a monorepo with a **Node.js/Express/TypeScript backend** and a **Svelte 5 SPA frontend**. |
| 40 | + |
| 41 | +### Plugin-based integration system |
| 42 | + |
| 43 | +All infrastructure integrations (Bolt, PuppetDB, Puppetserver, Hiera, Ansible, SSH) are plugins registered in `backend/src/integrations/`. Every plugin: |
| 44 | + |
| 45 | +- Extends `BasePlugin` (`integrations/BasePlugin.ts`) and implements `isEnabled()`, `initialize()`, `healthCheck()` |
| 46 | +- Optionally implements `ExecutionToolPlugin` (can run commands) or `InformationSourcePlugin` (provides inventory/facts) |
| 47 | +- Is registered with `IntegrationManager` (`integrations/IntegrationManager.ts`), which handles lifecycle, health aggregation, and routes data requests to the correct plugin |
| 48 | + |
| 49 | +`IntegrationManager` is the central registry. When inventory or facts are requested, it fans out to all enabled `InformationSourcePlugin`s and merges results using a priority system (SSH: 50, Bolt/PuppetDB: 10, Puppetserver: 20, Ansible: 8, Hiera: 6). When executing commands, it dispatches to the correct `ExecutionToolPlugin`. |
| 50 | + |
| 51 | +### Backend (`backend/src/`) |
| 52 | + |
| 53 | +- **`server.ts`** — Express app init, plugin registration, middleware wiring, route mounting |
| 54 | +- **`config/`** — `ConfigService` wraps all env vars with Zod validation; always use this, never `process.env` directly |
| 55 | +- **`integrations/<name>/`** — One directory per integration: `<Name>Plugin.ts` (lifecycle + routing) and `<Name>Service.ts` (business logic, CLI spawning, API calls) |
| 56 | +- **`services/`** — Cross-cutting services: `ExecutionQueue` (concurrent limiting, FIFO), `StreamingExecutionManager` (SSE real-time output), `CommandWhitelistService` (security), `DatabaseService`, `AuthenticationService`, `BatchExecutionService`, and RBAC services (`UserService`, `RoleService`, `PermissionService`, `GroupService`) |
| 57 | +- **`routes/`** — Express route handlers. All async handlers must be wrapped with `asyncHandler()` from `utils/` |
| 58 | +- **`middleware/`** — Auth (JWT), RBAC, error handler, rate limiting, security headers |
| 59 | +- **`database/`** — `DatabaseService.ts` (SQLite, schema/migration on startup), `ExecutionRepository.ts` (CRUD for execution history). Schema in `database/schema.sql`, migrations in `database/migrations.sql` |
| 60 | +- **`errors/`** — Typed error classes extending base classes; use these instead of generic `Error` |
| 61 | +- **`validation/`** — Zod schemas for request body validation |
| 62 | + |
| 63 | +Bolt command output is parsed from JSON; both `_output` and `_error` fields must be extracted from failed task results. Inventory and facts are cached (30 s and 5 min TTL respectively) inside each plugin's service. |
| 64 | + |
| 65 | +### Frontend (`frontend/src/`) |
| 66 | + |
| 67 | +- **`App.svelte`** — Root: initializes router, auth guard, and setup check |
| 68 | +- **`pages/`** — One Svelte component per page route |
| 69 | +- **`components/`** — Shared UI components |
| 70 | +- **`lib/`** — Core utilities and reactive state: |
| 71 | + - `router.svelte.ts` — Client-side router using Svelte 5 runes (`$state`) |
| 72 | + - `auth.svelte.ts` — JWT auth state |
| 73 | + - `api.ts` — Centralized HTTP client with error handling |
| 74 | + - `executionStream.svelte.ts` — SSE client for real-time command output |
| 75 | + - `expertMode.svelte.ts` — Debug info toggle |
| 76 | + - `integrationColors.svelte.ts` — Per-integration color constants |
| 77 | + - `toast.svelte.ts` — Notification system |
| 78 | + |
| 79 | +The frontend uses **Svelte 5 runes** throughout (`$state()`, `$effect()`, `$derived()`). State that needs to persist across components lives in the `lib/*.svelte.ts` files as module-level rune state. |
| 80 | + |
| 81 | +### Configuration |
| 82 | + |
| 83 | +All configuration is via `backend/.env`. Run `scripts/setup.sh` for interactive setup. Key variable groups: `PORT/HOST/LOG_LEVEL`, `JWT_SECRET/AUTH_ENABLED`, `BOLT_*`, `PUPPETDB_*`, `PUPPETSERVER_*`, `HIERA_*`, `ANSIBLE_*`, `SSH_*`, `COMMAND_WHITELIST*`, `CACHE_*`, `CONCURRENT_EXECUTION_LIMIT`. |
| 84 | + |
| 85 | +See `docs/configuration.md` for the full reference. |
| 86 | + |
| 87 | +### Testing conventions |
| 88 | + |
| 89 | +- Backend tests live in `backend/test/` (unit, integration, security, middleware, properties with fast-check) |
| 90 | +- Frontend tests co-located with source in `frontend/src/**/*.test.ts` |
| 91 | +- E2E tests in `e2e/` using Playwright |
| 92 | +- Database tests use in-memory SQLite |
| 93 | +- Use `supertest` for HTTP route testing in backend |
| 94 | + |
| 95 | +### Logging |
| 96 | + |
| 97 | +Use `LoggerService` everywhere — never `console.log`. Pass structured metadata: `{ component, integration, operation }`. |
0 commit comments