diff --git a/packages/core/src/domain/entities/BaseEntity.ts b/packages/core/src/domain/entities/BaseEntity.ts new file mode 100644 index 0000000..5d77ae2 --- /dev/null +++ b/packages/core/src/domain/entities/BaseEntity.ts @@ -0,0 +1,44 @@ +import { v4 as uuidv4 } from 'uuid'; + +/** + * Base entity class with ID and timestamps + */ +export abstract class BaseEntity { + protected readonly _id: string; + protected readonly _createdAt: Date; + protected _updatedAt: Date; + + constructor(id?: string) { + this._id = id ?? uuidv4(); + this._createdAt = new Date(); + this._updatedAt = new Date(); + } + + public get id(): string { + return this._id; + } + + public get createdAt(): Date { + return this._createdAt; + } + + public get updatedAt(): Date { + return this._updatedAt; + } + + protected touch(): void { + this._updatedAt = new Date(); + } + + public equals(entity: BaseEntity): boolean { + if (entity === null || entity === undefined) { + return false; + } + + if (this === entity) { + return true; + } + + return this._id === entity._id; + } +} \ No newline at end of file diff --git a/packages/core/src/domain/events/DomainEvent.ts b/packages/core/src/domain/events/DomainEvent.ts new file mode 100644 index 0000000..afdf9eb --- /dev/null +++ b/packages/core/src/domain/events/DomainEvent.ts @@ -0,0 +1,25 @@ +import { v4 as uuidv4 } from 'uuid'; + +/** + * Base interface for all domain events + */ +export interface IDomainEvent { + readonly eventId: string; + readonly occurredOn: Date; + readonly eventType: string; +} + +/** + * Base class for domain events + */ +export abstract class DomainEvent implements IDomainEvent { + public readonly eventId: string; + public readonly occurredOn: Date; + public readonly eventType: string; + + constructor(eventType: string) { + this.eventId = uuidv4(); + this.occurredOn = new Date(); + this.eventType = eventType; + } +} \ No newline at end of file diff --git a/packages/core/src/domain/index.ts b/packages/core/src/domain/index.ts new file mode 100644 index 0000000..a164700 --- /dev/null +++ b/packages/core/src/domain/index.ts @@ -0,0 +1,4 @@ +export * from './entities/BaseEntity'; +export * from './value-objects/ValueObject'; +export * from './repositories/IRepository'; +export * from './events/DomainEvent'; \ No newline at end of file diff --git a/packages/core/src/domain/repositories/IRepository.ts b/packages/core/src/domain/repositories/IRepository.ts new file mode 100644 index 0000000..56bb5d7 --- /dev/null +++ b/packages/core/src/domain/repositories/IRepository.ts @@ -0,0 +1,14 @@ +import { BaseEntity } from '../entities/BaseEntity'; + +/** + * Generic repository interface + * Defines standard CRUD operations for entities + */ +export interface IRepository { + findById(id: string): Promise; + findAll(): Promise; + save(entity: T): Promise; + update(entity: T): Promise; + delete(id: string): Promise; + exists(id: string): Promise; +} \ No newline at end of file diff --git a/packages/core/src/domain/value-objects/ValueObject.ts b/packages/core/src/domain/value-objects/ValueObject.ts new file mode 100644 index 0000000..503f7e2 --- /dev/null +++ b/packages/core/src/domain/value-objects/ValueObject.ts @@ -0,0 +1,23 @@ +/** + * Base class for Value Objects + * Value objects are immutable and compared by value, not identity + */ +export abstract class ValueObject { + protected readonly props: T; + + constructor(props: T) { + this.props = Object.freeze(props); + } + + public equals(vo?: ValueObject): boolean { + if (vo === null || vo === undefined) { + return false; + } + + if (vo.props === undefined) { + return false; + } + + return JSON.stringify(this.props) === JSON.stringify(vo.props); + } +} \ No newline at end of file