# Go Implementation Plan for AutoStore ## Overview Implementation of AutoStore system using Go, following Clean Architecture principles. The system stores items with expiration dates and automatically orders new items when they expire. ## Architecture Approach - **Clean Architecture** with clear separation of concerns - **Domain-Driven Design** with rich domain models - **Hexagonal Architecture** with dependency inversion - **Repository Pattern** for data persistence - **CQRS-like** command/query separation - **Dependency Injection** using Go's interface system and a DI container ## Core Domain Logic ### ItemExpirationSpec - Single Source of Truth for Expiration **File**: `internal/domain/specifications/item_expiration_spec.go` **Purpose**: Centralized expiration checking logic - the single source of truth for determining if items are expired **Key Methods**: - `IsExpired(item *ItemEntity, currentTime time.Time) bool` - Checks if item expired - `GetSpec(currentTime time.Time) Specification[ItemEntity]` - Returns specification for repository queries **Place in the flow**: - Called by `AddItemCommand.Execute()` to check newly created items for immediate expiration - Called by `HandleExpiredItemsCommand.Execute()` to find expired items for processing - Used by `ItemRepository.FindWhere()` to query database for expired items ## Detailed Implementation Plan ### Domain Layer #### 1. Entities **File**: `internal/domain/entities/item.go` **Purpose**: Core business entity representing an item **Key Methods**: - `NewItem(id ItemID, name string, expirationDate ExpirationDate, orderURL string, userID UserID) (*ItemEntity, error)` - Creates item with validation - `GetID() ItemID` - Returns item ID - `GetName() string` - Returns item name - `GetExpirationDate() ExpirationDate` - Returns expiration date - `GetOrderURL() string` - Returns order URL - `GetUserID() UserID` - Returns user ID **Place in the flow**: - Created by `AddItemCommand.Execute()` - Retrieved by `ItemRepository` methods - Passed to `ItemExpirationSpec.IsExpired()` for expiration checking **File**: `internal/domain/entities/user.go` **Purpose**: User entity for item ownership and authentication purposes **Key Methods**: - `NewUser(id UserID, username string, passwordHash string) (*UserEntity, error)` - Creates user with validation - `GetID() UserID` - Returns user ID - `GetUsername() string` - Returns username - `GetPasswordHash() string` - Returns password hash - `ValidatePassword(password string) bool` - Validates password #### 2. Value Objects **File**: `internal/domain/value_objects/item_id.go` **Purpose**: Strong typing for item identifiers **Key Methods**: - `NewItemID(value string) (ItemID, error)` - Validates UUID format - `String() string` - Returns string value - `Equals(other ItemID) bool` - Compares with another ItemID **File**: `internal/domain/value_objects/user_id.go` **Purpose**: Strong typing for user identifiers **Key Methods**: - `NewUserID(value string) (UserID, error)` - Validates UUID format - `String() string` - Returns string value - `Equals(other UserID) bool` - Compares with another UserID **File**: `internal/domain/value_objects/expiration_date.go` **Purpose**: Immutable expiration date with validation **Key Methods**: - `NewExpirationDate(value time.Time) (ExpirationDate, error)` - Validates date format (allows past dates per business rules) - `Time() time.Time` - Returns time.Time object - `String() string` - Returns ISO string format - `IsExpired(currentTime time.Time) bool` - Checks if date is expired **Place in the flow**: - Used by `ItemEntity` constructor for type-safe date handling - Validated by `ItemExpirationSpec.IsExpired()` for expiration logic #### 3. Specifications **File**: `internal/domain/specifications/specification.go` **Purpose**: Generic specification pattern interface **Key Methods**: - `IsSatisfiedBy(candidate T) bool` - Evaluates specification - `And(other Specification[T]) Specification[T]` - Combines with AND - `Or(other Specification[T]) Specification[T]` - Combines with OR - `Not() Specification[T]` - Negates specification **File**: `internal/domain/specifications/item_expiration_spec.go` **Purpose**: Implementation of expiration specification **Key Methods**: - `IsExpired(item *ItemEntity, currentTime time.Time) bool` - Checks if item is expired - `GetSpec(currentTime time.Time) Specification[ItemEntity]` - Returns specification for repository queries **Place in the flow**: - Implemented by `ItemExpirationSpec` for type-safe specifications - Used by `ItemRepository.FindWhere()` for database queries ### Application Layer #### 4. Commands **File**: `internal/application/commands/add_item_command.go` **Purpose**: Use case for creating new items with expiration handling **Key Methods**: - `NewAddItemCommand(itemRepo IItemRepository, orderService IOrderService, timeProvider ITimeProvider, expirationSpec *ItemExpirationSpec, logger ILogger) *AddItemCommand` - Constructor with dependency injection - `Execute(ctx context.Context, name string, expirationDate time.Time, orderURL string, userID string) (string, error)` - Creates item, handles expired items immediately **Flow**: 1. `ItemsController.CreateItem()` calls `AddItemCommand.Execute()` 2. Creates `ItemEntity` with validated data 3. Calls `ItemExpirationSpec.IsExpired()` to check if item is expired 4. If expired: - calls `OrderHTTPService.OrderItem()` - **returns item ID** (business rule: expired items trigger ordering but still return ID field that might be empty or invalid) 5. If not expired: calls `ItemRepository.Save()` and returns item ID **File**: `internal/application/commands/handle_expired_items_command.go` **Purpose**: Background command to process expired items **Key Methods**: - `NewHandleExpiredItemsCommand(itemRepo IItemRepository, orderService IOrderService, timeProvider ITimeProvider, expirationSpec *ItemExpirationSpec, logger ILogger) *HandleExpiredItemsCommand` - Constructor with dependency injection - `Execute(ctx context.Context) error` - Finds and processes all expired items **Flow**: 1. `ExpiredItemsScheduler.Run()` calls `HandleExpiredItemsCommand.Execute()` 2. Gets current time from `ITimeProvider` 3. Calls `ItemExpirationSpec.GetSpec()` to get expiration specification 4. Calls `ItemRepository.FindWhere()` to find expired items 5. For each expired item: calls `OrderHTTPService.OrderItem()` then `ItemRepository.Delete()` **File**: `internal/application/commands/delete_item_command.go` **Purpose**: Use case for deleting user items **Key Methods**: - `NewDeleteItemCommand(itemRepo IItemRepository, logger ILogger) *DeleteItemCommand` - Constructor with dependency injection - `Execute(ctx context.Context, itemID string, userID string) error` - Validates ownership and deletes item **Flow**: 1. `ItemsController.DeleteItem()` calls `DeleteItemCommand.Execute()` 2. Calls `ItemRepository.FindByID()` to retrieve item 3. Validates ownership by comparing user IDs 4. Calls `ItemRepository.Delete()` to remove item **File**: `internal/application/commands/login_user_command.go` **Purpose**: User authentication use case **Key Methods**: - `NewLoginUserCommand(authService IAuthService, logger ILogger) *LoginUserCommand` - Constructor with dependency injection - `Execute(ctx context.Context, username string, password string) (string, error)` - Authenticates and returns JWT token #### 5. Queries **File**: `internal/application/queries/get_item_query.go` **Purpose**: Retrieves single item by ID with authorization **Key Methods**: - `NewGetItemQuery(itemRepo IItemRepository, logger ILogger) *GetItemQuery` - Constructor with dependency injection - `Execute(ctx context.Context, itemID string, userID string) (*ItemEntity, error)` - Validates ownership and returns item **Flow**: 1. `ItemsController.GetItem()` calls `GetItemQuery.Execute()` 2. Calls `ItemRepository.FindByID()` to retrieve item 3. Validates ownership by comparing user IDs 4. Returns item entity **File**: `internal/application/queries/list_items_query.go` **Purpose**: Retrieves all items for authenticated user **Key Methods**: - `NewListItemsQuery(itemRepo IItemRepository, logger ILogger) *ListItemsQuery` - Constructor with dependency injection - `Execute(ctx context.Context, userID string) ([]*ItemEntity, error)` - Returns user's items **Flow**: 1. `ItemsController.ListItems()` calls `ListItemsQuery.Execute()` 2. Calls `ItemRepository.FindByUserID()` to retrieve user's items 3. Returns array of item entities #### 6. DTOs **File**: `internal/application/dto/create_item_dto.go` **Purpose**: Request validation for item creation **Key Properties**: - `Name string` - Item name (validation: not empty, max 255 chars) - `ExpirationDate time.Time` - Date (validation: valid date) - `OrderURL string` - Order URL (validation: valid URL format) **Key Methods**: - `Validate() error` - Validates DTO fields **Place in the flow**: - Used by `ItemsController.CreateItem()` for request body validation **File**: `internal/application/dto/item_response_dto.go` **Purpose**: Standardized item response format **Key Properties**: - `ID string` - Item ID - `Name string` - Item name - `ExpirationDate time.Time` - Expiration date - `OrderURL string` - Order URL - `UserID string` - Owner user ID - `CreatedAt time.Time` - Creation timestamp **Key Methods**: - `FromEntity(item *ItemEntity) *ItemResponseDTO` - Creates DTO from entity **Place in the flow**: - Used by all item controller methods for response transformation **File**: `internal/application/dto/login_dto.go` **Purpose**: Login request validation **Key Properties**: - `Username string` - Username (validation: not empty) - `Password string` - Password (validation: not empty) **Key Methods**: - `Validate() error` - Validates DTO fields #### 7. Interfaces **File**: `internal/application/interfaces/item_repository.go` **Purpose**: Repository interface for item persistence **Key Methods**: - `Save(ctx context.Context, item *ItemEntity) error` - `FindByID(ctx context.Context, id ItemID) (*ItemEntity, error)` - `FindByUserID(ctx context.Context, userID UserID) ([]*ItemEntity, error)` - `FindWhere(ctx context.Context, spec Specification[ItemEntity]) ([]*ItemEntity, error)` - `Delete(ctx context.Context, id ItemID) error` - `Exists(ctx context.Context, id ItemID) (bool, error)` **File**: `internal/application/interfaces/user_repository.go` **Purpose**: Repository interface for user persistence **Key Methods**: - `FindByUsername(ctx context.Context, username string) (*UserEntity, error)` - `FindByID(ctx context.Context, id UserID) (*UserEntity, error)` - `Save(ctx context.Context, user *UserEntity) error` **File**: `internal/application/interfaces/auth_service.go` **Purpose**: Authentication service interface **Key Methods**: - `Authenticate(ctx context.Context, username string, password string) (string, error)` - `ValidateToken(ctx context.Context, token string) (bool, error)` - `GetUserIDFromToken(ctx context.Context, token string) (string, error)` **File**: `internal/application/interfaces/order_service.go` **Purpose**: Order service interface **Key Methods**: - `OrderItem(ctx context.Context, item *ItemEntity) error` **File**: `internal/application/interfaces/time_provider.go` **Purpose**: Time provider interface for testing **Key Methods**: - `Now() time.Time` **File**: `internal/application/interfaces/logger.go` **Purpose**: Logger interface **Key Methods**: - `Info(ctx context.Context, msg string, fields ...interface{})` - `Error(ctx context.Context, msg string, fields ...interface{})` - `Debug(ctx context.Context, msg string, fields ...interface{})` - `Warn(ctx context.Context, msg string, fields ...interface{})` ### Infrastructure Layer #### 8. Repositories **File**: `internal/infrastructure/repositories/file_item_repository.go` **Purpose**: File-based implementation of item repository using JSON files **Key Methods**: - `Save(ctx context.Context, item *ItemEntity) error` - Persists item entity - `FindByID(ctx context.Context, id ItemID) (*ItemEntity, error)` - Finds by ID - `FindByUserID(ctx context.Context, userID UserID) ([]*ItemEntity, error)` - Finds by user - `FindWhere(ctx context.Context, spec Specification[ItemEntity]) ([]*ItemEntity, error)` - Finds by specification using `ItemExpirationSpec` - `Delete(ctx context.Context, id ItemID) error` - Deletes item - `Exists(ctx context.Context, id ItemID) (bool, error)` - Checks existence **Place in the flow**: - Called by all commands and queries for data persistence and retrieval - Uses `ItemExpirationSpec` for finding expired items **File**: `internal/infrastructure/repositories/file_user_repository.go` **Purpose**: File-based implementation of user repository using JSON files **Key Methods**: - `FindByUsername(ctx context.Context, username string) (*UserEntity, error)` - Finds by username - `FindByID(ctx context.Context, id UserID) (*UserEntity, error)` - Finds by ID - `Save(ctx context.Context, user *UserEntity) error` - Saves user #### 9. HTTP Services **File**: `internal/infrastructure/http/order_http_service.go` **Purpose**: HTTP implementation of order service **Key Methods**: - `NewOrderHTTPService(client *http.Client, logger ILogger) *OrderHTTPService` - Constructor with dependency injection - `OrderItem(ctx context.Context, item *ItemEntity) error` - Sends POST request to order URL **Place in the flow**: - Called by `AddItemCommand.Execute()` for expired items - Called by `HandleExpiredItemsCommand.Execute()` for batch processing #### 10. Authentication **File**: `internal/infrastructure/auth/jwt_auth_service.go` **Purpose**: JWT implementation of authentication service **Key Methods**: - `NewJWTAuthService(userRepo IUserRepository, secretKey string, logger ILogger) *JWTAuthService` - Constructor with dependency injection - `Authenticate(ctx context.Context, username string, password string) (string, error)` - Validates credentials and generates JWT - `ValidateToken(ctx context.Context, token string) (bool, error)` - Validates JWT token - `GetUserIDFromToken(ctx context.Context, token string) (string, error)` - Extracts user ID from token **Place in the flow**: - Called by `LoginUserCommand.Execute()` for user authentication - Used by `JWTMiddleware` for route protection #### 11. Time Provider **File**: `internal/infrastructure/time/system_time_provider.go` **Purpose**: System time implementation **Key Methods**: - `NewSystemTimeProvider() *SystemTimeProvider` - Constructor - `Now() time.Time` - Returns current system time #### 12. Logger **File**: `internal/infrastructure/logging/standard_logger.go` **Purpose**: Standard library logger implementation **Key Methods**: - `NewStandardLogger(writer io.Writer) *StandardLogger` - Constructor - `Info(ctx context.Context, msg string, fields ...interface{})` - Logs info message - `Error(ctx context.Context, msg string, fields ...interface{})` - Logs error message - `Debug(ctx context.Context, msg string, fields ...interface{})` - Logs debug message - `Warn(ctx context.Context, msg string, fields ...interface{})` - Logs warning message ### Presentation Layer #### 13. Controllers **File**: `internal/presentation/controllers/items_controller.go` **Purpose**: REST API endpoints for item management **Key Methods**: - `NewItemsController(addItemCmd *AddItemCommand, getItemQry *GetItemQuery, listItemsQry *ListItemsQuery, deleteItemCmd *DeleteItemCommand, logger ILogger) *ItemsController` - Constructor with dependency injection - `CreateItem(c *gin.Context)` - POST /items - `GetItem(c *gin.Context)` - GET /items/:id - `ListItems(c *gin.Context)` - GET /items - `DeleteItem(c *gin.Context)` - DELETE /items/:id **Flow**: - Receives HTTP requests and validates input - Calls appropriate commands/queries based on HTTP method - Returns standardized responses with DTOs **File**: `internal/presentation/controllers/auth_controller.go` **Purpose**: Authentication endpoints **Key Methods**: - `NewAuthController(loginUserCmd *LoginUserCommand, logger ILogger) *AuthController` - Constructor with dependency injection - `Login(c *gin.Context)` - POST /login #### 14. Middleware **File**: `internal/presentation/middleware/jwt_middleware.go` **Purpose**: JWT authentication middleware **Key Methods**: - `NewJWTMiddleware(authService IAuthService, logger ILogger) *JWTMiddleware` - Constructor with dependency injection - `Middleware() gin.HandlerFunc` - Returns gin middleware function **Place in the flow**: - Applied to all protected routes by Gin router group - Uses `JWTAuthService` for token validation #### 15. Server **File**: `internal/presentation/server/server.go` **Purpose**: HTTP server setup and configuration **Key Methods**: - `NewServer(config *Config, logger ILogger) *Server` - Constructor with dependency injection - `Start() error` - Starts the HTTP server - `SetupRoutes() *gin.Engine` - Sets up routes and middleware ### Background Processing **File**: `internal/infrastructure/scheduler/expired_items_scheduler.go` **Purpose**: Scheduled job for processing expired items using a ticker **Key Methods**: - `NewExpiredItemsScheduler(handleExpiredItemsCmd *HandleExpiredItemsCommand, logger ILogger) *ExpiredItemsScheduler` - Constructor with dependency injection - `Start(ctx context.Context) error` - Starts the scheduler - `Stop() error` - Stops the scheduler - `processExpiredItems(ctx context.Context) error` - Processes expired items **Flow**: 1. **On startup**: `processExpiredItems()` immediately calls `HandleExpiredItemsCommand.Execute()` 2. **Every minute**: Ticker triggers `processExpiredItems()` to process expired items 3. All methods use context for cancellation and error handling 4. Comprehensive logging for monitoring and debugging **Configuration**: - Uses `time.Ticker` for periodic execution - Implements graceful shutdown with context cancellation - Configurable interval (default: 1 minute) ### Dependency Injection **File**: `internal/container/container.go` **Purpose**: Dependency injection container setup **Key Methods**: - `NewContainer(config *Config) *Container` - Constructor - `Initialize() error` - Initializes all dependencies - `GetItemRepository() IItemRepository` - Returns item repository - `GetUserRepository() IUserRepository` - Returns user repository - `GetAuthService() IAuthService` - Returns auth service - `GetOrderService() IOrderService` - Returns order service - `GetTimeProvider() ITimeProvider` - Returns time provider - `GetLogger() ILogger` - Returns logger - `GetAddItemCommand() *AddItemCommand` - Returns add item command - `GetHandleExpiredItemsCommand() *HandleExpiredItemsCommand` - Returns handle expired items command - `GetDeleteItemCommand() *DeleteItemCommand` - Returns delete item command - `GetLoginUserCommand() *LoginUserCommand` - Returns login user command - `GetGetItemQuery() *GetItemQuery` - Returns get item query - `GetListItemsQuery() *ListItemsQuery` - Returns list items query - `GetItemsController() *ItemsController` - Returns items controller - `GetAuthController() *AuthController` - Returns auth controller - `GetJWTMiddleware() *JWTMiddleware` - Returns JWT middleware - `GetExpiredItemsScheduler() *ExpiredItemsScheduler` - Returns expired items scheduler ### Configuration **File**: `internal/config/config.go` **Purpose**: Application configuration **Key Properties**: - `ServerPort int` - Server port - `JWTSecret string` - JWT secret key - `DataDirectory string` - Directory for data files - `LogLevel string` - Log level - `SchedulerInterval time.Duration` - Scheduler interval **Key Methods**: - `Load() (*Config, error)` - Loads configuration from environment variables - `Validate() error` - Validates configuration ### Main Application **File**: `cmd/main.go` **Purpose**: Application entry point **Key Methods**: - `main()` - Main function - `setupGracefulShutdown(server *Server, scheduler *ExpiredItemsScheduler)` - Sets up graceful shutdown **Flow**: 1. Loads configuration 2. Initializes dependency container 3. Creates server and scheduler 4. Starts scheduler 5. Starts server 6. Sets up graceful shutdown ## Complete Flow Summary ### Item Creation Flow ``` POST /items ├── JWTMiddleware (authentication) ├── CreateItemDTO validation ├── ItemsController.CreateItem() │ ├── AddItemCommand.Execute() │ │ ├── ItemEntity constructor (validation) │ │ ├── ItemExpirationSpec.IsExpired() ← SINGLE SOURCE OF TRUTH │ │ ├── If expired: OrderHTTPService.OrderItem() │ │ └── If not expired: ItemRepository.Save() │ └── ItemResponseDTO transformation └── HTTP response ``` ### Expired Items Processing Flow ``` Scheduler (every minute) └── ExpiredItemsScheduler.processExpiredItems() └── HandleExpiredItemsCommand.Execute() ├── ITimeProvider.Now() ├── ItemExpirationSpec.GetSpec() ← SINGLE SOURCE OF TRUTH ├── ItemRepository.FindWhere() (using spec) ├── For each expired item: │ ├── OrderHTTPService.OrderItem() │ └── ItemRepository.Delete() └── Logging ``` ### Item Retrieval Flow ``` GET /items/:id ├── JWTMiddleware (authentication) ├── ItemsController.GetItem() │ ├── GetItemQuery.Execute() │ │ ├── ItemRepository.FindByID() │ │ ├── Ownership validation │ │ └── Return ItemEntity │ └── ItemResponseDTO transformation └── HTTP response ``` ## Key Design Principles 1. **Single Source of Truth**: `ItemExpirationSpec` is the only component that determines expiration logic 2. **Clear Flow**: Each component has a well-defined place in the execution chain 3. **Dependency Inversion**: High-level modules don't depend on low-level modules 4. **Separation of Concerns**: Each layer has distinct responsibilities 5. **Testability**: All components can be tested in isolation 6. **Context Propagation**: All methods accept context for cancellation, deadlines, and tracing 7. **Error Handling**: Comprehensive error handling with proper error types 8. **Configuration Management**: Environment-based configuration with validation ## Go-Specific Best Practices 1. **Package Organization**: Follow Go's standard package layout with `internal/` for private packages 2. **Error Handling**: Use Go's error handling pattern with proper error wrapping 3. **Context Usage**: Use context for cancellation, deadlines, and request-scoped values 4. **Interface Segregation**: Keep interfaces small and focused 5. **Naming Conventions**: Follow Go's naming conventions (camelCase for exported, camelCase for unexported) 6. **Pointer vs Value**: Use pointers for mutable state and large structs, values for immutable data 7. **Concurrency**: Use goroutines and channels for concurrent operations 8. **Testing**: Write comprehensive tests with table-driven tests 9. **Documentation**: Use Go's documentation comments for all exported types and functions 10. **Dependencies**: Use Go modules for dependency management ## Directory Structure ``` golang/ ├── cmd/ │ └── main.go # Application entry point ├── internal/ │ ├── application/ │ │ ├── commands/ # Command handlers │ │ ├── queries/ # Query handlers │ │ ├── dto/ # Data transfer objects │ │ └── interfaces/ # Application interfaces │ ├── domain/ │ │ ├── entities/ # Domain entities │ │ ├── value_objects/ # Value objects │ │ └── specifications/ # Domain specifications │ ├── infrastructure/ │ │ ├── repositories/ # Repository implementations │ │ ├── http/ # HTTP services │ │ ├── auth/ # Authentication services │ │ ├── time/ # Time provider │ │ ├── logging/ # Logger implementations │ │ └── scheduler/ # Background scheduler │ ├── presentation/ │ │ ├── controllers/ # HTTP controllers │ │ ├── middleware/ # HTTP middleware │ │ └── server/ # HTTP server │ ├── config/ │ │ └── config.go # Configuration │ └── container/ │ └── container.go # Dependency injection container ├── pkg/ │ └── specifications/ # Reusable specification patterns ├── data/ # Data files (JSON) ├── docker/ │ ├── docker-compose.yml # Docker compose │ └── Dockerfile # Docker image ├── go.mod # Go module file ├── go.sum # Go module checksums └── README.md # Go implementation README ``` This implementation plan ensures consistent development regardless of the implementer, providing clear flow definitions and emphasizing `ItemExpirationSpec` as the centralized source for expiration logic, while following Go best practices and idioms.