Skip to main content

Domain Driven Design in Farfalla

Introduction

Farfalla uses Domain Driven Design (DDD) as its main architectural pattern to organize its codebase. The implementation keeps a clear separation between business areas, which helps maintainability, scalability, and the team's shared understanding of the system.

This document describes the current domain layout, known challenges, and the planned direction toward a more decoupled architecture.

Domain Structure

Domains live under the App\Domains\ namespace. Each represents a specific business area of the digital publishing platform.

farfalla/app/Domains/
├── AI/ # Artificial Intelligence
├── Analytics/ # Analytics and metrics
├── BulkOperations/ # Bulk operations
├── Commerce/ # Commerce and payments
├── Content/ # Content management
├── Dashboard/ # Admin panel
├── Exports/ # Data exports
├── Identity/ # Authentication and identity
├── Metadata/ # Metadata and taxonomies
├── Reader/ # Reading experience
├── SaaS/ # SaaS-specific features
├── Shared/ # Cross-cutting components
├── Storefront/ # Storefront and catalog
└── User/ # User management

Main Domains

Domain descriptions are intentionally high-level. They declare responsibility, not implementation. Class and service names are kept in code, not in this document.

Commerce

Transactions, payments, plans, and marketplace operations.

Content

Digital content management (books, audiobooks, PDFs) including availability, encryption, and pricing rules.

Identity

Authentication, authorization, and platform access management.

Open question: the scope of Identity — platform access vs. content access — needs to be clarified. Current convention leans toward platform access, with content-level access gated through Content itself. To be confirmed.

Metadata

Taxonomies, categories, and content classification (terms, BISAC, accessibility).

Open question: whether Metadata should be a top-level domain or sit inside Content. Raised during review; pending architectural decision.

Storefront

Shopping and catalog navigation experience (libraries, lists, menus).

The Shared Domain

Shared contains cross-cutting components used by multiple domains.

Multi-Tenancy Components

  • Tenant traits — provide automatic multi-tenant behavior on models.
  • Global scopes — filter data by tenant context.
  • Global helpers — ease access to the current tenant context.

Current Architectural Patterns

1. Separation of Responsibilities

Each domain owns specific business responsibilities. Logic is not duplicated across functional areas.

2. Communication Between Domains

Domains today communicate through direct dependencies. This is a known weak point and is targeted for refactoring (see Improvement Plan).

3. Domain Models

Models encapsulate both data and domain-specific behavior, following DDD principles.

Domain Dependencies

The current dependency graph between domains is entangled. The diagram below is a simplified view of the main coupling points discussed during review; a full dependency diagram derived from the codebase is pending.

Much of this direct coupling should move to domain gateways (for synchronous access through an abstraction) or to domain events (for asynchronous reactions). See the Improvement Plan.

Architectural Challenges

Complex Interdependencies

The current architecture has a high level of interdependency between domains. This affects:

  • Code maintainability.
  • Team scalability.
  • Flexibility for future changes.

Problematic Domains

  • Dashboard — behaves more like a presentation layer than a business domain.
  • User — needs to be consolidated with Identity to clarify responsibilities.
  • Exports — would fit better in the infrastructure layer.

Multi-Tenancy and DDD

Multi-tenancy is implemented at the domain level through:

  • Shared traits for automatic multi-tenant behavior.
  • Global scopes for data filtering by tenant.
  • Global context for access to the current tenant.

Improvement Plan

1. Gateway Services to Decouple Domains

Goal: reduce direct dependencies between domains.

Each major domain exposes a gateway that other domains consume instead of reaching into the domain directly:

  • ContentGateway — how other domains access Content.
  • CommerceGateway — abstraction for commerce operations.
  • MetadataGateway — access to classifications and taxonomies.

2. Event-Driven Architecture

Goal: asynchronous communication between domains.

Introduce Domain Events for asynchronous communication. Initial candidates:

  • IssuePublished
  • OrderCompleted
  • UserSubscribed

Primary target: reduce direct coupling between Commerce and Content.

3. Refactor Problematic Domains

  • Dashboard — move to application/presentation layer.
  • User — consolidate into Identity as a full Identity / Access Management domain.
  • Exports — move to infrastructure / reporting layer.

4. Anti-Corruption Layers

Between Commerce and Content:

  • Prevent contamination of business models.
  • Keep domain integrity.

Between Reader and Storefront:

  • Clarify user experience responsibilities.
  • Avoid duplicating presentation logic.

5. CQRS Where It Pays Off

Apply CQRS selectively in complex domains:

  • Separate commands (write) from queries (read).
  • Primary candidates: Commerce and Content.
  • Expected gains: performance and scalability.

6. Bounded Contexts and Context Maps

Documentation required:

  • Explicit Context Maps between domains.
  • Ubiquitous Language per domain.
  • Clear integration contracts.

7. Migration Strategy

Gradual approach:

  1. Start with more isolated domains (AI, Analytics).
  2. Introduce gateways incrementally.
  3. Maintain backward compatibility during the transition.
  4. Migrate problematic domains last.

Expected outcomes:

  • A more decoupled and maintainable architecture.
  • Stricter compliance with DDD principles.
  • Greater flexibility for future changes.

X

Graph View