Skip to main content

Domain-Driven Design (DDD) & Feature-Sliced Design (FSD)

The frontend architecture blends Domain-Driven Design (DDD) bounded contexts with Feature-Sliced Design (FSD) modularity to achieve scalable, robust, and decoupled applications.


1. Architectural Concept & Overview

Domain-Driven Design (DDD)

Domain-Driven Design (DDD) organizes complex business logic into isolated, domain-centric modules called Bounded Contexts, where each domain owns its model integrity and vocabulary. This avoids tight coupling between different areas of the application and keeps models focused.

Feature-Sliced Design (FSD)

Feature-Sliced Design (FSD) is a modern architectural methodology designed specifically for frontend applications. It segregates code into a standardized hierarchy of layers, slices, and segments, establishing strict unidirectional dependency flows, preventing circular imports, and ensuring high modularity.

By combining DDD context segregation with FSD layer separation, our applications remain maintainable even as team sizes and feature sets grow.


2. Project-Specific Utilization

In tupynambalucas.dev, the combination of DDD and FSD governs both the folder structure and the import rules:

A. Bounded Context Segregation

The monorepo is split into distinct contexts (instance/ and portal/) at the root level. These boundaries ensure that community operations (Instance) and global SaaS onboarding workflows (Portal) remain structurally and logically independent. Shared design tokens or brand assets are imported exclusively from the @tupynambalucas-studio/design workspace.

B. Frontend Layer Hierarchy (FSD)

Inside each frontend React application, the codebase is structured into strict architectural layers:

src/
├── domains/ <-- Global Domains layer (e.g., auth, product, cycle)
│ └── auth/
│ ├── hooks/
│ └── auth.store.ts
├── features/ <-- User workflows and interactive modules (e.g., shop, admin)
│ ├── shop/
│ │ ├── domains/ <-- Feature-specific private domains (e.g., cart)
│ │ └── components/
│ └── admin/
└── shared/ <-- Reusable agnostic utilities and common components
└── ui/ <-- Buttons, Modals, Loaders, Input components
  • Global Domains (src/domains): Represent core business concepts (e.g., auth, product, cycle). This layer houses domain-specific Zustand state stores, Axios API clients, and domain orchestration hooks.
  • Features (src/features): House user workflows and interactive app modules (e.g., admin, shop). Features orchestrate multiple underlying domains to deliver high-level application flows, but remain strictly isolated from other features.
  • Feature-Specific Private Domains (src/features/*/domains): Dedicated sub-domains enclosed inside a specific feature (such as a private cart domain inside the shop feature). This keeps the global namespace clean and prevents global domain pollution.
  • Shared UI Layer (src/shared/ui): Features reusable, domain-agnostic UI building blocks (such as loaders, buttons, inputs, and modals) which contain zero business logic.

3. Strict Import Boundaries

To maintain long-term scalability, we enforce strict unidirectional import boundaries:

  1. Unidirectional Flow: Code can only import from layers located below it in the hierarchy: Features -> Domains -> Shared
  2. No Upward Imports: Global domains or shared components are strictly forbidden from importing from features.
  3. No Feature Cross-Imports: Feature modules cannot import from other feature modules directly; they can only collaborate through high-level page orchestration or by subscribing to shared global domains.