Agrego carpeta del source sql de la Base de Datos

This commit is contained in:
Pablo
2026-08-22 19:10:49 -03:00
parent 11e36bd6c2
commit 88d724fbcf
94 changed files with 7820 additions and 0 deletions
@@ -0,0 +1,14 @@
-- ============================================================================
-- internal.app_config
-- ============================================================================
-- Configuración runtime del sistema. Pares clave/valor (ambos TEXT).
-- Lee internal.get_config_int y fc_obtener_config.
-- ============================================================================
CREATE TABLE internal.app_config (
clave text NOT NULL,
valor text NOT NULL,
descripcion text,
actualizado_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT app_config_pkey PRIMARY KEY (clave)
);
@@ -0,0 +1,72 @@
-- ============================================================================
-- internal.archivo_exports
-- ============================================================================
-- Bitácora de control del pipeline mensual de archivado
-- (Documentation/PoliticaRetencion.md §5.3). Cada fila registra un intento
-- de archivar una entidad para un mes objetivo: su resultado, cuándo
-- ocurrió y, si falló, el detalle del error.
--
-- Cumple tres roles:
-- - IDEMPOTENCIA: el unique parcial garantiza que no haya dos archivados
-- `ok` para el mismo (anio_mes_target, tipo). Si la corrida mensual se
-- repite (reintento, doble disparo del cron), el segundo `ok` choca y
-- no se duplica el archivado ni el DELETE posterior.
-- - REINTENTO: una fila `fallo` deja registrado el mes pendiente; la
-- corrida siguiente puede detectar que ese mes no tiene `ok` y
-- reprocesarlo (los meses pendientes tienen prioridad — §5.2).
-- - VISIBILIDAD: la vista admin (US-R21) lee esta tabla vía
-- public.fc_obtener_estado_archivo.
--
-- COLUMNAS
-- anio_mes_target DATE (día 1 del mes archivado). NULLABLE a propósito:
-- durante el primer año de vida del sistema ningún pago
-- cumple 12 meses, así que la corrida de pagos archiva
-- "nada" y registra `ok` con target NULL (§4.3, US-R17).
-- Los NULL son distintos entre sí en el unique parcial,
-- de modo que esas corridas vacías no se bloquean entre
-- ellas — son no-ops inofensivos.
-- tipo 'pagos' | 'agregado_reservas'. Las dos cosas que se
-- archivan (§3); cada una lleva su propia fila por mes.
-- ejecutado_en timestamptz del intento (default now()).
-- resultado 'ok' | 'fallo'.
-- detalle_error texto libre del error cuando resultado = 'fallo';
-- NULL en los `ok`.
--
-- AUTORIZACIÓN
-- Tabla en el schema `internal`, no alcanzable por roles cliente
-- (hardening en 00_schemas.sql). Escribe el pipeline (US-R17); lee la
-- fachada public.fc_obtener_estado_archivo (SECURITY DEFINER).
--
-- DEPENDE DE
-- Nada (sin FKs). Nivel 0 en apply.sh.
-- ============================================================================
CREATE TABLE internal.archivo_exports (
id integer GENERATED ALWAYS AS IDENTITY (
SEQUENCE NAME internal.archivo_exports_id_seq
START WITH 1 INCREMENT BY 1
NO MINVALUE NO MAXVALUE CACHE 1
) NOT NULL,
anio_mes_target date,
tipo text NOT NULL,
ejecutado_en timestamp with time zone DEFAULT now() NOT NULL,
resultado text NOT NULL,
detalle_error text,
CONSTRAINT archivo_exports_pkey PRIMARY KEY (id),
CONSTRAINT archivo_exports_tipo_check
CHECK (tipo IN ('pagos', 'agregado_reservas')),
CONSTRAINT archivo_exports_resultado_check
CHECK (resultado IN ('ok', 'fallo'))
);
-- Idempotencia: a lo sumo un `ok` por (mes, tipo). Parcial sobre 'ok' para
-- que los reintentos fallidos no cuenten y puedan repetirse hasta lograrlo.
CREATE UNIQUE INDEX archivo_exports_ok_unico
ON internal.archivo_exports (anio_mes_target, tipo)
WHERE resultado = 'ok';
-- Para listar fallos recientes y barrer pendientes por mes.
CREATE INDEX idx_archivo_exports_target_tipo
ON internal.archivo_exports (anio_mes_target, tipo, ejecutado_en DESC);
ALTER TABLE internal.archivo_exports ENABLE ROW LEVEL SECURITY;
@@ -0,0 +1,21 @@
-- ============================================================================
-- internal.permisos
-- ============================================================================
-- Matriz de autorización. Cada fila es una acción posible del sistema y
-- el array de roles que la pueden ejecutar. La consulta canónica está en
-- internal.validate_permission.
-- ============================================================================
CREATE TABLE internal.permisos (
id integer GENERATED ALWAYS AS IDENTITY (
SEQUENCE NAME internal.permisos_id_permiso_seq
START WITH 1 INCREMENT BY 1
NO MINVALUE NO MAXVALUE CACHE 1
) NOT NULL,
accion text NOT NULL,
roles_permitidos text[] NOT NULL,
CONSTRAINT permisos_pkey PRIMARY KEY (id),
CONSTRAINT permisos_accion_key UNIQUE (accion)
);
ALTER TABLE internal.permisos ENABLE ROW LEVEL SECURITY;
@@ -0,0 +1,31 @@
-- ============================================================================
-- internal.sesiones
-- ============================================================================
-- Sesiones activas. Cada usuario tiene a lo sumo una sesión vigente; el
-- trigger trg_clean_old_sessions (definido en triggers/auth/) lo garantiza
-- al insertar.
--
-- DEPENDE DE
-- public.usuarios
-- ============================================================================
CREATE TABLE internal.sesiones (
id uuid DEFAULT gen_random_uuid() NOT NULL,
usuario_id uuid NOT NULL,
token uuid NOT NULL,
expires_at timestamp with time zone NOT NULL,
CONSTRAINT sessions_pkey PRIMARY KEY (id),
CONSTRAINT sessions_usuario_id_fkey
FOREIGN KEY (usuario_id) REFERENCES public.usuarios(id)
);
CREATE INDEX idx_sesiones_token
ON internal.sesiones USING btree (token);
CREATE INDEX idx_sesiones_token_expires
ON internal.sesiones USING btree (token, expires_at);
CREATE INDEX idx_sesiones_usuario_expires
ON internal.sesiones USING btree (usuario_id, expires_at);
ALTER TABLE internal.sesiones ENABLE ROW LEVEL SECURITY;