erp-construccion/docs/04-modelado/domain-models/PROJECT-CONTEXT.md

620 lines
11 KiB
Markdown

# 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*