12 KiB
Agent Instructions
Read WORKSPACE_MEMORY.md before making structural changes to page code.
Stack
- Runtime: Bun — not Node. Use
buncommands, nevernpm/npx. - Framework:
@moduletrace/bunext— not Next.js. Routing is filesystem-based undersrc/pages/, served byBun.serveinsrc/server.ts. - Database:
@moduletrace/bun-sqlite— MariaDB database. Schema indb/schema.ts, generated types indb/types/db.ts. Config inbun-sqlite.config.ts(DB namerpe.dbin./db). - UI: Tailwind CSS v4 + local
twuicomponents (src/components/twui) + shadcn/ui (src/components/ui). shadcn/ui configured viacomponents.json(style:radix-vega), CSS entry atsrc/components/twui/base.css(imported bysrc/styles/globals.css). Uses@shadcnblocksregistry for extra blocks (src/components/shadcnblocks). - Icons:
lucide-react. - Validation:
zodv4 ([email protected]).
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-mcpto 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-systemsto pull canonical UI patterns, atomic component guidelines, and standard prop naming conventions before creating custom components.
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.
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) |
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>.
Architecture
Root Component & Context
src/pages/__root.tsx — sets up:
- Layout selection (admin/auth/public)
- WebSocket connection via
useWebSocket+useWebSocketEventHandler AppContext(React context) providingAppContextTypeglobally — includes user data, WebSocket, andsendWebsocketData- Server-navigated URL push via
server:navigate-to-urlWebSocket event
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. Requiresadminorexcorole./admin/security/*— Security features: gate control, guest access monitoring, dependant verification. Requiressecurity,exco,manager, oracorole.
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).
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/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-getsrc/functions/— Shared functions split by target:src/functions/backend/— Server-only: DB queries (grab-usersinbackend/db/), email client, RAG ingest, media upload, embed/face ingestsrc/functions/frontend/— Client-safe: CRUD handlers, fetch handlers, Paystack script loader, URL parsersrc/functions/general/— Platform-agnostic: join builders ingeneral/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.tsfiles (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 keyssrc/data/— Static data:app-data.ts(app constants — cookie names, limits, default models, Paystack endpoint), location data, super admin users, role documentationsrc/types/— Type definitions (~1,350 lines total across 4 files):index.ts(1,037 lines),sql-joins.ts,paystack.ts,search-api.tssrc/lib/—utils.tsexportscn()(clsx + tailwind-merge), used by shadcn/ui componentssrc/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) |
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.
.envis 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.tsexcludesonnxruntime-nodeand@xenova/transformersfrom SSR/page compilation (native modules that must stay server-side). tsconfig.jsonexcludessrc/components/twui/mdx,src/components/twui/elements/RemoteCodeBlock.tsx, andsrc/components/twui/mdx/markdown/MarkdownEditorPreviewComponent.tsxfrom 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 viaclassName(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 ownpackage.json), not scoped to this repo. Do not modify its components unless strictly necessary. Customize/appearance overrides for this project belong insrc/styles/globals.css(e.g. tweaking.twui-card,--color-*tokens, font/type styles) rather than editing twui source files.