A modern boilerplate monorepo setup with Go backend (JWT Auth + PostgreSQL) and Next.js frontend using Turborepo for efficient development and deployment.
monorepo/
βββ apps/
β βββ backend/ # Go API server dengan JWT Auth
β β βββ config/ # Database configuration
β β βββ controllers/ # Auth, User, Role controllers
β β βββ middleware/ # Authentication middleware
β β βββ models/ # Database models (User, Role, Permission)
β β βββ main.go # Server utama dengan protected routes
β β βββ go.mod # Dependencies (Gin, GORM, JWT, PostgreSQL)
β βββ web/ # Next.js frontend dengan Auth UI
β βββ app/
β βββ components/ # Auth components (Login, Register)
β βββ lib/ # Authentication service
β βββ package.json
β βββ tailwind.config.js
β βββ next.config.js
βββ packages/ # Shared packages (future)
βββ package.json # Root package.json
βββ turbo.json # Turborepo configuration
βββ Makefile # Development commands
βββ README.md
- Next.js 14 - React framework with App Router
- TypeScript - Type safety
- Tailwind CSS - Utility-first CSS framework
- Authentication UI - Login/Register components
- ESLint - Code linting
- Gin - HTTP web framework
- GORM - ORM untuk PostgreSQL
- JWT - JSON Web Token authentication
- bcrypt - Password hashing
- CORS - Cross-origin resource sharing
- PostgreSQL 15 - Production database
- Auto Migration - GORM auto migration with refresh tokens table
- Multi-Role System - Dynamic role-based permissions
- JWT Tokens - Dual token system (Access + Refresh)
- Access Token - Short-lived (15 minutes) for API requests
- Refresh Token - Long-lived (7 days) for token renewal
- Role-Based Access Control (RBAC) - Dynamic permissions
- Multi-Role Support - Users can have multiple roles
- Permission System - Resource-action based permissions
- Auto Token Refresh - Frontend automatically refreshes expired tokens
- Menu Access Control - Role-based menu visibility and access
- Feature Flags - Permission-based feature access control
- Turborepo - Monorepo build system
- npm workspaces - Package management
- Makefile - Development shortcuts
- Node.js 18+
- Go 1.21+
- npm or yarn
- Automated Setup (Recommended):
./start-dev.sh- Manual Installation:
# Install root dependencies
npm install
# Install frontend dependencies
cd apps/web && npm install && cd ../..
# Install backend dependencies
cd apps/backend && go mod download && cd ../..- Test Setup:
./test-setup.shOption 1: Complete setup with PostgreSQL
make dev-with-dbOption 2: Manual database + apps
# Terminal 1 - Start PostgreSQL
make db-up
# Terminal 2 - Start both apps (after DB is ready)
npm run devOption 1: Using Turborepo
npm run devOption 2: Using parallel script
./dev-parallel.shPostgreSQL only:
make db-up # Start database
make db-down # Stop database
make db-reset # Reset database (delete data)Backend only:
cd apps/backend && npm run dev
# or
cd apps/backend && go run main.goFrontend only:
cd apps/web && npm run dev- Frontend: http://localhost:3000
- Backend API: http://localhost:8080
- PostgreSQL: localhost:5432
- Health check: http://localhost:8080/health
GET /health- Server health statusGET /api/v1/hello- Hello messagePOST /api/v1/auth/register- User registrationPOST /api/v1/auth/login- User login
GET /api/v1/auth/me- Current user infoGET /api/v1/auth/menu-access- Get accessible menus and featuresPOST /api/v1/auth/logout- Logout (revoke refresh token)POST /api/v1/auth/logout-all- Logout from all devicesPOST /api/v1/auth/refresh- Refresh access token
GET /api/v1/users- Get all users (requires users.read)GET /api/v1/users/:id- Get user by ID (requires users.read)POST /api/v1/users- Create user (requires users.write)PUT /api/v1/users/:id- Update user (requires users.write)DELETE /api/v1/users/:id- Delete user (requires users.delete)POST /api/v1/users/:id/roles- Assign roles (requires admin role)
GET /api/v1/roles- Get all roles (requires roles.read)GET /api/v1/roles/:id- Get role by ID (requires roles.read)POST /api/v1/roles- Create role (requires roles.write)PUT /api/v1/roles/:id- Update role (requires roles.write)DELETE /api/v1/roles/:id- Delete role (requires roles.delete)
GET /api/v1/permissions- Get all permissions (requires permissions.read)
npm run dev- Start development serversnpm run build- Build all applicationsnpm run lint- Lint all applicationsnpm run clean- Clean build artifacts
make backend-dev- Start Go servermake backend-build- Build Go binarymake backend-test- Run Go testsmake backend-clean- Clean build artifacts
make web-dev- Start Next.js dev servermake web-build- Build Next.js applicationmake web-test- Run frontend tests
./start-dev.sh # Complete setup + start both apps
./dev-parallel.sh # Start both apps in parallel
./test-setup.sh # Test if everything builds correctly
./test-connection.sh # Test API connection between frontend/backendβ
Monorepo Setup - Turborepo for efficient builds and caching
β
Go Backend - RESTful API with Gin framework
β
Next.js Frontend - Modern React with App Router
β
Tailwind CSS - Utility-first styling
β
TypeScript - Type safety across the frontend
β
Dual JWT Authentication - Access + Refresh token system
β
Auto Token Refresh - Frontend handles token renewal automatically
β
Auto Migration - GORM auto migration with refresh tokens table
β
Multi-role System - Dynamic role-based permissions
β
CORS Configuration - Proper cross-origin setup
β
Development Tools - ESLint, Prettier, and more
β
Hot Reload - Both frontend and backend support hot reload
cd apps/backend
go build -o bin/main main.go
./bin/maincd apps/web
npm run build
npm startPORT- Server port (default: 8080)GIN_MODE- Gin mode (debug/release)DB_HOST- PostgreSQL hostDB_PORT- PostgreSQL portDB_USER- PostgreSQL usernameDB_PASSWORD- PostgreSQL passwordDB_NAME- PostgreSQL database nameJWT_SECRET- JWT signing secretJWT_ACCESS_EXPIRY- Access token expiry (default: 15m)JWT_REFRESH_EXPIRY- Refresh token expiry (default: 7d)
NEXT_PUBLIC_API_URL- Backend API URL
If npm run dev doesn't start both applications:
-
Check if both apps have package.json with dev scripts:
# Should exist: apps/backend/package.json with "dev": "go run main.go" # Should exist: apps/web/package.json with "dev": "next dev"
-
Use alternative methods:
# Option 1: Parallel script ./dev-parallel.sh # Option 2: Manual start in separate terminals # Terminal 1: cd apps/backend && go run main.go # Terminal 2: cd apps/web && npm run dev
-
Test individual components:
# Test backend only cd apps/backend && go run main.go # Test frontend only (in new terminal) cd apps/web && npm run dev # Test connection ./test-connection.sh
If you encounter turbo_json_parse_error with unknown key errors, make sure you're using the correct turbo version specified in package.json. The configuration format has changed between versions:
- Turbo v1.x uses
pipelinekey - Turbo v2.x uses
taskskey
Current project uses Turbo v1.13.4 with pipeline configuration.
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting
- Submit a pull request
- Dual Token System: Short-lived access tokens (15m) + long-lived refresh tokens (7d)
- Database Storage: Refresh tokens stored in
refresh_tokenstable with expiry tracking - Auto-cleanup: Expired tokens automatically cleaned from database
- Token Revocation: Support for single logout and logout from all devices
- Security: Refresh tokens are cryptographically secure random strings
- Auto Refresh: Automatically refreshes expired access tokens
- Transparent Handling: Token refresh happens behind the scenes
- Secure Storage: Tokens stored in localStorage with proper cleanup
- Error Handling: Graceful fallback when refresh fails
POST /api/v1/auth/refresh- Refresh access token using refresh tokenPOST /api/v1/auth/logout- Logout and revoke specific refresh tokenPOST /api/v1/auth/logout-all- Logout from all devices (revoke all user's refresh tokens)
// Login returns both tokens
const response = await authService.login({ username, password })
// { access_token, refresh_token, expires_at, user }
// Get user's accessible menus
const { menus, features } = await authService.getMenuAccess()
// Returns filtered menus based on user's role permissions
// API calls automatically handle token refresh
const user = await authService.getCurrentUser()
// If access token expired, it's automatically refreshed
// Logout revokes refresh token
await authService.logout()
// Logout from all devices
await authService.logoutAll()| Role | Description | Menu Access | Features |
|---|---|---|---|
| admin | Full system access | All menus | All features |
| manager | Business analytics | Dashboard, Analytics, Reports, Billing | Export, Import |
| editor | Content management | Dashboard, User Management, Support | Export |
| viewer | Read-only access | Dashboard, Analytics, Reports | - |
| support | User assistance | Dashboard, Support, User Management | Export |
| user | Basic access | Dashboard only | - |
- Dashboard (menu.dashboard) - Basic home page
- Analytics (menu.analytics) - Business analytics
- Reports (menu.reports) - Data reports
- Administration (menu.admin) - Admin panel
βββ User Management (menu.users) - User CRUD
βββ Role Management (menu.roles) - Role CRUD
βββ Audit Logs (menu.audit) - System logs
- Billing (menu.billing) - Payment management
- Support (menu.support) - Customer support
- Settings (menu.settings) - System settings// Feature permissions
feature.export - Data export capability
feature.import - Data import capability
feature.backup - System backup access
feature.maintenance - Maintenance mode access
// Menu permissions
menu.dashboard - Dashboard access
menu.analytics - Analytics page access
menu.admin - Admin panel access
// ... etc- Sidebar - Dynamically renders menus based on permissions
- RolePermissionManager - Admin interface for role management
- MenuAccess - Utility for checking menu permissions
MIT License