Skip to main content

Architecture

Loch Panel is made of three projects, each in its own Git repository, grouped in one workspace directory.

ProjectRoleStack
host-panel-apiREST and WebSocket API, drives Docker (port 2538)Go 1.27, standard net/http, Moby Docker SDK
host-panel-interfaceWeb interface (port 5173 in development), in 10 languagesReact 19, TypeScript, Vite, Ant Design 6, TanStack Query
host-panel-cliloch CLI and MCP serverGo, Cobra, Viper

How the projects talk​

FromToChannelAuthentication
InterfaceAPIREST (Axios, withCredentials: true)Session cookie
InterfaceAPIWebSocket /ws: shell, live logs, live statsSession cookie
CLIAPIREST and WebSocket /ws (also the TCP port proxy)X-API-Key header
APIDockerDocker socket—
APISFTPGoSFTPGo admin REST API (when SFTP_ENABLED)X-SFTPGO-API-KEY header

Session (browser). The API runs the OIDC login itself (/openid-connect/login, then /openid-connect/redirect). It stores the token in a signed authorization cookie and checks it against the provider's JWKS on each request. When the API answers 401, the interface redirects to /openid-connect/login. A session has every permission of its user.

API key (CLI, scripts, MCP). The X-API-Key header is checked first. A key carries its user's profile and can be limited by scopes. See API reference.

Request path in the API​

  1. Global middlewares, in this order: Recovery, Logging, AuditRequests, RateLimit (120 requests per minute per IP), SecurityHeaders, CORS(FRONT_URL), SameOrigin(FRONT_URL) (CSRF).
  2. Route wrapper: authenticated (API key, otherwise JWT and user) or adminOnly (the same, plus the admin check). Routes are declared in cmd/server/main.go.
  3. Handler: checks the API key scope with middleware.RequireScope, then answers with writeJSON / writeError.

API packages​

PackageRole
cmd/serverEntry point: configuration, wiring, routes, service engine registration (serviceEngines())
internal/config, internal/envEnvironment loading, validation and lint
internal/authOIDC providers, JWKS, signed cookies
internal/middlewareAuthentication, CSRF, CORS, rate limit, audit, logging
internal/handlerHTTP and WebSocket handlers, error codes
internal/wsWebSocket hub: logs, shell, stats, port proxy
internal/dockerDocker client, container cache (3 s), exec, networks
internal/store, internal/modelAtomic JSON persistence; users, API keys
internal/cronScheduled tasks: scheduler, executor, store
internal/auditAudit log writer and reader
internal/hosting, internal/composekitWeb hosting; helpers to write and run compose projects
internal/sftpgoSFTPGo admin client
internal/servicesManaged services core; one sub-package per engine (postgres, mysqlfamily, mongodb, redisfamily, nats, rabbitmq, elasticmq, mosquitto, s3)
internal/networksPrivate networks: registry, verification, members
internal/functionsFunctions (work in progress): manager, compose rendering, code upload, runtime binary, invocation
internal/registry, internal/releasesImage references (mirror.gcr.io, ghcr.io); version discovery

The API stores its state in JSON files under DATA_DIR (users.json, apikeys.json, cron.json, networks.json) and writes the audit trail to audit.log in its log directory.

Interface structure​

PathContent
src/config.tsRuntime configuration: window.__APP_CONFIG__, then VITE_* variables, then defaults
src/i18n/i18next setup, typed keys, locale files
src/Services/<Area>/API calls (service.ts), models, React Query hooks
src/Pages/<Area>/One folder per page
src/Components/Shared components; menu in Components/Layout/MenuLayout.tsx
src/App.tsxRoutes
tests/Mocked API, Vitest setup, Playwright tests

Good to know​

  • Each project has its own Git repository: commit in the project you changed.
  • The CLI has no access to Docker: everything goes through the API.
  • The detailed design notes stay in the API repository (host-panel-api/docs/).