Domain-Driven Design

MangroveAI organizes code by business domain rather than by technical layer. Each domain encapsulates its routes, services, data layer, and models in a self-contained directory.

Standard Domain Structure

Each domain follows this file layout:
src/MangroveAI/domains/{domain_name}/
    __init__.py
    routes.py         # Flask-RESTX namespace, endpoint definitions
    services.py       # Business logic, orchestration
    data_layer.py     # SQL queries, database access
    models.py         # Pydantic/dataclass models (optional)
    README.md         # Domain documentation

Layer Responsibilities

routes.py

  • Defines the Flask-RESTX namespace
  • Registers endpoint parsers and models
  • Delegates all logic to the service layer
  • Returns API responses with proper status codes

services.py

  • Contains all business logic
  • Calls data layers for persistence
  • Calls integrations for external APIs
  • Orchestrates multi-step operations
  • Owns business-level logging

data_layer.py

  • Executes SQL queries
  • Manages database connections
  • Returns plain dictionaries or domain objects
  • Contains no business logic

Domain Interactions

Domains communicate through their service layers. Direct data layer access across domains is prohibited.
ai_copilot/services.py
    -> signals/services.py       (signal matching)
    -> strategies/services.py    (strategy persistence)
    -> backtesting/services.py   (backtest execution)

Naming Conventions

  • Domain directories: lowercase, underscores (ai_copilot, crypto_assets)
  • Route files: always routes.py
  • Service files: always services.py
  • Data layer files: always data_layer.py
  • Namespace prefixes: match the URL path (/api/v1/signals, /api/v1/strategies)

Integration vs Domain

Integrations are external API clients, not business domains:
  • integrations/coinapi/ — Market data client
  • integrations/coingecko/ — Asset data client
  • integrations/nansen/ — On-chain analytics client
  • integrations/x/ — Social signals client
Integrations are consumed by domain services but never access domain data layers directly.