hands-clappingUsage example

Uuid Value Object

A strongly-typed, immutable UUID wrapper.

Prevents primitive obsession and ensures valid IDs.

import { Uuid } from '@nestjstools/domain-driven-starter';

const id = Uuid.generate();
const fromString = Uuid.fromString('f47ac10b-58cc-4372-a567-0e02b2c3d479');

console.log(id.toString());

Why use Uuid as a Value Object?

Instead of:

const id: string = '...';

You get:

  • Validation

  • Explicit domain meaning

  • Type safety

  • Immutable identity

Supports:

  • UUID v7 (recommended)

  • UUID v4 (compatible)


2️⃣ DomainEvent Interface

Minimal interface for domain events.

You define your own events:


Why Domain Events?

They allow:

  • Decoupled side effects

  • Clear domain traceability

  • Event-driven architecture

  • Integration with messaging systems

  • Auditability


3️⃣ AggregateRoot<T extends DomainEvent>

The central building block of your domain model.

Provides:

  • Identity handling

  • Event recording

  • Controlled creation

  • Event extraction


Constructor Pattern

The constructor is protected, meaning:

  • Only subclasses can instantiate it

  • Prevents uncontrolled aggregate creation

  • Encourages static factory methods

In your aggregate, you usually make the constructor private and expose a createNew() method.


Methods

recordEvent(event: T): void

Records a domain event internally.

Used inside aggregate methods when something meaningful changes.


popRecordedEvents(): T[]

Returns recorded events and clears the internal list.

Used after persisting the aggregate to publish events externally.


🧩 Example: Order Aggregate


πŸ” Typical Usage Flow

  1. Create aggregate via static factory.

  2. Aggregate records domain events.

  3. Repository saves aggregate.

  4. Application layer calls popRecordedEvents().

  5. Events are published to an event bus (e.g. messaging library).

This keeps:

  • Domain pure

  • Infrastructure separate

  • Side effects decoupled


πŸ— Where This Library Fits

Perfect for:

  • DDD projects

  • CQRS systems

  • Event-driven architecture

  • Clean architecture

  • Microservices

  • Monoliths with strong domain boundaries

Works with:

  • NestJS

  • Express

  • Fastify

  • Standalone Node.js

  • Any framework


πŸ§ͺ Testing

Because it is framework-agnostic:

  • No DI required

  • No mocking frameworks needed

  • Pure unit tests

  • Aggregates are deterministic

Example:

Last updated

Was this helpful?