Backend TypeScript untuk studi pilot EMERA — Hono di Cloudflare Workers dengan Supabase/PostgreSQL. Backend adalah satu-satunya pemilik aturan studi (eligibility, randomisasi, pemilihan intervensi); mobile hanya menampilkan state server dan mengirim command.
Product baseline:
PRD.md. Setiap perubahan scope yang disetujui dicatat didocs/decision-log.md.
| Layer | Pilihan |
|---|---|
| Framework | Hono + @hono/zod-openapi |
| Runtime | Cloudflare Workers (kode aplikasi runtime-agnostic) |
| Database / Auth / Storage | Supabase (PostgREST over HTTP, JWT, Storage signed URLs) |
| Validation & Contracts | Zod (satu canonical contract → OpenAPI) |
| Testing | Vitest (app.request() — tanpa server) |
| Package manager | pnpm |
| OpenAPI | openapi.yaml di root (dibangkitkan deterministik, lihat pnpm openapi:*) |
# 1. Install dependencies (memakai lockfile)
pnpm install
# 2. Siapkan env development (placeholder synthetic sudah cukup untuk M0)
cp .env.example .env
cp .dev.vars.example .dev.vars # dibaca `wrangler dev`
# 3. Jalankan server lokal di http://localhost:8787
pnpm dev
# 4. Validasi lokal
pnpm typecheck
pnpm lint
pnpm format:check
pnpm test
pnpm build # wrangler deploy --dry-run (bundle check)
pnpm openapi:check # drift check OpenAPISetelah pnpm dev berjalan:
GET http://localhost:8787/healthGET http://localhost:8787/openapi.json
| Script | Fungsi |
|---|---|
pnpm dev |
Jalankan Workers lokal (wrangler) |
pnpm deploy |
Deploy ke Cloudflare Workers |
pnpm build |
Bundle check via wrangler deploy --dry-run |
pnpm typecheck |
tsc --noEmit strict |
pnpm lint / pnpm format:check |
ESLint + Prettier check |
pnpm test / pnpm test:watch |
Vitest |
pnpm openapi:generate / openapi:check |
Generate / drift-check openapi.yaml |
pnpm bootstrap:owner |
Bootstrap researcher owner pertama (script) |
pnpm cf:types |
Generate tipe bindings via wrangler (opsional) |
src/
app.ts # komposisi route + middleware + onError
server.ts # entry Cloudflare Workers
config.ts # validasi env (fail closed di produksi)
types.ts # Env bindings + variabel per-request
auth/ # M1: verifikasi bearer + role resolution
modules/ # accounts, team, protocol, onboarding, decision-points,
# safety, researcher, exports, notifications
infrastructure/ # supabase, storage, email
shared/ # errors, http, observability, validation
test/ # integration tests via app.request()
supabase/ # migrations + seed.sql
scripts/openapi.ts # generator openapi.yaml deterministik
Pola module: route.ts (validasi transport → panggil satu use case) →
use-cases.ts (logika bisnis, termasuk trial-critical) → repository.ts
(adapter Supabase/Postgres). Keputusan trial-critical tidak pernah ada di
route handler (PRD §6).
| Milestone | Status |
|---|---|
| M0 — Repository Initialization | ✅ selesai |
| M1 — Contracts And Auth Skeleton | ✅ selesai (JWT HS256 via jose, roles) |
| M2 — Protocol And Team | ✅ selesai (launch-blocking validation) |
| M3 — Onboarding And Enrollment | ✅ selesai (consent, screening, enroll atomik) |
| M4 — Decision-Point Vertical Slice | ✅ selesai (jadwal, EMA, evaluate, randomize) |
| M5 — Safety Operations | ✅ selesai (alert, queue, transisi audit) |
| M6 — Researcher Monitoring And Export | ✅ selesai (overview, timeline, export sanitasi) |
| M7 — Pilot Hardening | ⏳ parsial — item butuh input manusia = launch blockers |
Detail: ARCHITECTURE.md · SECURITY.md ·
CONTRIBUTING.md · docs/runbook.md ·
docs/CHECKPOINT.md (progres & next steps)
⚠️ Launch blockers (PRD §14) memerlukan input manusia sebelum deployment participant nyata. Daftar lengkap:docs/launch-blockers.md.