Files
desa-darmasaba/CLAUDE.md
nico 37940fc7e2 fix(img): fix WebP Content-Type bug and seed 232 missing FileStorage records
- img.ts: replace hardcoded 'image/jpeg' Content-Type with dynamic MIME_MAP
  lookup per file extension — WebP files now served with correct 'image/webp'
  header so browsers can decode them
- img.ts: skip sharp resize when no size param (serve original buffer directly)
- Adds migration 20260423072135 to add stok and umkmId columns to PasarDesa
- FileStorage DB now has all 232 MinIO images seeded (was 80, missing 152)
- All domain records (Berita 18/18, GalleryFoto 3/3, PasarDesa 4/4, etc.)
  now have imageId properly linked after full re-seed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 15:41:20 +08:00

138 lines
5.3 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Desa Darmasaba is a full-stack digital village management platform for a village in Badung, Bali. It serves both a public-facing website (`/darmasaba/*`) and an admin CMS (`/admin/*`).
## Commands
```bash
# Development
bun run dev # Start dev server (port 3000)
bun run build # Production build
bun run tsc --noEmit # Type-check only
# Testing
bun run test # All tests
bun run test:api # Unit tests (Vitest)
bun run test:e2e # E2E tests (Playwright)
# Database
bunx prisma migrate deploy # Apply migrations
bunx prisma migrate dev --name <name> # Create migration
bun run prisma/seed.ts # Seed database
bunx prisma studio # Interactive DB viewer
# Linting
bun eslint . --fix
```
## Architecture
### Tech Stack
- **Framework**: Next.js 15 (App Router) + React 19
- **Runtime/Package manager**: Bun (not npm)
- **API server**: Elysia.js (mounted at `/api/[[...slugs]]`)
- **ORM**: Prisma + PostgreSQL
- **UI**: Mantine UI v7-8
- **State**: Jotai (atoms), Valtio (proxies), SWR (data fetching)
- **Auth**: iron-session + JWT
- **File storage**: Local uploads + Seafile (self-hosted)
### Request Flow
```
Browser → Next.js middleware (src/middleware.ts)
→ Public pages: src/app/darmasaba/
→ Admin pages: src/app/admin/
→ API: src/app/api/[[...slugs]]/route.ts (Elysia.js)
└── _lib/*.ts (domain modules)
```
The Elysia server is a single entry point with domain-specific modules: `desa.ts`, `kesehatan.ts`, `ekonomi.ts`, `keamanan.ts`, `lingkungan.ts`, `pendidikan.ts`, `kependudukan.ts`, `ppid.ts`, `inovasi.ts`, `auth/`, `user/`, `fileStorage/`. Swagger docs are auto-generated at `/api/docs`.
### Domain Modules
Each domain (desa, kesehatan, ekonomi, etc.) has:
- API handler in `src/app/api/[[...slugs]]/_lib/<domain>.ts`
- Admin CMS pages in `src/app/admin/(dashboard)/<domain>/`
- Public pages in `src/app/darmasaba/(pages)/<domain>/`
### Database (Prisma)
- Schema at `prisma/schema.prisma` (~2400 lines, 100+ models)
- Common model conventions: `@default(cuid())` IDs, `createdAt`/`updatedAt` timestamps, `deletedAt DateTime?` (soft delete), `isActive Boolean @default(true)`
- Seeders per-module in `prisma/_seeder_list/`, orchestrated by `prisma/seed.ts`
### Authentication Flow
1. User submits phone → OTP sent (email/SMS)
2. OTP validated → JWT created + iron-session stored
3. `UserSession` model tracks active sessions
4. `src/middleware.ts` validates on each request
5. `src/lib/api-auth.ts` handles JWT/session checks in API routes
### File Handling
All uploaded files reference the `FileStorage` Prisma model. Uploads land in `WIBU_UPLOAD_DIR` (default: `uploads/`). Seafile is the external storage fallback.
## Key Files
| File | Purpose |
|------|---------|
| `src/middleware.ts` | Route guards and auth |
| `src/lib/prisma.ts` | Prisma client singleton |
| `src/lib/api-auth.ts` | JWT/session validation |
| `src/lib/api-fetch.ts` | Typed fetch wrapper used by frontend |
| `src/lib/session.ts` | iron-session config |
| `next.config.ts` | Next.js config (cache headers, allowed origins) |
| `postcss.config.cjs` | Mantine CSS preset and breakpoints |
| `docker-entrypoint.sh` | Runs `prisma migrate deploy` then starts app |
## Environment Variables
Copy `.env.example` to `.env`. Required variables:
```env
DATABASE_URL="postgresql://..."
NEXT_PUBLIC_BASE_URL="/"
BASE_SESSION_KEY="..." # random string
BASE_TOKEN_KEY="..." # random string
SESSION_PASSWORD="..." # min 32 chars
SEAFILE_TOKEN="..."
SEAFILE_REPO_ID="..."
SEAFILE_URL="..."
```
## Docker
Multi-stage build: `oven/bun:1-debian` → builder → runner. The runner creates a `nextjs` user (UID 1001), exposes port 3000, and mounts `/app/uploads` as a volume. Entrypoint runs migrations automatically.
## CI/CD
GitHub Actions workflows in `.github/workflows/`:
- `docker-publish.yml` — triggers on `v*` tags, pushes to GHCR
- `publish.yml` — manual build & push
- `re-pull.yml` — triggers Portainer to redeploy latest image
To release: tag with `git tag -a v0.1.x -m "..."` and push the tag.
### Workflow for Code Changes
1. **Commit** existing changes before starting new work
2. **Create plan** at `MIND/PLAN/[plan-name].md`
3. **Create task** at `MIND/PLAN/[task-name].md`
4. **Execute the task** and update task progress
5. **Create summary** at `MIND/SUMMARY/[summary-name].md` when done
6. **Run build** (`bun run build`) to ensure no compile errors
7. **Fix any build errors** if they occur
8. **Commit** all changes AFTER successful build
9. **Update version** in `package.json` for every change
10. **Push** to new branch with format: `tasks/[task-name]/[what-is-being-done]/[date-time]`
11. **Push ke 2 Remote** - Push ke 2 remote origin dan deploy
12. **Merge ke Branch** - Merge ke branch target (biasanya `stg` untuk staging atau `prod` untuk production) ke 2 remote origin dan deploy
### GitHub Workflows
1. **publish.yml**: Uses branch `main`, stack env and image tag matching version from `package.json`.
2. **re-pull.yml**: **Wait for `publish.yml` to complete successfully before running.** Uses branch `main`, stack env and stack name `desa-darmasaba`.
### After Progress
- Always give option to continue to GitHub workflows or not