Table of Contents

Domain modeling

The SaaS template and CodeBlock DevKit are organized around Domain-Driven Design (DDD): the domain model is where business concepts and rules live, separate from UI, HTTP, databases, and third-party integrations. The goal is a model you can reason about, test, and evolve without scattering business logic across every layer.

This page explains the ideas DevKit assumes. When you want the exact types and embedded source (Entity, AggregateRoot, IDomainEvent, ISpecification, repository bases, and so on), open Domain model under Modules → Supporting modules → Building blocks.

Aggregates and aggregate roots

An aggregate is a cluster of objects that must stay consistent together. One object, the aggregate root, is the only entry point the rest of the application uses to change that cluster. External code loads the root, calls methods on it, and saves it; it does not reach past the root to tweak internal pieces in isolation.

That boundary keeps invariants (business rules that must always hold) enforceable in one place. DevKit’s AggregateRoot base type reflects that pattern in code.

Entities and value objects

An entity is something with identity and a lifecycle: two “things” are different entities if their identities differ, even when other fields look the same. Identity and lifecycle are modeled explicitly so persistence and APIs can refer to the same business object over time.

A value object has no identity of its own; it is defined entirely by its attributes (money, date range, address parts). Value objects are compared by value, are typically immutable, and are a good place to hide small rules (“a price cannot be negative”) without growing entity methods forever. DevKit provides BaseValueObject and related helpers for that style.

Domain events

Domain events record something meaningful that already happened in the domain (“order placed”, “subscription renewed”). They let the model stay focused on state and rules while other parts of the system react (projections, notifications, integration) without the aggregate knowing every consumer.

DevKit distinguishes domain events (inside the bounded context) from integration events that may cross service boundaries; both concepts show up in the Domain model reference.

Specifications

A specification encapsulates a reusable rule or query predicate (“is this customer eligible?”, “active subscriptions only”). Instead of duplicating LINQ or business checks, you compose specifications so the same rule backs validation, authorization hints, and repository queries. DevKit exposes ISpecification as the shared abstraction.

Domain validation

Domain validation means rules that belong to the model itself: an entity or aggregate refuses invalid transitions, often by throwing a DomainException with a clear, domain-specific message. That is different from input validation on DTOs and commands (required fields, formats), which runs earlier and is documented with Exception handling.

Keeping hard rules in the domain ensures invalid states cannot appear “only when called from the API” or “only from the admin UI”—the model is the single authority.

Repositories

In DDD, a repository is a domain-facing contract for loading and persisting aggregates. The interface expresses what the domain needs (“get by id”, “add”, “update with concurrency”); infrastructure supplies the implementation (for example MongoDB). DevKit’s IBaseAggregateRepository<T> and related bases give you a consistent shape for that split.

See also