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

13 KiB

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)

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)

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)

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)

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)

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)

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)

interface ApprovalWorkflow {
  id: UUID;
  tenantId: UUID;

  name: string;
  description?: string;

  documentTypes: DocumentType[];
  totalLevels: number;

  isActive: boolean;

  levels: WorkflowLevel[];
}

WorkflowLevel (Entity)

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)

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)

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

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

FolderPath

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

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

VersionNumber

interface VersionNumber {
  major: number;
  minor: number;
  revision?: string;

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

Dimensions

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

Domain Events

Document Events

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

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

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

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


Ultima actualizacion: 2025-12-05