generated from erangel1/generic-template
123 lines
6.8 KiB
Markdown
123 lines
6.8 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
LabGraph is a HomeLab infrastructure documentation engine. It maps physical hardware to virtual services using a graph model (Nodes + Edges). The stack is Django + Celery on the backend, Next.js 14 + DaisyUI on the frontend, all orchestrated via Docker Compose.
|
|
|
|
## Running the Stack
|
|
|
|
```bash
|
|
# Start everything (from repo root)
|
|
docker compose up -d
|
|
|
|
# Include Flower (Celery monitoring at localhost:5555)
|
|
docker compose --profile dev-tools up -d
|
|
|
|
# View logs
|
|
docker compose logs -f web
|
|
docker compose logs -f celery-worker
|
|
|
|
# Rebuild after Dockerfile or requirements.txt changes
|
|
docker compose build
|
|
docker compose up -d
|
|
```
|
|
|
|
The web service runs `backend/scripts/entrypoint.sh` which runs migrate → collectstatic → gunicorn.
|
|
|
|
## Backend Commands (inside container)
|
|
|
|
```bash
|
|
# Run migrations
|
|
docker compose exec web python manage.py migrate
|
|
|
|
# Create superuser
|
|
docker compose exec web python manage.py createsuperuser
|
|
|
|
# Make migrations after model changes
|
|
docker compose exec web python manage.py makemigrations
|
|
|
|
# Open Django shell
|
|
docker compose exec web python manage.py shell
|
|
|
|
# Inspect Celery workers
|
|
docker compose exec celery-worker celery -A config.celery inspect ping
|
|
docker compose exec celery-worker celery -A config.celery inspect active
|
|
```
|
|
|
|
## Frontend Commands
|
|
|
|
```bash
|
|
cd frontend
|
|
npm run dev # Dev server at localhost:3000
|
|
npm run type-check # TypeScript check (tsc --noEmit)
|
|
npm run lint # ESLint
|
|
npm run build # Production build
|
|
```
|
|
|
|
## Environment Setup
|
|
|
|
Copy `.env.example` to `.env` (repo root). Copy `frontend/.env.local.example` to `frontend/.env.local`.
|
|
|
|
Required variables that have no defaults and will crash on startup if missing:
|
|
- `SECRET_KEY` — Django secret key (`python3 -c "import secrets; print(secrets.token_urlsafe(50))"`)
|
|
- `POSTGRES_PASSWORD` — PostgreSQL password (used directly by docker-compose)
|
|
- `REDIS_PASSWORD` — Redis password (used directly by docker-compose)
|
|
- `NEXTAUTH_SECRET` — NextAuth JWT signing key (`openssl rand -base64 32`)
|
|
|
|
Critical: `DATABASE_URL`, `REDIS_URL`, and `CELERY_BROKER_URL` must use the Docker service hostnames `db` and `redis`, not `localhost`. The Redis URL format is `redis://:PASSWORD@redis:6379/0` (colon before password, no username).
|
|
|
|
## Architecture
|
|
|
|
### Backend (`backend/`)
|
|
|
|
**Settings** are split into `config/settings/base.py` (shared) → `config/settings/development.py` / `production.py`. Settings are loaded via `django-environ` from the root `.env` file (`BASE_DIR.parent / ".env"`). Never import `base` directly — always use `development` or `production`.
|
|
|
|
**Celery** is configured in `config/celery.py` and referenced by docker-compose as `-A config.celery`. Three queues: `discovery` (nmap/Proxmox scans), `heartbeat` (ICMP/TCP liveness), `default` (maintenance). Beat uses `DatabaseScheduler`, so periodic tasks are stored in the DB and can be edited at runtime via admin.
|
|
|
|
**Graph model** in `apps/core/models.py`:
|
|
- `Node` — any infrastructure component (location → hardware → hypervisor → VM/container → application). All have UUID PKs, a `node_type` TextChoices enum, `status`, optional `ip_address`, and a `metadata` JSONField for per-type flexible data.
|
|
- `Edge` — directed source→target relationship with `edge_type` (parent_child, network, dependency, physical). Unique constraint on `(source, target, edge_type)`.
|
|
- `Network` — VLAN/subnet records (separate from Nodes).
|
|
- `WikiPage` — OneToOne to Node, stores raw Markdown; `rendered_html()` converts via the `Markdown` package.
|
|
- `HeartbeatLog` — high-volume time-series; pruned nightly by `tasks/maintenance.py`.
|
|
|
|
**Input validation** uses Pydantic v2 schemas (`apps/core/schemas.py`) at the API boundary before data reaches the ORM. DRF serializers (to be added in Phase 2) handle output.
|
|
|
|
**Celery tasks** live in `tasks/` (not inside an app). Phase 1 stubs are in `tasks/discovery.py`, `tasks/heartbeat.py`, `tasks/maintenance.py`. Autodiscovery is configured for the `tasks` package.
|
|
|
|
**RLS**: `apps/core/apps.py` connects a `post_migrate` signal that enables PostgreSQL Row-Level Security on `core_node`. The handler checks `information_schema.tables` first — it fires after every app's migrations, not just after core.
|
|
|
|
**Health check** at `GET /api/health/` (no auth required) checks DB (`SELECT 1`) and Redis (cache round-trip). Returns `{"status": "ok"|"degraded", "services": {...}, "version": "1.0.0"}`. Used by docker-compose healthcheck.
|
|
|
|
**OpenAPI schema** at `GET /api/schema/`, Swagger UI at `GET /api/docs/`.
|
|
|
|
### Frontend (`frontend/`)
|
|
|
|
Next.js 14 App Router. TypeScript strict mode with `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes` — avoid `any`.
|
|
|
|
**Auth flow**: NextAuth (`src/lib/auth.ts`) uses `CredentialsProvider`. In development, any non-empty credentials are accepted (stub). Phase 2 wires `authorize()` to `POST /api/auth/login/` on the Django backend. `NEXTAUTH_SECRET` must be stable in `.env.local` — changing it invalidates all existing sessions.
|
|
|
|
**API client** (`src/lib/api.ts`): all backend calls go through `apiFetch()` which validates responses against Zod schemas before returning. Throws `ApiError` on non-2xx, `ZodError` on schema mismatch.
|
|
|
|
**Types** (`src/types/index.ts`): Zod schemas are the source of truth; TypeScript types are inferred with `z.infer<>`. The schemas mirror the Django models exactly — keep them in sync when models change.
|
|
|
|
**Routing**: `next.config.mjs` proxies `/backend/*` → Django. Route groups: `(auth)` for login, `(dashboard)` for protected pages. Auth guard is done server-side with `getServerSession(authOptions)` + `redirect()`.
|
|
|
|
**Styling**: Tailwind CSS + DaisyUI. Theme is set via `html[data-theme]` in `layout.tsx`. DaisyUI component classes (e.g. `btn`, `card`, `alert`) — no custom CSS unless DaisyUI can't cover it.
|
|
|
|
## Phase Status
|
|
|
|
- **Phase 1** ✅ Complete — Docker stack, Django models, Celery stubs, Next.js scaffold
|
|
- **Phase 2** 🔄 In Progress — DRF ViewSets, discovery scrapers (Proxmox/nmap), heartbeat (icmplib), Django auth endpoint
|
|
- **Phase 3** ⏳ Pending — Nested inventory list, React Flow topology graph, Markdown wiki editor
|
|
|
|
## Key Constraints
|
|
|
|
- The `requirements.txt` lives in `backend/` (Docker build context is `./backend`).
|
|
- `next.config.ts` is not supported in Next.js 14 — use `next.config.mjs`.
|
|
- YAML `>` folded scalars in docker-compose do NOT fold newlines on more-indented continuation lines — use a shell script instead of multi-line `sh -c` commands.
|
|
- `HeartbeatLog` is high-volume — always filter by `node` and use the `(node, -timestamp)` index; never do full-table scans.
|
|
- `Node.metadata` is a free-form JSONField — validate its contents with the Pydantic schemas in `apps/core/schemas.py` before writing.
|