erp-construccion-backend-v2/src/modules/documents/entities/document.entity.ts
Adrian Flores Cortes 22b9692e3a [MAE-016] feat: Add Documents module (Gestion Documental)
- Create 11 entities matching DDL:
  - DocumentCategory: Hierarchical categories
  - Document: Main document registry
  - DocumentVersion: Version control with files
  - DocumentPermission: Granular permissions
  - ApprovalWorkflow: Workflow definitions
  - ApprovalInstance: Active workflow instances
  - ApprovalStep: Steps per instance
  - ApprovalActionEntity: Actions taken
  - Annotation: Comments and markups
  - AccessLog: Access history
  - DocumentShare: External sharing links
- Create DocumentService with full CRUD
- Create DocumentVersionService for version management
- All entities follow ERP-Construction patterns

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 08:22:49 -06:00

235 lines
6.1 KiB
TypeScript

/**
* Document Entity - Registro Principal de Documentos
* Sistema de gestion documental.
*
* @module Documents (MAE-016)
*/
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
OneToMany,
JoinColumn,
Index,
} from 'typeorm';
import { DocumentCategory, AccessLevel } from './document-category.entity';
import { DocumentVersion } from './document-version.entity';
import { Annotation } from './annotation.entity';
export type DocumentType =
| 'plan'
| 'specification'
| 'contract'
| 'permit'
| 'report'
| 'photograph'
| 'drawing'
| 'manual'
| 'procedure'
| 'form'
| 'correspondence'
| 'invoice'
| 'estimate'
| 'other';
export type DocumentStatus =
| 'draft'
| 'pending_review'
| 'in_review'
| 'approved'
| 'rejected'
| 'obsolete'
| 'archived';
@Entity('documents', { schema: 'documents' })
@Index(['tenantId', 'documentCode'], { unique: true })
@Index(['tenantId', 'categoryId'])
@Index(['tenantId', 'documentType'])
@Index(['tenantId', 'status'])
@Index(['tenantId', 'projectId'])
export class Document {
@PrimaryGeneratedColumn('uuid')
id!: string;
@Column({ name: 'tenant_id', type: 'uuid' })
@Index()
tenantId!: string;
// Identificacion
@Column({ name: 'document_code', length: 100 })
documentCode!: string;
@Column({ length: 500 })
title!: string;
@Column({ type: 'text', nullable: true })
description?: string;
// Clasificacion
@Column({ name: 'category_id', type: 'uuid', nullable: true })
categoryId?: string;
@ManyToOne(() => DocumentCategory, { nullable: true })
@JoinColumn({ name: 'category_id' })
category?: DocumentCategory;
@Column({
name: 'document_type',
type: 'enum',
enum: ['plan', 'specification', 'contract', 'permit', 'report', 'photograph', 'drawing', 'manual', 'procedure', 'form', 'correspondence', 'invoice', 'estimate', 'other'],
enumName: 'document_type',
})
documentType!: DocumentType;
@Column({
type: 'enum',
enum: ['draft', 'pending_review', 'in_review', 'approved', 'rejected', 'obsolete', 'archived'],
enumName: 'document_status',
default: 'draft',
})
status!: DocumentStatus;
@Column({
name: 'access_level',
type: 'enum',
enum: ['public', 'internal', 'confidential', 'restricted'],
enumName: 'access_level',
default: 'internal',
})
accessLevel!: AccessLevel;
// Version actual
@Column({ name: 'current_version_id', type: 'uuid', nullable: true })
currentVersionId?: string;
@Column({ name: 'current_version_number', length: 20, default: '1.0' })
currentVersionNumber!: string;
// Proyecto/Contexto
@Column({ name: 'project_id', type: 'uuid', nullable: true })
projectId?: string;
@Column({ name: 'project_code', length: 50, nullable: true })
projectCode?: string;
@Column({ name: 'project_name', length: 255, nullable: true })
projectName?: string;
// Metadatos del documento
@Column({ length: 255, nullable: true })
author?: string;
@Column({ type: 'varchar', array: true, nullable: true })
keywords?: string[];
@Column({ type: 'varchar', array: true, nullable: true })
tags?: string[];
// Fechas importantes
@Column({ name: 'document_date', type: 'date', nullable: true })
documentDate?: Date;
@Column({ name: 'effective_date', type: 'date', nullable: true })
effectiveDate?: Date;
@Column({ name: 'expiry_date', type: 'date', nullable: true })
expiryDate?: Date;
@Column({ name: 'review_date', type: 'date', nullable: true })
reviewDate?: Date;
// Origen
@Column({ length: 100, nullable: true })
source?: string;
@Column({ name: 'external_reference', length: 255, nullable: true })
externalReference?: string;
@Column({ name: 'original_filename', length: 500, nullable: true })
originalFilename?: string;
// Relaciones de documentos
@Column({ name: 'parent_document_id', type: 'uuid', nullable: true })
parentDocumentId?: string;
@ManyToOne(() => Document, { nullable: true })
@JoinColumn({ name: 'parent_document_id' })
parentDocument?: Document;
@Column({ name: 'related_documents', type: 'uuid', array: true, nullable: true })
relatedDocuments?: string[];
// Flujo de aprobacion
@Column({ name: 'requires_approval', type: 'boolean', default: false })
requiresApproval!: boolean;
@Column({ name: 'current_workflow_id', type: 'uuid', nullable: true })
currentWorkflowId?: string;
@Column({ name: 'approved_by_id', type: 'uuid', nullable: true })
approvedById?: string;
@Column({ name: 'approved_at', type: 'timestamptz', nullable: true })
approvedAt?: Date;
// Estadisticas
@Column({ name: 'view_count', type: 'int', default: 0 })
viewCount!: number;
@Column({ name: 'download_count', type: 'int', default: 0 })
downloadCount!: number;
@Column({ name: 'last_accessed_at', type: 'timestamptz', nullable: true })
lastAccessedAt?: Date;
// Flags
@Column({ name: 'is_template', type: 'boolean', default: false })
isTemplate!: boolean;
@Column({ name: 'is_locked', type: 'boolean', default: false })
isLocked!: boolean;
@Column({ name: 'locked_by_id', type: 'uuid', nullable: true })
lockedById?: string;
@Column({ name: 'locked_at', type: 'timestamptz', nullable: true })
lockedAt?: Date;
// Notas y metadatos
@Column({ type: 'text', nullable: true })
notes?: string;
@Column({ name: 'custom_fields', type: 'jsonb', nullable: true })
customFields?: Record<string, any>;
@Column({ type: 'jsonb', nullable: true })
metadata?: Record<string, any>;
// Relaciones
@OneToMany(() => DocumentVersion, (version) => version.document)
versions?: DocumentVersion[];
@OneToMany(() => Annotation, (annotation) => annotation.document)
annotations?: Annotation[];
// Auditoria
@Column({ name: 'created_by', type: 'uuid', nullable: true })
createdBy?: string;
@Column({ name: 'updated_by', type: 'uuid', nullable: true })
updatedBy?: string;
@CreateDateColumn({ name: 'created_at', type: 'timestamptz' })
createdAt!: Date;
@UpdateDateColumn({ name: 'updated_at', type: 'timestamptz' })
updatedAt!: Date;
@Column({ name: 'deleted_at', type: 'timestamptz', nullable: true })
deletedAt?: Date;
}