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]>
This commit is contained in:
2026-10-15 21:09:27 +01:00
co-authored by Claude Opus 5.5
parent 617400c19f
commit fe4b1b02d1
6 changed files with 38 additions and 325 deletions
+32 -67
View File
@@ -1,15 +1,14 @@
# Agent Instructions
Read `WORKSPACE_MEMORY.md` before making structural changes to page code.
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` — MariaDB database. Schema in `db/schema.ts`, generated types in `db/types/db.ts`. Config in `bun-sqlite.config.ts` (DB name `rpe.db` in `./db`).
- **UI:** Tailwind CSS v4 + local `twui` components (`src/components/twui`) + shadcn/ui (`src/components/ui`). shadcn/ui configured via `components.json` (style: `radix-vega`), CSS entry at `src/components/twui/base.css` (imported by `src/styles/globals.css`). Uses `@shadcnblocks` registry for extra blocks (`src/components/shadcnblocks`).
- **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`.
- **Validation:** `zod` v4 (`[email protected]`).
## MCP Tool Usage Guidelines
@@ -27,48 +26,35 @@ When building, refactoring, styling, or auditing UI components and layouts, acti
## Entrypoint
`src/server.ts` — runs `bunextInit()`, initializes a persistent **Piper TTS daemon** (global `PIPER_MANAGER`), starts `Bun.serve` with WebSocket upgrade on `/ws`, then starts cron.
`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 `bun src/server.ts`) |
| Production | `bun run start` (`NODE_ENV=production bun src/server.ts`) |
| Type-check only | `bunx tsc --noEmit` |
| DB schema (tables) | `bun run db:schema` |
| DB schema (+vectors) | `bun run db:schema:vector` |
| DB admin UI | `bun run db:admin` |
| DB backup | `bun run db:backup` |
| Port SQLite → MariaDB | `bun run db:port-sqlite` |
| Install (private registry) | `bun install` (uses registry in `bunfig.toml`) |
| 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 is the primary verification step. 33 project-level `.test.ts`/`.test.tsx` files exist but no test runner script is configured — run individual tests with `bun test <file>`.
No linter or formatter configured. Type-check and `bun test` are the verification steps.
## Architecture
### Root Component & Context
`src/pages/__root.tsx` — sets up:
- Layout selection (admin/auth/public)
- WebSocket connection via `useWebSocket` + `useWebSocketEventHandler`
- `AppContext` (React context) providing `AppContextType` globally — includes user data, WebSocket, and `sendWebsocketData`
- Server-navigated URL push via `server:navigate-to-url` WebSocket event
- `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/ui/button`, `@/db/types/db`, `@/external/cloudflare/r2`.
## Admin Route Hierarchy
Two tiers of admin pages:
- **`/admin/*`** — Resident-facing features: access booking (`/admin/access`), payments (`/admin/payments/*`), chat (`/admin/chat/*`), dependants (`/admin/dependants`), notifications (`/admin/notification`), events (`/admin/events`), settings/profile, support/complaints. Additional sections: `association/`, `devops/`, `management/`, `workers/`
- **`/admin/admin/*`** — Admin-only features: user management (`/admin/admin/users/*`), payment schemes, payment management, documents/constitution, chat group management. Requires `admin` or `exco` role.
- **`/admin/security/*`** — Security features: gate control, guest access monitoring, dependant verification. Requires `security`, `exco`, `manager`, or `aco` role.
Admin sidebar navigation data in `src/layouts/admin/(data)/`. ElevenLabs voice agent widget integrated into admin layout (`src/layouts/admin/(partials)/eleven-labs-widget.tsx`).
`@/*` resolves from repo root. Import like `@/src/components/general/admin-card`, `@/db/types/db`.
## Page Directory Rules
@@ -89,45 +75,24 @@ Server functions use `index.server.ts` alongside `index.tsx` (e.g. `single-docum
## Shared Code Organization
- **`src/hooks/`** — Shared React hooks: `use-admin-crud-get`, `use-all-users-list-init`, `use-annual-dues-status`, `useAppContext`, `use-fetch-get`, `use-form-init`, `useLocalUser`, `use-mobile`, `use-payments-query`, `use-users-get`
- **`src/functions/`** — Shared functions split by target:
- `src/functions/backend/` — Server-only: DB queries (`grab-users` in `backend/db/`), email client, RAG ingest, media upload, embed/face ingest
- `src/functions/frontend/` — Client-safe: CRUD handlers, fetch handlers, Paystack script loader, URL parser
- `src/functions/general/` — Platform-agnostic: join builders in `general/joins/` (users, payments, guests, messages, chat groups)
- **`src/utils/`** — Utility modules: auth, cookies, crypto, CSRF, hashing, contact classification, RAG text chunking, user type parsing. Most have corresponding `.test.ts` files (auth, cookies, crypto, CSRF, hashing, contact classification, user type parsing).
- **`src/dict/`** — Dictionaries/constants: user types, access codes, gates, LLM providers/models, TTS voices, WebSocket rooms, messaging types, localStorage keys
- **`src/data/`** — Static data: `app-data.ts` (app constants — cookie names, limits, default models, Paystack endpoint), location data, super admin users, role documentation
- **`src/types/`** — Type definitions (~1,350 lines total across 4 files): `index.ts` (1,037 lines), `sql-joins.ts`, `paystack.ts`, `search-api.ts`
- **`src/lib/`** — `utils.ts` exports `cn()` (clsx + tailwind-merge), used by shadcn/ui components
- **`src/scripts/`** — Seed scripts for location and resident data
## Component Systems
| Directory | Description |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `src/components/twui/` | Local design system — publishable package with its own `package.json`. Contains elements, composites, editors (TinyMCE), form components, MDX support, hooks, layout, SVGs, and utilities |
| `src/components/general/` | Shared page components: AI chat, date-picker, logo, Paystack widgets, status-tag, user-avatar, face-search-card, guarantor-preview-modal, guarantor-info-row, etc. (search-select lives in `src/components/twui/form/SearchSelect.tsx`) |
| `src/components/pages/` | Public page components: `about/`, `constitution/`, `homepage/` |
| `src/components/shadcnblocks/` | Components from shadcnblocks.com registry (logo) |
- **`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.
- **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.
- **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.
- `.env` is gitignored but exists locally with secrets. Do not commit it.
- `secrets/` directory is also gitignored.
- `external/` binary directories (`**/models`, `**/bin`, `**/x-86`, `**/arm-64`) are gitignored.
- The `bunext.config.ts` excludes `onnxruntime-node` and `@xenova/transformers` from SSR/page compilation (native modules that must stay server-side).
- `tsconfig.json` excludes `src/components/twui/mdx`, `src/components/twui/elements/RemoteCodeBlock.tsx`, and `src/components/twui/mdx/markdown/MarkdownEditorPreviewComponent.tsx` from type-checking.
## Conventions
- Prefer one function/component per file over monolithic files with multiple exports.
- **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/globals.css` (e.g. tweaking `.twui-card`, `--color-*` tokens, font/type styles) rather than editing twui source files.
- **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.
+2 -224
View File
File diff suppressed because it is too large Load Diff
+4 -14
View File
@@ -9,20 +9,19 @@
"build": "bunx bunext build",
"db:schema": "bunx bun-sqlite schema -t",
"db:admin": "bunx bun-sqlite admin",
"start": "NODE_ENV=production bun src/server.ts"
"start": "NODE_ENV=production bun src/server.ts",
"typecheck": "bunx tsc --noEmit",
"test": "bun test"
},
"devDependencies": {
"@next/mdx": "^16.3.0",
"@types/ace": "^0.0.52",
"@types/bun": "latest",
"@types/lodash": "^4.17.25",
"@types/mdx": "^2.0.14",
"@types/node": "^26.2.0",
"@types/nodemailer": "^8.0.1",
"@types/qrcode": "^1.5.6",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4",
"@types/turndown": "^5.0.6",
"ace-builds": "^1.44.0",
"tailwindcss": "^4.3.3"
},
@@ -32,28 +31,19 @@
"dependencies": {
"@moduletrace/bun-sqlite": "^1.2.0",
"@moduletrace/bunext": "^1.2.4",
"gray-matter": "^4.0.3",
"html-to-react": "^1.7.0",
"lodash": "^4.18.1",
"lucide-react": "^1.31.0",
"mammoth": "^1.12.1",
"mdx": "^0.3.1",
"next-mdx-remote": "^6.0.0",
"nodemailer": "^9.0.5",
"onnxruntime-node": "^1.27.0",
"openai": "^7.4.0",
"qrcode": "^1.5.4",
"react-code-blocks": "^0.1.6",
"react-markdown": "^10.1.0",
"react-responsive-modal": "^7.2.0",
"rehype-prism-plus": "^2.0.2",
"remark-gfm": "^4.0.1",
"sharp": "^0.35.3",
"tailwind-merge": "^3.6.0",
"turndown": "^7.2.4",
"unpdf": "^1.8.0",
"uuid": "^14.0.2",
"xlsx": "^0.18.5"
"uuid": "^14.0.2"
},
"repository": {
"url": "https://git.tben.me/Moduletrace/wireguard-ui"
@@ -17,7 +17,6 @@ import BunSQLite from "@moduletrace/bun-sqlite";
import { existsSync, mkdirSync } from "fs";
import path from "path";
import sharp from "sharp";
import fileToText from "./file-to-text";
import MediaDataToArrayBuffer from "./media-data-to-array-buffer";
import sniffMediaExtension from "./sniff-media-ext";
import mediaDataToSharpInput from "./meida-data-to-sharp-input";
@@ -31,7 +30,6 @@ type Params = {
data?: MediaDataType;
is_primary?: boolean;
update_on_duplicate?: boolean;
extract_media_text_content?: boolean;
media?: BUN_SQLITE_WGUI_MEDIA;
media_name?: string;
media_mime_type?: string;
@@ -50,7 +48,6 @@ export default async function uploadAndRecordMedia({
media_type,
is_primary,
update_on_duplicate,
extract_media_text_content,
media,
media_mime_type,
media_name,
@@ -189,17 +186,6 @@ export default async function uploadAndRecordMedia({
await Bun.write(media_write_path_full, media_array_buffer, {
mode: 1,
});
if (extract_media_text_content) {
const media_text = await fileToText({
file_type: media_ext,
file_stream: Buffer.from(media_array_buffer),
});
if (media_text) {
media_text_content = media_text;
}
}
}
if (existsSync(media_write_path_full)) {
-2
View File
@@ -41,7 +41,6 @@ export const handler: BunextAPIRouteHandler<APIResponseObject> = async (
is_media_primary,
update_on_duplicate,
reauth,
return_media_text_content,
media,
is_media_private,
media_name,
@@ -61,7 +60,6 @@ export const handler: BunextAPIRouteHandler<APIResponseObject> = async (
media_type,
is_primary: is_media_primary,
update_on_duplicate,
extract_media_text_content: return_media_text_content,
media,
media_mime_type: ext,
user: { id: twuiNumberfy(user_id) },
-4
View File
@@ -2,10 +2,6 @@ import bunext from "@moduletrace/bunext";
import syncWireguardHosts from "./functions/backend/setup/sync-wireguard-hosts";
import handleMediaServer from "./functions/server/media/handle-media-server";
import { SiteData } from "./data/site-data";
import { execFile, execSync } from "node:child_process";
import path from "node:path";
declare global {}
const development = process.env.NODE_ENV == "development";
const port = SiteData["ServerPort"];