Internal Architecture
This document describes the clean architecture implementation for the POS backend with complete separation of concerns between database entities, business models, and constants.
๐ Package Structure
/constants - Business Constants
- Purpose: All business logic constants, enums, and validation helpers
- Usage: Used by models, services, and validation layers
- Features:
- Type-safe enums (UserRole, OrderStatus, PaymentStatus, etc.)
- Business validation functions (IsValidUserRole, etc.)
- Default values and limits
- No dependencies on database or frameworks
/entities - Database Models
- Purpose: Database-specific models with GORM tags and hooks
- Usage: ONLY used by repository layer for database operations
- Features:
- GORM annotations (
gorm:tags) - Database relationships and constraints
- BeforeCreate/AfterCreate hooks
- Table name specifications
- SQL-specific data types
- Never used in business logic
- GORM annotations (
/models - Business Models
- Purpose: Pure business domain models without any framework dependencies
- Usage: Used by services, handlers, and business logic
- Features:
- Clean JSON serialization (
json:tags) - Validation rules (
validate:tags) - Request/Response DTOs
- Zero GORM dependencies
- Zero database annotations
- Uses constants package for type safety
- Pure business logic methods
- Clean JSON serialization (
/mappers - Data Transformation
- Purpose: Convert between entities and business models
- Usage: Bridge between repository and service layers
- Features:
- Entity โ Model conversion functions
- Request DTO โ Entity conversion
- Entity โ Response DTO conversion
- Null-safe conversions
- Slice/collection conversions
- Type conversions between constants and entities
/repository - Data Access Layer
- Purpose: Database operations using entities exclusively
- Usage: Only works with database entities
- Features:
- CRUD operations with entities
- Query methods with entities
- Private repository implementations
- Interface-based contracts
- Never references business models
๐ Data Flow
API Request (JSON)
โ
Request DTO (models)
โ
Business Logic (services with models + constants)
โ
Entity (via mapper)
โ
Repository Layer (entities only)
โ
Database
โ
Entity (from database)
โ
Business Model (via mapper)
โ
Response DTO (models)
โ
API Response (JSON)
๐ฏ Key Design Principles
โ Clean Business Models
type User struct {
ID uuid.UUID `json:"id"`
Role constants.UserRole `json:"role"`
}
type User struct {
ID uuid.UUID `gorm:"primaryKey" json:"id"`
Role string `gorm:"size:50" json:"role"`
}
โ Type-Safe Constants
type UserRole string
const (
RoleAdmin UserRole = "admin"
)
func IsValidUserRole(role UserRole) bool { /* ... */ }
const AdminRole = "admin" ```
### โ
**Repository Isolation**
```go
func (r *userRepository) Create(ctx context.Context, user *entities.User) error {
return r.db.Create(user).Error
}
func (r *userRepository) Create(ctx context.Context, user *models.User) error {
}
๐ Example Usage
Service Layer (Business Logic)
func (s *userService) CreateUser(req *models.UserCreateRequest) (*models.UserResponse, error) {
if !constants.IsValidUserRole(req.Role) {
return nil, errors.New("invalid role")
}
entity := mappers.UserCreateRequestToEntity(req, hashedPassword)
err := s.userRepo.Create(ctx, entity)
if err != nil {
return nil, err
}
return mappers.UserEntityToResponse(entity), nil
}
Repository Layer (Data Access)
func (r *userRepository) Create(ctx context.Context, user *entities.User) error {
return r.db.WithContext(ctx).Create(user).Error
}
Handler Layer (API)
func (h *userHandler) CreateUser(c *gin.Context) {
var req models.UserCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
resp, err := h.userService.CreateUser(&req)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, resp)
}
๐๏ธ Architecture Benefits
- ๐ฏ Single Responsibility: Each package has one clear purpose
- ๐ Zero Database Leakage: Business logic never sees database concerns
- ๐งช Testability: Easy to mock interfaces and test business logic
- ๐ง Maintainability: Changes to database don't affect business models
- ๐ Flexibility: Can change ORM without touching business logic
- ๐ API Stability: Business models provide stable contracts
- ๐ก๏ธ Type Safety: Constants package prevents invalid states
- ๐งน Clean Code: No mixed concerns anywhere in the codebase
๐ Development Guidelines
Constants Package (/constants)
- โ Define all business enums and constants
- โ Provide validation helper functions
- โ Include default values and limits
- โ Never import database or framework packages
- โ No business logic, only constants and validation
Models Package (/models)
- โ Pure business structs with JSON tags only
- โ Use constants package for type safety
- โ Include validation tags for input validation
- โ Separate Request/Response DTOs
- โ Add business logic methods (validation, calculations)
- โ NEVER include GORM tags or database annotations
- โ NEVER import database packages
- โ No database relationships or foreign keys
Entities Package (/entities)
- โ Include GORM tags and database constraints
- โ Define relationships and foreign keys
- โ Add database hooks (BeforeCreate, etc.)
- โ Use database-specific types
- โ NEVER use in business logic or handlers
- โ NEVER add business validation rules
Mappers Package (/mappers)
- โ Always check for nil inputs
- โ Handle type conversions between constants and strings
- โ Provide slice conversion helpers
- โ Keep conversions simple and direct
- โ No business logic in mappers
- โ No database operations
Repository Package (/repository)
- โ Work exclusively with entities
- โ Use private repository implementations
- โ Provide clean interface contracts
- โ NEVER reference business models
- โ NEVER import models package
๐ Migration Complete
All packages have been successfully reorganized:
- โ 4 Constants files - All business constants moved to type-safe enums
- โ 10 Clean Model files - Zero GORM dependencies, pure business logic
- โ 11 Entity files - Database-only models with GORM tags
- โ 11 Repository files - Updated to use entities exclusively
- โ 2 Mapper files - Handle conversions between layers
- โ Complete separation - No cross-layer dependencies
The codebase now follows strict clean architecture principles with complete separation of database concerns from business logic! ๐