# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Real-time dashboard for monitoring Proxmox VE nodes, VMs, and LXC containers. Next.js 15 App Router with Tailwind CSS 4. ## Commands ``` npm run dev # Start dev server (usually on port 3002) npm run build # Production build npm run start # Start production server ``` ## Architecture ``` src/ ├── app/ │ ├── api/ # Next.js API routes (server-side) │ │ ├── proxy/[...]/route.js # Reverse proxy to Proxmox web UI │ │ ├── power/route.js # Power control (start/stop/restart) │ │ ├── nodes/vms/lxc/route.js # Query endpoints (aggregates across nodes) │ │ └── status/route.js # Aggregated summary stats │ ├── layout.js # Root layout (Inter font, metadata) │ └── page.js # Entry — renders ├── components/ │ ├── Dashboard.js # Main UI: tabs, summary cards, polling, power action handler │ ├── NodeList.js / NodeCard.js # Node overview (collapsible cards with subtotals) │ ├── VMList.js / LXCList.js # VM/LXC lists grouped by node with search, power actions, console links, IPs │ └── StatusBadge.js # Status indicator └── lib/ └── proxmox.js # Proxmox API client — getNodes, getVMs, getLXC, getSummary, powerControl, getConfigIPs ``` ## Key Patterns - **Dual API endpoints**: Queries use `/api2/json`, power operations use `/api2/extjs`. Power actions send empty body `{}`. - **API routes** aggregate data across all Proxmox nodes before returning to the client. They are thin wrappers around `lib/proxmox.js`. - **Dashboard** uses direct React state + manual `setInterval` polling (not SWR) for periodic data fetching. Power actions use direct `axios.get()` calls for instant UI sync. - **Power action flow**: `handlePowerAction` in Dashboard.js fires `POST /api/power`, then immediately re-fetches all four caches (`/api/nodes`, `/api/vms`, `/api/lxc`, `/api/status`) and sets state directly. Use `requestAnimationFrame` flush before the API call so status messages paint. - **Auth**: PVEAPIToken header: `Authorization: PVEAPIToken=${TOKEN_ID}=${TOKEN_SECRET}`. - **Console**: VMList/LXCList build `consoleUrl` from `PROXMOX_WEB_URL` with `?console={qemu|lxc}&vmid={id}&node={node}&resize=scale` params. Dashboard opens it via `window.open()` in a new tab so browser session cookies handle Proxmox auth. LXC console uses `xtermjs=1`, QEMU uses `novnc=1`. - **Per-VM/LXC IPs**: `getConfigIPs()` in proxmox.js fetches QEMU IPs from `/agent/network-get-interfaces`, LXC IPs from `/interfaces` endpoint (fallback to `/config` `net0`-`net7` parsing). IPv4 only. - **TLS**: `NODE_TLS_REJECT_UNAUTHORIZED=0` in `.env.local` for self-signed certs. Shows a console warning — acceptable for internal lab use. - **Tailwind CSS 4**: Uses `@tailwindcss/postcss` config. CSS vars in `globals.css` for theming. - **All API routes return 502 on Proxmox failures** with `{ error, data: null }`. ## Environment Variables | Variable | Required | Description | |---|---|---| | `PROXMOX_API_URL` | Yes | Base URL, e.g. `https://host:8006/api2/json` | | `PROXMOX_TOKEN_ID` | Yes | API token ID | | `PROXMOX_TOKEN_SECRET` | Yes | API token secret | | `PROXMOX_WEB_URL` | No | Web UI URL (defaults from PROXMOX_API_URL) | | `API_POLL_INTERVAL` | No | Poll interval ms (default 30000) | | `NODE_TLS_REJECT_UNAUTHORIZED` | No | `0` for self-signed certs | ## Git Workflow Repository is on Gitea. User works in feature branches, merges via PR. Use clean main as base. Gitea token may need to be embedded in remote URL for auth.