A complete recreation of the Bunely project using Golang, following Domain-Driven Design (DDD) principles.
This project follows Clean Architecture and DDD principles with clear separation of concerns:
- Domain Layer: Core business logic and entities
- Application Layer: Use cases and business rules
- Infrastructure Layer: External concerns (database, logging, config)
- Interfaces Layer: HTTP handlers and DTOs
- Language: Go 1.22+
- Web Framework: Gin
- ORM: GORM with PostgreSQL driver
- Configuration: Viper
- Logging: Zap
- Authentication: JWT with bcrypt
- Validation: go-playground/validator
- Testing: Testify
- Go 1.22 or higher
- PostgreSQL 14 or higher
- Make (optional, for convenience commands)
cd backend-golanggo mod downloadCreate PostgreSQL database:
createdb bunely
# or using psql
psql -U salju -c "CREATE DATABASE bunely;"Copy the example environment file and update with your settings:
cp .env.example .envEdit .env and set your configuration:
# Application
APP_NAME=Gonely
APP_ENV=development
APP_URL=http://localhost:8080
APP_PORT=8080
BASE_PATH=/api
# Database
DB_HOST=localhost
DB_PORT=5432
DB_USER=salju
DB_PASSWORD=password
DB_NAME=bunely
DB_SSL_MODE=disable
DB_TIMEZONE=Asia/Jakarta
# Authentication (IMPORTANT: Change this in production!)
JWT_SECRET=your-very-secure-secret-key-minimum-32-characters-long
JWT_EXPIRY=168h
SESSION_EXPIRY=7d
# Logging
LOG_LEVEL=info
LOG_FORMAT=json
# CORS
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8080
CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,OPTIONS
CORS_ALLOWED_HEADERS=Origin,Content-Type,Accept,AuthorizationUsing Make:
make runOr directly with Go:
go run cmd/api/main.goThe server will start at http://localhost:8080
GET /health- Health status
POST /api/auth/register- Register new userPOST /api/auth/login- Login userPOST /api/auth/anonymous- Create anonymous userPOST /api/auth/logout- Logout (requires auth)GET /api/auth/me- Get current user (requires auth)
GET /api/v1/posts- List all posts (public)GET /api/v1/posts/:id- Get post by ID (public)POST /api/v1/posts- Create post (requires auth)GET /api/v1/posts/:id/comments- Get post comments (public)POST /api/v1/posts/:id/comments- Add comment (requires auth)
curl -X POST http://localhost:8080/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"password": "securePassword123"
}'curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "john@example.com",
"password": "securePassword123"
}'curl -X POST http://localhost:8080/api/v1/posts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-d '{
"content": "My first post!"
}'curl http://localhost:8080/api/v1/posts?page=0&limit=20Run all tests:
make testRun tests with coverage:
make test-coverageAll available Make commands:
make help # Display all available commands
make build # Build the application
make run # Run the application
make dev # Run with hot reload (requires air)
make test # Run tests
make test-coverage # Run tests with coverage report
make lint # Run linter
make fmt # Format code
make vet # Run go vet
make tidy # Tidy dependencies
make clean # Clean build artifacts
make docker-up # Start docker containers
make docker-down # Stop docker containers
make db-reset # Reset databasebackend-golang/
βββ cmd/
β βββ api/
β βββ main.go # Application entry point
βββ internal/
β βββ domain/ # Domain layer (business entities)
β β βββ auth/ # Authentication domain
β β β βββ user.go
β β β βββ account.go
β β β βββ session.go
β β β βββ verification.go
β β β βββ repository.go # Repository interfaces
β β βββ feeds/ # Feeds domain
β β βββ post.go
β β βββ comment.go
β β βββ repository.go
β βββ application/ # Application layer (use cases)
β β βββ auth/
β β β βββ auth_service.go
β β βββ feeds/
β β βββ feed_service.go
β βββ infrastructure/ # Infrastructure layer
β β βββ config/
β β β βββ config.go # Configuration management
β β βββ database/
β β β βββ database.go # Database connection & migrations
β β βββ logger/
β β β βββ logger.go # Logging setup
β β βββ repository/ # Repository implementations
β β βββ auth/
β β β βββ user_repository.go
β β β βββ account_repository.go
β β β βββ session_repository.go
β β βββ feeds/
β β βββ post_repository.go
β β βββ comment_repository.go
β βββ interfaces/ # Interfaces layer (HTTP)
β βββ http/
β βββ handler/ # HTTP handlers
β β βββ auth_handler.go
β β βββ feed_handler.go
β βββ middleware/ # HTTP middleware
β β βββ auth.go
β β βββ error.go
β β βββ logger.go
β βββ dto/ # Data Transfer Objects
β β βββ auth.go
β β βββ post.go
β β βββ response.go
β βββ router.go # Route definitions
βββ pkg/ # Shared packages
β βββ errors/
β βββ errors.go # Custom error types
βββ .env.example # Example environment variables
βββ .gitignore
βββ go.mod
βββ go.sum
βββ Makefile
βββ PROJECT_ANALYSIS.md # Detailed project analysis
βββ README.md
- β Clean Architecture: Clear separation of concerns with DDD principles
- β JWT Authentication: Secure token-based authentication
- β Anonymous Users: Support for anonymous user sessions
- β GORM Integration: Type-safe database operations
- β Structured Logging: Zap logger with contextual logging
- β Error Handling: Centralized error handling middleware
- β CORS Support: Configurable CORS for frontend integration
- β Graceful Shutdown: Proper cleanup on application termination
- β Database Migrations: Automatic schema migrations
- β Validation: Request validation with struct tags
- β Configuration: Environment-based configuration with Viper
- JWT Secret: Always use a strong, random secret (minimum 32 characters) in production
- Password Hashing: Uses bcrypt with default cost factor
- SQL Injection: Protected by GORM's parameterized queries
- CORS: Configure allowed origins appropriately for production
- Rate Limiting: Consider adding rate limiting middleware for production
Create a Dockerfile:
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /gonely cmd/api/main.go
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /gonely .
COPY .env.example .env
EXPOSE 8080
CMD ["./gonely"]- id (varchar, PK)
- name (varchar)
- handle (varchar, indexed)
- email (varchar, unique, indexed)
- email_verified (boolean)
- is_anonymous (boolean)
- image (varchar)
- created_at, updated_at (timestamp)
- id (varchar, PK)
- account_id (varchar)
- provider_id (varchar)
- user_id (varchar, FK)
- access_token (varchar, indexed)
- password (varchar, hashed)
- created_at, updated_at (timestamp)
- id (varchar, PK)
- user_id (varchar, FK)
- token (varchar, unique, indexed)
- user_agent, ip_address (varchar)
- revoked (boolean)
- expires_at (timestamp)
- created_at, updated_at (timestamp)
- id (varchar, PK)
- content (text)
- created_at (timestamp, indexed)
- updated_at (timestamp)
- id (varchar, PK)
- post_id (varchar, FK, cascade delete)
- content (text)
- created_at (timestamp, indexed)
- updated_at (timestamp)
- Follow Go best practices and conventions
- Maintain test coverage above 80%
- Use meaningful commit messages
- Update documentation for new features
- Run
make fmtandmake lintbefore committing
This project is a recreation for educational purposes.