Skip to content

Architecture Overview

Gary Norman edited this page Dec 14, 2025 · 2 revisions

Architecture Overview

Codex follows a clean architecture pattern with clear separation of concerns, emphasizing production-ready concurrency patterns and fault tolerance.

Project Structure

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

Core Architecture Patterns

UUID System

Codex uses a custom UUIDField type for user identification:

  • Type Safety: UUIDField wraps github.com/google/uuid
  • Database Integration: Implements driver.Valuer and sql.Scanner
  • BLOB Storage: 16-byte BLOBs in SQLite (not strings)
  • JSON Support: Automatic string conversion for API responses

Location: internal/models/uuidfield-models.go

Concurrency & Fault Tolerance

Request Tracing

UUID-based request correlation for distributed tracing:

  • Request ID generated in WithTracing middleware
  • Propagated via context.Context through all layers
  • X-Request-ID response header for client debugging
  • Automatic log correlation across concurrent operations

Location: internal/http/middleware/tracing.go

Circuit Breaker Pattern

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.RWMutex for 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
})

Async Logging System

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

Colorized Logging

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)

Graceful Shutdown

Ordered cleanup sequence prevents data corruption:

  1. HTTP Server: Stop accepting requests, wait for handlers
  2. Logger Pool: Drain pending logs to database
  3. Database: Close connection after all operations complete

Context-based timeout: 10 seconds for complete shutdown

Location: cmd/server/main.go

Concurrent Image Processing

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)

Dependency Injection

Manual dependency injection via internal/http/routes/registry.go:

  1. Create flat handlers (Session, Reaction, Auth)
  2. Create handlers with single-level deps (Comment, Channel)
  3. Create complex handlers (User, Post, Home)
  4. Wire into RouteHandler struct

Database Patterns

Current Implementation:

  • Model-specific SQL implementations in internal/sqlite/
  • Each model has dedicated *Model struct with database methods
  • Direct SQL queries with db tag 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

Database Models

All models implement the DBModel interface:

type DBModel interface {
    TableName() string
}

Struct fields use db tags for column mapping.

Template Rendering

  • Templates parsed once at startup
  • TempHelper provides access to App instance
  • Custom template functions for common operations
  • Composed from partials (.tmpl files)
  • Conditional rendering with nil checks for optional data

Authentication Flow

  1. Session tokens stored in cookies
  2. auth middleware extracts user
  3. Context injection via WithUser middleware
  4. Handlers access user from r.Context()

Middleware Stack

Applied in order (outermost to innermost):

  1. Tracing - Request ID generation and propagation
  2. LoggingEnhanced - Async request logging to database
  3. Timeout - Context-based request timeout (10s)
  4. WithUser - User authentication and context injection

Routing (Go 1.22+)

Uses enhanced servemux with method-based routing:

POST /register
GET /post/{postId}
POST /cdx/post/{postId}/store-comment

Data Models

Core 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

CSS Architecture

Modular System:

  • main.css imports 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

Technology Stack

  • 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

Configuration

Environment variables loaded from .env:

DB_ENV=dev
DB_PATH=./identifier.sqlite

Performance & Reliability Features

Concurrency

  • Worker pools for background processing
  • Context-based cancellation
  • Atomic state management
  • Graceful shutdown with cleanup

Fault Tolerance

  • Circuit breaker for database protection
  • Request timeout middleware
  • Non-blocking async operations
  • Error correlation with request IDs

Performance

  • Database indexes for common queries
  • Template caching
  • Static file serving
  • Connection pooling
  • Concurrent search with fan-out/fan-in pattern

Observability

  • Structured request logging
  • Request ID correlation
  • Colorized console output
  • Slow request detection (>1s)
  • pprof server on localhost:6060

Development Tools

  • pprof Profiling: localhost:6060 for performance analysis
  • Colored Output: Catppuccin Mocha palette for logs and errors
  • Interactive Menu: make menu for common tasks
  • Automatic Migrations: Run on dev startup
  • Script Management: Checksum verification and backups

Testing

Image Worker Tests

  • Unit Tests: 9 tests covering pool lifecycle and concurrency
  • Integration Tests: Real image file processing
  • Database Tests: In-memory SQLite integration

Circuit Breaker Tests

  • 6 tests covering all state transitions
  • Concurrent access validation
  • Timeout and recovery testing

Deployment

Local Development

make build && make run

Docker

make menu  # Interactive Docker options
# Or:
make configure
make build-image
make run-container

Server runs on http://localhost:8888 by default.

Migration Guide

For updating handlers to use the new logging system, see LOGGING_MIGRATION.md in the project root.

Clone this wiki locally