-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture Overview
Codex follows a clean architecture pattern with clear separation of concerns, emphasizing production-ready concurrency patterns and fault tolerance.
codex/
├── cmd/server/ # Application entry point
│ ├── main.go # Server initialization, CLI, graceful shutdown
│ ├── migrations.go # Database migrations
│ └── seed.go # Database seeding
├── internal/
│ ├── app/ # App initialization & config
│ ├── db/ # Database connection
│ ├── sqlite/ # Model-specific database implementations
│ ├── models/ # Data models & business logic
│ ├── service/ # Business logic layer
│ ├── patterns/ # Design patterns (circuit breaker)
│ ├── workers/ # Background job processing
│ │ ├── image_worker.go # Image processing pool
│ │ └── logger_pool.go # Async logging pool
│ ├── http/
│ │ ├── handlers/ # HTTP handlers
│ │ ├── middleware/ # Middleware (auth, logging, tracing, timeout)
│ │ └── routes/ # Router & DI registry
│ └── view/ # Template rendering
├── migrations/ # SQL schema files
├── assets/ # Static files (CSS, JS, icons, templates)
└── scripts/ # Build & deployment scripts
Codex uses a custom UUIDField type for user identification:
-
Type Safety:
UUIDFieldwrapsgithub.com/google/uuid -
Database Integration: Implements
driver.Valuerandsql.Scanner - BLOB Storage: 16-byte BLOBs in SQLite (not strings)
- JSON Support: Automatic string conversion for API responses
Location: internal/models/uuidfield-models.go
UUID-based request correlation for distributed tracing:
- Request ID generated in
WithTracingmiddleware - Propagated via
context.Contextthrough all layers -
X-Request-IDresponse header for client debugging - Automatic log correlation across concurrent operations
Location: internal/http/middleware/tracing.go
Protects database from cascading failures:
- States: Closed (normal), Open (blocking), Half-Open (testing)
- Configuration: 5 failures threshold, 5 second timeout
- Shared State: Circuit shared across all goroutines
-
Thread-Safe: Uses
sync.RWMutexfor atomic state transitions - Recovery Testing: Half-open state gradually tests service health
Location: internal/patterns/circuitbreaker.go
Usage in concurrent search:
err := app.DBCircuit.Execute(func() error {
users, execErr = app.Users.All()
return execErr
})Non-blocking request logging with worker pool:
- Worker Pool: 3 workers processing log queue
- Buffered Queue: 1000 entries for high throughput
- Database Persistence: Structured request logs with metrics
- Graceful Shutdown: Queue draining before exit
Location: internal/workers/logger_pool.go
Context-aware logging with visual formatting:
- Levels: Info (🟢 green), Warn (🟠 orange), Error (🔴 red)
- Request IDs: Automatic injection from context
- Timestamps: Neutral gray for easy scanning
- Icons: Emoji for quick visual identification
Location: internal/models/logs-models.go
API:
models.LogInfoWithContext(r.Context(), "User %s logged in", username)
models.LogWarnWithContext(r.Context(), "Partial failure: %v", err)
models.LogErrorWithContext(r.Context(), "Database query failed", err)Ordered cleanup sequence prevents data corruption:
- HTTP Server: Stop accepting requests, wait for handlers
- Logger Pool: Drain pending logs to database
- Database: Close connection after all operations complete
Context-based timeout: 10 seconds for complete shutdown
Location: cmd/server/main.go
Production-ready worker pool for background image processing:
- Worker Pool Pattern: Configurable goroutines with buffered queue
- Non-Blocking Submission: Returns error immediately if queue full
-
Atomic State Management: Race-free shutdown with
sync/atomic - Database Integration: Metadata persistence after successful processing
Location: internal/workers/image_worker.go
Features:
- Image validation (JPEG, PNG, GIF)
- Directory-based organization (post-images, user-images, channel-images)
- Graceful shutdown with context timeout
- Comprehensive test coverage (unit, integration, database tests)
Manual dependency injection via internal/http/routes/registry.go:
- Create flat handlers (Session, Reaction, Auth)
- Create handlers with single-level deps (Comment, Channel)
- Create complex handlers (User, Post, Home)
- Wire into RouteHandler struct
Current Implementation:
- Model-specific SQL implementations in
internal/sqlite/ - Each model has dedicated
*Modelstruct with database methods - Direct SQL queries with
dbtag mapping
Planned:
- Generic DAO layer with Go generics:
DAO[T models.DBModel] - Type-safe CRUD operations via reflection
- Location:
internal/dao/(not yet implemented)
Migration System:
- Sequential SQL migrations in
migrations/directory - Automatic tracking of applied migrations
- Run with:
bin/codex migrate
Recent Migrations:
-
005_add_image_path.sql- Adds Path column for image worker pool integration
All models implement the DBModel interface:
type DBModel interface {
TableName() string
}Struct fields use db tags for column mapping.
- Templates parsed once at startup
-
TempHelperprovides access to App instance - Custom template functions for common operations
- Composed from partials (
.tmplfiles) - Conditional rendering with nil checks for optional data
- Session tokens stored in cookies
-
authmiddleware extracts user - Context injection via
WithUsermiddleware - Handlers access user from
r.Context()
Applied in order (outermost to innermost):
- Tracing - Request ID generation and propagation
- LoggingEnhanced - Async request logging to database
- Timeout - Context-based request timeout (10s)
- WithUser - User authentication and context injection
Uses enhanced servemux with method-based routing:
POST /register
GET /post/{postId}
POST /cdx/post/{postId}/store-commentCore entities:
- Users - User accounts with UUID identification
- Posts - Forum posts (pointer-based for concurrency)
- Comments - Threaded discussions
- Reactions - Likes/dislikes
- Channels - Topic organization (pointer-based for concurrency)
- Memberships - User-channel relationships
- Flags - Content moderation (planned)
- Loyalty - User engagement tracking
- Saved - Bookmarked posts
- Mods - Channel moderators (planned)
- Rules - Channel guidelines
- Images - Media uploads with path tracking
- MutedChannels - Hidden channels
- RequestLogs - HTTP request metrics
Modular System:
-
main.cssimports 27+ specialized modules - Logical separation by concern (typography, layout, buttons, forms)
- OKLCH color space with Catppuccin Mocha palette
- CSS variables for centralized theming
Benefits:
- Easy navigation and maintenance
- Reduced merge conflicts
- Better browser caching
- Clear separation of concerns
- Backend: Go 1.22+
-
Database: SQLite3 (
github.com/mattn/go-sqlite3) - Routing: Standard library enhanced servemux
-
Templates: Go
html/template - Frontend: Vanilla JavaScript, CSS, HTML
-
UUID:
github.com/google/uuid - Build: Make with interactive menu
- Containerization: Docker
Environment variables loaded from .env:
DB_ENV=dev
DB_PATH=./identifier.sqlite- Worker pools for background processing
- Context-based cancellation
- Atomic state management
- Graceful shutdown with cleanup
- Circuit breaker for database protection
- Request timeout middleware
- Non-blocking async operations
- Error correlation with request IDs
- Database indexes for common queries
- Template caching
- Static file serving
- Connection pooling
- Concurrent search with fan-out/fan-in pattern
- Structured request logging
- Request ID correlation
- Colorized console output
- Slow request detection (>1s)
- pprof server on
localhost:6060
-
pprof Profiling:
localhost:6060for performance analysis - Colored Output: Catppuccin Mocha palette for logs and errors
-
Interactive Menu:
make menufor common tasks - Automatic Migrations: Run on dev startup
- Script Management: Checksum verification and backups
- Unit Tests: 9 tests covering pool lifecycle and concurrency
- Integration Tests: Real image file processing
- Database Tests: In-memory SQLite integration
- 6 tests covering all state transitions
- Concurrent access validation
- Timeout and recovery testing
make build && make runmake menu # Interactive Docker options
# Or:
make configure
make build-image
make run-containerServer runs on http://localhost:8888 by default.
For updating handlers to use the new logging system, see LOGGING_MIGRATION.md in the project root.