[MAE-016] feat: Add documents schema DDL with 11 tables and 8 ENUMs
- document_categories: Categorias jerarquicas - documents: Registro principal - document_versions: Control de versiones - document_permissions: Permisos granulares - approval_workflows: Definicion de flujos - approval_instances: Instancias de aprobacion - approval_steps: Pasos de aprobacion - approval_actions: Acciones de aprobacion - annotations: Anotaciones sobre documentos - access_logs: Historial de acceso - document_shares: Compartidos externos Includes: RLS, indices, triggers, fulltext search Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
e927cafc90
commit
80dd204db2
832
schemas/10-documents-schema-ddl.sql
Normal file
832
schemas/10-documents-schema-ddl.sql
Normal file
@ -0,0 +1,832 @@
|
|||||||
|
-- ============================================================================
|
||||||
|
-- 10-documents-schema-ddl.sql
|
||||||
|
-- Schema: documents
|
||||||
|
-- ERP Construccion - Modulo Gestion Documental (MAE-016)
|
||||||
|
-- ============================================================================
|
||||||
|
-- Descripcion: Sistema de gestion documental incluyendo:
|
||||||
|
-- - Repositorio de documentos estructurado
|
||||||
|
-- - Control de versiones
|
||||||
|
-- - Flujos de aprobacion
|
||||||
|
-- - Permisos granulares
|
||||||
|
-- - Anotaciones sobre planos
|
||||||
|
-- - Integracion con almacenamiento externo (S3)
|
||||||
|
-- ============================================================================
|
||||||
|
-- Autor: Claude-Arquitecto-Orquestador
|
||||||
|
-- Fecha: 2026-01-25
|
||||||
|
-- Version: 1.0.0
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Crear schema si no existe
|
||||||
|
CREATE SCHEMA IF NOT EXISTS documents;
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- ENUMS
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Tipo de documento
|
||||||
|
CREATE TYPE documents.document_type AS ENUM (
|
||||||
|
'plan', -- Planos arquitectonicos/estructurales
|
||||||
|
'specification', -- Especificaciones tecnicas
|
||||||
|
'contract', -- Contratos
|
||||||
|
'permit', -- Permisos y licencias
|
||||||
|
'report', -- Reportes
|
||||||
|
'photograph', -- Fotografias
|
||||||
|
'drawing', -- Dibujos y croquis
|
||||||
|
'manual', -- Manuales
|
||||||
|
'procedure', -- Procedimientos
|
||||||
|
'form', -- Formatos
|
||||||
|
'correspondence', -- Correspondencia
|
||||||
|
'invoice', -- Facturas
|
||||||
|
'estimate', -- Estimaciones/Presupuestos
|
||||||
|
'other' -- Otro
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Estado del documento
|
||||||
|
CREATE TYPE documents.document_status AS ENUM (
|
||||||
|
'draft', -- Borrador
|
||||||
|
'pending_review', -- Pendiente de revision
|
||||||
|
'in_review', -- En revision
|
||||||
|
'approved', -- Aprobado
|
||||||
|
'rejected', -- Rechazado
|
||||||
|
'obsolete', -- Obsoleto
|
||||||
|
'archived' -- Archivado
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Nivel de acceso
|
||||||
|
CREATE TYPE documents.access_level AS ENUM (
|
||||||
|
'public', -- Publico (todos en el tenant)
|
||||||
|
'internal', -- Interno (empleados)
|
||||||
|
'confidential', -- Confidencial
|
||||||
|
'restricted' -- Restringido (solo autorizados)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Estado de version
|
||||||
|
CREATE TYPE documents.version_status AS ENUM (
|
||||||
|
'current', -- Version actual
|
||||||
|
'superseded', -- Reemplazada
|
||||||
|
'archived' -- Archivada
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Estado de flujo de aprobacion
|
||||||
|
CREATE TYPE documents.workflow_status AS ENUM (
|
||||||
|
'draft', -- Borrador
|
||||||
|
'pending', -- Pendiente
|
||||||
|
'in_progress', -- En progreso
|
||||||
|
'approved', -- Aprobado
|
||||||
|
'rejected', -- Rechazado
|
||||||
|
'cancelled' -- Cancelado
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Tipo de paso de aprobacion
|
||||||
|
CREATE TYPE documents.approval_step_type AS ENUM (
|
||||||
|
'review', -- Revision
|
||||||
|
'approval', -- Aprobacion
|
||||||
|
'signature', -- Firma
|
||||||
|
'comment' -- Solo comentario
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Accion de aprobacion
|
||||||
|
CREATE TYPE documents.approval_action AS ENUM (
|
||||||
|
'approve', -- Aprobar
|
||||||
|
'reject', -- Rechazar
|
||||||
|
'request_changes' -- Solicitar cambios
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Tipo de anotacion
|
||||||
|
CREATE TYPE documents.annotation_type AS ENUM (
|
||||||
|
'comment', -- Comentario
|
||||||
|
'markup', -- Marcado
|
||||||
|
'highlight', -- Resaltado
|
||||||
|
'arrow', -- Flecha
|
||||||
|
'dimension', -- Dimension
|
||||||
|
'stamp', -- Sello
|
||||||
|
'signature' -- Firma
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- TABLAS
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 1. Categorias de Documentos
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.document_categories (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Informacion basica
|
||||||
|
code VARCHAR(50) NOT NULL,
|
||||||
|
name VARCHAR(100) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
|
||||||
|
-- Jerarquia
|
||||||
|
parent_id UUID REFERENCES documents.document_categories(id),
|
||||||
|
level INTEGER NOT NULL DEFAULT 1,
|
||||||
|
path VARCHAR(500), -- Path completo separado por /
|
||||||
|
|
||||||
|
-- Configuracion
|
||||||
|
default_access_level documents.access_level DEFAULT 'internal',
|
||||||
|
requires_approval BOOLEAN DEFAULT FALSE,
|
||||||
|
retention_days INTEGER, -- Tiempo de retencion en dias
|
||||||
|
allowed_extensions VARCHAR(255)[], -- Extensiones permitidas
|
||||||
|
|
||||||
|
-- Icono y color
|
||||||
|
icon VARCHAR(50),
|
||||||
|
color VARCHAR(20),
|
||||||
|
|
||||||
|
-- Estado
|
||||||
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
sort_order INTEGER DEFAULT 0,
|
||||||
|
|
||||||
|
-- Metadatos
|
||||||
|
metadata JSONB,
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_by UUID,
|
||||||
|
updated_by UUID,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
deleted_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
CONSTRAINT uq_document_categories_tenant_code UNIQUE (tenant_id, code)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 2. Documentos (Registro Principal)
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.documents (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Identificacion
|
||||||
|
document_code VARCHAR(100) NOT NULL,
|
||||||
|
title VARCHAR(500) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
|
||||||
|
-- Clasificacion
|
||||||
|
category_id UUID REFERENCES documents.document_categories(id),
|
||||||
|
document_type documents.document_type NOT NULL,
|
||||||
|
status documents.document_status NOT NULL DEFAULT 'draft',
|
||||||
|
access_level documents.access_level NOT NULL DEFAULT 'internal',
|
||||||
|
|
||||||
|
-- Version actual
|
||||||
|
current_version_id UUID, -- Se actualiza con trigger
|
||||||
|
current_version_number VARCHAR(20) DEFAULT '1.0',
|
||||||
|
|
||||||
|
-- Proyecto/Contexto
|
||||||
|
project_id UUID,
|
||||||
|
project_code VARCHAR(50),
|
||||||
|
project_name VARCHAR(255),
|
||||||
|
|
||||||
|
-- Metadatos del documento
|
||||||
|
author VARCHAR(255),
|
||||||
|
keywords VARCHAR(255)[],
|
||||||
|
tags VARCHAR(100)[],
|
||||||
|
|
||||||
|
-- Fechas importantes
|
||||||
|
document_date DATE,
|
||||||
|
effective_date DATE,
|
||||||
|
expiry_date DATE,
|
||||||
|
review_date DATE,
|
||||||
|
|
||||||
|
-- Origen
|
||||||
|
source VARCHAR(100), -- internal, external, contractor
|
||||||
|
external_reference VARCHAR(255), -- Referencia externa si aplica
|
||||||
|
original_filename VARCHAR(500),
|
||||||
|
|
||||||
|
-- Relaciones
|
||||||
|
parent_document_id UUID REFERENCES documents.documents(id), -- Documento padre
|
||||||
|
related_documents UUID[], -- Array de IDs relacionados
|
||||||
|
|
||||||
|
-- Flujo de aprobacion
|
||||||
|
requires_approval BOOLEAN DEFAULT FALSE,
|
||||||
|
current_workflow_id UUID,
|
||||||
|
approved_by_id UUID,
|
||||||
|
approved_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
-- Estadisticas
|
||||||
|
view_count INTEGER DEFAULT 0,
|
||||||
|
download_count INTEGER DEFAULT 0,
|
||||||
|
last_accessed_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
-- Flags
|
||||||
|
is_template BOOLEAN DEFAULT FALSE,
|
||||||
|
is_locked BOOLEAN DEFAULT FALSE,
|
||||||
|
locked_by_id UUID,
|
||||||
|
locked_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
-- Notas y metadatos
|
||||||
|
notes TEXT,
|
||||||
|
custom_fields JSONB,
|
||||||
|
metadata JSONB,
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_by UUID,
|
||||||
|
updated_by UUID,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
deleted_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
CONSTRAINT uq_documents_tenant_code UNIQUE (tenant_id, document_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 3. Versiones de Documentos
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.document_versions (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Documento padre
|
||||||
|
document_id UUID NOT NULL REFERENCES documents.documents(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
-- Version
|
||||||
|
version_number VARCHAR(20) NOT NULL,
|
||||||
|
version_label VARCHAR(100), -- Etiqueta opcional (ej: "Final", "Para construccion")
|
||||||
|
status documents.version_status NOT NULL DEFAULT 'current',
|
||||||
|
|
||||||
|
-- Archivo
|
||||||
|
file_name VARCHAR(500) NOT NULL,
|
||||||
|
file_extension VARCHAR(20) NOT NULL,
|
||||||
|
file_size_bytes BIGINT NOT NULL,
|
||||||
|
mime_type VARCHAR(100),
|
||||||
|
checksum_md5 VARCHAR(32),
|
||||||
|
checksum_sha256 VARCHAR(64),
|
||||||
|
|
||||||
|
-- Almacenamiento
|
||||||
|
storage_provider VARCHAR(50) NOT NULL DEFAULT 's3', -- s3, azure, local
|
||||||
|
storage_bucket VARCHAR(255),
|
||||||
|
storage_key VARCHAR(1000) NOT NULL, -- Path en el storage
|
||||||
|
storage_url VARCHAR(2000), -- URL de acceso
|
||||||
|
thumbnail_url VARCHAR(2000),
|
||||||
|
preview_url VARCHAR(2000),
|
||||||
|
|
||||||
|
-- Procesamiento
|
||||||
|
is_processed BOOLEAN DEFAULT FALSE,
|
||||||
|
ocr_text TEXT, -- Texto extraido por OCR
|
||||||
|
extracted_metadata JSONB,
|
||||||
|
|
||||||
|
-- Paginas (para PDFs/planos)
|
||||||
|
page_count INTEGER,
|
||||||
|
page_dimensions JSONB, -- Dimensiones por pagina
|
||||||
|
|
||||||
|
-- Cambios
|
||||||
|
change_summary TEXT,
|
||||||
|
change_type VARCHAR(50), -- major, minor, patch
|
||||||
|
|
||||||
|
-- Subido por
|
||||||
|
uploaded_by_id UUID,
|
||||||
|
uploaded_by_name VARCHAR(255),
|
||||||
|
upload_source VARCHAR(50), -- web, mobile, api, email
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
superseded_at TIMESTAMPTZ,
|
||||||
|
superseded_by_version_id UUID
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 4. Permisos de Documentos
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.document_permissions (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Objeto
|
||||||
|
document_id UUID REFERENCES documents.documents(id) ON DELETE CASCADE,
|
||||||
|
category_id UUID REFERENCES documents.document_categories(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
-- Sujeto (quien tiene el permiso)
|
||||||
|
user_id UUID,
|
||||||
|
role_id UUID,
|
||||||
|
team_id UUID,
|
||||||
|
|
||||||
|
-- Permisos
|
||||||
|
can_view BOOLEAN DEFAULT FALSE,
|
||||||
|
can_download BOOLEAN DEFAULT FALSE,
|
||||||
|
can_edit BOOLEAN DEFAULT FALSE,
|
||||||
|
can_delete BOOLEAN DEFAULT FALSE,
|
||||||
|
can_share BOOLEAN DEFAULT FALSE,
|
||||||
|
can_approve BOOLEAN DEFAULT FALSE,
|
||||||
|
can_annotate BOOLEAN DEFAULT FALSE,
|
||||||
|
|
||||||
|
-- Vigencia
|
||||||
|
valid_from TIMESTAMPTZ,
|
||||||
|
valid_until TIMESTAMPTZ,
|
||||||
|
|
||||||
|
-- Otorgado por
|
||||||
|
granted_by_id UUID,
|
||||||
|
granted_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
|
||||||
|
CONSTRAINT chk_permission_target CHECK (
|
||||||
|
(document_id IS NOT NULL AND category_id IS NULL) OR
|
||||||
|
(document_id IS NULL AND category_id IS NOT NULL)
|
||||||
|
),
|
||||||
|
CONSTRAINT chk_permission_subject CHECK (
|
||||||
|
(user_id IS NOT NULL AND role_id IS NULL AND team_id IS NULL) OR
|
||||||
|
(user_id IS NULL AND role_id IS NOT NULL AND team_id IS NULL) OR
|
||||||
|
(user_id IS NULL AND role_id IS NULL AND team_id IS NOT NULL)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 5. Flujos de Aprobacion (Definicion)
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.approval_workflows (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Identificacion
|
||||||
|
workflow_code VARCHAR(50) NOT NULL,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
|
||||||
|
-- Aplica a
|
||||||
|
category_id UUID REFERENCES documents.document_categories(id),
|
||||||
|
document_type documents.document_type,
|
||||||
|
|
||||||
|
-- Pasos (JSON array con la definicion)
|
||||||
|
steps JSONB NOT NULL, -- [{step_number, name, type, approvers[], required_count}]
|
||||||
|
|
||||||
|
-- Configuracion
|
||||||
|
allow_parallel BOOLEAN DEFAULT FALSE, -- Pasos pueden ser paralelos
|
||||||
|
allow_skip BOOLEAN DEFAULT FALSE, -- Permitir saltar pasos
|
||||||
|
auto_archive_on_approval BOOLEAN DEFAULT FALSE,
|
||||||
|
|
||||||
|
-- Estado
|
||||||
|
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
|
||||||
|
-- Metadatos
|
||||||
|
metadata JSONB,
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_by UUID,
|
||||||
|
updated_by UUID,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
deleted_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
CONSTRAINT uq_approval_workflows_tenant_code UNIQUE (tenant_id, workflow_code)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 6. Instancias de Flujo de Aprobacion
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.approval_instances (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Flujo y documento
|
||||||
|
workflow_id UUID NOT NULL REFERENCES documents.approval_workflows(id),
|
||||||
|
document_id UUID NOT NULL REFERENCES documents.documents(id),
|
||||||
|
version_id UUID REFERENCES documents.document_versions(id),
|
||||||
|
|
||||||
|
-- Estado
|
||||||
|
status documents.workflow_status NOT NULL DEFAULT 'draft',
|
||||||
|
current_step INTEGER DEFAULT 1,
|
||||||
|
total_steps INTEGER NOT NULL,
|
||||||
|
|
||||||
|
-- Fechas
|
||||||
|
started_at TIMESTAMPTZ,
|
||||||
|
completed_at TIMESTAMPTZ,
|
||||||
|
due_date TIMESTAMPTZ,
|
||||||
|
|
||||||
|
-- Iniciador
|
||||||
|
initiated_by_id UUID,
|
||||||
|
initiated_by_name VARCHAR(255),
|
||||||
|
|
||||||
|
-- Resultado final
|
||||||
|
final_action documents.approval_action,
|
||||||
|
final_comments TEXT,
|
||||||
|
final_approver_id UUID,
|
||||||
|
|
||||||
|
-- Notas
|
||||||
|
notes TEXT,
|
||||||
|
metadata JSONB,
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 7. Pasos de Aprobacion (Instancias)
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.approval_steps (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Instancia
|
||||||
|
instance_id UUID NOT NULL REFERENCES documents.approval_instances(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
-- Paso
|
||||||
|
step_number INTEGER NOT NULL,
|
||||||
|
step_name VARCHAR(255) NOT NULL,
|
||||||
|
step_type documents.approval_step_type NOT NULL,
|
||||||
|
|
||||||
|
-- Aprobadores requeridos
|
||||||
|
required_approvers UUID[], -- IDs de usuarios requeridos
|
||||||
|
required_count INTEGER DEFAULT 1, -- Cuantas aprobaciones se necesitan
|
||||||
|
|
||||||
|
-- Estado
|
||||||
|
status documents.workflow_status NOT NULL DEFAULT 'pending',
|
||||||
|
|
||||||
|
-- Fechas
|
||||||
|
started_at TIMESTAMPTZ,
|
||||||
|
completed_at TIMESTAMPTZ,
|
||||||
|
due_date TIMESTAMPTZ,
|
||||||
|
|
||||||
|
-- Resultado
|
||||||
|
action_taken documents.approval_action,
|
||||||
|
approved_by UUID[],
|
||||||
|
rejected_by UUID[],
|
||||||
|
|
||||||
|
-- Notas
|
||||||
|
notes TEXT,
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 8. Acciones de Aprobacion
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.approval_actions (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Paso
|
||||||
|
step_id UUID NOT NULL REFERENCES documents.approval_steps(id) ON DELETE CASCADE,
|
||||||
|
instance_id UUID NOT NULL REFERENCES documents.approval_instances(id),
|
||||||
|
|
||||||
|
-- Accion
|
||||||
|
action documents.approval_action NOT NULL,
|
||||||
|
comments TEXT,
|
||||||
|
|
||||||
|
-- Usuario que toma la accion
|
||||||
|
user_id UUID NOT NULL,
|
||||||
|
user_name VARCHAR(255),
|
||||||
|
|
||||||
|
-- Firma digital (si aplica)
|
||||||
|
signature_data TEXT,
|
||||||
|
signature_timestamp TIMESTAMPTZ,
|
||||||
|
signature_ip VARCHAR(45),
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 9. Anotaciones sobre Documentos
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.annotations (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Documento y version
|
||||||
|
document_id UUID NOT NULL REFERENCES documents.documents(id) ON DELETE CASCADE,
|
||||||
|
version_id UUID REFERENCES documents.document_versions(id),
|
||||||
|
|
||||||
|
-- Tipo
|
||||||
|
annotation_type documents.annotation_type NOT NULL,
|
||||||
|
|
||||||
|
-- Ubicacion en el documento
|
||||||
|
page_number INTEGER,
|
||||||
|
x_position DECIMAL(10,4),
|
||||||
|
y_position DECIMAL(10,4),
|
||||||
|
width DECIMAL(10,4),
|
||||||
|
height DECIMAL(10,4),
|
||||||
|
rotation DECIMAL(5,2),
|
||||||
|
|
||||||
|
-- Contenido
|
||||||
|
content TEXT, -- Texto del comentario o SVG del dibujo
|
||||||
|
style JSONB, -- Estilos (color, grosor, fuente, etc.)
|
||||||
|
|
||||||
|
-- Respuesta a otra anotacion
|
||||||
|
parent_annotation_id UUID REFERENCES documents.annotations(id),
|
||||||
|
|
||||||
|
-- Estado
|
||||||
|
is_resolved BOOLEAN DEFAULT FALSE,
|
||||||
|
resolved_by_id UUID,
|
||||||
|
resolved_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
-- Visibilidad
|
||||||
|
is_private BOOLEAN DEFAULT FALSE,
|
||||||
|
visible_to UUID[], -- Array de user_ids si es privado
|
||||||
|
|
||||||
|
-- Autor
|
||||||
|
author_id UUID NOT NULL,
|
||||||
|
author_name VARCHAR(255),
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
deleted_at TIMESTAMPTZ
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 10. Historial de Acceso a Documentos
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.access_logs (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Documento
|
||||||
|
document_id UUID NOT NULL REFERENCES documents.documents(id),
|
||||||
|
version_id UUID REFERENCES documents.document_versions(id),
|
||||||
|
|
||||||
|
-- Accion
|
||||||
|
action VARCHAR(50) NOT NULL, -- view, download, print, share, edit
|
||||||
|
action_details JSONB,
|
||||||
|
|
||||||
|
-- Usuario
|
||||||
|
user_id UUID NOT NULL,
|
||||||
|
user_name VARCHAR(255),
|
||||||
|
user_ip VARCHAR(45),
|
||||||
|
user_agent TEXT,
|
||||||
|
|
||||||
|
-- Contexto
|
||||||
|
session_id VARCHAR(100),
|
||||||
|
request_source VARCHAR(50), -- web, mobile, api
|
||||||
|
|
||||||
|
-- Timestamp
|
||||||
|
accessed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
-- 11. Compartidos Externos
|
||||||
|
-- ----------------------------------------------------------------------------
|
||||||
|
CREATE TABLE documents.document_shares (
|
||||||
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
tenant_id UUID NOT NULL,
|
||||||
|
|
||||||
|
-- Documento
|
||||||
|
document_id UUID NOT NULL REFERENCES documents.documents(id) ON DELETE CASCADE,
|
||||||
|
version_id UUID REFERENCES documents.document_versions(id),
|
||||||
|
|
||||||
|
-- Link compartido
|
||||||
|
share_token VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
share_url VARCHAR(2000),
|
||||||
|
|
||||||
|
-- Destinatario
|
||||||
|
shared_with_email VARCHAR(255),
|
||||||
|
shared_with_name VARCHAR(255),
|
||||||
|
|
||||||
|
-- Permisos
|
||||||
|
can_download BOOLEAN DEFAULT FALSE,
|
||||||
|
can_comment BOOLEAN DEFAULT FALSE,
|
||||||
|
|
||||||
|
-- Seguridad
|
||||||
|
password_hash VARCHAR(255), -- Si requiere password
|
||||||
|
max_downloads INTEGER,
|
||||||
|
download_count INTEGER DEFAULT 0,
|
||||||
|
|
||||||
|
-- Vigencia
|
||||||
|
expires_at TIMESTAMPTZ,
|
||||||
|
is_revoked BOOLEAN DEFAULT FALSE,
|
||||||
|
revoked_at TIMESTAMPTZ,
|
||||||
|
revoked_by_id UUID,
|
||||||
|
|
||||||
|
-- Compartido por
|
||||||
|
shared_by_id UUID NOT NULL,
|
||||||
|
shared_by_name VARCHAR(255),
|
||||||
|
|
||||||
|
-- Notificacion
|
||||||
|
notification_sent BOOLEAN DEFAULT FALSE,
|
||||||
|
notification_sent_at TIMESTAMPTZ,
|
||||||
|
|
||||||
|
-- Auditoria
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||||
|
last_accessed_at TIMESTAMPTZ
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- INDICES
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Document Categories
|
||||||
|
CREATE INDEX idx_document_categories_tenant ON documents.document_categories(tenant_id);
|
||||||
|
CREATE INDEX idx_document_categories_parent ON documents.document_categories(parent_id);
|
||||||
|
|
||||||
|
-- Documents
|
||||||
|
CREATE INDEX idx_documents_tenant ON documents.documents(tenant_id);
|
||||||
|
CREATE INDEX idx_documents_tenant_category ON documents.documents(tenant_id, category_id);
|
||||||
|
CREATE INDEX idx_documents_tenant_type ON documents.documents(tenant_id, document_type);
|
||||||
|
CREATE INDEX idx_documents_tenant_status ON documents.documents(tenant_id, status);
|
||||||
|
CREATE INDEX idx_documents_tenant_project ON documents.documents(tenant_id, project_id);
|
||||||
|
CREATE INDEX idx_documents_keywords ON documents.documents USING gin(keywords);
|
||||||
|
CREATE INDEX idx_documents_tags ON documents.documents USING gin(tags);
|
||||||
|
CREATE INDEX idx_documents_fulltext ON documents.documents USING gin(
|
||||||
|
to_tsvector('spanish', coalesce(title, '') || ' ' || coalesce(description, ''))
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Document Versions
|
||||||
|
CREATE INDEX idx_document_versions_tenant ON documents.document_versions(tenant_id);
|
||||||
|
CREATE INDEX idx_document_versions_document ON documents.document_versions(document_id);
|
||||||
|
CREATE INDEX idx_document_versions_status ON documents.document_versions(status);
|
||||||
|
|
||||||
|
-- Document Permissions
|
||||||
|
CREATE INDEX idx_document_permissions_document ON documents.document_permissions(document_id);
|
||||||
|
CREATE INDEX idx_document_permissions_category ON documents.document_permissions(category_id);
|
||||||
|
CREATE INDEX idx_document_permissions_user ON documents.document_permissions(user_id);
|
||||||
|
CREATE INDEX idx_document_permissions_role ON documents.document_permissions(role_id);
|
||||||
|
|
||||||
|
-- Approval Workflows
|
||||||
|
CREATE INDEX idx_approval_workflows_tenant ON documents.approval_workflows(tenant_id);
|
||||||
|
CREATE INDEX idx_approval_workflows_category ON documents.approval_workflows(category_id);
|
||||||
|
|
||||||
|
-- Approval Instances
|
||||||
|
CREATE INDEX idx_approval_instances_tenant ON documents.approval_instances(tenant_id);
|
||||||
|
CREATE INDEX idx_approval_instances_document ON documents.approval_instances(document_id);
|
||||||
|
CREATE INDEX idx_approval_instances_status ON documents.approval_instances(status);
|
||||||
|
|
||||||
|
-- Approval Steps
|
||||||
|
CREATE INDEX idx_approval_steps_instance ON documents.approval_steps(instance_id);
|
||||||
|
CREATE INDEX idx_approval_steps_status ON documents.approval_steps(status);
|
||||||
|
|
||||||
|
-- Approval Actions
|
||||||
|
CREATE INDEX idx_approval_actions_step ON documents.approval_actions(step_id);
|
||||||
|
CREATE INDEX idx_approval_actions_user ON documents.approval_actions(user_id);
|
||||||
|
|
||||||
|
-- Annotations
|
||||||
|
CREATE INDEX idx_annotations_tenant ON documents.annotations(tenant_id);
|
||||||
|
CREATE INDEX idx_annotations_document ON documents.annotations(document_id);
|
||||||
|
CREATE INDEX idx_annotations_version ON documents.annotations(version_id);
|
||||||
|
CREATE INDEX idx_annotations_author ON documents.annotations(author_id);
|
||||||
|
|
||||||
|
-- Access Logs
|
||||||
|
CREATE INDEX idx_access_logs_tenant ON documents.access_logs(tenant_id);
|
||||||
|
CREATE INDEX idx_access_logs_document ON documents.access_logs(document_id);
|
||||||
|
CREATE INDEX idx_access_logs_user ON documents.access_logs(user_id);
|
||||||
|
CREATE INDEX idx_access_logs_accessed ON documents.access_logs(accessed_at);
|
||||||
|
|
||||||
|
-- Document Shares
|
||||||
|
CREATE INDEX idx_document_shares_tenant ON documents.document_shares(tenant_id);
|
||||||
|
CREATE INDEX idx_document_shares_document ON documents.document_shares(document_id);
|
||||||
|
CREATE INDEX idx_document_shares_token ON documents.document_shares(share_token);
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- ROW LEVEL SECURITY (RLS)
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
ALTER TABLE documents.document_categories ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.documents ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.document_versions ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.document_permissions ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.approval_workflows ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.approval_instances ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.approval_steps ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.approval_actions ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.annotations ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.access_logs ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE documents.document_shares ENABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- TRIGGERS DE AUDITORIA
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION documents.set_updated_at()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
NEW.updated_at = NOW();
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_document_categories_updated_at
|
||||||
|
BEFORE UPDATE ON documents.document_categories
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.set_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_documents_updated_at
|
||||||
|
BEFORE UPDATE ON documents.documents
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.set_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_document_permissions_updated_at
|
||||||
|
BEFORE UPDATE ON documents.document_permissions
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.set_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_approval_workflows_updated_at
|
||||||
|
BEFORE UPDATE ON documents.approval_workflows
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.set_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_approval_instances_updated_at
|
||||||
|
BEFORE UPDATE ON documents.approval_instances
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.set_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_approval_steps_updated_at
|
||||||
|
BEFORE UPDATE ON documents.approval_steps
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.set_updated_at();
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_annotations_updated_at
|
||||||
|
BEFORE UPDATE ON documents.annotations
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.set_updated_at();
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- FUNCIONES AUXILIARES
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
-- Actualizar version actual del documento
|
||||||
|
CREATE OR REPLACE FUNCTION documents.update_current_version()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
IF NEW.status = 'current' THEN
|
||||||
|
-- Marcar versiones anteriores como superseded
|
||||||
|
UPDATE documents.document_versions
|
||||||
|
SET status = 'superseded',
|
||||||
|
superseded_at = NOW(),
|
||||||
|
superseded_by_version_id = NEW.id
|
||||||
|
WHERE document_id = NEW.document_id
|
||||||
|
AND id != NEW.id
|
||||||
|
AND status = 'current';
|
||||||
|
|
||||||
|
-- Actualizar documento con version actual
|
||||||
|
UPDATE documents.documents
|
||||||
|
SET current_version_id = NEW.id,
|
||||||
|
current_version_number = NEW.version_number,
|
||||||
|
updated_at = NOW()
|
||||||
|
WHERE id = NEW.document_id;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_update_current_version
|
||||||
|
AFTER INSERT OR UPDATE ON documents.document_versions
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.update_current_version();
|
||||||
|
|
||||||
|
-- Incrementar contador de vistas
|
||||||
|
CREATE OR REPLACE FUNCTION documents.increment_view_count()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
BEGIN
|
||||||
|
IF NEW.action = 'view' THEN
|
||||||
|
UPDATE documents.documents
|
||||||
|
SET view_count = view_count + 1,
|
||||||
|
last_accessed_at = NOW()
|
||||||
|
WHERE id = NEW.document_id;
|
||||||
|
ELSIF NEW.action = 'download' THEN
|
||||||
|
UPDATE documents.documents
|
||||||
|
SET download_count = download_count + 1,
|
||||||
|
last_accessed_at = NOW()
|
||||||
|
WHERE id = NEW.document_id;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_increment_view_count
|
||||||
|
AFTER INSERT ON documents.access_logs
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.increment_view_count();
|
||||||
|
|
||||||
|
-- Actualizar path de categoria
|
||||||
|
CREATE OR REPLACE FUNCTION documents.update_category_path()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
DECLARE
|
||||||
|
v_parent_path VARCHAR(500);
|
||||||
|
BEGIN
|
||||||
|
IF NEW.parent_id IS NULL THEN
|
||||||
|
NEW.path := '/' || NEW.code;
|
||||||
|
NEW.level := 1;
|
||||||
|
ELSE
|
||||||
|
SELECT path, level + 1 INTO v_parent_path, NEW.level
|
||||||
|
FROM documents.document_categories
|
||||||
|
WHERE id = NEW.parent_id;
|
||||||
|
|
||||||
|
NEW.path := v_parent_path || '/' || NEW.code;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN NEW;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE TRIGGER trg_update_category_path
|
||||||
|
BEFORE INSERT OR UPDATE ON documents.document_categories
|
||||||
|
FOR EACH ROW EXECUTE FUNCTION documents.update_category_path();
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- COMENTARIOS DE DOCUMENTACION
|
||||||
|
-- ============================================================================
|
||||||
|
|
||||||
|
COMMENT ON SCHEMA documents IS 'Modulo de Gestion Documental (MAE-016) - ERP Construccion';
|
||||||
|
|
||||||
|
COMMENT ON TABLE documents.document_categories IS 'Categorias jerarquicas para clasificar documentos';
|
||||||
|
COMMENT ON TABLE documents.documents IS 'Registro principal de documentos';
|
||||||
|
COMMENT ON TABLE documents.document_versions IS 'Versiones de documentos con archivos';
|
||||||
|
COMMENT ON TABLE documents.document_permissions IS 'Permisos granulares por documento o categoria';
|
||||||
|
COMMENT ON TABLE documents.approval_workflows IS 'Definicion de flujos de aprobacion';
|
||||||
|
COMMENT ON TABLE documents.approval_instances IS 'Instancias de flujos de aprobacion activos';
|
||||||
|
COMMENT ON TABLE documents.approval_steps IS 'Pasos de aprobacion por instancia';
|
||||||
|
COMMENT ON TABLE documents.approval_actions IS 'Acciones tomadas en pasos de aprobacion';
|
||||||
|
COMMENT ON TABLE documents.annotations IS 'Anotaciones y comentarios sobre documentos';
|
||||||
|
COMMENT ON TABLE documents.access_logs IS 'Historial de acceso a documentos';
|
||||||
|
COMMENT ON TABLE documents.document_shares IS 'Links de compartido externo';
|
||||||
|
|
||||||
|
-- ============================================================================
|
||||||
|
-- FIN DEL SCRIPT
|
||||||
|
-- ============================================================================
|
||||||
Loading…
Reference in New Issue
Block a user