Backend service for BN Mobile using:
- Gin (HTTP framework)
- GORM (ORM)
- PostgreSQL
- JWT access token + refresh token rotation
- Google OAuth login via Google ID Token verification
- Versioned SQL migrations with
golang-migrate
Structure follows the architecture style from belajar-go:
server/
├── cmd/
├── configs/
├── internal/
│ ├── delivery/
│ │ ├── data/
│ │ ├── handlers/
│ │ ├── middleware/
│ │ └── router/
│ ├── domain/
│ │ ├── models/
│ │ ├── repositories/
│ │ └── services/
│ └── infrastructure/
│ └── database/
└── pkg/
GET /healthPOST /api/v1/auth/googlePOST /api/v1/auth/google/oauthPOST /api/v1/auth/refreshPOST /api/v1/auth/logoutGET /api/v1/auth/me(Bearer token required)GET /api/v1/user(Bearer token required)PATCH /api/v1/user(Bearer token required)GET /api/v1/progress(Bearer token required)POST /api/v1/progress(Bearer token required)GET /api/v1/progress/:module/:itemId(Bearer token required)GET /api/v1/bookmarks(Bearer token required)POST /api/v1/bookmarks(Bearer token required)DELETE /api/v1/bookmarks/:id(Bearer token required)GET /api/v1/dhikrs(Public)GET /api/v1/dhikr/counters(Bearer token required)POST /api/v1/dhikr/counters(Bearer token required)GET /api/v1/habits(Bearer token required)POST /api/v1/habits(Bearer token required)PATCH /api/v1/habits/:id(Bearer token required)DELETE /api/v1/habits/:id(Bearer token required)POST /api/v1/habits/completions(Bearer token required)GET /api/v1/push/public-key(Public)POST /api/v1/push/subscriptions(Bearer token required)DELETE /api/v1/push/subscriptions(Bearer token required)GET /api/v1/schools(Public)POST /api/v1/schools(Bearer token required)GET /api/v1/quiz/attempts(Bearer token required)POST /api/v1/quiz/attempts(Bearer token required)GET /api/v1/quiz/stats(Bearer token required)POST /api/v1/ai/coach(Bearer token required)GET /api/v1/audio-proxyGET /api/v1/prayer-times
/auth/refresh and /auth/logout read refresh token from HttpOnly cookie.
Swagger UI tersedia setelah server jalan:
GET /swagger/index.html- Raw OpenAPI JSON:
GET /swagger/doc.json
Contoh URL lokal (default port 8080):
http://localhost:8080/swagger/index.html
Generate ulang file Swagger jika endpoint berubah:
cd server
go run github.com/swaggo/swag/cmd/swag@v1.16.6 init -g main.go -d ./cmd,./internal,./configs,./pkg -o ./docs --parseDependency --parseInternalcd server
cp .env.example .env
go mod tidy
go run ./cmd/migrate -action up
go run ./cmdCLI migration ada di cmd/migrate dan memakai golang-migrate.
Jalankan dari folder server:
cd serverCommand utama:
# cek versi migration saat ini
go run ./cmd/migrate -action version
# apply semua migration baru
go run ./cmd/migrate -action up
# rollback semua migration
go run ./cmd/migrate -action down
# apply/rollback beberapa step
go run ./cmd/migrate -action steps -steps 1
go run ./cmd/migrate -action steps -steps -1
# force versi jika state dirty
go run ./cmd/migrate -action force -force 5Troubleshooting cepat:
- Jika muncul error
relation "<table>" does not exist, jalankan:go run ./cmd/migrate -action up
- Jika muncul
dirty migration state:go run ./cmd/migrate -action force -force <version>- lalu ulang
go run ./cmd/migrate -action up
Fitur push reminder berjalan jika konfigurasi VAPID diaktifkan.
Tambahkan env di server/.env:
PUSH_ENABLED=true
PUSH_VAPID_PUBLIC_KEY=<public-key>
PUSH_VAPID_PRIVATE_KEY=<private-key>
PUSH_VAPID_SUBJECT=mailto:admin@example.com
PUSH_DISPATCH_INTERVAL=1mGenerate VAPID key (contoh):
npx web-push generate-vapid-keysCatatan:
- Scheduler push berjalan di proses backend yang sama (
cmd/main.go), interval default1m. - Subscription disimpan di tabel
push_subscriptions(migration000007). - Client perlu register service worker
public/sw.jsdan grant permission notifikasi.
POST /api/v1/auth/google
Content-Type: application/json
{
"idToken": "<google-id-token-from-frontend>"
}POST /api/v1/auth/google/oauth
Content-Type: application/json
{
"code": "<google-oauth-authorization-code>",
"redirectUri": "http://localhost:3000/auth/callback"
}POST /api/v1/auth/refresh
Cookie: bn_refresh_token=<refresh-token>GET /api/v1/auth/me
Authorization: Bearer <access-token>- Layered architecture (handler -> service -> repository)
- Context timeout at handler layer
- JWT short-lived access token + rotating refresh token
- Refresh token stored in DB as SHA-256 hash (never store raw token)
- Refresh token delivered via
HttpOnlycookie - Transactional refresh-token rotation
- Versioned SQL migration files (no runtime automigrate)
- Auth endpoint rate limiting by client IP
- Fail-fast config validation
- Graceful shutdown for HTTP server
- Centralized CORS and auth middleware