08 · File Structure
Navigating the lp-coupon-api and lp-reward-store-api repos
lp-coupon-api Layout
lp-coupon-api/
├── main.go ← entry point, app wiring, graceful shutdown
├── go.mod ← dependency list (like package.json)
├── go.sum ← dependency lock (like package-lock.json)
├── Makefile ← dev commands: make run, make test, make build
├── Dockerfile
├── docker-compose.yml
├── config/
│ └── config.go ← Viper config loading from env vars
├── database/
│ └── connection.go ← GORM connection manager with retry logic
├── internal/ ← private: cannot be imported by external packages
│ ├── handlers/ ← HTTP layer: parse request, call service, format response
│ ├── services/ ← Business logic layer
│ ├── repository/ ← Data access layer (GORM queries)
│ │ └── interfaces.go ← All repo contracts defined here
│ ├── models/ ← GORM entity structs (Coupon, UserCoupon, ...)
│ ├── middleware/ ← Fiber middleware: auth, logging, rate limit, pagination
│ ├── clients/ ← External HTTP clients (ECI), Redis, Kafka
│ ├── routes/
│ │ └── routes.go ← Dependency injection + route registration
│ └── constants/ ← Error codes, status enums
├── pkg/ ← Public reusable utilities (can be imported externally)
│ ├── logger/ ← Structured logger wrapper
│ ├── zlog/ ← Low-level zerolog interface used in services/repos
│ ├── retryer/ ← Configurable retry with backoff or fixed delay
│ ├── ratelimit/ ← Redis-backed rate limit key helpers
│ ├── helpers/ ← Cache key builder, misc utilities
│ ├── pagination/ ← Pagination parameter parsing
│ └── context/ ← Context helpers: get client, trace ID, user ID
├── scripts/
│ └── migration/ ← SQL migration files + migrate.sh runner
└── tests/ ← Integration tests
The internal/ Rule
Go enforces that code in internal/ can only be imported by code in the parent directory tree. It is not accessible to external packages or other repos. Use it for everything that is specific to this service.
pkg/ has no such restriction — it is meant for utilities that could theoretically be shared (logger, retryer, helpers).
Where to Add New Code
| What you're adding | Where it goes |
|---|---|
| New API endpoint | internal/handlers/ + wire in routes/routes.go |
| Business logic | internal/services/ |
| Database query | internal/repository/ + add method to interface in interfaces.go |
| New DB table | internal/models/ + new migration in scripts/migration/sql/ |
| New env config variable | config/config.go + .env.example |
| New middleware | internal/middleware/ + register in main.go initFiber() |
| Reusable utility | pkg/ |
lp-reward-store-api Differences
Same layered structure, but uses MongoDB instead of PostgreSQL (no GORM — uses the official MongoDB driver). No scripts/migration/ directory. Same pkg/ utilities pattern.
Key Takeaways
internal/= private to this repo.pkg/= shareable utilities.- All dependency wiring happens in
internal/routes/routes.go. - All repository contracts are in
internal/repository/interfaces.go— add new methods there first. - New endpoints: add handler → service → repo → wire in routes.go → add interface method.