- tambah Elysia Swagger di /docs dengan deskripsi lengkap semua endpoint - tambah API key auth (X-API-Key) untuk klien eksternal di POST /api/bugs - tambah normalisasi BugSource: SYSTEM/USER untuk eksternal, QC/SYSTEM/USER untuk dashboard - perbaiki source schema jadi optional string agar tidak reject nilai unknown dari klien lama - hapus field status dari form create bug (selalu OPEN) - perbaiki typo desa_plus → appId di apps.$appId.errors.tsx - tambah toggle hide/show stack trace di bug-reports.tsx dan apps.$appId.errors.tsx - perbaiki grafik desa (width(-1)/height(-1)) dengan minWidth: 0 pada grid item - perbaiki error &[data-active] inline style di DashboardLayout → pindah ke CSS class - update CLAUDE.md dengan arsitektur lengkap Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.5 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Runtime
Default to Bun instead of Node.js everywhere:
bun <file>notnode/ts-nodebun testnotjest/vitestbun installnotnpm install/yarn/pnpmbun run <script>notnpm runbunx <pkg>notnpx- Bun auto-loads
.env— never use dotenv.
Common Commands
bun run dev # dev server with hot reload (bun --watch src/serve.ts)
bun run build # Vite production build
bun run start # production server (NODE_ENV=production)
bun run typecheck # tsc --noEmit
bun run lint # biome check src/
bun run lint:fix # biome check --write src/
# Database
bun run db:migrate # prisma migrate dev
bun run db:seed # seed demo data
bun run db:generate # regenerate prisma client
bun run db:studio # Prisma Studio GUI
bun run db:push # push schema without migration
# Tests
bun run test # all tests
bun run test:unit # tests/unit/
bun run test:integration # tests/integration/ — no server needed
bun run test:e2e # tests/e2e/ — requires Lightpanda Docker
Run a single test file: bun test tests/integration/auth.test.ts
Architecture
Server
Elysia.js on Bun. All API routes are in src/app.ts as createApp() — testable via app.handle(request) without starting a server. src/index.tsx adds Vite middleware (dev) or static serving (prod) and calls .listen(). src/serve.ts is the dev entry point (dynamic import workaround for Bun EADDRINUSE race).
Database
PostgreSQL via Prisma v6. Client generated to ./generated/prisma (gitignored — run bun run db:generate after checkout or schema changes).
Schema models: User, Session, App, Log, Bug, BugImage, BugLog
Enums: Role (ADMIN, DEVELOPER), BugStatus (OPEN, ON_HOLD, IN_PROGRESS, RESOLVED, RELEASED, CLOSED), BugSource (QC, SYSTEM, USER), LogType (CREATE, UPDATE, DELETE, LOGIN, LOGOUT)
Import the singleton: import { prisma } from './lib/db'
Auth & Roles
Session-based auth with HttpOnly cookies stored in the DB (24h expiry). Two roles: DEVELOPER (super admin) and ADMIN. Users listed in SUPER_ADMIN_EMAIL env var are auto-promoted to DEVELOPER on login.
Endpoints: POST /api/auth/login, POST /api/auth/logout, GET /api/auth/session
Auth state on the frontend is managed via useSession() / useLogin() / useLogout() in src/frontend/hooks/useAuth.ts (TanStack Query).
Frontend
React 19 + Vite 8 (middleware mode in dev). TanStack Router with file-based routing in src/frontend/routes/. All routes are wrapped in DashboardLayout from src/frontend/components/DashboardLayout.tsx.
Route structure:
/→ redirect/login→ login page/dashboard→ stats overview/apps→ app list/apps/$appId→ per-app layout with nested routes:index,errors,logs,users,villages,orders,products,payments/users→ operator management/logs→ system activity log/bug-reports→ cross-app bug reports/profile→ user profile
App configs are defined in src/frontend/config/appMenus.ts — each app has an ID and a menu list. Currently active: desa-plus. Add new app entries here to register them.
routeTree.gen.ts is auto-generated by the TanStack Router Vite plugin — never edit it manually.
UI: Mantine v8, dark theme forced (#242424). Charts use @mantine/charts (recharts under the hood). Icons from react-icons/tb.
API Structure
All API routes live in src/app.ts. Key groups:
/api/auth/*— authentication/api/dashboard/*— stats and recent errors/api/apps,/api/apps/:appId— app listing and detail/api/bugs,/api/bugs/:id/status,/api/bugs/:id/feedback— bug report CRUD/api/operators,/api/operators/:id— user management/api/logs— system activity log/api/system/status— health check with DB connectivity
Logging
createSystemLog(userId, type, message) from src/lib/logger.ts writes to the Log model. Call it for any significant user action (login/logout/CRUD). Logging errors are swallowed so they never break the main flow.
Environment Variables
Required: DATABASE_URL, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
Optional: PORT (default 3000), NODE_ENV, REACT_EDITOR, SUPER_ADMIN_EMAIL (comma-separated)
Validated at startup in src/lib/env.ts — missing required vars throw immediately.
Testing
- Unit tests: env, DB connection, bcrypt — in
tests/unit/ - Integration tests:
createApp().handle(new Request(...))— no running server needed, use these for mutations - E2E tests: Lightpanda browser via CDP (
ws://127.0.0.1:9222). App URLs usehost.docker.internalfrom inside Docker. Lightpanda executes JS but POST fetch returns 407 — use integration tests for anything that writes data. - Helpers:
tests/helpers.ts—createTestApp(),seedTestUser(),createTestSession(),cleanupTestData()
Dev Tools
- Click-to-source:
Ctrl+Shift+Cmd+Ctoggles inspector. Custom Vite plugin insrc/vite.tsinjectsdata-inspector-*attributes; reads original source from disk for accurate line numbers. - HMR: Vite 8 +
@vitejs/plugin-reactv6.dedupeRefreshPlugininsrc/vite.tsprevents double React Refresh injection. - Editor: Set
REACT_EDITORenv var.zed/sublusefile:line:col; others get--goto file:line:col. - Playwright MCP:
bun run mcp:playwrightstarts headless browser MCP server (config in.qwen/settings.json).