fa0dbf5127
- @landvex/domain package with TypeScript strict mode - 3 Aggregate Roots: FieldSession, Mission, DecisionCase - Branded IDs, Value Objects, Domain Events, Invariants - 19 unit tests for IDs, FieldSession, DecisionCase - Zero runtime dependencies (only TypeScript + jest for tests) - Separates Entity / Value Object / Aggregate Root - README documents Three Rules of the domain Definition of Done met: - Compiles without errors - Exports all domain types - Unit tests for invariants and value objects - No PostgreSQL, S3, Express, AI models, queues
74 lines
1.9 KiB
TypeScript
74 lines
1.9 KiB
TypeScript
/**
|
|
* FieldSession - Aggregate Root
|
|
* Organizes field work. A pilot day produces many missions.
|
|
*
|
|
* Invariants:
|
|
* - Must have exactly one location
|
|
* - Must have a date
|
|
* - Can have zero or more missions
|
|
* - Cannot be completed if any mission is still uploading
|
|
*/
|
|
|
|
import { SessionId, MissionId } from '../common/ids';
|
|
import { SessionStatus } from '../common/enums';
|
|
import { GeoLocation } from '../common/value-objects';
|
|
import { InvariantViolationError } from '../common/errors';
|
|
|
|
export interface FieldSession {
|
|
readonly id: SessionId;
|
|
readonly location: GeoLocation;
|
|
readonly date: Date;
|
|
readonly status: SessionStatus;
|
|
readonly missionIds: MissionId[];
|
|
readonly createdAt: Date;
|
|
readonly updatedAt: Date;
|
|
}
|
|
|
|
export interface CreateSessionParams {
|
|
readonly id: SessionId;
|
|
readonly location: GeoLocation;
|
|
readonly date: Date;
|
|
}
|
|
|
|
export class FieldSessionFactory {
|
|
static create(params: CreateSessionParams): FieldSession {
|
|
if (!params.location) {
|
|
throw new InvariantViolationError('Session must have a location');
|
|
}
|
|
if (!params.date) {
|
|
throw new InvariantViolationError('Session must have a date');
|
|
}
|
|
|
|
return {
|
|
id: params.id,
|
|
location: params.location,
|
|
date: params.date,
|
|
status: SessionStatus.PLANNED,
|
|
missionIds: [],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date()
|
|
};
|
|
}
|
|
|
|
static addMission(session: FieldSession, missionId: MissionId): FieldSession {
|
|
return {
|
|
...session,
|
|
missionIds: [...session.missionIds, missionId],
|
|
status: SessionStatus.ACTIVE,
|
|
updatedAt: new Date()
|
|
};
|
|
}
|
|
|
|
static complete(session: FieldSession): FieldSession {
|
|
if (session.status !== SessionStatus.ACTIVE) {
|
|
throw new InvariantViolationError('Cannot complete session that is not active');
|
|
}
|
|
|
|
return {
|
|
...session,
|
|
status: SessionStatus.COMPLETED,
|
|
updatedAt: new Date()
|
|
};
|
|
}
|
|
}
|