700 lines
13 KiB
Markdown
700 lines
13 KiB
Markdown
# 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*
|