Files
wireguard-ui/AGENTS.md
T
tbenandClaude Opus 5.5 fe4b1b02d1 Remove unused dependencies and dead code, refresh AGENTS.md
- Drop unused email module and media text extraction path
- Remove 12 unused dependencies
- Remove unused imports in server.ts
- Add typecheck and test scripts
- Rewrite AGENTS.md to describe this project

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 21:09:27 +01:00

8.6 KiB
Raw Blame History

Agent Instructions

WireGuard UI — a self-hosted web admin for WireGuard hosts and clients. The app runs as root and executes system commands (wg, ip, iptables, wg-quick, firewall managers). Treat every API route and every value that reaches a shell or a WireGuard config as security-sensitive.

Stack

  • Runtime: Bun — not Node. Use bun commands, never npm/npx.
  • Framework: @moduletrace/bunext — not Next.js. Routing is filesystem-based under src/pages/, served by Bun.serve in src/server.ts.
  • Database: @moduletrace/bun-sqlite — SQLite. Schema in db/schema.ts, generated types in db/types/db.ts. Config in bun-sqlite.config.ts (DB name wgui in ./db). Import its types from @moduletrace/bun-sqlite/types (not /dist/types).
  • UI: Tailwind CSS v4 + local twui components (src/components/twui). Global styles in src/styles/main.css.
  • Icons: lucide-react.

MCP Tool Usage Guidelines

When building, refactoring, styling, or auditing UI components and layouts, actively invoke these configured MCP servers:

1. design-mcp (UI/UX Engineering & Design Standards)

  • When to call: Before constructing new page layouts, design systems, empty/loading states, or interactive UI flows.
  • Instruction: Query design-mcp to ensure accessibility (a11y), proper layout hierarchy, visual balance, and consistent interaction patterns across application workflows.

2. design-systems (Design System Specs & Reference Patterns)

  • When to call: When creating or extending reusable component interfaces, verifying design token structures, or inspecting component composition patterns.
  • Instruction: Query design-systems to pull canonical UI patterns, atomic component guidelines, and standard prop naming conventions before creating custom components.

Entrypoint

src/server.ts — runs bunextInit(), starts Bun.serve on 0.0.0.0 (port from SiteData.ServerPort), serves /media/* via handleMediaServer, then runs syncWireguardHosts() to bring host tunnels in line with the DB.

On-disk state: WireGuard keys/configs/iptables scripts live under /var/lib/wgui (grabDirNames() in src/utils/grab-dir-names.ts); uploaded media under DATA_DIR (default ./.data).

Commands

Purpose Command
Dev server bun run dev (runs sudo bun src/server.ts)
Production bun run start
Build bun run build
Type-check bun run typecheck (bunx tsc --noEmit)
Tests bun run test (bun test)
DB schema bun run db:schema
DB admin UI bun run db:admin

No linter or formatter configured. Type-check and bun test are the verification steps.

Architecture

  • src/pages/__root.tsx — picks the layout (src/layouts/main or src/layouts/admin, or LoginShell for auth pages) and provides AppContext.
  • Pages: / + about, privacy, terms; /auth/{login,logout,signup}; /admin (dashboard), /admin/setup, /admin/settings, /admin/clients, /admin/hosts/* (add/edit hosts, [host_id]/clients/* add/edit/view clients).
  • API: src/pages/api/admin/* (host/client setup, network info, firewall status, service restart/update, media), generic CRUD at src/pages/api/admin/crud/[[...paths]].ts with per-table handlers in crud/(tables)/<table>/{get,post,put,del}.ts, plus api/auth/login.ts and api/create-first-user.ts.
  • Every /api/admin/* route must authenticate — nothing guards the prefix globally. Use adminApiGuard({ req }) (src/functions/backend/auth/admin-api-guard.ts) or userAuth + checkUserAccess.
  • Shell safety: never interpolate request/DB values into execSync strings. Use execFileSync with an args array or node:fs APIs, and validate values before they reach a WireGuard config (newlines there can inject PostUp commands). Validators live in src/utils/ (validate-ipv4, validate-ipv4-cidr, validate-allowed-ips, validate-endpoint-host, validate-interface-name).

Path Alias

@/* resolves from repo root. Import like @/src/components/general/admin-card, @/db/types/db.

Page Directory Rules

For route-local code under src/pages, use non-routed meta folders:

  • (sections) — page sections
  • (partials) — components used by sections
  • (data) — page-local data
  • (functions) — page-local functions
  • (utils) — page-local utilities
  • (hooks) — page-local hooks

Keep route files (e.g. index.tsx) thin — compose from route-local meta folders.

Dynamic routes use [param] syntax (e.g. [id], [user_type], [key]). Catch-all routes use [[...paths]].

Server functions use index.server.ts alongside index.tsx (e.g. single-document/[id]/index.server.ts).

Shared Code Organization

  • src/functions/backend/ — Server-only: auth/, db/, firewall/ (firewalld/ufw rules, status), media/, setup/ (host/client setup, iptables script builder, network detection).
  • src/functions/frontend/ — Client-safe: CRUD/fetch handlers, media upload/delete, client rule label formatting.
  • src/functions/server/ — Request-level server handlers (media server).
  • src/hooks/ — use-admin-crud-get, use-client-rules-map, use-fetch-get, use-form-init, use-users-get.
  • src/utils/ — Cookies, crypto, dir names, IP/CIDR/port/interface validators, WireGuard interface naming. Most have .test.ts files.
  • src/dict/, src/data/ — Constants (app-data.ts, site-data.ts), user types, client rules, links.
  • src/scripts/ — Shell scripts: install-wg-ui.sh, setup-wireguard.sh, wg-quick-manage.sh.
  • src/components/general/ — Shared app components (admin cards/buttons, clients table, host IP field, login shell, user form).

Conventions

  • Prefer one function/component per file over monolithic files with multiple exports.
  • Every rendered array must have a separate component for each array item. Always extract the item JSX into its own component and render it via items.map((item) => <ItemComponent {...item} />) — never inline the item's JSX inside the map callback.
  • Always use object parameters ({ foo, bar }) instead of comma-separated positional parameters.
  • Prefer existing patterns over new abstractions.
  • Modularization is non-negotiable: prioritize modularization over monolithic functions/components. Repeated UI blocks must be extracted into their own reusable components driven by props (e.g. an info row component taking { icon, text }), never repeated inline markup.
  • UNCHANGEABLE RULE — twui components always win over raw JSX elements. ALWAYS use twui components (H1–H5, P, Span, List, Img, Row, Stack, Container, Section, Border, Card, Button, Tag, Link, etc.) before basic JSX elements (<h1>–<h6>, <p>, <span>, <ul>, <li>, <img>, <a>, <button>, <div>-as-card, etc.). Never introduce or reintroduce a raw JSX element where a twui equivalent exists. Override twui defaults via className (e.g. mb-0!) rather than reaching for the raw element.
  • UNCHANGEABLE RULE — twui components are preferred over shadcn/ui components. Use twui before src/components/ui/* (shadcn) whenever a twui equivalent exists. The long-term goal is to phase out shadcn/ui entirely — do not introduce new shadcn usage where twui covers the need, and prefer migrating existing shadcn call sites to twui when touching them anyway.
  • LIMIT EDITS TO src/components/twui/ — it is a general, publishable library shared across projects (its own package.json), not scoped to this repo. Do not modify its components unless strictly necessary. Customize/appearance overrides for this project belong in src/styles/main.css (e.g. tweaking .twui-card, --color-* tokens, font/type styles) rather than editing twui source files.
  • twui Input/Textarea: prefer defaultValue over value. The component manages internal state and patches the DOM directly (src/components/twui/form/Input/index.tsx), so value is not a true controlled prop — a static value gets reverted on every re-render, wiping in-progress edits. value only works well when the parent updates it on each change (live display), not for pre-filling an editable field. Use defaultValue to pre-fill editable inputs; onChange/changeHandler still fire.
  • .env is gitignored but exists locally. Do not commit it.