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:
IssuePublishedOrderCompletedUserSubscribed
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:
- Start with more isolated domains (AI, Analytics).
- Introduce gateways incrementally.
- Maintain backward compatibility during the transition.
- Migrate problematic domains last.
Expected outcomes:
- A more decoupled and maintainable architecture.
- Stricter compliance with DDD principles.
- Greater flexibility for future changes.