Architecture Overview

IOTA SDK follows a layered, modular architecture built on Domain-Driven Design (DDD) principles.

System Architecture

graph TB
    subgraph Client["Client Layer"]
        Browser["Browser<br/>HTMX + Alpine.js"]
        API["API Clients<br/>GraphQL / REST"]
    end
    
    subgraph Application["Application Layer"]
        Router["Router<br/>gorilla/mux"]
        Middleware["Middleware<br/>Auth, Logging, Tenant"]
        Controller["Controllers<br/>HTTP Handlers"]
    end
    
    subgraph Domain["Domain Layer"]
        Service["Services<br/>Business Logic"]
        Entity["Entities<br/>Business Rules"]
        Event["Domain Events"]
    end
    
    subgraph Infrastructure["Infrastructure Layer"]
        Repo["Repositories<br/>Data Access"]
        DB["PostgreSQL<br/>Multi-tenant"]
        EventBus["Event Bus<br/>pub/sub"]
    end
    
    Browser --> Router
    API --> Router
    Router --> Middleware
    Middleware --> Controller
    Controller --> Service
    Service --> Entity
    Service --> Repo
    Service --> Event
    Repo --> DB
    Event --> EventBus

Design Principles

1. Domain-Driven Design (DDD)

The codebase is organized around business domains rather than technical concerns. Each module represents a bounded context with its own:

  • Ubiquitous Language - Domain terms used consistently
  • Aggregates - Consistency boundaries
  • Entities - Objects with identity
  • Value Objects - Immutable concepts

2. Layered Architecture

Clear separation of concerns with four distinct layers:

LayerResponsibilityDependencies
PresentationHandle HTTP, render UIDepends on Services
ApplicationCoordinate use casesDepends on Domain
DomainBusiness logic & rulesNo external deps
InfrastructurePersistence, external APIsDepends on Domain

3. Multi-Tenancy

Single deployment serves multiple organizations (tenants) with complete data isolation:

graph LR
    subgraph "IOTA SDK Platform"
        subgraph "Tenant A"
            DB1["Database<br/>tenant_a schema"]
            Cache1["Cache<br/>tenant_a prefix"]
        end
        
        subgraph "Tenant B"
            DB2["Database<br/>tenant_b schema"]
            Cache2["Cache<br/>tenant_b prefix"]
        end
        
        subgraph "Tenant C"
            DB3["Database<br/>tenant_c schema"]
            Cache3["Cache<br/>tenant_c prefix"]
        end
    end
    
    User1["User A"] --> DB1
    User2["User B"] --> DB2
    User3["User C"] --> DB3

Module System

Module Lifecycle

sequenceDiagram
    participant Engine as Composition Engine
    participant Comp as Component
    participant Container as Container
    participant App as Application
    participant Web as Web Server

    Engine->>Comp: Build(builder)
    Comp->>Container: Provide / Contribute
    Engine->>Container: Compile(capabilities)
    Engine->>App: AttachRuntimeSource(container)
    Engine->>Container: Start hooks
    App->>Web: Start Server

Module Communication

Modules communicate through:

  1. Event Bus - Loose coupling via domain events
  2. Composition Container - Typed service access via composition.ProvideFunc (constructors with typed parameters) and composition.Resolve[T](container) from inside Contribute* closures
  3. Shared Entities - Core entities used across modules
graph LR
    A[Core Module] -->|Events| EventBus[(Event Bus)]
    B[Finance Module] -->|Events| EventBus
    C[Warehouse Module] -->|Events| EventBus
    
    EventBus -->|Subscribe| A
    EventBus -->|Subscribe| B
    EventBus -->|Subscribe| C
    
    B -->|Service Call| A
    C -->|Service Call| A

Technology Stack

Backend

ComponentTechnologyPurpose
LanguageGo 1.24+Type-safe, performant
Routergorilla/muxHTTP routing
DatabasePostgreSQL 13+ACID, JSON support
Data accesssqlx + pgxQueries and driver
GraphQLgqlgenAPI schema
Validationgo-playground/validatorInput validation
i18ngo-i18nLocalization

Frontend

ComponentTechnologyPurpose
TemplatingTemplType-safe HTML
InteractivityHTMXAJAX via HTML
ReactivityAlpine.jsLightweight JS
StylingTailwind CSSUtility classes
IconsLucideSVG icons

Infrastructure

ComponentTechnologyPurpose
SessionsCookies + RedisStateful sessions
FilesHashFSFingerprinted assets
WebSocketCustom HubReal-time updates
EventsIn-memory BusPub/sub messaging

Request Flow

HTTP Request Processing

sequenceDiagram
    participant Client
    participant Router
    participant Middleware
    participant Controller
    participant Service
    participant Domain
    participant Repo
    participant DB
    
    Client->>Router: HTTP Request
    Router->>Middleware: Apply middleware
    Middleware->>Middleware: Auth check
    Middleware->>Middleware: Tenant detection
    Middleware->>Middleware: Logging
    Middleware->>Controller: Route to handler
    Controller->>Controller: Parse & validate DTO
    Controller->>Service: Call service method
    Service->>Domain: Create/modify entity
    Domain->>Domain: Validate business rules
    Service->>Repo: Save entity
    Repo->>DB: Execute SQL
    DB-->>Repo: Return data
    Repo-->>Service: Return entity
    Service-->>Controller: Return result
    Service->>Service: Publish domain event
    Controller-->>Client: HTTP Response

HTMX Request

For HTMX requests (AJAX), the flow is similar but:

  • Response is partial HTML (not full page)
  • Triggers client-side updates via HTMX attributes
  • Supports out-of-band swaps for multiple elements

Data Flow

Write Operation

graph TD
    A[User Action] --> B[Controller receives DTO]
    B --> C[Service validates business rules]
    C --> D[Domain Entity enforces invariants]
    D --> E[Repository persists to DB]
    E --> F[Domain Event published]
    F --> G[Event Handlers react]

Read Operation

graph TD
    A[User Request] --> B[Controller receives params]
    B --> C[Service fetches via Repository]
    C --> D[Repository queries DB]
    D --> E[Data mapped to ViewModel]
    E --> F[Template renders HTML]

Next Steps

Learn more about specific architectural patterns:

Last updated on