A RESTful API built with Go following Clean Architecture principles. Features role-based access control (RBAC) with token-based auth, contact management, and address management with scoped data ownership.
- Go 1.26 with Fiber HTTP framework
- PostgreSQL with GORM ORM
- golang-migrate for database migrations
- golangci-lint with 18 linters enabled
- Viper for configuration, Logrus for logging
Clean Architecture with layered dependency flow:
Entity → Repository → UseCase → Controller → Route
| Layer | Path | Responsibility |
|---|---|---|
| Entity | internal/entity/ |
GORM database models |
| Repository | internal/repository/ |
Data access with generic Repository[T] base |
| UseCase | internal/usecase/ |
Business logic, transactions, validation |
| Controller | internal/delivery/http/ |
HTTP handlers (Fiber) |
| Route | internal/delivery/http/route/ |
Route registration (guest & auth) |
| Middleware | internal/delivery/http/middleware/ |
Auth + RBAC permission middleware |
| Model | internal/model/ |
Request/response DTOs with validation tags |
| Config | internal/config/ |
Infrastructure init & DI wiring via Bootstrap() |
- Go 1.26+
- PostgreSQL
- golangci-lint
- air (optional, for live reload)
-
Clone the repository:
git clone https://github.com/rfajarachmad/golang-rbac-starter.git cd golang-rbac-starter -
Configure the database connection in
config.json:{ "database": { "host": "localhost", "port": 5432, "username": "your_user", "password": "your_password", "name": "your_db", "sslmode": "disable" } } -
Run database migrations:
make migrate-up
-
Start the server:
make run
Or with live reload:
make dev
The server starts on http://localhost:8080.
A default admin user is seeded by the migration:
- Email:
admin@example.com - Password:
admin123
The system enforces two layers of access control:
- Permission-based access — Each route is protected by
RequirePermission()middleware that checks the user's role permissions - Data ownership scoping — Users can only access their own contacts and addresses (enforced at the repository level)
| Role | Description | Permissions |
|---|---|---|
admin |
Full system access | All 16 permissions including admin endpoints |
user |
Standard user | CRUD on own data (11 permissions) |
viewer |
Read-only access | Read own profile, contacts, addresses (3 permissions) |
New registrations default to the user role. Admins can assign roles via PATCH /api/admin/users/:userId/role.
Full OpenAPI 3.0.3 spec available at api/api-spec.json.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/users |
Register new user |
| POST | /api/users/_login |
Login (returns token) |
All require Authorization: <token> header. Permission required shown in parentheses.
| Method | Endpoint | Description | Permission |
|---|---|---|---|
| GET | /api/users/_current |
Get current user profile | user:read |
| PATCH | /api/users/_current |
Update current user | user:update |
| DELETE | /api/users |
Logout | user:delete |
| POST | /api/contacts |
Create contact | contact:create |
| GET | /api/contacts/:contactId |
Get contact | contact:read |
| PUT | /api/contacts/:contactId |
Update contact | contact:update |
| DELETE | /api/contacts/:contactId |
Delete contact | contact:delete |
| GET | /api/contacts |
Search contacts (with pagination) | contact:read |
| POST | /api/contacts/:contactId/addresses |
Create address | address:create |
| GET | /api/contacts/:contactId/addresses |
List addresses | address:read |
| GET | /api/contacts/:contactId/addresses/:addressId |
Get address | address:read |
| PUT | /api/contacts/:contactId/addresses/:addressId |
Update address | address:update |
| DELETE | /api/contacts/:contactId/addresses/:addressId |
Delete address | address:delete |
Require admin role.
| Method | Endpoint | Description | Permission |
|---|---|---|---|
| GET | /api/admin/users |
List all users (paginated) | admin:user:list |
| GET | /api/admin/users/:userId |
Get any user | admin:user:read |
| PATCH | /api/admin/users/:userId/role |
Assign role to user | admin:user:update |
| DELETE | /api/admin/users/:userId |
Delete any user | admin:user:delete |
| GET | /api/admin/roles |
List all roles | admin:role:manage |
| GET | /api/admin/roles/:roleId |
Get role with permissions | admin:role:manage |
Six tables managed via sequential migrations in db/migrations/:
- users — serial PK, email/password/token auth, FK to roles
- roles — serial PK, name (admin/user/viewer)
- permissions — serial PK, name (e.g.,
contact:create) - role_permissions — join table (role_id, permission_id)
- contacts — UUID PK, belongs to user
- addresses — UUID PK, belongs to contact
make help # Show all available commands
make run # Start server
make dev # Live reload via air
make build # Compile to bin/go-rbac-starter
make test # Run all tests
make test-cover # Tests with HTML coverage report
make test-cover-check # Enforce coverage thresholds
make test-race # Tests with race detector
make lint # Run golangci-lint (18 linters)
make check # fmt + vet + tidy + lint + test + coverage
make migrate-up # Apply all migrations
make migrate-down # Rollback last migration
make migrate-create # Create new migrationIntegration tests in test/ bootstrap the full Fiber app against a real PostgreSQL database. Tests require a running PostgreSQL instance with migrations applied.
# Run all tests
make test
# Run a single test
go test -v -count=1 -run TestCreateContact ./test/
# Coverage thresholds: overall >= 70%, usecase >= 60%, delivery >= 70%
make test-cover-checkMIT