Boilerplate berbasis Clean Architecture untuk runtime Bun, dengan lapisan yang jelas dan siap dipakai untuk pengembangan fitur baru.
- Kenapa pakai boilerplate ini?
- Tech stack
- Struktur folder
- Peta layer (target per folder)
- Installasi & setup
- Scripts & perintah
- Generate code (scaffolding)
- Testing
- Lisensi
- Pemisahan lapisan: Aturan bisnis terpisah dari framework, DB, dan HTTP.
- Mudah di-test: Use case dan repository bisa di-test tanpa server atau DB nyata.
- Type-safe: TypeScript di seluruh codebase.
- Repository independen: Layer repository hanya bergantung pada schema/DB dan types sendiri, tidak ke module tertentu.
- Siap dipakai: Migrasi, validasi (Joi), logging (Winston), CORS, Swagger, cron, seed.
| Bagian | Teknologi |
|---|---|
| Runtime | Bun v1.3+ |
| Bahasa | TypeScript |
| Framework HTTP | ElysiaJS |
| ORM | Sequelize |
| Validasi | Joi |
| Logging | Winston |
| Testing | Bun Test |
src/
βββ app.ts # Entry point
βββ config/ # Konfigurasi app + validasi env
βββ cron/ # Job terjadwal (cron)
βββ database/
β βββ repository/ # Akses data per entity: repository.ts, types.ts, contract.ts (enum / kontrak nilai)
β β βββ category/
β βββ sequelize/ # Koneksi Sequelize, model, relasi, migrasi
β βββ models/
β βββ migrations/
β βββ interface.ts
β βββ relations.ts
β βββ sequelize.ts
βββ external/ # Integrasi eksternal (contoh: redis)
βββ helpers/ # Utility (request params, validasi, date, regex, dll)
βββ modules/ # Fitur/domain (entity, usecase, delivery/http)
β βββ category/
βββ pkg/ # Shared package (logger, jwt, status code, error, i18n)
βββ transport/ # Setup HTTP (Elysia), middleware
βββ migrater.ts # CLI migrasi DB (up/down)
βββ examples/ # Contoh (curl, upload file); lihat README di folder
Bagian ini untuk cepat orientasi (termasuk kalau kerja ala βvibe codeβ): kamu cukup tahu file yang kamu sentuh itu βmasuk layer manaβ dan boleh ngapain / jangan ngapain. Template Plop tidak perlu diubah; yang perlu konsisten adalah arah dependency (lihat diagram di bawah).
Request masuk dari HTTP β Handler β Use case β Repository β DB.
Jangan balik arah (misalnya repository tidak boleh import handler atau Elysia).
| Layer (istilah umum) | Lokasi di repo ini | Target / tugas | Hindari |
|---|---|---|---|
| Frameworks & drivers | transport/, config/, database/sequelize/, external/, app.ts |
Wiring server (Elysia), plugin global, koneksi DB, env, Redis, entry app | Taruh aturan bisnis di sini |
| Interface adapters (masuk) | modules/<x>/delivery/http/ |
Terjemahin HTTP (query, body, params) β panggil use case; format response | Query DB langsung, logic bisnis berat |
| Application (use cases) | modules/<x>/usecase/ |
Orkestrasi bisnis satu fitur: panggil repo(s), validasi aturan domain | Import elysia, Context, atau raw SQL di sini |
| Domain (entity) | modules/<x>/entity/ |
Bentuk data + schema validasi request (Joi) untuk fitur itu | Akses DB atau HTTP |
| Interface adapters (keluar) | database/repository/<entity>/ |
CRUD/query Sequelize; types.ts + contract.ts (enum / kontrak nilai per entity) |
Import module modules/... |
| Shared kernel | helpers/, pkg/ |
Util murni (parse query, error, logger, JWT) yang dipakai banyak layer | Jadi βtempatβ fitur bisnis baru |
- Kolom/tabel baru β
make:modelβdatabase/sequelize+database/repository. - Endpoint + alur bisnis β
make:moduleβmodules/<nama>/(entity β usecase β handler). - Daftarkan module β
src/app.ts(generator biasanya sudah menyisipkan). - Global HTTP (CORS, error shape,
/docs) βtransport/http/http.tssaja.
flowchart LR
subgraph outer ["Framework dan infra"]
T[transport/http]
C[config]
SEQ[database/sequelize]
EXT[external]
end
subgraph module ["modules / fitur"]
H[delivery/http handler]
U[usecase]
E[entity]
end
REP[database/repository]
H --> U
U --> REP
U --> E
REP --> SEQ
T --> H
Ringkasnya: pusat ada di use case; HTTP dan DB hanya adapter. Dependency mengalir ke dalam: entity dan use case tidak boleh bergantung pada Elysia atau detail HTTP.
Prasyarat: Bun v1.3+
git clone https://github.com/ayocodingit/clean-architecture-bun.git
cd clean-architecture-bun
bun install
cp .env.example .env
# Edit .env (DB, JWT, dll)
bun run migrate| Perintah | Deskripsi |
|---|---|
bun run dev |
Jalankan app (watch mode) |
bun run build |
Build production (minify) ke ./build |
bun start |
Jalankan hasil build (./build/app.js) |
bun run migrate |
Jalankan migrasi DB (up) |
bun run migrate:rollback |
Rollback satu migrasi (down) |
bun run make:model |
Generate model + migrasi + repository (lihat bawah) |
bun run make:module |
Generate module (usecase + handler + entity) |
bun run make:migration |
Generate file migrasi kosong |
bun run make:cron |
Generate file cron kosong |
bun run seed:run -- --name=<nama> |
Jalankan seed (src/database/seeds/<nama>.seed.ts) |
SEED_NAME=<nama> bun run seed:run |
Alternatif tanpa argumen CLI (berguna di CI / script) |
bun run cron:run -- --name=<nama> |
Jalankan cron (src/cron/<nama>.cron.ts) |
CRON_NAME=<nama> bun run cron:run |
Alternatif tanpa argumen CLI |
bun test / bun run test:unit |
Jalankan test (helpers) |
bun run lint |
Cek format (Prettier) |
bun run lint:fix |
Perbaiki format otomatis |
Semua generator memakai Plop dan menyesuaikan struktur Clean Architecture di repo ini.
Menambah satu entity di sisi persistence:
- Migrasi β
src/database/sequelize/migrations/<timestamp>-<name>.ts(up/down) - Model Sequelize β
src/database/sequelize/models/<repository>.ts - Repository β
src/database/repository/<repository>/repository.ts(classXxxRepository) - Types repository β
src/database/repository/<repository>/types.ts(CreateXxxInput,UpdateXxxInput,XxxFilter) - Contract (enum / nilai tetap) β
src/database/repository/<repository>/contract.ts(starter dari generator; sesuaikan dengan kolom DB)
Model dan repository otomatis didaftar di src/database/sequelize/interface.ts dan sequelize.ts.
Prompt:
- Migration name (contoh:
create-posts) - Repository name (contoh:
post) β dipakai untuk nama folder, class, dan model - Table name (contoh:
posts) β nama tabel di DB
Contoh: Repository name post, table posts β folder repository/post/, model models/post.ts, tabel posts.
Menambah satu fitur (module) di sisi aplikasi:
- Entry module β
src/modules/<name>/<name>.ts(registrasi route & inject repository, usecase, handler) - Usecase β
src/modules/<name>/usecase/usecase.ts - Handler HTTP β
src/modules/<name>/delivery/http/handler.ts - Entity β
src/modules/<name>/entity/interface.tsdanschema.ts(Joi)
Module otomatis di-import dan didaftar di src/app.ts.
Prompt:
- Module name (contoh:
post) β route mis./v1/posts,/v1/public/posts - Repository name(s) (opsional, dipisah koma)
contoh:postataupost,useratau kosong
Perilaku generator:
- Jika diisi 1 repository (contoh
post): template usecase CRUD otomatis terhubung kePostRepository. - Jika diisi lebih dari 1 repository (contoh
post,user) atau kosong: semua repository (jika ada) tetap di-import/inject, tetapi method usecase dibuat sebagai skeleton (NOT_IMPLEMENTED) agar bisa kamu isi manual sesuai flow bisnis module.
Penting: Repository yang kamu isi tetap harus sudah ada (buat dulu via make:model atau manual).
Hanya menambah satu file migrasi di src/database/sequelize/migrations/ (up/down kosong, isi manual).
Prompt: Migration name, Table name.
Menambah satu file cron di src/cron/<name>.cron.ts.
Prompt: Cron job name (contoh: sync-users).
Test fokus ke helper di src/helpers:
bun test
# atau
bun run test:unitMIT.