Un flujo de n8n que orquesta el ciclo de un litigation hold: emite el aviso por correo y Slack a los custodios designados, hace seguimiento de los acuses con recordatorios en una cadencia configurable, escala los casos sin acuse al responsable de legal-ops y al manager del custodio, y registra cada acción en una tabla de auditoría inmutable que el despacho usa si más tarde se cuestiona la suficiencia del hold. Reemplaza el ciclo manual del admin de legal-ops a base de hojas de cálculo y reglas de Outlook (típicamente una carga continua de 2 a 4 horas por semana cuando hay varios holds activos) por un flujo determinista que no puede dejar fuera a un custodio.
Cuándo usarlo
El despacho emite litigation holds con una frecuencia en la que el seguimiento manual empieza a fallar — usualmente >3 holds activos en cualquier momento.
Tienes una fuente de custodios oficial: una tabla de gestión de custodios en la plataforma de e-discovery (Relativity, Everlaw, Logikcull) o un CSV mantenido por legal-ops.
El despacho necesita un audit trail defendible sobre la suficiencia del hold. La tabla de auditoría del flujo es la respuesta a “demuéstrennos que actuaron razonablemente para preservar”.
El responsable de legal-ops y el outside counsel autorizan la emisión del hold; el flujo gestiona el seguimiento continuo, no la decisión de emitir.
Cuándo NO usarlo
Asuntos con un solo hold donde el seguimiento manual basta. El costo de setup (120 minutos, más la integración con la fuente de custodios) se amortiza alrededor de los ~3 holds activos, no con uno.
Auto-escalación que pasa por encima del counsel. Las rutas de escalación del flujo son configurables, pero por defecto envían al responsable de legal-ops, NO directamente al GC ni al outside counsel. El responsable aplica criterio sobre qué casos sin acuse ameritan atención del counsel.
Avisos de hold que requieren lenguaje a medida por custodio. El flujo plantilla por matter; si cada aviso necesita lenguaje hecho a mano, el cuello de botella no es la orquestación.
Sustituir el criterio del counsel sobre el alcance del hold. El flujo hace seguimiento del hold a los custodios que designó el counsel. Agregar o quitar custodios es una decisión de counsel, no del flujo.
Setup
Importa el flujo. Coloca apps/web/public/artifacts/litigation-hold-orchestration-n8n/litigation-hold-orchestration-n8n.json en tu instancia de n8n.
Conecta credenciales. Cuatro requeridas: PLACEHOLDER_CUSTODIAN_DB_CRED_ID (acceso de lectura a la fuente de custodios), PLACEHOLDER_SMTP_CRED_ID (SMTP para el correo del aviso), PLACEHOLDER_SLACK_CRED_ID (Slack para la notificación in-channel), PLACEHOLDER_AUDIT_DB_CRED_ID (acceso de escritura a la tabla de auditoría inmutable).
Redacta la plantilla del aviso de hold. Por matter, escribe una plantilla en Markdown bajo n8n/data/hold-notices/<matter-id>.md. La plantilla incluye lenguaje aprobado por counsel sobre el alcance de preservación, las acciones prohibidas (eliminación, alteración) y las instrucciones de acuse.
Configura las rutas de escalación. Por defecto: recordatorio en +3, +7, +14 días; escalación al responsable de legal-ops en +14; escalación al manager del custodio en +21. Ajusta según la postura de riesgo del despacho.
Levanta la tabla de auditoría. Una tabla en Postgres / Snowflake con clave en (hold_id, custodian_id, action, timestamp) y un constraint append-only impuesto a nivel de DB (inmutable; el counsel necesita poder demostrar que el audit log no se puede editar de forma retroactiva).
Dry-run sobre un hold cerrado. Reproduce la lista de custodios de un hold cerrado. Confirma que los tiempos de notificación, recordatorio y escalación coinciden con lo que el admin de legal-ops hacía manualmente.
Qué hace el flujo
Siete nodos, en dos fases. Fase 1 (emisión) se dispara una vez por hold. Fase 2 (seguimiento) es un cron diario que revisa los casos sin acuse y dispara recordatorios / escalaciones.
Issue Trigger — disparador manual o webhook desde la plataforma de legal-ops cuando counsel marca un hold como listo para emitir.
Load Custodian List — obtiene la lista de custodios desde la fuente configurada para el matter.
Send Hold Notice — correo + Slack a cada custodio. El correo incluye la plantilla del aviso y un enlace de acuse único por custodio. Audit log: una fila por custodio por notice_sent.
Daily Cron Tracker (workflow trigger separado) — lunes a viernes a las 9am en la TZ de la oficina. Revisa la tabla de auditoría buscando custodios que no han acusado dentro de la ventana configurada.
Determine Action — nodo Code. Para cada custodio sin acuse, determina: enviar recordatorio (en +3, +7), escalar al responsable de legal-ops (en +14), escalar al manager (en +21).
Dispatch Reminder / Escalation — envía el recordatorio o la escalación, según la acción determinada. Una entrada en el audit log por envío.
Acknowledgement Webhook — webhook separado que recibe el clic de acuse del custodio. Registra en la tabla de auditoría; detiene los recordatorios siguientes para ese custodio.
Realidad de costos
Costo de n8n — self-hosted gratis; n8n Cloud al volumen de ejecuciones que esto genera (~3-5/día por hold activo) cabe cómodamente en el plan Starter.
Tokens de LLM — ninguno. El flujo es determinista.
SMTP / Slack — dentro de cuotas estándar.
Tiempo del admin de legal-ops — la ganancia. El seguimiento manual de 5 a 10 holds activos es de 4 a 8 horas/semana. Operar el flujo es monitorear la tabla de auditoría por excepciones reales, ~30 min/semana.
Tiempo de setup — 120 minutos incluyendo el aprovisionamiento de la tabla de auditoría, más 30 a 60 minutos por matter para la redacción de la plantilla del aviso.
Métrica de éxito
Tiempo de emisión desde la decisión “issue” del counsel — debería bajar a menos de 1 hora (manualmente suele tomar un día para listas grandes de custodios).
Tasa de acuse a +14 días — debería superar 95% en holds rutinarios. Por debajo de eso, la plantilla del aviso necesita reescritura o la lista de custodios tiene registros desactualizados.
Completitud de la auditoría en revisión del counsel — porcentaje de holds donde el counsel puede producir una cadena completa y defendible bajo demanda. Debería ser 100%; la tabla de auditoría es la fuente.
vs alternativas
vs el módulo de hold integrado de la plataforma de e-discovery (Relativity Legal Hold, Logikcull, Everlaw). Elige el módulo de la plataforma si vives dentro de la herramienta de e-discovery. Elige el flujo si tus custodios están repartidos entre Slack, correo y sistemas de RR. HH., y necesitas superficies de notificación más allá de las que trae la plataforma.
vs herramientas SaaS de gestión de holds (Onna, Exterro Legal Hold). Elige esas para self-service avanzado del custodio y preservación integrada. Elige el flujo si quieres la orquestación en tu propia infraestructura con el audit log en tu propia DB.
vs hoja de cálculo + reglas de Outlook. El default y la fuente de custodios olvidados a escala. El flujo es el reemplazo determinista.
A vigilar
Drift de la lista de custodios.Resguardo: el flujo vuelve a obtener la lista en cada revisión, validando el last_updated_at de la fuente. Si la lista cambió (custodios agregados/quitados) sin aprobación del counsel, el flujo expone el diff al responsable de legal-ops en lugar de actuar silenciosamente sobre la lista nueva.
Mutabilidad del audit table.Resguardo: la tabla de auditoría debe ser append-only a nivel de DB (Postgres: REVOKE UPDATE, DELETE FROM ALL). El flujo no fuerza esto — la DB sí. El README documenta el schema con el constraint inline.
Drift del texto del aviso.Resguardo: las plantillas por matter se hashean con SHA al momento de emitir; el audit log captura el SHA. Si counsel quiere modificar el aviso, la modificación es una acción aparte en el flujo, no una re-emisión silenciosa.
Opt-out o silencio del custodio.Resguardo: la escalación al manager en +21 días convierte el problema de custodio en problema de management. Más allá de eso, el responsable de legal-ops puede necesitar involucrar al outside counsel — el flujo expone, pero no actúa.
Diferencias de hold entre jurisdicciones.Resguardo: el flujo asume semántica de litigation hold al estilo de EE. UU. La “duty to preserve” al estilo europeo bajo el AI Act y el GDPR tiene un alcance distinto; la plantilla del aviso por matter cubre esos casos.
Postura de privacidad en el correo al custodio.Resguardo: los avisos pueden revelar la existencia de un asunto en litigio al custodio; la ruta SMTP usa el relay de correo del despacho (no un SaaS de terceros) por confidencialidad.
Stack
El bundle vive en apps/web/public/artifacts/litigation-hold-orchestration-n8n/:
litigation-hold-orchestration-n8n.json — el export del flujo
_README.md — setup de credenciales, schema del audit table, procedimiento de dry-run
audit-table-schema.sql — DDL para la tabla de auditoría inmutable
hold-notice-template.md — plantilla de aviso de hold a completar por matter
Tools: n8n (orquestación), Slack (notificación in-channel), Claude (opcional — para el resumen diario de actividad del audit log al responsable de legal-ops, no para ningún paso de decisión).
# Litigation hold orchestration — n8n flow
Orchestrates a litigation-hold issue cycle: notification, acknowledgement tracking, reminder cadence, escalation paths, and an immutable audit log. Replaces the spreadsheet-and-Outlook-rules manual cycle with a deterministic flow that can't drop a custodian.
## Import
1. Import `litigation-hold-orchestration-n8n.json` into n8n.
2. Set workflow timezone to your office TZ.
3. Provision the audit table (DDL in `audit-table-schema.sql`).
4. Wire credentials.
5. Do NOT enable until dry-run confirms behavior on a closed hold.
## What ships in this bundle
This n8n export covers the **issuance** half of the cycle (Phase 1). The tracking + escalation half (Phase 2 — daily cron, reminders, escalation) is intentionally a separate workflow you wire to the same audit table; that lets the issuance flow be triggered fresh per hold while the tracker runs continuously across all active holds.
The Phase 2 tracker is a 4-node workflow:
1. Cron daily 9am office TZ.
2. Postgres query against the audit table: select hold/custodian pairs without `acknowledged` action.
3. Code node: determine action (reminder at +3, +7; escalation to legal-ops lead at +14; escalation to manager at +21).
4. Email send + audit-log append.
The DDL and the audit-query are in this README's appendix below; the Phase 2 export is left to the legal-ops engineer to assemble per the firm's escalation paths (which vary by jurisdiction and matter type more than the issuance step does).
## Credentials
### `PLACEHOLDER_CUSTODIAN_DB_CRED_ID` — Custodian source
Read access to wherever the custodian list lives:
- **In-house Postgres** — the default. Schema documented in the `Load Custodian List` node.
- **Relativity / Everlaw / Logikcull** — replace the Postgres node with an HTTP node calling the platform's custodian endpoint.
- **HRIS** — possible if HRIS is the source of truth, but legal-ops typically maintains the custodian list separately.
### `PLACEHOLDER_SMTP_CRED_ID` — SMTP
Use the **firm's own mail relay**, not a third-party SaaS like SendGrid. Hold notices may flag the existence of a litigation matter; routing them through a third party expands the privilege exposure.
### `PLACEHOLDER_SLACK_CRED_ID` — Slack bot token
`chat:write` scope. The bot needs to be invited to the workspaces where custodians live; per-custodian DMs require user-level scope which Slack handles automatically when the bot is in the workspace.
### `PLACEHOLDER_AUDIT_DB_CRED_ID` — Audit table
Write access to the audit table. The table itself must be append-only at the DB level (DDL below).
## Audit table schema
```sql
CREATE TABLE hold_audit (
audit_id BIGSERIAL PRIMARY KEY,
hold_id TEXT NOT NULL,
custodian_id TEXT NOT NULL,
action TEXT NOT NULL CHECK (action IN (
'notice_sent',
'reminder_sent',
'escalated_to_lead',
'escalated_to_manager',
'acknowledged',
'released'
)),
template_sha TEXT,
payload_json JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX hold_audit_lookup_idx ON hold_audit (hold_id, custodian_id, action);
-- Immutability: the audit table is the firm's defensibility chain.
-- Counsel needs to be able to demonstrate the log can't be edited.
REVOKE UPDATE, DELETE, TRUNCATE ON hold_audit FROM PUBLIC;
REVOKE UPDATE, DELETE, TRUNCATE ON hold_audit FROM <legal_ops_app_role>;
GRANT INSERT, SELECT ON hold_audit TO <legal_ops_app_role>;
```
The `REVOKE` statements are NOT optional. Without them the table is editable, and counsel cannot demonstrate the audit log's defensibility under e-discovery scrutiny.
## Hold-notice template
Save per-matter templates as `n8n/data/hold-notices/<matter-id>.md`. The template uses these placeholders, replaced per custodian by the `Personalize Notice` node:
- `{{custodian_name}}` — custodian's full name
- `{{matter_id}}` — matter identifier
- `{{hold_id}}` — hold identifier
- `{{ack_url}}` — per-custodian acknowledgement URL
Sample template structure (counsel approves the actual language):
```
Dear {{custodian_name}},
This is a litigation hold notice for Matter {{matter_id}}.
You are required to preserve all documents, communications, and electronic
data related to [counsel-defined scope]. This includes [specific systems
and document types].
You must NOT delete, alter, or destroy any potentially relevant material,
even if it would be deleted under normal retention policy.
Please acknowledge receipt of this notice by clicking the link below
within 7 business days:
{{ack_url}}
If you have questions about scope or what to preserve, contact [legal-ops
contact].
This hold remains in effect until you receive a written release notice
from the legal department.
[counsel signature block]
```
## Phase 2 tracker query
The Phase 2 daily cron uses this query to find non-acknowledgers:
```sql
WITH last_action AS (
SELECT hold_id, custodian_id, MAX(created_at) AS last_action_at,
BOOL_OR(action = 'acknowledged') AS acknowledged
FROM hold_audit
WHERE action IN ('notice_sent', 'reminder_sent', 'acknowledged', 'released')
GROUP BY hold_id, custodian_id
)
SELECT
la.hold_id,
la.custodian_id,
la.last_action_at,
EXTRACT(EPOCH FROM (NOW() - la.last_action_at)) / 86400 AS days_since_last_action,
(SELECT MIN(created_at) FROM hold_audit ha
WHERE ha.hold_id = la.hold_id AND ha.custodian_id = la.custodian_id
AND ha.action = 'notice_sent') AS first_notice_at
FROM last_action la
WHERE la.acknowledged = false
AND NOT EXISTS (
SELECT 1 FROM hold_audit ha
WHERE ha.hold_id = la.hold_id AND ha.custodian_id = la.custodian_id
AND ha.action = 'released'
);
```
The tracker computes `days_since_first_notice`, decides action, dispatches.
## Dry-run procedure
1. Provision the audit table on a non-production DB.
2. Wire credentials against staging endpoints (test SMTP, test Slack workspace).
3. Replay a closed hold's custodian list manually.
4. Confirm: notification fires once per custodian; audit log records each send; per-custodian acknowledgement URLs are unique.
5. Switch to production DB. Issue your next real hold via the flow.
## Known limits
- Phase 1 issuance only ships in this n8n export; Phase 2 tracker is documented but not bundled.
- The flow assumes per-custodian email + Slack. Custodians without Slack accounts (contractors, alumni) get email only — the Slack node fails gracefully but the failure is silent in the audit log. The Phase 2 tracker should treat email-only custodians the same as Slack+email.
- Acknowledgement URL routing requires a separate webhook endpoint (the `/ack/<hold>/<custodian>/<token>` URL) — deploy that as a small Express / Flask endpoint that writes `action: acknowledged` to the audit table. The endpoint is NOT bundled.
- The flow does not handle hold-release. Release is its own action — when counsel releases, a separate webhook writes `action: released` to the audit table per custodian. The tracker stops sending reminders to released custodian/hold pairs.
-- Litigation hold audit table — append-only DDL.
-- Counsel's defensibility chain depends on this table being immutable.
CREATE TABLE hold_audit (
audit_id BIGSERIAL PRIMARY KEY,
hold_id TEXT NOT NULL,
custodian_id TEXT NOT NULL,
action TEXT NOT NULL CHECK (action IN (
'notice_sent',
'reminder_sent',
'escalated_to_lead',
'escalated_to_manager',
'acknowledged',
'released'
)),
template_sha TEXT,
payload_json JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX hold_audit_lookup_idx
ON hold_audit (hold_id, custodian_id, action);
CREATE INDEX hold_audit_created_idx
ON hold_audit (created_at);
-- Immutability constraints. NOT optional.
-- Replace <legal_ops_app_role> with the DB role your n8n flow uses.
REVOKE UPDATE, DELETE, TRUNCATE ON hold_audit FROM PUBLIC;
GRANT INSERT, SELECT ON hold_audit TO <legal_ops_app_role>;
-- Optional: row-level revisioning if you anticipate legitimate
-- corrections (e.g. a custodian acknowledged offline and the lead
-- needs to record it). Even then, NEVER UPDATE existing rows —
-- INSERT a 'corrected_offline' action with a payload_json reference
-- to the prior row's audit_id, preserving the original record.
# Hold notice template
Per-matter template the litigation-hold flow personalizes per custodian. Copy this file to `n8n/data/hold-notices/<matter-id>.md` per matter and customize counsel-approved language.
The template uses these placeholders, replaced per custodian by the `Personalize Notice` node:
- `{{custodian_name}}`
- `{{matter_id}}`
- `{{hold_id}}`
- `{{ack_url}}`
---
# Litigation Hold Notice — Matter {{matter_id}} — Hold {{hold_id}}
Dear {{custodian_name}},
The firm's legal department is issuing a litigation hold related to Matter {{matter_id}}. As a custodian whose records may be relevant, you are required to take immediate steps to preserve potentially relevant material.
## What you must preserve
You must preserve all documents, communications, and electronic data related to [counsel-defined scope — replace with matter-specific scope]. This includes, but is not limited to:
- Email (work and any personal email used for work-related communication on this matter)
- Slack messages, including DMs and channel posts
- Documents (Google Drive, SharePoint, OneDrive, local files)
- Calendar entries
- [Other systems specific to this matter — replace with named systems]
The scope covers material from [counsel-defined date range] to the date this hold is released in writing.
## What you must NOT do
You must NOT delete, alter, modify, or destroy any potentially relevant material, even if the firm's normal retention policy would otherwise permit deletion.
You must NOT discuss this hold's scope or substance with anyone outside the legal team and your direct counsel of record.
## What this means in practice
- **Auto-deletion settings:** check email, Slack, and document-system retention settings. If any are set to delete material in the relevant scope, contact [legal-ops contact] immediately.
- **Personal devices:** if you have used personal devices or accounts for any work related to this matter, [legal-ops contact] will work with you on appropriate preservation.
- **Departing the firm:** if you leave the firm while this hold is in effect, [legal-ops contact] will work with HR and IT to preserve your records before any account decommissioning.
- **Replacement of equipment:** do not destroy or recycle hardware in scope until [legal-ops contact] confirms preservation.
## Acknowledgement
You must acknowledge receipt of this notice within 7 business days. Please click the link below:
[{{ack_url}}]({{ack_url}})
If you have not received an automated reminder by [date + 14 days], please contact [legal-ops contact] to confirm your acknowledgement was recorded.
## Questions
For questions about scope or what to preserve, contact:
- [legal-ops contact name and email]
- [outside counsel contact, if applicable]
Do NOT discuss the substance of the matter outside this channel.
## When this hold ends
This hold remains in effect until you receive a written release notice from the legal department. Verbal release is not sufficient. Until you receive written release, you must continue to preserve material in scope.
---
[counsel signature block]
[firm letterhead — match firm's standard hold-notice formatting]