RPLibrary Backend API
RPLibrary Backend API untuk sistem manajemen perpustakaan Lab RPL yang mendukung autentikasi dan autorisasi, manajemen katalog buku, peminjaman, pengembalian, dan waitlist buku.
1. Skema Database

Entitas utama:
prodis
users
books
tags
book_tags
borrowed_books
waitlists
Relasi penting:
- User -> Prodi (many-to-one)
- Book <-> Tag (many-to-many via
book_tags)
- BorrowedBook -> User dan Book
- Waitlist -> User dan Book
Enum penting:
- Role user:
Admin, User
- Borrow status:
pending, borrowed, returned, overdue
- Waitlist status:
waiting, notified, expired, completed, cancelled
2. Justifikasi Tech Stack
| Komponen |
Pilihan |
Alasan |
| Bahasa |
Go |
Cepat, efisien, concurrency baik, cocok untuk API production |
| HTTP Framework |
Gin |
Ringan, performa tinggi, middleware ecosystem matang |
| ORM |
GORM |
Produktif untuk CRUD, relasi, migrasi, transaksi, dan easy to read |
| Database |
PostgreSQL |
Kuat untuk relasi data, konsisten, battle-tested |
| Auth |
JWT |
Stateless auth yang sederhana untuk API mobile/webdan banyak digunakan |
| Dependency Injection |
samber/do |
Wiring dependency rapi dan testability lebih baik |
| Validasi |
go-playground/validator |
Validasi request terstruktur dan konsisten |
| Mailer |
gomail (SMTP) |
Mendukung alur verifikasi email, reset password, dan notifikasi melalui email |
| Encryption |
AES + bcrypt |
Menyediakan enkripsi data sensitif dan hashing password |
| Logging |
logrus |
Menyediakan logging yang konsisten dan mudah diatur |
| Storage |
FileSystem (aktif), AWS S3 (opsi) |
Dev-friendly local storage dan karena bisa diakses publicaly (karena ini open proejct), siap cloud jika dibutuhkan |
| Deployment |
Docker + Docker Compose |
Setup environment cepat dan reproducible |
3. Arsitektur Codebase
Menggunakan Layered Architecture karena gampang untuk dipahami, maintainable, dan juga gampang untuk di scale up jika nanti aplikasinya berkembang.

Sehingga alur request mengikuti pattern diagram berikut:
+--------------------------------------------------------------+
| Application Entry Point |
| main.go -> load .env -> init DB -> |
| cmd.Command (if args) OR config.NewRestConfig(db) |
+-------------------------------+------------------------------+
|
+-------------------------------v------------------------------+
| Configuration Layer (internal/config/) |
| - NewRouter: NoRoute, CORS, /api/ping, static /assets |
| - NewProvider: DI repositories/services/controllers (do) |
| - NewRestConfig: register routes + start background workers |
+-------------------------------+------------------------------+
|
+-------------------------------v------------------------------+
| HTTP Layer (internal/api/routes + internal/api/controller) |
| - Routing per modul: Auth, Book, Tag, Borrow, Waitlist, File |
| - Bind and validate input via internal/pkg/validate |
| - Response envelope via internal/pkg/response |
+-------------------------------+------------------------------+
|
+-------------------------------v------------------------------+
| Business Layer (internal/api/service/) |
| - User, Book, Tag, Borrow, Waitlist, JWT service |
| - Rule borrow/waitlist, status transition, token/email flow |
| - Worker: waitlist queue (startup + tiap 15 menit) |
| - Worker: overdue checker (startup + harian 00:00 WIB) |
+-------------------------------+------------------------------+
|
+-------------------------------v------------------------------+
| Data Access Layer (internal/api/repository/) |
| - Abstraksi query GORM, preload relasi, pagination |
| - Operasi CRUD + transaksi dari service layer |
+-------------------------------+------------------------------+
|
+-------------------------------v------------------------------+
| Database Layer (PostgreSQL via GORM) |
| - Persistensi users, books, tags, borrows, waitlists |
+--------------------------------------------------------------+
Cross-cutting concerns yang aktif:
internal/middleware/: authentication, cors, only_allow, time.
internal/pkg/: logger, mailer, storage, validate, response, error, pagination, utils.
constants/: konstanta global (termasuk context keys untuk auth/role).
database/migrations dan database/seeders: manajemen skema dan data awal.
scripts/cron_functional: verifikasi flow cron waitlist dan overdue.
4. Project Structure
rpl-LIB/
├── cmd/ # CLI command untuk migration, seeding, help
│ └── command.go
├── constants/ # Konstanta aplikasi yang dipakai lintas package
│ └── common.go
├── database/ # Setup koneksi DB, migration, seeders, dan seed JSON
│ ├── database.go
│ ├── json/
│ │ ├── books.json
│ │ ├── book_tags.json
│ │ ├── borrowed_books.json
│ │ ├── tags.json
│ │ ├── users.json
│ │ └── waitlists.json
│ ├── migrations/
│ │ └── migrate.go
│ └── seeders/
│ ├── seeder.go
│ └── seeds/
│ ├── book_seed.go
│ ├── book_tag_seed.go
│ ├── borrowed_book_seed.go
│ ├── prodi_seed.go
│ ├── tag_seed.go
│ ├── user_seed.go
│ └── waitlist_seed.go
├── docs/ # Bruno collection dan environment untuk dokumentasi API
│ ├── api/
│ │ ├── Auth/
│ │ ├── Book/
│ │ ├── Borrow/
│ │ ├── Tag/
│ │ └── Waitlist/
│ ├── environments/
│ │ └── local.bru
│ └── bruno.json
├── image/
│ ├── layered-architecture.jpg
│ └── skema-db.png
├── assets/ # File upload statis (covers, profiles)
│ ├── covers/
│ └── profiles/
├── internal/
│ ├── api/
│ │ ├── controller/ # HTTP handler per modul (auth, book, borrow, tag, waitlist, file)
│ │ │ ├── book_controller.go
│ │ │ ├── borrow_controller.go
│ │ │ ├── file_controller.go
│ │ │ ├── tag_controller.go
│ │ │ ├── user_controller.go
│ │ │ └── waitlist_controller.go
│ │ ├── repository/ # Abstraksi query/operasi data berbasis GORM
│ │ │ ├── book_repository.go
│ │ │ ├── borrow_repository.go
│ │ │ ├── common.go
│ │ │ ├── masterdata_repository.go
│ │ │ ├── tag_repository.go
│ │ │ ├── user_repository.go
│ │ │ └── waitlist_repository.go
│ │ ├── routes/ # Definisi route + middleware per domain endpoint
│ │ │ ├── book_route.go
│ │ │ ├── borrow_route.go
│ │ │ ├── file_route.go
│ │ │ ├── tag_route.go
│ │ │ ├── user_route.go
│ │ │ └── waitlist_route.go
│ │ └── service/ # Business rules, orchestration workflow, dan scheduler logic
│ │ ├── book_service.go
│ │ ├── borrow_service.go
│ │ ├── jwt_service.go
│ │ ├── tag_service.go
│ │ ├── user_service.go
│ │ └── waitlist_service.go
│ ├── config/ # Router setup, DI provider, dan lifecycle HTTP server
│ │ ├── provide.go
│ │ ├── rest_config.go
│ │ └── rest_router_config.go
│ ├── dto/ # Kontrak request/response dan pesan domain
│ │ ├── book_dto.go
│ │ ├── borrow_dto.go
│ │ ├── common.go
│ │ ├── masterdata_dto.go
│ │ ├── tag_dto.go
│ │ ├── user_dto.go
│ │ └── waitlist_dto.go
│ ├── entity/ # Model tabel dan relasi domain
│ │ ├── book_entity.go
│ │ ├── borrowed_book_entity.go
│ │ ├── common.go
│ │ ├── prodi_entity.go
│ │ ├── tag_entity.go
│ │ ├── user_entity.go
│ │ └── waitlist_entity.go
│ ├── middleware/ # Middleware auth, CORS, role guard, dan pembatasan waktu
│ │ ├── authentication.go
│ │ ├── cors.go
│ │ ├── only_allow.go
│ │ └── time.go
│ └── pkg/
│ ├── error/ # Error mapping dan formatting error aplikasi
│ │ └── errors.go
│ ├── form/ # Parser helper untuk multipart/form
│ │ └── parser.go
│ ├── logger/ # Wrapper logging
│ │ └── logger.go
│ ├── mailer/ # Mail builder + template email
│ │ ├── mailer.go
│ │ ├── makeMail.go
│ │ └── template/
│ │ ├── borrow_overdue_email.html
│ │ ├── forgot_password_email.html
│ │ ├── verification_email.html
│ │ └── waitlist_notification_email.html
│ ├── pagination/ # Utility pagination/filter metadata
│ │ ├── conv.go
│ │ └── meta.go
│ ├── response/ # Standard response envelope API
│ │ └── response.go
│ ├── storage/ # Adapter storage (filesystem, AWS S3)
│ │ ├── aws_s3.go
│ │ └── filesystem.go
│ ├── utils/ # Utility AES, password hash, dan helper env
│ │ ├── aes.go
│ │ ├── is_prod.go
│ │ └── password.go
│ └── validate/ # Request/body/file validation
│ ├── file_validate.go
│ └── validator.go
├── scripts/ # Script verifikasi fungsional cron waitlist/overdue
│ └── cron_functional/
│ └── main.go
├── .dockerignore
├── .env.example
├── .gitignore
├── docker-compose.yml
├── Dockerfile
├── go.mod
├── go.sum
├── LICENSE
├── main.go
└── README.md
5. Alur Logika Bisnis Penting
5.1 System High-Level Flow

5.2 Auth and Profile Flow

Alur Auth & Profil
- Register user akan memvalidasi email unik dan
prodi_id, lalu simpan user dengan role User dan is_verified=false.
- Setelah register, sistem mengirim email verifikasi dengan token AES (format
email_expiredAt) dengan masa berlaku 2 menit.
- Login hanya berhasil jika email terdaftar, password valid, dan akun sudah terverifikasi.
- Verify email hanya menerima token valid dan belum expired, lalu mengubah
is_verified=true.
- Forgot/reset password memakai token AES dengan TTL 2 menit; jika token invalid/expired maka reset ditolak.
5.3 Borrow Flow

Alur Ketersediaan Buku
- Slot tersedia dihitung dari:
quantity - (active_borrows + active_notified_waitlist).
can_borrow=true hanya jika slot masih ada dan tidak ada antrean waiting.
- Jika masih ada antrean
waiting, user baru tidak bisa langsung borrow walaupun ada slot.
Alur Peminjaman
- User membuat request borrow, sistem cek
book_id valid dan buku ada.
- Sistem menolak jika user sudah punya borrow aktif untuk buku yang sama.
- Sistem menolak jika masih ada waitlist
waiting pada buku tersebut.
- Sistem menolak jika kuota tidak tersedia (berdasarkan perhitungan slot aktif).
- Jika lolos validasi, borrow dibuat dengan status awal
pending.
- Admin hanya bisa ubah status
pending -> borrowed (wajib isi due_date).
- Admin hanya bisa ubah status
borrowed/overdue -> returned.
5.4 Waitlist Flow

Alur Waitlist
- User join waitlist hanya jika belum punya waitlist aktif (
waiting/notified) untuk buku yang sama.
- Jika antrean masih kosong tapi slot buku masih tersedia, join waitlist ditolak (user diminta borrow langsung).
- Waitlist baru disimpan dengan status
waiting.
- Saat queue processor berjalan, entri
notified yang melewati expired_at akan diubah jadi expired.
- Selama masih ada slot, antrean
waiting terdepan dipromosikan ke notified dengan TTL claim 30 menit.
- Setiap promosi
waiting -> notified akan memicu email notifikasi.
- Claim waitlist hanya bisa oleh pemilik entri dan hanya saat status
notified serta belum expired.
- Saat claim valid, sistem membuat borrow
pending lalu mengubah waitlist menjadi completed.
5.5 Background Scheduler Flow

Alur Otomasi Cron di Runtime
- Processor waitlist berjalan sekali saat startup, lalu periodik setiap 15 menit.
- Processor overdue berjalan sekali saat startup, lalu harian pada pukul 00:00 zona waktu Asia/Jakarta.
- Borrow dengan status aktif yang melewati due date akan diubah ke
overdue dan mengirim email notifikasi keterlambatan.
6. Dokumentasi API
Dokumentasi request API disediakan dalam format Bruno Collection.
Note: Semua endpoint di dalam folder User bisa diakses oleh role Admin dan User, sedangkan endpoint di dalam folder Admin hanya bisa diakses oleh role Admin. Untuk endpoint yang memiliki akses role Admin dan User, maka pada bagian request header harus menyertakan token JWT yang didapatkan dari proses login.
Collection & Environment
Daftar Dokumen Endpoint (Bruno)
Auth
Book
Tag
Borrow
Waitlist
Cara Menggunakan Dokumentasi Bruno
- Install Bruno: https://www.usebruno.com/
- Pastikan repo sudah di clone ke lokal
- Buka Bruno, lalu pilih
Open Collection dan arahkan ke folder docs sebagai collection.

- Pilih environment docs/environments/local.bru.
- Pastikan server API berjalan di host/port yang sama.
- Jalankan request per modul.
Endpoint list mendukung parameter berikut:
page (default 1)
take (default 10)
sort (asc atau desc)
sort_by (contoh: id, title, author, published_year, created_at, updated_at)
filter
filter_by
Contoh filter buku:
filter_by=title&filter=clean architecture
filter_by=author&filter=martin
filter_by=published_year&filter=2023
filter_by=tag_name&filter=backend,go
8. Setup Project
8.1 Prasyarat
8.2 Konfigurasi Environment
- Clone Repository
git clone https://github.com/Shabrinashsf/go-gin-gorm-boilerplate.git
cd go-gin-gorm-boilerplate
- Salin
.env.example ke .env
cp .env.example .env
- Isi variabel sesuai environment lokal.
Daftar variabel utama:
- Database:
DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT
- SMTP:
SMTP_HOST, SMTP_PORT, SMTP_SENDER_NAME, SMTP_SENDER_EMAIL, SMTP_AUTH_EMAIL, SMTP_AUTH_PASSWORD
- Security:
JWT_SECRET, AES_KEY
- App:
APP_PORT, APP_ENV, BE_URL, APP_URL
- Storage cloud (opsional):
AWS_ACCESS_KEY, AWS_SECRET_KEY, AWS_REGION, S3_BUCKET
Referensi lengkap: .env.example
Cara mendapatkan akun SMTP gratis menggunakan akun google:
- Buka Google Account
- Pilih menu Security dan aktifkan 2-Step Verification.
- Setelah itu, pilih menu App Passwords
- Buat nama aplikasi (ex: RPLibrary)
- Salin password yang diberikan, lalu masukkan ke variabel
SMTP_AUTH_PASSWORD di file .env
8.3 Menjalankan Dengan Docker
docker-compose up --build -d
docker-compose exec app go run main.go --migrate
docker-compose exec app go run main.go --seed
docker-compose logs -f app
8.4 Menjalankan Lokal (Tanpa Docker App)
go mod download
go run main.go --migrate
go run main.go --seed
go run main.go
Server default berjalan di: http://localhost:8888
Jika ingin testing mengenai cron service untuk scheduler waitlist dan overdue, bisa dilihat di folder scripts/cron_functional untuk menjalankan skrip verifikasi fungsionalnya. Sebagai tambahan aplikasi mendukung graceful shutdown ketika menerima interrupt signal.
Data seeding untuk tabel borrowed_books dan waitlists bisa jadi tidak sinkron dengan response yang sudah ada (karena data testing api belum dipindah ke seeding, karena terlanjur drop db dan ternyata lupa data testing api belum dipindah ke seeding, maafkan :D).
Made with ❤️ by Shabrinashsf