11 KiB
11 KiB
DOMAIN MODEL: Project Management Context
Version: 1.0.0 Fecha: 2025-12-05 Modulos: MAI-002, MAI-003, MAI-005
Descripcion
El contexto de Project Management es el nucleo del ERP de Construccion. Gestiona todo el ciclo de vida de proyectos de obra, desde la planeacion hasta la entrega, incluyendo presupuestos, control de avances y estimaciones.
Agregados
1. Project Aggregate
Project (Aggregate Root)
|
+-- Development (Entity)
| +-- Section (Entity)
| +-- HousingUnit (Entity)
|
+-- ProjectManager (Value Object)
+-- Location (Value Object)
+-- ProjectStatus (Value Object)
Project (Root)
interface Project {
id: UUID;
tenantId: UUID;
code: string;
name: string;
description?: string;
// Location
address?: string;
city?: string;
state?: string;
postalCode?: string;
location?: Location;
// Timeline
startDate?: Date;
endDate?: Date;
actualStartDate?: Date;
actualEndDate?: Date;
// Status
status: ProjectStatus;
progressPercentage: Percentage;
// Financial
totalBudget?: Money;
totalSpent: Money;
// Relationships
projectManager?: User;
developments: Development[];
budgets: Budget[];
schedules: Schedule[];
// Audit
createdAt: Timestamp;
createdBy: UUID;
updatedAt?: Timestamp;
updatedBy?: UUID;
}
enum ProjectStatus {
PLANNING = 'planning',
IN_PROGRESS = 'in_progress',
PAUSED = 'paused',
COMPLETED = 'completed',
CANCELLED = 'cancelled'
}
Development (Entity)
interface Development {
id: UUID;
projectId: UUID;
code: string;
name: string;
description?: string;
address?: string;
location?: Location;
areaM2?: number;
totalSections: number;
totalUnits: number;
completedUnits: number;
status: ProjectStatus;
sections: Section[];
}
Section (Entity)
interface Section {
id: UUID;
developmentId: UUID;
code: string;
name: string;
boundary?: Polygon;
areaM2?: number;
totalUnits: number;
completedUnits: number;
housingUnits: HousingUnit[];
}
HousingUnit (Entity)
interface HousingUnit {
id: UUID;
sectionId: UUID;
prototypeId?: UUID;
unitNumber: string;
lotNumber?: string;
block?: string;
location?: Location;
address?: string;
// Construction Status
status: HousingUnitStatus;
progressPercentage: Percentage;
// Timeline
constructionStartDate?: Date;
constructionEndDate?: Date;
deliveryDate?: Date;
// Sales (if sold)
buyerName?: string;
buyerContact?: string;
salePrice?: Money;
saleDate?: Date;
}
enum HousingUnitStatus {
LAND = 'land',
FOUNDATION = 'foundation',
STRUCTURE = 'structure',
FINISHING = 'finishing',
COMPLETED = 'completed',
DELIVERED = 'delivered'
}
2. Budget Aggregate
Budget (Aggregate Root)
|
+-- BudgetPartida (Entity)
| +-- BudgetConcept (Entity)
| +-- APUItem (Entity)
|
+-- MaterialsExplosion (Entity)
+-- BudgetVersion (Value Object)
Budget (Root)
interface Budget {
id: UUID;
tenantId: UUID;
projectId?: UUID;
prototypeId?: UUID;
code: string;
name: string;
description?: string;
version: number;
// Type
isBase: boolean; // Base budget (prototype) vs Executive (project)
// Totals (calculated)
totalDirectCost: Money;
totalIndirectCost: Money;
totalCost: Money;
// Indirect costs
indirectPercentage: Percentage;
profitPercentage: Percentage;
// Status
status: BudgetStatus;
approvedAt?: Timestamp;
approvedBy?: UUID;
// Relationships
partidas: BudgetPartida[];
}
enum BudgetStatus {
DRAFT = 'draft',
APPROVED = 'approved',
ACTIVE = 'active',
CLOSED = 'closed'
}
BudgetPartida (Entity)
interface BudgetPartida {
id: UUID;
budgetId: UUID;
parentId?: UUID;
code: string;
name: string;
description?: string;
sortOrder: number;
level: number;
// Calculated
totalCost: Money;
concepts: BudgetConcept[];
children: BudgetPartida[];
}
BudgetConcept (Entity)
interface BudgetConcept {
id: UUID;
partidaId: UUID;
code: string;
name: string;
description?: string;
// Unit and quantity
unitId?: UUID;
unitCode: string;
quantity: number;
// Pricing
unitPrice: Money;
totalPrice: Money; // quantity * unitPrice
// Type
conceptType: ConceptType;
hasAPU: boolean;
sortOrder: number;
apuItems: APUItem[];
}
enum ConceptType {
MATERIAL = 'material',
LABOR = 'labor',
EQUIPMENT = 'equipment',
SUBCONTRACT = 'subcontract',
INDIRECT = 'indirect'
}
APUItem (Entity)
interface APUItem {
id: UUID;
conceptId: UUID;
itemType: ConceptType;
// Product reference
productId?: UUID;
productCode: string;
productName: string;
// Unit and quantity
unitCode: string;
quantity: number;
// Cost
unitCost: Money;
totalCost: Money; // quantity * unitCost
// Yield (for labor)
yieldFactor: number;
sortOrder: number;
}
3. Schedule Aggregate
Schedule (Aggregate Root)
|
+-- ScheduleItem (Entity)
| +-- Predecessor (Value Object)
|
+-- Milestone (Value Object)
Schedule (Root)
interface Schedule {
id: UUID;
tenantId: UUID;
projectId: UUID;
name: string;
description?: string;
version: number;
startDate: Date;
endDate: Date;
isActive: boolean;
items: ScheduleItem[];
}
ScheduleItem (Entity)
interface ScheduleItem {
id: UUID;
scheduleId: UUID;
parentId?: UUID;
conceptId?: UUID;
code: string;
name: string;
// Planned dates
plannedStart: Date;
plannedEnd: Date;
durationDays: number;
// Actual dates
actualStart?: Date;
actualEnd?: Date;
// Progress
plannedProgress: Percentage;
actualProgress: Percentage;
// Dependencies (WBS)
predecessors: UUID[];
sortOrder: number;
level: number;
children: ScheduleItem[];
}
4. Progress Aggregate
ProgressRecord (Aggregate Root)
|
+-- ProgressPhoto (Entity)
|
+-- Approval (Value Object)
LogbookEntry (Aggregate Root)
|
+-- EntryPhoto (Entity)
Estimation (Aggregate Root)
|
+-- EstimationLine (Entity)
ProgressRecord (Entity)
interface ProgressRecord {
id: UUID;
tenantId: UUID;
projectId: UUID;
housingUnitId?: UUID;
conceptId?: UUID;
scheduleItemId?: UUID;
recordDate: Date;
progressType: ProgressType;
// Values
previousProgress: number;
currentProgress: number;
progressIncrement: number;
// For quantity type
quantityExecuted?: number;
unitCode?: string;
notes?: string;
// Approval
approvedAt?: Timestamp;
approvedBy?: UUID;
photos: ProgressPhoto[];
}
enum ProgressType {
QUANTITY = 'quantity',
PERCENTAGE = 'percentage'
}
Estimation (Entity)
interface Estimation {
id: UUID;
tenantId: UUID;
projectId: UUID;
estimationNumber: string;
periodStart: Date;
periodEnd: Date;
// Amounts
previousAccumulated: Money;
currentPeriod: Money;
totalAccumulated: Money;
// Deductions
advanceAmortization: Money;
retentions: Money;
otherDeductions: Money;
netAmount: Money;
status: EstimationStatus;
// Workflow
submittedAt?: Timestamp;
submittedBy?: UUID;
approvedAt?: Timestamp;
approvedBy?: UUID;
lines: EstimationLine[];
}
enum EstimationStatus {
DRAFT = 'draft',
SUBMITTED = 'submitted',
APPROVED = 'approved',
REJECTED = 'rejected',
PAID = 'paid'
}
Value Objects
Location
interface Location {
latitude: number;
longitude: number;
altitude?: number;
}
Money
interface Money {
amount: number;
currency: string; // Default: MXN
}
Percentage
interface Percentage {
value: number; // 0-100
}
Period
interface Period {
startDate: Date;
endDate: Date;
}
Domain Events
Project Lifecycle
// When a new project is created
interface ProjectCreated {
projectId: UUID;
code: string;
name: string;
tenantId: UUID;
timestamp: Timestamp;
}
// When project status changes
interface ProjectStatusChanged {
projectId: UUID;
previousStatus: ProjectStatus;
newStatus: ProjectStatus;
changedBy: UUID;
timestamp: Timestamp;
}
Progress Events
// When progress is recorded
interface ProgressRecorded {
progressRecordId: UUID;
projectId: UUID;
housingUnitId?: UUID;
conceptId?: UUID;
progressIncrement: number;
recordedBy: UUID;
timestamp: Timestamp;
}
// When estimation is approved
interface EstimationApproved {
estimationId: UUID;
projectId: UUID;
netAmount: Money;
approvedBy: UUID;
timestamp: Timestamp;
}
Budget Events
// When budget is approved
interface BudgetApproved {
budgetId: UUID;
projectId: UUID;
totalCost: Money;
approvedBy: UUID;
timestamp: Timestamp;
}
// When materials are exploded
interface MaterialsExploded {
budgetId: UUID;
materialsCount: number;
totalCost: Money;
timestamp: Timestamp;
}
Business Rules
Project Rules
- Un proyecto debe tener al menos un presupuesto antes de iniciar
- El status solo puede avanzar en orden: planning -> in_progress -> completed
- Solo se puede pausar un proyecto en status in_progress
- El progreso de proyecto se calcula como promedio ponderado de viviendas
Budget Rules
- Una poliza debe estar balanceada (total_debit = total_credit)
- El presupuesto base (prototipo) no puede tener proyecto_id
- El presupuesto ejecutivo debe derivar de un base
- Los APU deben sumar al precio unitario del concepto
Progress Rules
- El avance no puede superar 100%
- El avance actual debe ser >= avance anterior
- Las estimaciones requieren avance registrado
- Las fotos son obligatorias para ciertos conceptos
Invariantes
Project.progressPercentage = AVG(HousingUnit.progressPercentage)Budget.totalCost = SUM(Partida.totalCost) * (1 + indirect%) * (1 + profit%)Partida.totalCost = SUM(Concept.totalPrice)Concept.unitPrice = SUM(APUItem.totalCost) / Concept.quantityEstimation.totalAccumulated = previousAccumulated + currentPeriod
Referencias
Ultima actualizacion: 2025-12-05