2
Arsitektur Berlapis
Template ini membagi kode menjadi empat lapisan: delivery, usecase, repository, dan gateway. Aturan utamanya satu arah — lapisan luar boleh memanggil lapisan dalam, tidak sebaliknya. README menuliskan urutan itu secara eksplisit, dari external system yang mengirim request sampai gateway yang memanggil sistem luar. README.md:7-211
Empat Lapisan dan Perannya
| Lapisan | Paket | Tanggung jawab | Identifier contoh |
|---|---|---|---|
| Delivery HTTP | internal/delivery/http | membaca request, memanggil usecase, menulis response | UserController.Register |
| Delivery messaging | internal/delivery/messaging | membongkar event, meneruskan ke handler | UserConsumer.Consume |
| Usecase | internal/usecase | validasi, batas transaksi, orkestrasi | AddressUseCase.Create |
| Repository | internal/repository | operasi database lewat entity | Repository[T].Create |
| Gateway | internal/gateway/messaging | menyusun dan mengirim pesan ke sistem luar | Producer[T].Send |
Lapisan delivery HTTP menerima request, membentuk model, lalu memanggil usecase. UserController.Register membaca body ke model.RegisterUserRequest, memanggil UseCase.Create, dan membalas model.WebResponse. internal/delivery/http/user_controller.go:24-392 Delivery messaging memegang peran yang sama untuk event: UserConsumer.Consume membongkar JSON menjadi model.UserEvent, lalu mencatat isinya ke log. internal/delivery/messaging/user_consumer.go:21-313
Lapisan usecase memegang aturan bisnis dan batas transaksi. Struct UserUseCase menyimpan DB, Log, Validate, UserRepository, dan UserProducer. internal/usecase/user_usecase.go:19-254 AddressUseCase.Create memperlihatkan pola lengkapnya: validasi request, ambil entity.Contact lewat ContactRepository, bentuk entity.Address, simpan lewat AddressRepository.Create, commit, lalu kirim event lewat AddressProducer.Send. internal/usecase/address_usecase.go:40-875
Lapisan repository hanya berbicara dengan database memakai entity. Repository[T] menyediakan Create, Update, Delete, CountById, dan FindById di atas *gorm.DB. internal/repository/repository.go:5-296
Lapisan gateway menyusun panggilan ke sistem luar. Producer[T model.Event] melakukan json.Marshal pada event lalu mengirim sarama.ProducerMessage ke topic miliknya. internal/gateway/messaging/producer.go:11-427 Tiap producer konkret hanya menetapkan topic: UserProducer memakai topic users. internal/gateway/messaging/user_producer.go:10-218 Kontrak antara usecase dan gateway adalah interface model.Event dengan satu method GetId. internal/model/event.go:3-59
Arah Dependensi
graph TD
web["cmd/web"] --> config["internal/config"]
worker["cmd/worker"] --> config
worker --> dmsg["delivery/messaging"]
config --> dhttp["delivery/http"]
config --> dmsg
config --> uc["usecase"]
config --> repo["repository"]
config --> gw["gateway/messaging"]
dhttp --> uc
dhttp --> mw["delivery/http/middleware"]
dhttp --> model["model"]
mw --> uc
dmsg --> model
uc --> repo
uc --> gw
uc --> entity["entity"]
uc --> model
uc --> conv["model/converter"]
repo --> entity
repo --> model
gw --> model
conv --> entity
conv --> model
style repo fill:#336791,color:#fff
style entity fill:#336791,color:#fff
style model fill:#8b5cf6,color:#fff
style conv fill:#8b5cf6,color:#fff
style gw fill:#f59e0b,color:#000
style config fill:#f59e0b,color:#000
%% fig: Arah dependensi antar paket di internal
%% desc: Setiap panah menunjuk paket yang diimpor; delivery memanggil usecase, usecase memanggil repository dan gateway, dan keduanya hanya menyentuh entity serta model.Diagram di atas dibaca dari import nyata, bukan dari niat desain. delivery/http mengimpor model, usecase, dan middleware. internal/delivery/http/user_controller.go:3-1010 Middleware auth juga memanggil usecase, karena NewAuth menerima *usecase.UserUseCase dan memanggil Verify. internal/delivery/http/middleware/auth_middleware.go:10-2511
usecase mengimpor entity, gateway/messaging, model, model/converter, dan repository — lima paket dalam sekaligus. internal/usecase/user_usecase.go:3-1712 repository mengimpor entity dan model. internal/repository/contact_repository.go:3-913 gateway/messaging hanya mengimpor model, sehingga tidak tahu apa pun soal database maupun HTTP. internal/gateway/messaging/producer.go:11-427 model/converter mengimpor entity dan model untuk memetakan satu ke yang lain lewat UserToResponse dan UserToEvent. internal/model/converter/user_converter.go:8-2914
Entity sebagai Titik Netral
entity tidak mengimpor paket internal lain. Struct User hanya membawa tag gorm yang mengikat setiap field ke kolom tabel users. internal/entity/user_entity.go:1-1615 Posisi ini membuat repository dan usecase dapat berbagi bentuk data tanpa saling bergantung pada tipe konkret milik lapisan lain.
model juga hanya berisi struct data. WebResponse[T] dipakai lintas lapisan sebagai amplop response, dengan field Data, Paging, dan Errors. internal/model/model.go:3-1916
Penyimpangan dari Aturan
⚠️ Dua ketergantungan keluar dari pakem dan perlu diketahui sebelum menambah kode.
ContactRepositorymengimporinternal/modelkarena methodSearchmenerima*model.SearchContactRequestdan memakainya diFilterContact. internal/repository/contact_repository.go:26-3817UserUseCasemengimporgithub.com/gofiber/fiber/v2untuk mengembalikanfiber.ErrBadRequestsaat validasi gagal. internal/usecase/user_usecase.go:3-1712 Akibatnya usecase tidak lagi sepenuhnya bebas dari framework HTTP: error yang dikembalikannya sudah berupafiber.Error. Pemakaian itu terlihat diVerify. internal/usecase/user_usecase.go:38-4618
Titik Perakitan
Tidak ada lapisan yang membuat lapisan lain sendiri. internal/config mengimpor delivery/http, delivery/http/middleware, delivery/http/route, gateway/messaging, repository, dan usecase sekaligus, lalu merangkainya di satu fungsi Bootstrap. internal/config/app.go:3-1719 Urutannya tetap: repository dulu, lalu producer, usecase, controller, middleware, dan terakhir route. internal/config/app.go:28-6620 Route mendaftarkan controller ke fiber.App, dengan middleware auth dipasang sebelum grup route terautentikasi. internal/delivery/http/route/route.go:17-2521
Dua entrypoint memakai perakitan yang berbeda. cmd/web membuat fiber.App dan sarama.SyncProducer lalu memanggil config.Bootstrap. cmd/web/main.go:8-3022 cmd/worker tidak memakai Bootstrap sama sekali; ia menjalankan tiga consumer dan menyerahkan topic serta handler ke messaging.ConsumeTopic. cmd/worker/main.go:43-6223 ConsumeTopic menjalankan consumerGroup.Consume di dalam goroutine dan menutup group saat context dibatalkan. internal/delivery/messaging/consumer.go:46-7524
Rincian perakitan dan urutan bootstrap ada di Konfigurasi dan Bootstrap. Siklus satu request HTTP dibahas di Alur Request HTTP, dan perjalanan event dibahas di Alur Event Kafka.