# DOMAIN MODEL: Documents Context (DMS)

**Version:** 1.0.0
**Fecha:** 2025-12-05
**Modulos:** MAE-016

---

## Descripcion

El contexto de Documents gestiona el sistema de gestion documental (DMS) enterprise. Incluye repositorio centralizado, versionado de planos, flujos de aprobacion, anotaciones y control de acceso granular.

---

## Agregados

### 1. Document Aggregate

```
Document (Aggregate Root)
|
+-- DocumentVersion (Entity)
|   +-- VersionMetadata (Value Object)
|
+-- DocumentShare (Entity)
|
+-- AccessLog (Entity)
```

#### Document (Root)
```typescript
interface Document {
  id: UUID;
  tenantId: UUID;
  folderId?: UUID;

  documentNumber?: string;
  title: string;
  description?: string;

  documentType: DocumentType;
  subcategory?: string;

  // Project link
  projectId?: UUID;
  housingUnitId?: UUID;

  // Current version
  currentVersionId?: UUID;
  currentVersionNumber: string;
  totalVersions: number;

  // File info
  fileUrl: string;
  fileName: string;
  fileSize?: number;
  mimeType?: string;
  fileExtension?: string;

  thumbnailUrl?: string;
  previewUrl?: string;

  // Metadata
  tags?: string[];
  customFields?: Record<string, any>;

  status: DocumentStatus;
  accessLevel: AccessLevel;

  // Dates
  documentDate?: Date;
  expiryDate?: Date;

  // OCR
  ocrText?: string;
  isOcrProcessed: boolean;
  ocrProcessedAt?: Timestamp;

  versions: DocumentVersion[];
  shares: DocumentShare[];
}

enum DocumentType {
  PLAN = 'plan',
  SPECIFICATION = 'specification',
  CONTRACT = 'contract',
  PERMIT = 'permit',
  INVOICE = 'invoice',
  REPORT = 'report',
  PHOTO = 'photo',
  DRAWING = 'drawing',
  MANUAL = 'manual',
  CERTIFICATE = 'certificate',
  OTHER = 'other'
}

enum DocumentStatus {
  DRAFT = 'draft',
  IN_REVIEW = 'in_review',
  APPROVED = 'approved',
  REJECTED = 'rejected',
  OBSOLETE = 'obsolete',
  ARCHIVED = 'archived'
}

enum AccessLevel {
  PUBLIC = 'public',
  RESTRICTED = 'restricted',
  CONFIDENTIAL = 'confidential',
  PRIVATE = 'private'
}
```

#### DocumentVersion (Entity)
```typescript
interface DocumentVersion {
  id: UUID;
  documentId: UUID;

  versionNumber: string;  // 1.0, Rev. A, etc.
  versionSequence: number;

  fileUrl: string;
  fileName: string;
  fileSize?: number;
  mimeType?: string;

  thumbnailUrl?: string;
  previewUrl?: string;

  changeSummary?: string;
  changeType?: ChangeType;

  status: DocumentStatus;
  isCurrent: boolean;

  approvedBy?: UUID;
  approvedAt?: Timestamp;
}

enum ChangeType {
  MINOR = 'minor',
  MAJOR = 'major',
  REVISION = 'revision'
}
```

#### DocumentShare (Entity)
```typescript
interface DocumentShare {
  id: UUID;
  documentId: UUID;

  shareType: ShareType;
  sharedWithUserId?: UUID;
  sharedWithRole?: string;
  sharedWithEmail?: string;

  // Permissions
  canView: boolean;
  canDownload: boolean;
  canAnnotate: boolean;
  canShare: boolean;

  expiresAt?: Timestamp;
  accessToken?: string;  // For external links

  isActive: boolean;
}

enum ShareType {
  USER = 'user',
  ROLE = 'role',
  EXTERNAL = 'external'
}
```

---

### 2. Folder Aggregate

```
Folder (Aggregate Root)
|
+-- FolderPath (Value Object)
+-- AccessControl (Value Object)
```

#### Folder (Root)
```typescript
interface Folder {
  id: UUID;
  tenantId: UUID;

  name: string;
  description?: string;

  parentId?: UUID;
  fullPath: string;
  level: number;

  projectId?: UUID;
  folderType?: FolderType;

  accessLevel: AccessLevel;
  allowedRoles?: string[];

  sortOrder: number;
  isActive: boolean;

  children: Folder[];
  documents: Document[];
}

enum FolderType {
  PLANS = 'plans',
  CONTRACTS = 'contracts',
  PERMITS = 'permits',
  SPECIFICATIONS = 'specifications',
  REPORTS = 'reports',
  PHOTOS = 'photos',
  GENERAL = 'general'
}
```

---

### 3. Plan Aggregate (Extended Document)

```
Plan (Aggregate Root - extends Document)
|
+-- PlanAnnotation (Entity)
|   +-- AnnotationShape (Value Object)
|
+-- PlanRevision (Value Object)
```

#### Plan (Root)
```typescript
interface Plan extends Document {
  id: UUID;
  documentId: UUID;

  planType: PlanType;
  discipline?: string;

  planNumber: string;
  sheetNumber?: string;
  totalSheets?: number;

  scale?: string;

  // Dimensions
  format?: string;  // A0, A1, A2, A3, A4
  widthMm?: number;
  heightMm?: number;

  // Georeferencing
  northCoordinate?: number;
  eastCoordinate?: number;
  coordinateSystem?: string;

  // Source
  sourceSoftware?: string;  // AutoCAD, Revit
  sourceFileUrl?: string;   // .dwg, .rvt

  currentRevision: string;

  isForConstruction: boolean;
  isAsBuilt: boolean;

  annotations: PlanAnnotation[];
}

enum PlanType {
  ARCHITECTURAL = 'architectural',
  STRUCTURAL = 'structural',
  ELECTRICAL = 'electrical',
  PLUMBING = 'plumbing',
  HVAC = 'hvac',
  LANDSCAPE = 'landscape',
  CIVIL = 'civil',
  DETAIL = 'detail',
  AS_BUILT = 'as_built'
}
```

#### PlanAnnotation (Entity)
```typescript
interface PlanAnnotation {
  id: UUID;
  planId: UUID;
  versionId?: UUID;

  annotationType: AnnotationType;

  // Position
  xPosition: number;
  yPosition: number;
  width?: number;
  height?: number;
  rotation?: number;

  content?: string;
  color?: string;
  style?: Record<string, any>;

  // Shape (for markups)
  shapeType?: ShapeType;
  shapePoints?: Point[];

  isResolved: boolean;
  resolvedBy?: UUID;
  resolvedAt?: Timestamp;
}

enum AnnotationType {
  COMMENT = 'comment',
  MARKUP = 'markup',
  MEASUREMENT = 'measurement',
  SYMBOL = 'symbol'
}

enum ShapeType {
  RECTANGLE = 'rectangle',
  CIRCLE = 'circle',
  ARROW = 'arrow',
  FREEHAND = 'freehand',
  POLYGON = 'polygon',
  LINE = 'line'
}

interface Point {
  x: number;
  y: number;
}
```

---

### 4. Approval Aggregate

```
ApprovalWorkflow (Aggregate Root)
|
+-- WorkflowLevel (Entity)
|
+-- ApproverConfig (Value Object)

DocumentApproval (Aggregate Root)
|
+-- ApprovalAction (Entity)
|
+-- ApprovalResult (Value Object)
```

#### ApprovalWorkflow (Root)
```typescript
interface ApprovalWorkflow {
  id: UUID;
  tenantId: UUID;

  name: string;
  description?: string;

  documentTypes: DocumentType[];
  totalLevels: number;

  isActive: boolean;

  levels: WorkflowLevel[];
}
```

#### WorkflowLevel (Entity)
```typescript
interface WorkflowLevel {
  id: UUID;
  workflowId: UUID;

  levelNumber: number;
  levelName: string;

  approverType: ApproverType;
  approverIds?: UUID[];
  approverRoles?: string[];

  requiresAll: boolean;  // true = all must approve
  canSkip: boolean;

  sortOrder: number;
}

enum ApproverType {
  USER = 'user',
  ROLE = 'role',
  DEPARTMENT = 'department'
}
```

#### DocumentApproval (Root)
```typescript
interface DocumentApproval {
  id: UUID;
  tenantId: UUID;
  documentId: UUID;
  versionId?: UUID;

  workflowId?: UUID;
  currentLevel: number;

  status: ApprovalStatus;

  submittedAt?: Timestamp;
  submittedBy?: UUID;
  completedAt?: Timestamp;

  finalAction?: ApprovalAction;
  finalComments?: string;

  actions: ApprovalActionRecord[];
}

enum ApprovalStatus {
  PENDING = 'pending',
  IN_PROGRESS = 'in_progress',
  APPROVED = 'approved',
  REJECTED = 'rejected'
}
```

#### ApprovalActionRecord (Entity)
```typescript
interface ApprovalActionRecord {
  id: UUID;
  approvalId: UUID;

  levelNumber: number;
  action: ApprovalAction;
  actionBy: UUID;
  actionAt: Timestamp;

  comments?: string;
}

enum ApprovalAction {
  SUBMIT = 'submit',
  APPROVE = 'approve',
  REJECT = 'reject',
  REQUEST_CHANGES = 'request_changes',
  WITHDRAW = 'withdraw'
}
```

---

## Value Objects

### FileInfo
```typescript
interface FileInfo {
  url: string;
  name: string;
  size: number;
  mimeType: string;
  extension: string;
  checksum?: string;
}
```

### FolderPath
```typescript
interface FolderPath {
  path: string;
  segments: string[];
  depth: number;

  static fromString(path: string): FolderPath;
  static join(parent: FolderPath, name: string): FolderPath;
  getParent(): FolderPath;
}
```

### VersionNumber
```typescript
interface VersionNumber {
  major: number;
  minor: number;
  revision?: string;

  static parse(str: string): VersionNumber;
  static next(current: VersionNumber, changeType: ChangeType): VersionNumber;
  toString(): string;
}
```

### Dimensions
```typescript
interface Dimensions {
  width: number;
  height: number;
  unit: 'mm' | 'cm' | 'in';
}
```

---

## Domain Events

### Document Events
```typescript
interface DocumentUploaded {
  documentId: UUID;
  fileName: string;
  fileSize: number;
  documentType: DocumentType;
  uploadedBy: UUID;
  timestamp: Timestamp;
}

interface DocumentVersionCreated {
  documentId: UUID;
  versionId: UUID;
  versionNumber: string;
  changeType: ChangeType;
  createdBy: UUID;
  timestamp: Timestamp;
}

interface DocumentStatusChanged {
  documentId: UUID;
  previousStatus: DocumentStatus;
  newStatus: DocumentStatus;
  changedBy: UUID;
  timestamp: Timestamp;
}

interface DocumentShared {
  documentId: UUID;
  shareId: UUID;
  shareType: ShareType;
  sharedWith: string;
  permissions: string[];
  sharedBy: UUID;
  timestamp: Timestamp;
}
```

### Plan Events
```typescript
interface PlanRevisionCreated {
  planId: UUID;
  versionId: UUID;
  revision: string;
  createdBy: UUID;
  timestamp: Timestamp;
}

interface AnnotationAdded {
  planId: UUID;
  annotationId: UUID;
  annotationType: AnnotationType;
  createdBy: UUID;
  timestamp: Timestamp;
}

interface AnnotationResolved {
  annotationId: UUID;
  planId: UUID;
  resolvedBy: UUID;
  timestamp: Timestamp;
}
```

### Approval Events
```typescript
interface ApprovalSubmitted {
  approvalId: UUID;
  documentId: UUID;
  workflowId: UUID;
  submittedBy: UUID;
  timestamp: Timestamp;
}

interface ApprovalLevelCompleted {
  approvalId: UUID;
  documentId: UUID;
  levelNumber: number;
  action: ApprovalAction;
  actionBy: UUID;
  timestamp: Timestamp;
}

interface ApprovalCompleted {
  approvalId: UUID;
  documentId: UUID;
  finalAction: ApprovalAction;
  completedBy: UUID;
  timestamp: Timestamp;
}
```

### Access Events
```typescript
interface DocumentAccessed {
  documentId: UUID;
  action: AccessAction;
  userId: UUID;
  versionId?: UUID;
  timestamp: Timestamp;
}

enum AccessAction {
  VIEW = 'view',
  DOWNLOAD = 'download',
  PRINT = 'print',
  ANNOTATE = 'annotate',
  SHARE = 'share'
}
```

---

## Business Rules

### Document Rules
1. Los documentos requieren al menos un archivo
2. El numero de documento debe ser unico por proyecto
3. Solo la version actual puede modificarse
4. Documentos archivados son de solo lectura

### Version Rules
1. Cada nueva version incrementa secuencia automaticamente
2. Solo puede haber una version 'current' a la vez
3. El historial de versiones es inmutable
4. Los cambios mayores requieren nueva revision

### Plan Rules
1. Los planos deben tener numero de plano unico
2. Las revisiones siguen secuencia (A, B, C... o 1, 2, 3...)
3. Los planos 'for construction' requieren aprobacion
4. Las anotaciones no resueltas bloquean nueva revision

### Approval Rules
1. El flujo de aprobacion respeta niveles en orden
2. 'requiresAll' exige aprobacion de todos los aprobadores del nivel
3. Rechazo en cualquier nivel rechaza todo el documento
4. 'request_changes' regresa al nivel anterior

### Access Rules
1. 'private' solo visible por propietario
2. 'confidential' requiere permiso explicito
3. 'restricted' limita por roles
4. Links externos expiran automaticamente

---

## Invariantes

1. `Document.currentVersionId = MAX(versions.versionSequence).id WHERE isCurrent = true`
2. `Document.totalVersions = COUNT(versions)`
3. `Folder.fullPath = parent.fullPath + '/' + name`
4. `Folder.level = parent.level + 1`
5. `DocumentApproval.currentLevel <= workflow.totalLevels`

---

## Integraciones

### Con Project Context
- Documentos asociados a proyectos
- Planos vinculados a viviendas/conceptos
- Fotos de avance como documentos

### Con Compliance Context
- Evidencias almacenadas como documentos
- Reportes de auditoria
- Certificaciones

### Con Finance Context
- Facturas digitales
- Polizas exportadas
- Contratos

### Con Storage (Externo)
- S3/Azure Blob para archivos
- CDN para previews
- OCR externo para busqueda

---

## Referencias

- [DDL-SPEC-documents.md](../database-design/schemas/DDL-SPEC-documents.md)

---

*Ultima actualizacion: 2025-12-05*
