ImagFlow — Modelo de Datos
Base de Datos
- Nombre:
imagy_flow - Usuario:
imagy_flow_app(NOBYPASSRLS) - RLS: Habilitado en todas las tablas con
tenant_id
Diagrama ER
Tablas
flows
Definicion de un flujo (metadata, no la configuracion de pasos).
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
name | VARCHAR(255) | Nombre del flujo |
slug | VARCHAR(100) UNIQUE | Slug URL-friendly |
description | TEXT | Descripcion |
is_template | BOOLEAN | Si es un template reutilizable |
template_category | VARCHAR(100) | Categoria del template (nullable) |
source_flow_id | UUID FK | Flujo origen si fue duplicado (nullable) |
is_active | BOOLEAN | Si esta activo |
row_version | INT | Concurrencia optimista |
created_at | TIMESTAMPTZ | Fecha de creacion |
updated_at | TIMESTAMPTZ | Ultima modificacion |
created_by | UUID | Actor que lo creo |
Nota: Esta tabla NO tiene tenant_id — los flujos son globales (creados por platform admin). La asignacion a tenants se hace via flow_assignments.
flow_versions
Version inmutable de un flujo con toda su configuracion.
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
flow_id | UUID FK | Flujo padre |
version_number | INT | Numero secuencial (1, 2, 3...) |
status | VARCHAR(20) | draft, published, archived, discarded |
metadata | JSONB | Metadata adicional |
row_version | INT | Concurrencia optimista |
created_at | TIMESTAMPTZ | Fecha de creacion |
published_at | TIMESTAMPTZ | Cuando se publico (nullable) |
archived_at | TIMESTAMPTZ | Cuando se archivo (nullable) |
published_by | UUID | Quien publico (nullable) |
flow_steps
Pasos configurados en una version del flujo.
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
flow_version_id | UUID FK | Version del flujo |
step_order | INT | Orden de ejecucion (1, 2, 3...) |
step_type | VARCHAR(50) | form, liveness, card_capture, signature, validation, custom |
name | VARCHAR(255) | Nombre del paso |
description | TEXT | Descripcion |
provider_config_id | UUID FK | Proveedor a usar (nullable para form) |
step_config | JSONB | Configuracion especifica del tipo de paso |
max_attempts | INT | Reintentos permitidos (default 1) |
cooldown_seconds | INT | Espera entre reintentos (default 0) |
flow_rules
Reglas de decision configuradas en una version.
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
flow_version_id | UUID FK | Version del flujo |
evaluation_order | INT | Orden de evaluacion |
name | VARCHAR(255) | Nombre de la regla |
description | TEXT | Descripcion |
condition | JSONB | Expresion evaluable (ver estructura de condiciones) |
action_type | VARCHAR(50) | approve, reject, flag, notify, escalate |
action_config | JSONB | Configuracion de la accion |
is_active | BOOLEAN | Si esta activa |
provider_configs
Configuracion de proveedores externos.
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
service_type | VARCHAR(50) | liveness, ocr, biometric, signature, demographic, registry, sms, storage |
provider_name | VARCHAR(255) | Nombre legible |
provider_code | VARCHAR(100) UNIQUE | Codigo unico del proveedor |
connection_config | JSONB | Configuracion de conexion (encrypted) |
failover_provider_id | UUID FK | Proveedor de failover (nullable) |
failover_conditions | JSONB | Condiciones para activar failover |
is_active | BOOLEAN | Si esta activo |
row_version | INT | Concurrencia optimista |
created_at | TIMESTAMPTZ | Fecha de creacion |
Nota: connection_config contiene API keys y secrets. Se almacena cifrado (KMS) y solo el Provider Gateway puede descifrarlo.
flow_assignments
Asignacion de flujos publicados a tenants/organizaciones.
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
tenant_id | UUID | Tenant al que se asigna (RLS) |
organization_id | UUID | Organizacion especifica (nullable = todo el tenant) |
flow_id | UUID FK | Flujo asignado |
flow_version_id | UUID FK | Version especifica asignada |
is_active | BOOLEAN | Si la asignacion esta activa |
assigned_at | TIMESTAMPTZ | Fecha de asignacion |
assigned_by | UUID | Quien asigno |
requests
Solicitudes (instancias de ejecucion de un flujo).
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
tenant_id | UUID | Tenant (RLS) |
organization_id | UUID | Organizacion (nullable) |
flow_version_id | UUID FK | Version del flujo que se ejecuta |
status | VARCHAR(30) | Estado actual del ciclo de vida |
access_token | VARCHAR(255) UNIQUE | Token para acceso publico |
subject_data | JSONB | Datos del sujeto (identificador, nombre) |
metadata | JSONB | Metadata adicional (origen, canal) |
row_version | INT | Concurrencia optimista |
created_at | TIMESTAMPTZ | Fecha de creacion |
expires_at | TIMESTAMPTZ | Fecha de expiracion |
completed_at | TIMESTAMPTZ | Fecha de completado (nullable) |
request_attempts
Intentos de ejecucion de cada paso.
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
request_id | UUID FK | Solicitud padre |
step_id | UUID FK | Paso ejecutado |
attempt_number | INT | Numero de intento (1, 2, 3...) |
status | VARCHAR(20) | success, failure, timeout |
request_data | JSONB | Datos enviados al proveedor |
response_data | JSONB | Respuesta del proveedor |
provider_code | VARCHAR(100) | Proveedor usado (puede ser failover) |
duration_ms | INT | Duracion en milisegundos |
created_at | TIMESTAMPTZ | Timestamp del intento |
enrichment_results
Resultados de procesos asincronos (post-captura).
| Columna | Tipo | Descripcion |
|---|---|---|
id | UUID PK | Identificador unico |
request_id | UUID FK | Solicitud padre |
process_type | VARCHAR(50) | ocr, biometric_match, demographic, signature |
status | VARCHAR(20) | pending, processing, completed, failed |
provider_code | VARCHAR(100) | Proveedor que proceso |
result_data | JSONB | Resultado del procesamiento |
duration_ms | INT | Duracion en milisegundos |
created_at | TIMESTAMPTZ | Cuando se creo |
completed_at | TIMESTAMPTZ | Cuando se completo (nullable) |
Tablas de Soporte
idempotency_keys
CREATE TABLE idempotency_keys (
key VARCHAR(255) NOT NULL,
tenant_id UUID NOT NULL,
response_status INT NOT NULL,
response_body JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + INTERVAL '24 hours',
PRIMARY KEY (key, tenant_id)
);processed_events
CREATE TABLE processed_events (
event_id UUID PRIMARY KEY,
event_type VARCHAR(100) NOT NULL,
processed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
source VARCHAR(100) NOT NULL
);RLS Policies
-- Tablas globales (sin RLS): flows, flow_versions, flow_steps, flow_rules,
-- flow_async_processes, flow_notification_configs, provider_configs
-- Razon: son gestionadas por platform admin, no pertenecen a un tenant
-- Tablas con RLS (por tenant):
ALTER TABLE flow_assignments ENABLE ROW LEVEL SECURITY;
ALTER TABLE requests ENABLE ROW LEVEL SECURITY;
ALTER TABLE request_attempts ENABLE ROW LEVEL SECURITY;
ALTER TABLE enrichment_results ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON flow_assignments
FOR ALL USING (tenant_id = get_current_tenant_id());
CREATE POLICY tenant_isolation ON requests
FOR ALL USING (tenant_id = get_current_tenant_id());
-- Control plane (platform admin sin tenant context)
CREATE POLICY control_plane ON flow_assignments
FOR ALL USING (
current_setting('app.current_tenant_id', true) IS NULL
OR current_setting('app.current_tenant_id', true) = ''
);Indices
-- Busqueda de flujos
CREATE INDEX idx_flows_slug ON flows(slug);
CREATE INDEX idx_flows_template ON flows(is_template) WHERE is_template = true;
-- Busqueda de versiones
CREATE INDEX idx_flow_versions_flow_status ON flow_versions(flow_id, status);
-- Busqueda de solicitudes
CREATE INDEX idx_requests_tenant_status ON requests(tenant_id, status);
CREATE INDEX idx_requests_access_token ON requests(access_token);
CREATE INDEX idx_requests_expires ON requests(expires_at) WHERE status IN ('created', 'in_progress');
-- Busqueda de asignaciones
CREATE INDEX idx_flow_assignments_tenant ON flow_assignments(tenant_id, is_active);
-- Limpieza
CREATE INDEX idx_idempotency_expires ON idempotency_keys(expires_at);
CREATE INDEX idx_processed_events_date ON processed_events(processed_at);Sesion de Ejecucion (Valkey)
La sesion de ejecucion se almacena en Valkey (no en PostgreSQL) para acceso rapido:
{
"key": "tenant:{tenant_id}:execution:{access_token}",
"ttl": "matches request.expires_at",
"value": {
"request_id": "uuid",
"flow_version_id": "uuid",
"current_step_index": 2,
"steps": [
{
"step_id": "uuid",
"step_type": "liveness",
"status": "completed",
"attempts_used": 1,
"max_attempts": 3
},
{
"step_id": "uuid",
"step_type": "card_capture",
"status": "in_progress",
"attempts_used": 0,
"max_attempts": 3
}
],
"started_at": "2026-05-18T10:30:00Z",
"version": 5
}
}version: para optimistic locking (previene doble-ejecucion concurrente)ttl: se sincroniza conrequest.expires_at- Se crea al primer acceso del usuario final
- Se elimina al completar o expirar