init
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
# 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!** π
|
||||
Reference in New Issue
Block a user