2025-06-24 19:56:56 +00:00
# Code Organization
## Project Structure
2025-09-09 19:34:03 +00:00
The project follows Go Standard Project Layout with enhanced organization for batch processing, observability, and background task management.
2025-06-24 19:56:56 +00:00
The codebase follows the [Standard Go Project Layout ](https://github.com/golang-standards/project-layout ) with additional conventions specific to the domain requirements.
### Directory Overview
```
query-orchestration.2/
├── cmd/ # Main applications and entry points
├── internal/ # Private application code
├── api/ # Generated API server implementations
├── pkg/ # Public library code
├── deployments/ # Deployment configurations
├── docs/ # Documentation
├── scripts/ # Build and automation scripts
├── test/ # Integration and e2e tests
├── assets/ # Test data and sample files
└── vendor/ # Vendored dependencies
```
## Package Architecture
### Command Layer (`cmd/`)
Entry points for all deployable services, following the pattern:
```
cmd/
├── [serviceName]/
│ └── main.go # Service bootstrap and configuration
```
**Naming Conventions ** :
- **APIs**: `[functionality]API` (e.g., `queryAPI` )
- **Runners**: `[functionality]Runner` (e.g., `docInitRunner` )
- **Utilities**: Descriptive names (e.g., `healthcheck` )
### Internal Packages (`internal/`)
2025-09-09 19:34:03 +00:00
Core business logic and infrastructure components, organized by domain:
#### New Components (Since June 2025):
- **`internal/backgroundtask/` **: Background task execution framework with periodic scheduling
- **`internal/document/batch/` **: Batch upload processing and ZIP archive handling
- **`internal/serviceconfig/observability/prometheus/` **: Comprehensive Prometheus metrics framework
### Internal Packages (`internal/`)
2025-06-24 19:56:56 +00:00
Core business logic organized by domain boundaries:
#### Domain Services
```
internal/
├── client/ # Client management domain
2026-02-19 20:22:59 +00:00
├── document/ # Document processing domain
├── fieldextraction/ # Field extraction domain
2025-06-24 19:56:56 +00:00
├── collector/ # Client-specific configurations
└── export/ # Data export operations
```
#### Infrastructure Services
```
internal/
├── database/ # Data persistence layer
├── server/ # HTTP and queue server infrastructure
├── serviceconfig/ # Configuration management
├── cognitoauth/ # Authentication middleware
├── test/ # Testing utilities
└── validation/ # Input validation
```
### API Layer (`api/`)
Generated server implementations from OpenAPI specifications:
```
api/
├── queryAPI/ # REST API implementation
│ ├── api.gen.go # Generated types and interfaces
│ ├── controllers.go # Business logic implementation
│ ├── authHandlers.go # Authentication endpoints
│ └── *.go # Domain-specific handlers
└── [runnerName]/ # Queue-based service implementations
└── runner.go # Queue message processing
```
## Design Patterns and Principles
### Service Layer Pattern
Each domain follows a consistent service layer structure:
``` go
// Service struct with injected dependencies
type Service struct {
cfg ConfigProvider // Configuration interface
}
// Constructor with interface-based dependency injection
func New ( cfg ConfigProvider ) * Service {
return & Service { cfg : cfg }
}
// Business operations
func ( s * Service ) CreateEntity ( ctx context . Context , req CreateRequest ) ( * Entity , error ) {
// Business logic implementation
}
```
### Repository Pattern
Database access is abstracted through repositories:
``` go
// Generated by SQLC from SQL queries
type Repository interface {
CreateClient ( ctx context . Context , arg CreateClientParams ) ( Client , error )
GetClient ( ctx context . Context , clientID string ) ( Client , error )
// ... other operations
}
// Service uses repository interface
type Service struct {
repo Repository
}
```
### Configuration Provider Pattern
Services receive configuration through composed interfaces:
``` go
// Domain-specific configuration interface
type ConfigProvider interface {
serviceconfig . ConfigProvider // Base configuration
database . ConfigProvider // Database access
objectstore . ConfigProvider // S3 access
// ... other provider interfaces
}
// Concrete configuration embeds all providers
type Config struct {
serviceconfig . BaseConfig
database . Config
objectstore . Config
}
```
### Dependency Injection
Services are composed through constructor injection:
``` go
// In main.go
cfg := & Config {
BaseConfig : baseConfig ,
DatabaseConfig : dbConfig ,
// ... other configs
}
// Create service with injected dependencies
svc := service . New ( cfg )
// Create controller with service dependency
controller := api . NewController ( svc )
```
## Naming Conventions
### Package Names
2026-02-19 20:22:59 +00:00
- **Domain packages**: Singular nouns (`client` , `document` , `fieldextraction` )
2025-06-24 19:56:56 +00:00
- **Utility packages**: Descriptive (`serviceconfig` , `cognitoauth` )
- **Generated packages**: Match source (`queryAPI` from `queryAPI.yaml` )
### File Names
- **Service files**: `service.go` (main business logic)
- **Test files**: `*_test.go` (alongside source)
- **Private tests**: `*private_test.go` (package-private testing)
- **Interface files**: Match domain (`client.go` , `document.go` )
### Function and Method Names
- **Public functions**: PascalCase (`CreateClient` , `GetDocument` )
- **Private functions**: camelCase (`validateInput` , `processResult` )
- **Constructors**: `New` or `New[Type]` (`New` , `NewService` )
- **Getters**: No `Get` prefix for simple accessors (`ID()` , not `GetID()` )
### Variable Names
- **Short scope**: Single letters (`i` , `j` , `c` for client)
- **Medium scope**: Abbreviations (`ctx` , `req` , `resp` )
- **Long scope**: Descriptive names (`clientRepository` , `configProvider` )
- **Constants**: PascalCase (`MaxRetryAttempts` , `DefaultTimeout` )
### Type Names
- **Structs**: PascalCase nouns (`Client` , `DocumentProcessor` )
- **Interfaces**: PascalCase with optional "er" suffix (`ConfigProvider` , `Processor` )
- **Enums**: PascalCase with type suffix (`QueryType` , `ProcessingStatus` )
## Code Style Guidelines
### Import Organization
``` go
package main
import (
// Standard library
"context"
"fmt"
// Third-party packages
"github.com/labstack/echo/v4"
"github.com/google/uuid"
// Local packages
"queryorchestration/internal/client"
"queryorchestration/internal/database"
)
```
### Error Handling
``` go
// Wrap errors with context
func ( s * Service ) ProcessDocument ( ctx context . Context , id uuid . UUID ) error {
doc , err := s . repo . GetDocument ( ctx , id )
if err != nil {
return fmt . Errorf ( "failed to get document %s: %w" , id , err )
}
if err := s . processContent ( doc ) ; err != nil {
return fmt . Errorf ( "failed to process document content: %w" , err )
}
return nil
}
```
### Interface Design
``` go
// Prefer small, focused interfaces
type ClientReader interface {
GetClient ( ctx context . Context , id string ) ( * Client , error )
}
type ClientWriter interface {
CreateClient ( ctx context . Context , client * Client ) error
UpdateClient ( ctx context . Context , client * Client ) error
}
// Compose when needed
type ClientRepository interface {
ClientReader
ClientWriter
}
```
### Struct Design
``` go
// Group related fields
type Client struct {
// Identity
ID string
Name string
// Configuration
CanSync bool
// Metadata
CreatedAt time . Time
UpdatedAt time . Time
}
// Use embedding for composition
type APIClient struct {
Client
AuthToken string
}
```
## Testing Patterns
### Table-Driven Tests
``` go
func TestService_CreateClient ( t * testing . T ) {
tests := [ ] struct {
name string
input CreateClientRequest
want * Client
wantErr bool
} {
{
name : "valid client" ,
input : CreateClientRequest {
ID : "test-client" ,
Name : "Test Client" ,
} ,
want : & Client {
ID : "test-client" ,
Name : "Test Client" ,
} ,
wantErr : false ,
} ,
{
name : "empty ID" ,
input : CreateClientRequest {
Name : "Test Client" ,
} ,
want : nil ,
wantErr : true ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
// Test implementation
} )
}
}
```
### Mock Usage
``` go
// Generate mocks for interfaces
//go:generate mockery --name=ClientRepository --output=mocks
func TestService_WithMocks ( t * testing . T ) {
// Create mock
mockRepo := & mocks . ClientRepository { }
// Set expectations
mockRepo . On ( "GetClient" , mock . Anything , "test-id" ) .
Return ( & Client { ID : "test-id" } , nil )
// Create service with mock
svc := & Service { repo : mockRepo }
// Test and verify
result , err := svc . GetClient ( context . Background ( ) , "test-id" )
assert . NoError ( t , err )
assert . Equal ( t , "test-id" , result . ID )
mockRepo . AssertExpectations ( t )
}
```
### Integration Test Structure
``` go
func TestIntegration_DocumentProcessing ( t * testing . T ) {
// Setup test environment
ctx := context . Background ( )
testDB := test . NewDatabase ( t )
testS3 := test . NewObjectStore ( t )
// Create service with real dependencies
cfg := & Config {
Database : testDB ,
ObjectStore : testS3 ,
}
svc := New ( cfg )
// Run test scenario
client := test . CreateTestClient ( t , svc )
document := test . UploadTestDocument ( t , svc , client . ID )
// Verify results
result := test . ProcessDocument ( t , svc , document . ID )
assert . NotNil ( t , result )
// Cleanup handled by test utilities
}
```
## Architecture Decisions
### Configuration Management
- **Environment-first**: All configuration from environment variables
- **Type safety**: Strong typing with validation
- **Composition**: Interface-based configuration providers
- **Testing**: Override-friendly for test scenarios
### Error Handling
- **Wrap errors**: Add context at each layer
- **Structured logging**: Use slog for consistent error logging
- **Graceful degradation**: Continue operation when possible
- **Client-friendly**: Translate internal errors to appropriate HTTP status
### Database Access
- **Type safety**: SQLC generates type-safe database code
- **Migrations**: Version-controlled schema evolution
- **Connection pooling**: Shared connections across services
- **Transaction management**: Explicit transaction boundaries
### API Design
- **Contract-first**: OpenAPI specification drives implementation
- **Version compatibility**: Backward-compatible changes
- **Validation**: Automatic request/response validation
- **Documentation**: Auto-generated from specification
2026-02-19 20:22:59 +00:00
This organization enables maintainable, testable, and scalable code while following Go best practices and domain-driven design principles.