diff --git a/src/db/repositories/index.ts b/src/db/repositories/index.ts new file mode 100644 index 0000000..5c9166b --- /dev/null +++ b/src/db/repositories/index.ts @@ -0,0 +1,31 @@ +/** + * Repository Port Interfaces + * + * Re-exports all repository port interfaces. + * These are the PORTS in hexagonal architecture. + * Implementations in ./drizzle/ are ADAPTERS. + */ + +export type { + InitiativeRepository, + CreateInitiativeData, + UpdateInitiativeData, +} from './initiative-repository.js'; + +export type { + PhaseRepository, + CreatePhaseData, + UpdatePhaseData, +} from './phase-repository.js'; + +export type { + PlanRepository, + CreatePlanData, + UpdatePlanData, +} from './plan-repository.js'; + +export type { + TaskRepository, + CreateTaskData, + UpdateTaskData, +} from './task-repository.js'; diff --git a/src/db/repositories/initiative-repository.ts b/src/db/repositories/initiative-repository.ts new file mode 100644 index 0000000..f4e4417 --- /dev/null +++ b/src/db/repositories/initiative-repository.ts @@ -0,0 +1,60 @@ +/** + * Initiative Repository Port Interface + * + * Port for Initiative aggregate operations. + * Implementations (Drizzle, etc.) are adapters. + */ + +import type { Initiative, NewInitiative } from '../schema.js'; + +/** + * Data for creating a new initiative. + * Omits system-managed fields (id, createdAt, updatedAt). + */ +export type CreateInitiativeData = Omit; + +/** + * Data for updating an initiative. + * Partial of creation data - all fields optional. + */ +export type UpdateInitiativeData = Partial; + +/** + * Initiative Repository Port + * + * Defines operations for the Initiative aggregate. + * Only knows about initiatives - no knowledge of child entities. + */ +export interface InitiativeRepository { + /** + * Create a new initiative. + * Generates id and sets timestamps automatically. + */ + create(data: CreateInitiativeData): Promise; + + /** + * Find an initiative by its ID. + * Returns null if not found. + */ + findById(id: string): Promise; + + /** + * Find all initiatives. + * Returns empty array if none exist. + */ + findAll(): Promise; + + /** + * Update an initiative. + * Throws if initiative not found. + * Updates updatedAt timestamp automatically. + */ + update(id: string, data: UpdateInitiativeData): Promise; + + /** + * Delete an initiative. + * Throws if initiative not found. + * Cascades to child phases, plans, tasks via FK constraints. + */ + delete(id: string): Promise; +} diff --git a/src/db/repositories/phase-repository.ts b/src/db/repositories/phase-repository.ts new file mode 100644 index 0000000..ff787cf --- /dev/null +++ b/src/db/repositories/phase-repository.ts @@ -0,0 +1,62 @@ +/** + * Phase Repository Port Interface + * + * Port for Phase aggregate operations. + * Implementations (Drizzle, etc.) are adapters. + */ + +import type { Phase, NewPhase } from '../schema.js'; + +/** + * Data for creating a new phase. + * Omits system-managed fields (id, createdAt, updatedAt). + */ +export type CreatePhaseData = Omit; + +/** + * Data for updating a phase. + * Partial of creation data - all fields optional. + */ +export type UpdatePhaseData = Partial; + +/** + * Phase Repository Port + * + * Defines operations for the Phase aggregate. + * Only knows about phases - no knowledge of parent or child entities. + */ +export interface PhaseRepository { + /** + * Create a new phase. + * Generates id and sets timestamps automatically. + * Foreign key to initiative enforced by database. + */ + create(data: CreatePhaseData): Promise; + + /** + * Find a phase by its ID. + * Returns null if not found. + */ + findById(id: string): Promise; + + /** + * Find all phases for an initiative. + * Returns phases ordered by number. + * Returns empty array if none exist. + */ + findByInitiativeId(initiativeId: string): Promise; + + /** + * Update a phase. + * Throws if phase not found. + * Updates updatedAt timestamp automatically. + */ + update(id: string, data: UpdatePhaseData): Promise; + + /** + * Delete a phase. + * Throws if phase not found. + * Cascades to child plans and tasks via FK constraints. + */ + delete(id: string): Promise; +} diff --git a/src/db/repositories/plan-repository.ts b/src/db/repositories/plan-repository.ts new file mode 100644 index 0000000..1cb3f2a --- /dev/null +++ b/src/db/repositories/plan-repository.ts @@ -0,0 +1,62 @@ +/** + * Plan Repository Port Interface + * + * Port for Plan aggregate operations. + * Implementations (Drizzle, etc.) are adapters. + */ + +import type { Plan, NewPlan } from '../schema.js'; + +/** + * Data for creating a new plan. + * Omits system-managed fields (id, createdAt, updatedAt). + */ +export type CreatePlanData = Omit; + +/** + * Data for updating a plan. + * Partial of creation data - all fields optional. + */ +export type UpdatePlanData = Partial; + +/** + * Plan Repository Port + * + * Defines operations for the Plan aggregate. + * Only knows about plans - no knowledge of parent or child entities. + */ +export interface PlanRepository { + /** + * Create a new plan. + * Generates id and sets timestamps automatically. + * Foreign key to phase enforced by database. + */ + create(data: CreatePlanData): Promise; + + /** + * Find a plan by its ID. + * Returns null if not found. + */ + findById(id: string): Promise; + + /** + * Find all plans for a phase. + * Returns plans ordered by number. + * Returns empty array if none exist. + */ + findByPhaseId(phaseId: string): Promise; + + /** + * Update a plan. + * Throws if plan not found. + * Updates updatedAt timestamp automatically. + */ + update(id: string, data: UpdatePlanData): Promise; + + /** + * Delete a plan. + * Throws if plan not found. + * Cascades to child tasks via FK constraints. + */ + delete(id: string): Promise; +} diff --git a/src/db/repositories/task-repository.ts b/src/db/repositories/task-repository.ts new file mode 100644 index 0000000..1ae8e72 --- /dev/null +++ b/src/db/repositories/task-repository.ts @@ -0,0 +1,61 @@ +/** + * Task Repository Port Interface + * + * Port for Task aggregate operations. + * Implementations (Drizzle, etc.) are adapters. + */ + +import type { Task, NewTask } from '../schema.js'; + +/** + * Data for creating a new task. + * Omits system-managed fields (id, createdAt, updatedAt). + */ +export type CreateTaskData = Omit; + +/** + * Data for updating a task. + * Partial of creation data - all fields optional. + */ +export type UpdateTaskData = Partial; + +/** + * Task Repository Port + * + * Defines operations for the Task aggregate. + * Only knows about tasks - no knowledge of parent entities. + */ +export interface TaskRepository { + /** + * Create a new task. + * Generates id and sets timestamps automatically. + * Foreign key to plan enforced by database. + */ + create(data: CreateTaskData): Promise; + + /** + * Find a task by its ID. + * Returns null if not found. + */ + findById(id: string): Promise; + + /** + * Find all tasks for a plan. + * Returns tasks ordered by order field. + * Returns empty array if none exist. + */ + findByPlanId(planId: string): Promise; + + /** + * Update a task. + * Throws if task not found. + * Updates updatedAt timestamp automatically. + */ + update(id: string, data: UpdateTaskData): Promise; + + /** + * Delete a task. + * Throws if task not found. + */ + delete(id: string): Promise; +}