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