Restful API for managing task persistence.
==BEGINNER==: this version is properly for developer technical skills in the use of the technical stack, it is the foundational part for building projects of more complexity.
- Released on September 2025
- Unit tested
- Spec coverage of 55%
- Special features such as rate limiting, caching using Redis
graph TB
%% External Systems
Client[Client Applications]
Redis[(Redis Cache)]
Database[(Database)]
%% Infrastructure Layer
subgraph Infrastructure ["Infrastructure Layer"]
Docker[Docker Container]
Gin[Gin Web Server]
end
%% Primary Adapters (Driving)
subgraph PrimaryAdapters ["Primary Adapters (HTTP)"]
Router[Gin Router]
CORS[CORS Middleware]
RateLimit[Rate Limiter Middleware]
TaskHandler[Task Handler]
end
%% Core Hexagon
subgraph CoreDomain ["Core Domain (Hexagon)"]
subgraph Ports ["Ports (Interfaces)"]
TaskServicePort[TaskServiceInterface]
TaskRepoPort[TaskRepositoryInterface]
CachePort[CacheInterface]
ErrorLogPort[ErrorLoggerInterface]
end
subgraph Domain ["Domain Logic"]
TaskService[Task Service]
TaskModel[Task Model]
BusinessRules[Business Rules]
end
end
%% Secondary Adapters (Driven)
subgraph SecondaryAdapters ["Secondary Adapters"]
TaskRepoImpl[Task Repository Implementation]
CacheImpl[Redis Cache Implementation]
ErrorLogImpl[Error Logger Implementation]
ConfigManager[Configuration Manager]
end
%% API Endpoints Flow
subgraph APIEndpoints ["API Endpoints"]
GetTasks[GET /tasks/task]
GetTasksPage[GET /tasks/task/list/page]
GetTaskById[GET /tasks/task/:id]
PostTask[POST /tasks/task]
PutTask[PUT /tasks/task/:id]
PutTaskDone[PUT /tasks/task/:id/done]
DeleteTask[DELETE /tasks/task/:id]
end
%% Client to Infrastructure
Client --> Docker
Docker --> Gin
%% Request Flow Through Adapters
Gin --> Router
Router --> CORS
CORS --> RateLimit
RateLimit --> TaskHandler
%% API Endpoints to Handler
GetTasks --> TaskHandler
GetTasksPage --> TaskHandler
GetTaskById --> TaskHandler
PostTask --> TaskHandler
PutTask --> TaskHandler
PutTaskDone --> TaskHandler
DeleteTask --> TaskHandler
%% Primary Adapter to Domain
TaskHandler --> TaskServicePort
TaskServicePort --> TaskService
%% Domain Internal Flow
TaskService --> BusinessRules
TaskService --> TaskModel
%% Domain to Secondary Ports
TaskService --> TaskRepoPort
TaskService --> CachePort
TaskService --> ErrorLogPort
%% Secondary Ports to Adapters
TaskRepoPort --> TaskRepoImpl
CachePort --> CacheImpl
ErrorLogPort --> ErrorLogImpl
%% Secondary Adapters to External Systems
TaskRepoImpl --> Database
CacheImpl --> Redis
%% Rate Limiter to Redis
RateLimit --> Redis
%% Configuration Flow
ConfigManager --> TaskService
ConfigManager --> TaskRepoImpl
ConfigManager --> CacheImpl
%% Styling
classDef primary fill:#e1f5fe
classDef secondary fill:#f3e5f5
classDef domain fill:#e8f5e8
classDef external fill:#fff3e0
classDef infrastructure fill:#fce4ec
class TaskHandler,Router,CORS,RateLimit primary
class TaskRepoImpl,CacheImpl,ErrorLogImpl,ConfigManager secondary
class TaskService,TaskModel,BusinessRules,TaskServicePort,TaskRepoPort,CachePort,ErrorLogPort domain
class Client,Redis,Database external
class Docker,Gin infrastructure
sequenceDiagram
participant C as Client
participant M as Middleware
participant H as Handler
participant S as Service
participant R as Repository
participant Cache as Redis Cache
participant DB as Database
%% Read Operation Flow
C->>+M: GET /tasks/task/list/page?page=1&limit=10
M->>M: Rate Limiting Check
M->>+H: Forward Request
H->>H: Validate Parameters
H->>+Cache: Check Cache
alt Cache Hit
Cache-->>H: Return Cached Data
H-->>C: HTTP 200 + Cached Response
else Cache Miss
H->>+S: ListByPage(page, limit, order)
S->>+R: FindByPage(page, limit, order)
R->>+DB: SQL Query
DB-->>-R: Task Records
R-->>-S: Domain Objects
S-->>-H: Business Logic Result
H->>Cache: Store in Cache (TTL: 30s)
H-->>-C: HTTP 200 + Fresh Data
end
%% Write Operation Flow
C->>+M: POST /tasks/task
M->>M: Rate Limiting Check (30/min)
M->>+H: Forward Request
H->>H: Validate Request Body
H->>+S: Create(task)
S->>S: Apply Business Rules
S->>+R: Create(task)
R->>+DB: INSERT Query
DB-->>-R: Created Record
R-->>-S: Domain Object
S->>Cache: Invalidate List Caches
S-->>-H: Created Task
H-->>-C: HTTP 201 + Created Task
flowchart LR
subgraph CacheStrategy ["Cache Strategy"]
A[Request] --> B{Cache Check}
B -->|Hit| C[Return Cached Data]
B -->|Miss| D[Fetch from DB]
D --> E[Store in Cache]
E --> F[Return Fresh Data]
G[Write Operation] --> H[Update Database]
H --> I[Invalidate Related Caches]
I --> J{Cache Tags}
J -->|tasks:list| K[Invalidate List Caches]
J -->|task:id| L[Invalidate Specific Task Cache]
J -->|tasks:page:X| M[Invalidate Page Caches]
end
subgraph CacheKeys ["Cache Key Structure"]
N["task_123"]
O["tasks_page_1_limit_10_order_asc"]
P["tasks_cursor_abc123_limit_10_order_desc"]
end
flowchart TD
A[Incoming Request] --> B{Health Check?}
B -->|Yes| C[Skip Rate Limiting]
B -->|No| D[Determine Operation Type]
D --> E{HTTP Method}
E -->|GET| F{Prefetch Header?}
E -->|POST/PUT/DELETE| G[Write Operation: 30/min]
F -->|Yes| H[Prefetch Operation: 200/min]
F -->|No| I[Read Operation: 100/min]
G --> J[Check Redis Counter]
H --> J
I --> J
J --> K{Under Limit?}
K -->|Yes| L[Allow Request]
K -->|No| M[Return 429 + Retry-After]
L --> N[Continue to Handler]
M --> O[Client Waits]
- Domain-Centric Design: Business logic is isolated from external concerns
- Ports: Defined interfaces for interacting with the domain
- Adapters: Implementations that connect external systems to the domain through ports
- Dependency Inversion: Core domain depends on abstractions, not concrete implementations
-
Domain Layer (Core Hexagon)
- Contains business entities (Task models)
- Domain services with core business logic
- No dependencies on external frameworks or libraries
-
Ports Layer (Interfaces)
- Primary/Driving Ports: Service interfaces exposing domain functionality
- Secondary/Driven Ports: Repository interfaces defining storage requirements
-
Adapters Layer
- Primary/Driving Adapters: HTTP handlers (Gin controllers) translating HTTP to domain calls
- Secondary/Driven Adapters: Repository implementations (GORM), cache adapters (Redis)
External requests → Primary Adapters → Primary Ports → Domain Logic → Secondary Ports → Secondary Adapters → External systems
- Task management (core domain logic)
- Status transitions (domain rules)
- Validation logic (domain constraints)
TaskServiceInterface: Primary port for task operationsTaskRepositoryInterface: Secondary port for task persistenceCacheInterface: Secondary port for caching operations
- HTTP Handlers: Primary adapters converting HTTP to domain calls
- GORM Repositories: Secondary adapters implementing persistence ports
- Redis Cache: Secondary adapter implementing cache port
- Rate Limiter: Cross-cutting adapter for request throttling
- Language: Go 1.22.2 (Ideal for hexagonal due to interfaces and composition)
- Web Framework: Gin (Primary adapter for HTTP)
- Database: GORM (Secondary adapter for persistence)
- Cache: Redis (Secondary adapter for caching)
- Rate Limiting: Redis-based (Cross-cutting concern implemented as middleware)
- Containerization: Docker (Infrastructure concern, isolated from domain)
| Endpoint | Method | Hexagonal Role | Cache Strategy | Rate Limit |
|---|---|---|---|---|
/tasks/task |
GET | Primary adapter → TaskService port | 30s with ETag | 100/min |
/tasks/task/list/page |
GET | Primary adapter → TaskService port | 30s with ETag | 100/min |
/tasks/task/:id |
GET | Primary adapter → TaskService port | 30s with ETag | 100/min |
/tasks/task |
POST | Primary adapter → TaskService port | Invalidates list caches | 30/min |
/tasks/task/:id |
PUT | Primary adapter → TaskService port | Invalidates specific caches | 30/min |
/tasks/task/:id/done |
PUT | Primary adapter → TaskService port | Invalidates specific caches | 30/min |
/tasks/task/:id |
DELETE | Primary adapter → TaskService port | Invalidates all related caches | 30/min |
{
"id": 1,
"title": "Task title",
"description": "Task description",
"done": false,
"owner": 1,
"created_at": "2023-06-05T10:15:30Z",
"updated_at": "2023-06-05T10:15:30Z"
}{
"code": 200,
"resultMessage": "SUCCESS",
"data": {
/* domain object converted to DTO */
},
"timestamp": 1686061234,
"cacheTTL": 30
}{
"code": 400,
"resultMessage": "OPERATION_FAILED",
"error": "Error description"
}- Translate HTTP requests to domain operations
- Call appropriate service port methods
- Transform domain objects to DTOs for response
- Handle HTTP-specific concerns (status codes, headers)
- GORM implementation of repository interfaces
- Redis implementation of cache interfaces
- Isolate infrastructure details from domain logic
- Cache Port: Defines caching operations as interfaces
- Redis Adapter: Implements cache port with Redis
- Domain Event Listeners: Trigger cache invalidation on domain events
- Adapter-Specific Concerns: TTL, serialization handled in adapter layer
- Cross-cutting Concern: Implemented as middleware (outside the hexagon)
- Primary Adapter Extension: Enhances HTTP handling without touching domain
- Redis Adapter: Secondary adapter for distributed rate limiting
- Domain Tests: Unit tests for core business logic
- Port Tests: Tests ensuring port contracts are fulfilled
- Adapter Tests: Tests for adapter implementations
- Mock Ports: For testing adapters in isolation
- Integration Tests: Test full flows through the hexagon
- Testability: Domain logic can be tested without infrastructure
- Maintainability: Clear separation of concerns and dependencies
- Flexibility: Ability to swap out adapters (e.g., change from Redis to another cache)
- Focus on Domain: Business rules are centralized and explicit
- Technological Agnosticism: Core business logic is independent of frameworks
- Domain Events: Expand event-driven architecture for better decoupling
- Anti-corruption Layer: For integrating with external systems
- Command Query Responsibility Segregation (CQRS): Separate read and write models
- Bounded Contexts: Define clear boundaries between different domain areas
- Testing strategy needs to be implemented
- Monitoring and observability are missing
- Documentation could be enhanced
-
==Main==: it contains the latest deployed and published codebase, this one has been tested against unit, integration and end 2 end, also, there are special directories related to developer such as: devops (CI/CD pipelines), sshots (images for README file) and developer (diagrams, postman yaml files, documentation)
-
==Stage==: target branch for test the execution of the CI/CD pipelines, includes the interaction with the CI tools and cloud providers, the use of this branch is suggested for QA and DevOps teams. Pre-release version management, this one should be the only one merged with main branch.
-
==Unstable==: it containts the test codebase (unit, integration, end 2 end), it interacts with experimental and stage branches, must not merge with main.
-
==Experimental==: alpha version of the codebase, all features are built here, it interacts with unstable and stage, must not be merged directly with main branch.
-
==Refactor==: special feature requires by Experimental branch, the intention is to not affect the latest run version of the codebase contained in Experimental, if must be merged just with experimental branch.
- Stale Cache After Service Restart: Ensure Redis TTL values are reasonable to prevent very old data from being served
- Cache Stampede: When cache expires, multiple requests might try to rebuild it simultaneously - implement singleflight pattern
- Cache Inconsistency: If DB operations fail after cache invalidation, implement two-phase commit for critical operations
- Cache Size Limits: Add cache eviction policies to prevent memory issues with large datasets
- Database Timeouts: Add context with timeouts for all database operations
- Partial Updates: Ensure transactions are used for operations that modify multiple records
- Race Conditions: Implement optimistic locking for concurrent updates to the same record
- Connection Pool Exhaustion: Set reasonable pool sizes and handle connection limits
- Malformed JSON: Handle JSON parse errors gracefully
- Invalid UTF-8: Ensure proper encoding handling for international text
- XSS Protection: Sanitize inputs that might be displayed in UI
- Excessively Large Inputs: Limit request body sizes and pagination parameters
- Token Expiration: Gracefully handle expired tokens with clear error messages
- Rate Limit Bypass Attempts: Check for distributed attacks across multiple IPs
- Permission Boundary Cases: Verify edge cases where users might access resources they shouldn't
- Graceful Service Degradation: When Redis or other dependencies are down, degrade gracefully
- Request Timeout Handling: Add request-level timeouts to prevent hanging connections
- Health Check Endpoints: Skip rate limiting and authentication for health checks
- Logging Overflow: Protect against log flooding during error cascades
- Deadlocks: Ensure consistent lock acquisition order across your codebase
- Fan-out Overload: When spawning goroutines, use worker pools to limit concurrency
- Context Propagation: Ensure context cancellation propagates through all operations
-
- Handling Incomplete Downloads: Include Content-Length headers and ETag validation
- Browser Cache Inconsistencies: Test cache headers across different browsers
- Mobile Network Transitions: Support resumable operations for mobile clients
- Add structured logging for cache hits/misses
- Implement metrics for cache effectiveness and rate limit hits
- Add tracing for request flows through the system
- Create consistent error response formats
- Add correlation IDs for error tracking
- Implement better validation error messages
- Add support for HTTP/2
- Implement database query optimization
- Consider adding background refresh for frequently accessed data
- Add JWT validation
- Implement role-based access control
- Add request validation to prevent injection attacks