# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview VirtFusion Direct Provisioning Module for WHMCS — a PHP module that integrates WHMCS with the VirtFusion control panel API for automated VPS provisioning, management, and client self-service. No build system or package manager; the module is pure PHP installed by copying `modules/servers/VirtFusionDirect/` into a WHMCS installation. ## Development & Testing There is no automated test suite, linter, or build step. Testing is manual: - **Test connection:** WHMCS Admin → System Settings → Servers → Test Connection button - **Dry run validation:** `VirtFusionDirect_validateServerConfig()` tests configuration without creating a server - **Module logging:** WHMCS Admin → Utilities → Logs → Module Log captures all API calls and responses - **Server object viewer:** Admin services tab shows full JSON response from VirtFusion API ## Development Rules - **Error handling:** Always use try...catch blocks around API calls, database operations, and any code that may throw exceptions. Never let exceptions bubble up unhandled to the user. Log caught exceptions via `Log::insert()`. - **Ownership validation:** Every client-facing action MUST verify service ownership via `validateUserOwnsService()` before performing any operation. Server IDs must be cross-referenced against the authenticated client to prevent cross-customer data access. - **Security:** All input must be validated server-side. Never trust client-side validation alone. Cast IDs to `(int)`, validate strings with regex, escape output with `htmlspecialchars()`. - **Control flow:** Every `$vf->output()` call in switch cases must be followed by `break`. Do not rely on `exit()` inside `output()` for flow control. - **HTTP methods:** Read-only operations use GET. State-mutating operations (power, rebuild, rename, password reset, credit, VNC toggle) use POST with data in the request body. - **Caching:** Use the `Cache` class for slow-changing API responses. Never cache real-time data (server status, VNC sessions, login tokens) or mutation responses. ## Release Process Releases are triggered by pushing a git tag: ```bash git tag v1.1.0 git push origin v1.1.0 ``` The `publish-release.yml` workflow creates a GitHub/Gitea release with auto-generated notes from the commit log. Use **conventional commits** for clear changelogs: - `fix:` → patch-level change - `feat:` → feature addition - `refactor:` → code improvement without behavior change ## Architecture **Namespace:** `WHMCS\Module\Server\VirtFusionDirect` ### Entry Points | File | Purpose | |------|---------| | `modules/servers/VirtFusionDirect/VirtFusionDirect.php` | WHMCS module interface — non-namespaced functions (`VirtFusionDirect_CreateAccount()`, etc.) that delegate to library classes | | `modules/servers/VirtFusionDirect/client.php` | Client-facing AJAX API — authenticated by WHMCS session + service ownership validation. POST for mutations, GET for reads. | | `modules/servers/VirtFusionDirect/admin.php` | Admin-facing AJAX API — requires WHMCS admin authentication | | `modules/servers/VirtFusionDirect/hooks.php` | WHMCS hooks — checkout validation (OS selection), OS gallery + SSH key UI injection, slider UI for configurable options, daily PowerDNS reconciliation | | `modules/addons/VirtFusionDns/VirtFusionDns.php` | Optional companion addon — holds PowerDNS settings and provides a Test Connection admin page. See "Reverse DNS (PowerDNS)" below. | ### Core Classes (in `lib/`) | Class | Role | |-------|------| | `Module` | Base class with API integration, auth checks, and all feature methods (power, network, VNC, backup, resource, self-service, traffic, rename, password reset). Contains `resolveServiceContext()` for DRY service lookups and `groupOsTemplates()` for shared OS category logic. | | `ModuleFunctions` | Extends `Module`. Service lifecycle: create, suspend, unsuspend, terminate, change package, usage updates, client area rendering. | | `ConfigureService` | Extends `Module`. Order-time operations: package discovery, OS template fetching, server build initialization, SSH key retrieval and creation. | | `Database` | Static methods for `mod_virtfusion_direct` table operations and WHMCS DB queries. Auto-creates/migrates schema on first use. | | `Curl` | HTTP client wrapper with Bearer token auth, SSL verification, 30s timeout. Methods: `get`, `post`, `put`, `patch`, `delete`. Single-use — each instance makes one request. | | `Cache` | Two-tier caching: Redis (if `ext-redis` available) with atomic filesystem fallback. TTLs: OS templates 10min, traffic/backups 2min, packages 10min. | | `ServerResource` | Transforms VirtFusion API response into flat key-value format for Smarty templates. Only reads `interfaces[0]`; for rDNS use `PowerDns\IpUtil::extractIps()` which walks all interfaces. | | `AdminHTML` | Static methods generating admin services tab HTML (server ID editor, JSON viewer, action buttons, `rdnsSection()` widget). | | `Log` | Thin wrapper around WHMCS module logging. | | `PowerDns\Client` | PowerDNS HTTP API wrapper (`X-API-Key` auth): `ping`, `listZones`, `getZone`, `patchRRset`, `notifyZone`. PATCH success triggers an automatic NOTIFY so slaves pick up the SOA bump immediately. | | `PowerDns\Config` | Loads settings from `tbladdonmodules` (module="virtfusiondns") and decrypts `apiKey` via WHMCS `decrypt()`. `isEnabled()` gates every PowerDNS call site. | | `PowerDns\IpUtil` | Pure helpers: `ptrNameForIp` (v4/v6 nibble reversal), `expandIpv6`, `extractIps` (all interfaces), `findZoneAndPtrName` (standard + RFC 2317 classless), `parseClasslessZone`. | | `PowerDns\Resolver` | Forward-DNS verification via `dns_get_record()` with up-to-5-hop CNAME following. Cached per (hostname, ip) pair. | | `PowerDns\PtrManager` | Orchestrator: `syncServer`, `deleteForServer`, `listPtrs`, `setPtr`, `reconcile`, `reconcileAll`. Per-request zone cache. 10s per-IP write rate limit. Enforces FCrDNS before writes. | | `StockControl` | Orchestrator for dynamic inventory. `recalculateForProduct()` and `recalculateAll()` compute per-product qty from live `/packages/{id}` + `/compute/hypervisors/groups/{id}/resources` data and write to `tblproducts.qty`. Fail-safe: null return = qty untouched. | ### Class Hierarchy `ModuleFunctions` and `ConfigureService` both extend `Module`. Most business logic lives in `Module` — it handles API calls, auth, validation, and all feature-specific operations. The `resolveServiceContext()` method provides a standardized way to look up service → WHMCS service → control panel → curl client in a single call, eliminating boilerplate across all API methods. ### Client-Side - **`templates/overview.tpl`** — Smarty template for client area. Panel order top-down: Hypervisor maintenance banner → VNC Console (button only) → Server Overview (with location/OS/lifetime meta chips, Mask Sensitive toggle, IP rows with copy buttons, Login to Control Panel footer) → Traffic chart (12-month aggregates) → Live Stats (CPU/memory/disk I/O, 30s refresh) → Power Management → Manage (password reset + backups) → Rebuild (OS gallery) → Reverse DNS (when PowerDNS enabled) → Resources (with filesystem usage when qemu-agent reports it) → Self-Service Billing (when configoption4>0) → Billing Overview. - **`templates/js/module.js`** — Vanilla JS + jQuery handling AJAX calls, DOM updates, status badges, power actions, all management UIs. Key helpers: `vfUrl()` (URL builder), `vfShowAlert()` (alert display), `vfRenderOsGallery()` (accordion gallery), `vfDrawTrafficChart()` (canvas chart, monthly bars + centered legend), `vfRenderIpCells()` (IP-row + copy button), `vfRenderLiveStats()` / `vfRenderFilesystems()` (remoteState surfaces), `vfMaskString()` / `vfApplyIpMask()` / `vfToggleIpMask()` (Mask Sensitive — IPv4 keeps first 2 octets, IPv6 keeps first 2 hextets, hostnames keep first char per dot-label; inputs masked via `text-security: disc`), `vfBuildSectionNav()` (toggles sidebar Jump-To items based on visible-panel state). - **`templates/js/keygen.js`** — Client-side SSH Ed25519 key generator using Web Crypto API (loaded on checkout page) - **`templates/css/module.css`** — Cross-theme styles with Bootstrap 3/4/5 dual class support (`panel card`, `panel-body card-body`). Panel margins are `mb-2` (8px) for tight stacking; `.vf-panel-grid` provides side-by-side panel layouts when used. ### Sidebar Integration - **WHMCS Actions sidebar** receives an "On This Page" group via `ClientAreaPrimarySidebar` hook (in `hooks.php`), gated to productdetails for VF services only. Each entry carries `data-vf-target=` so the document-level smooth-scroll click handler in `module.js` picks it up regardless of theme markup. Visibility per entry is toggled by `vfBuildSectionNav()` after page load — works whether the theme renders sidebar items in `
  • ` wrappers (Six) or as bare `` elements (Twenty-One). - **`ServiceSingleSignOnLabel` metadata** is set to "Login to VirtFusion Panel" but the auto-render of this in the WHMCS 9 sidebar is unreliable. The reliable surface is the inline "Login to Control Panel" button in the Server Overview footer, which calls `vfLoginAsServerOwner()` to fetch a one-shot SSO URL via `Module::fetchLoginTokens()` and opens it in a new tab. ### VNC viewer security model - Customer clicks "Open Console" → `window.open('client.php?action=vncViewer&serviceID=X')`. - The route checks `isAuthenticated()` + `validateUserOwnsService()` + `requireProvisionedService()`, then POSTs to `/servers/{id}/vnc {vnc:true}` to rotate the wss token, returning `text/html` with the noVNC shell embedded (hidden `#con` / `#pass` / `#server-name` inputs + `