# 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) ```typescript 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) ```typescript 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) ```typescript interface Section { id: UUID; developmentId: UUID; code: string; name: string; boundary?: Polygon; areaM2?: number; totalUnits: number; completedUnits: number; housingUnits: HousingUnit[]; } ``` #### HousingUnit (Entity) ```typescript 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) ```typescript 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) ```typescript 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) ```typescript 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) ```typescript 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) ```typescript interface Schedule { id: UUID; tenantId: UUID; projectId: UUID; name: string; description?: string; version: number; startDate: Date; endDate: Date; isActive: boolean; items: ScheduleItem[]; } ``` #### ScheduleItem (Entity) ```typescript 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) ```typescript 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) ```typescript 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 ```typescript interface Location { latitude: number; longitude: number; altitude?: number; } ``` ### Money ```typescript interface Money { amount: number; currency: string; // Default: MXN } ``` ### Percentage ```typescript interface Percentage { value: number; // 0-100 } ``` ### Period ```typescript interface Period { startDate: Date; endDate: Date; } ``` --- ## Domain Events ### Project Lifecycle ```typescript // 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 ```typescript // 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 ```typescript // 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 1. Un proyecto debe tener al menos un presupuesto antes de iniciar 2. El status solo puede avanzar en orden: planning -> in_progress -> completed 3. Solo se puede pausar un proyecto en status in_progress 4. El progreso de proyecto se calcula como promedio ponderado de viviendas ### Budget Rules 1. Una poliza debe estar balanceada (total_debit = total_credit) 2. El presupuesto base (prototipo) no puede tener proyecto_id 3. El presupuesto ejecutivo debe derivar de un base 4. Los APU deben sumar al precio unitario del concepto ### Progress Rules 1. El avance no puede superar 100% 2. El avance actual debe ser >= avance anterior 3. Las estimaciones requieren avance registrado 4. Las fotos son obligatorias para ciertos conceptos --- ## Invariantes 1. `Project.progressPercentage = AVG(HousingUnit.progressPercentage)` 2. `Budget.totalCost = SUM(Partida.totalCost) * (1 + indirect%) * (1 + profit%)` 3. `Partida.totalCost = SUM(Concept.totalPrice)` 4. `Concept.unitPrice = SUM(APUItem.totalCost) / Concept.quantity` 5. `Estimation.totalAccumulated = previousAccumulated + currentPeriod` --- ## Referencias - [DDL-SPEC-construction.md](../database-design/schemas/DDL-SPEC-construction.md) - [EPIC-MAI-002](../../08-epicas/EPIC-MAI-002-proyectos.md) - [EPIC-MAI-003](../../08-epicas/EPIC-MAI-003-presupuestos.md) - [EPIC-MAI-005](../../08-epicas/EPIC-MAI-005-control-obra.md) --- *Ultima actualizacion: 2025-12-05*