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