# Phase 1: Shared Domain — Building Blocks ## Objetivo Crear las clases base que TODOS los módulos usarán. Esto es el cimiento. ## Result.ts ```typescript // Discriminated union, no classes type ResultOk = { readonly ok: true; readonly value: T }; type ResultErr = { readonly ok: false; readonly error: E }; export type Result = ResultOk | ResultErr; export const Ok = (value: T): Result => ({ ok: true, value }); export const Err = (error: E): Result => ({ ok: false, error }); export function isOk(r: Result): r is ResultOk { return r.ok; } export function isErr(r: Result): r is ResultErr { return !r.ok; } ``` ## UniqueId.ts ```typescript import { v4 as uuidv4 } from 'uuid'; export class UniqueId { private constructor(private readonly value: string) {} static create(): UniqueId { return new UniqueId(uuidv4()); } static from(value: string): UniqueId { return new UniqueId(value); } toString(): string { return this.value; } equals(other?: UniqueId): boolean { if (!other) return false; return this.value === other.value; } } ``` ## Entity.ts ```typescript export abstract class Entity { protected readonly _id: UniqueId; protected props: T; constructor(props: T, id?: UniqueId) { this._id = id ?? UniqueId.create(); this.props = props; } get id(): UniqueId { return this._id; } equals(other?: Entity): boolean { if (!other) return false; return this._id.equals(other._id); } } ``` ## AggregateRoot.ts ```typescript export abstract class AggregateRoot extends Entity { private _domainEvents: DomainEvent[] = []; get domainEvents(): ReadonlyArray { return this._domainEvents; } protected addDomainEvent(event: DomainEvent): void { this._domainEvents.push(event); } clearEvents(): DomainEvent[] { const events = [...this._domainEvents]; this._domainEvents = []; return events; } } ``` ## ValueObject.ts ```typescript export abstract class ValueObject { protected readonly props: T; constructor(props: T) { this.props = Object.freeze(props); } equals(other?: ValueObject): boolean { if (!other) return false; return JSON.stringify(this.props) === JSON.stringify(other.props); } } ``` ## DomainEvent.ts ```typescript export interface DomainEvent { readonly eventId: string; readonly eventName: string; readonly aggregateId: string; readonly occurredOn: Date; readonly payload: Record; } ``` ## UseCase.ts ```typescript export interface UseCase { execute(request: TRequest): Promise>; } ``` ## EventBus.ts + EventHandler.ts ```typescript // EventBus.ts export interface EventBus { publish(event: DomainEvent): Promise; subscribe(eventName: string, handler: EventHandler): void; } // EventHandler.ts export interface EventHandler { handle(event: DomainEvent): Promise; } ``` ## Tests requeridos (mínimo) 1. Result: Ok crea value accesible, Err crea error accesible, isOk/isErr discriminan 2. UniqueId: create genera string válido, equals funciona, from preserva valor 3. Entity: equals compara por id (no por props) 4. ValueObject: equals compara por props, props son inmutables ## IMPORTANTE - Estos archivos NO importan NADA externo excepto 'uuid' - NO usar decorators - NO usar classes abstractas complicadas — mantener simple - Cada archivo exporta UNA cosa principal