242 lines
7.1 KiB
Markdown
Raw Normal View History

2025-08-09 15:08:26 +07:00
# 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**
### `/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
### `/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**
```go
type User struct {
ID uuid.UUID `json:"id"`
Role constants.UserRole `json:"role"`
}
```
```go
type User struct {
ID uuid.UUID `gorm:"primaryKey" json:"id"`
Role string `gorm:"size:50" json:"role"`
}
```
### โœ… **Type-Safe Constants**
```go
type UserRole string
const (
RoleAdmin UserRole = "admin"
)
func IsValidUserRole(role UserRole) bool { /* ... */ }
```
```go
const AdminRole = "admin" ```
### โœ… **Repository Isolation**
```go
func (r *userRepository) Create(ctx context.Context, user *entities.User) error {
return r.db.Create(user).Error
}
```
```go
func (r *userRepository) Create(ctx context.Context, user *models.User) error {
}
```
## ๐Ÿ“Š Example Usage
### Service Layer (Business Logic)
```go
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)
```go
func (r *userRepository) Create(ctx context.Context, user *entities.User) error {
return r.db.WithContext(ctx).Create(user).Error
}
```
### Handler Layer (API)
```go
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
1. **๐ŸŽฏ Single Responsibility**: Each package has one clear purpose
2. **๐Ÿ”’ Zero Database Leakage**: Business logic never sees database concerns
3. **๐Ÿงช Testability**: Easy to mock interfaces and test business logic
4. **๐Ÿ”ง Maintainability**: Changes to database don't affect business models
5. **๐Ÿš€ Flexibility**: Can change ORM without touching business logic
6. **๐Ÿ“œ API Stability**: Business models provide stable contracts
7. **๐Ÿ›ก๏ธ Type Safety**: Constants package prevents invalid states
8. **๐Ÿงน 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!** ๐ŸŽ‰