diff --git a/.devenv/scripts/mermaid-to-dot.py b/.devenv/scripts/mermaid-to-dot.py
new file mode 100644
index 00000000..95d96099
--- /dev/null
+++ b/.devenv/scripts/mermaid-to-dot.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python3
+"""
+Convert schema.mermaid (erDiagram) to schema.dot (Graphviz) for optimized SVG rendering.
+
+Features:
+ - subgraph cluster per domain prefix (ACT_GE_, ACT_RE_, ACT_RU_, ACT_HI_, ACT_ID_)
+ - dotted cluster borders with domain color
+ - splines=ortho for rectangular routing
+ - HTML-table entity nodes with PK/FK markers and domain header color
+"""
+
+import re
+import sys
+from pathlib import Path
+
+# ── domain config ──────────────────────────────────────────────────────────────
+DOMAINS = {
+ "GE": {"label": "General", "header": "#4a6fa5", "fill": "#dbeeff", "border": "#4a6fa5"},
+ "RE": {"label": "Repository", "header": "#2e8b57", "fill": "#dff0e8", "border": "#2e8b57"},
+ "RU": {"label": "Runtime", "header": "#8b6914", "fill": "#fff8e1", "border": "#b8860b"},
+ "HI": {"label": "History", "header": "#8b5e2e", "fill": "#fef2e0", "border": "#cd853f"},
+ "ID": {"label": "Identity", "header": "#6a42a0", "fill": "#f3e8ff", "border": "#7b5ea7"},
+}
+
+def domain_of(name: str) -> str | None:
+ m = re.match(r"ACT_([A-Z]+)_", name)
+ return m.group(1) if m else None
+
+
+# ── parser ─────────────────────────────────────────────────────────────────────
+def parse(text: str):
+ entities: dict[str, list[tuple[str, str, str]]] = {}
+ rels: list[tuple[str, str, str, str]] = [] # (src, card_left, card_right, dst, label)
+
+ # entity blocks
+ for m in re.finditer(r"^\s{4}(\w+)\s*\{([^}]+)\}", text, re.MULTILINE):
+ name = m.group(1)
+ cols: list[tuple[str, str, str]] = []
+ for line in m.group(2).split("\n"):
+ line = line.strip()
+ if not line or line.startswith("%%"):
+ continue
+ parts = line.split(None, 2)
+ if len(parts) < 2:
+ continue
+ col_type = parts[0]
+ col_name = parts[1].rstrip(";")
+ rest = parts[2] if len(parts) > 2 else ""
+ marker = "PK" if "PK" in rest else ("FK" if "FK" in rest else "")
+ cols.append((col_type, col_name, marker))
+ entities[name] = cols
+
+ # relationships — e.g. ACT_GE_BYTEARRAY }o--|| ACT_RE_DEPLOYMENT : "DEPLOYMENT_ID_"
+ rel_re = re.compile(
+ r"^\s{4}(\w+)\s+([|o}{]+)--([|o}{]+)\s+(\w+)\s+:\s+\"([^\"]+)\"",
+ re.MULTILINE,
+ )
+ for m in rel_re.finditer(text):
+ rels.append((m.group(1), m.group(2), m.group(3), m.group(4), m.group(5)))
+
+ return entities, rels
+
+
+# ── Graphviz arrow mapping ─────────────────────────────────────────────────────
+# Mermaid notation: `}o` = crow+odot (many, optional), `||` = tee+tee (one, mandatory)
+def arrow_attrs(card: str) -> tuple[str, str]:
+ """Return (arrowhead_style, style_fragment) for one side of a relationship."""
+ if card in ("}|", "|{"): # one-or-more
+ return "crow", "tee"
+ if card in ("}o", "o{"): # zero-or-more
+ return "crow", "odot"
+ if card == "||": # exactly one
+ return "tee", "tee"
+ if card in ("o|", "|o"): # zero-or-one
+ return "tee", "odot"
+ return "normal", "normal"
+
+
+def rel_attrs(card_src: str, card_dst: str) -> str:
+ ah_head, _ = arrow_attrs(card_dst) # arrowhead near dst
+ ah_tail, _ = arrow_attrs(card_src) # arrowtail near src
+ return f'arrowhead="{ah_head}" arrowtail="{ah_tail}" dir=both'
+
+
+# ── node HTML label ───────────────────────────────────────────────────────────
+def node_label(name: str, cols: list[tuple[str, str, str]], dom: str) -> str:
+ d = DOMAINS.get(dom, {"header": "#999999", "fill": "#f5f5f5"})
+ rows = []
+ for col_type, col_name, marker in cols:
+ if marker == "PK":
+ col_fmt = f'{col_name}'
+ type_fmt = f'{col_type}'
+ badge = '
PK | '
+ elif marker == "FK":
+ col_fmt = f'{col_name}'
+ type_fmt = f'{col_type}'
+ badge = 'FK | '
+ else:
+ col_fmt = col_name
+ type_fmt = f'{col_type}'
+ badge = ' | '
+ rows.append(
+ f' | {col_fmt} | '
+ f'{type_fmt} | {badge}
'
+ )
+ rows_str = "\n".join(rows)
+ return (
+ f' {name} [label=<\n'
+ f' \n'
+ f' | '
+ f'{name} |
\n'
+ f'{rows_str}\n'
+ f'
\n'
+ f' > shape=none margin=0]'
+ )
+
+
+# ── DOT generator ─────────────────────────────────────────────────────────────
+def to_dot(entities: dict, rels: list) -> str:
+ by_domain: dict[str, dict] = {}
+ for name, cols in entities.items():
+ d = domain_of(name)
+ if d:
+ by_domain.setdefault(d, {})[name] = cols
+
+ out = [
+ "digraph ER {",
+ ' graph [',
+ ' splines=ortho',
+ ' rankdir=LR',
+ ' nodesep=0.6',
+ ' ranksep=3.0',
+ ' compound=true',
+ ' pad=0.8',
+ ' fontname="Helvetica Neue,Helvetica,Arial,sans-serif"',
+ ' fontsize=13',
+ ' ]',
+ ' node [shape=none fontname="Helvetica Neue,Helvetica,Arial,sans-serif" fontsize=10]',
+ ' edge [',
+ ' fontname="Helvetica Neue,Helvetica,Arial,sans-serif"',
+ ' fontsize=9',
+ ' color="#888888"',
+ ' fontcolor="#555555"',
+ ' penwidth=1.2',
+ ' ]',
+ "",
+ ]
+
+ for dom in ["GE", "RE", "RU", "HI", "ID"]:
+ tables = by_domain.get(dom, {})
+ if not tables:
+ continue
+ d = DOMAINS[dom]
+ out += [
+ f" subgraph cluster_{dom} {{",
+ f' label="{d["label"]} (ACT_{dom}_)"',
+ f' style=dashed',
+ f' color="{d["border"]}"',
+ f' penwidth=2',
+ f' fontcolor="{d["header"]}"',
+ f' fontsize=14',
+ f' bgcolor="{d["fill"]}18"', # 18 = ~10% alpha approximation in hex
+ "",
+ ]
+ for name in sorted(tables.keys()):
+ out.append(node_label(name, tables[name], dom))
+ out += [" }", ""]
+
+ # edges — deduplicate by (src, dst, label)
+ seen: set[tuple[str, str, str]] = set()
+ out.append(" // Relationships")
+ for src, c_src, c_dst, dst, label in rels:
+ key = (src, dst, label)
+ if key in seen:
+ continue
+ seen.add(key)
+ if src not in entities or dst not in entities:
+ continue
+ rattrs = rel_attrs(c_src, c_dst)
+ # self-referential: use different edge color
+ extra = ' color="#cc4444" style=dashed' if src == dst else ""
+ out.append(f' {src} -> {dst} [xlabel="{label}" {rattrs}{extra}]')
+
+ out.append("}")
+ return "\n".join(out)
+
+
+# ── main ───────────────────────────────────────────────────────────────────────
+if __name__ == "__main__":
+ if len(sys.argv) < 3:
+ print(f"Usage: {sys.argv[0]} ", file=sys.stderr)
+ sys.exit(1)
+
+ src = Path(sys.argv[1]).read_text()
+ entities, rels = parse(src)
+ dot = to_dot(entities, rels)
+ Path(sys.argv[2]).write_text(dot)
+ print(f"Wrote {len(entities)} entities, {len(rels)} relationships → {sys.argv[2]}")
diff --git a/.devenv/scripts/render-schema.sh b/.devenv/scripts/render-schema.sh
new file mode 100755
index 00000000..c72447e1
--- /dev/null
+++ b/.devenv/scripts/render-schema.sh
@@ -0,0 +1,69 @@
+#!/usr/bin/env bash
+# Converts schema.mermaid to SVG and/or PNG via Graphviz (dot).
+#
+# Pipeline:
+# schema.mermaid → mermaid-to-dot.py → schema.dot → dot → schema.svg / schema.png
+#
+# Usage: render-schema.sh [--svg] [--png] [--out DIR]
+#
+# Options:
+# --svg Render to SVG (default if neither --svg nor --png given)
+# --png Render to PNG (requires dot with PNG support)
+# --out DIR Output directory (default: same directory as schema.mermaid)
+#
+# Requirements: python3, graphviz (dot)
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
+SCHEMA_MERMAID="$REPO_ROOT/docs/documentation/reference/db-schema/schema.mermaid"
+SCHEMA_DOT="$REPO_ROOT/docs/documentation/reference/db-schema/schema.dot"
+CONVERTER="$SCRIPT_DIR/mermaid-to-dot.py"
+
+DO_SVG=false
+DO_PNG=false
+OUT_DIR=""
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --svg) DO_SVG=true ;;
+ --png) DO_PNG=true ;;
+ --out) OUT_DIR="$2"; shift ;;
+ *) echo "Unknown option: $1" >&2; exit 1 ;;
+ esac
+ shift
+done
+
+if ! $DO_SVG && ! $DO_PNG; then
+ DO_SVG=true
+fi
+
+if [[ -z "$OUT_DIR" ]]; then
+ OUT_DIR="$(dirname "$SCHEMA_MERMAID")"
+fi
+
+# ── dependency checks ──────────────────────────────────────────────────────────
+if ! command -v python3 &>/dev/null; then
+ echo "Error: python3 not found." >&2; exit 1
+fi
+if ! command -v dot &>/dev/null; then
+ echo "Error: graphviz 'dot' not found. Install with: brew install graphviz" >&2; exit 1
+fi
+
+# ── step 1: convert mermaid → dot ─────────────────────────────────────────────
+echo "Converting schema.mermaid → schema.dot"
+python3 "$CONVERTER" "$SCHEMA_MERMAID" "$SCHEMA_DOT"
+
+# ── step 2: render dot → output format(s) ─────────────────────────────────────
+render() {
+ local fmt="$1"
+ local out="$OUT_DIR/schema.$fmt"
+ echo "Rendering $fmt → $out"
+ dot "-T$fmt" "$SCHEMA_DOT" -o "$out"
+}
+
+$DO_SVG && render svg
+$DO_PNG && render png
+
+echo "Done."
diff --git a/.devenv/scripts/schema-theme.css b/.devenv/scripts/schema-theme.css
new file mode 100644
index 00000000..b846ac57
--- /dev/null
+++ b/.devenv/scripts/schema-theme.css
@@ -0,0 +1,23 @@
+/* Domain color overrides for rendered Mermaid ER diagram (schema.mermaid).
+ Applied via: mmdc --cssFile schema-theme.css
+ Colors are keyed to table prefixes: GE, RE, RU, HI, ID */
+
+/* General (GE) — steel blue */
+.node[id*="ACT_GE"] .label { background-color: #d0e4f7; }
+.node[id*="ACT_GE"] rect { fill: #d0e4f7; stroke: #4a6fa5; stroke-width: 2px; }
+
+/* Repository (RE) — sea green */
+.node[id*="ACT_RE"] .label { background-color: #d4edda; }
+.node[id*="ACT_RE"] rect { fill: #d4edda; stroke: #2e8b57; stroke-width: 2px; }
+
+/* Runtime (RU) — golden */
+.node[id*="ACT_RU"] .label { background-color: #fff3cd; }
+.node[id*="ACT_RU"] rect { fill: #fff3cd; stroke: #b8860b; stroke-width: 2px; }
+
+/* History (HI) — warm amber */
+.node[id*="ACT_HI"] .label { background-color: #fde8cc; }
+.node[id*="ACT_HI"] rect { fill: #fde8cc; stroke: #cd853f; stroke-width: 2px; }
+
+/* Identity (ID) — medium purple */
+.node[id*="ACT_ID"] .label { background-color: #e8d5f5; }
+.node[id*="ACT_ID"] rect { fill: #e8d5f5; stroke: #7b5ea7; stroke-width: 2px; }
diff --git a/docs/documentation/installation/database-schema.md b/docs/documentation/installation/database-schema.md
index d874f1f7..ca5dd8a9 100644
--- a/docs/documentation/installation/database-schema.md
+++ b/docs/documentation/installation/database-schema.md
@@ -7,7 +7,7 @@ description: "Install and update the Operaton database schema used by the Proces
---
## Install the Database Schema
-This document will guide you through the installation and update of the Operaton [database schema](../user-guide/process-engine/database/database-schema.md) used by the process engine.
+This document will guide you through the installation and update of the Operaton [database schema](../user-guide/process-engine/database/database-schema/database-schema.md) used by the process engine.
Regardless of the [architecture of your application setup](../introduction/architecture.md), the process engine always requires this database schema.
In a production environment, we recommend setting up this schema yourself and reference the prepared database instance in your application configuration.
Consult the installation guide related to your setup to configure the database for a [remote engine](../installation/operaton-bpm-run.md), [shared engine](../installation/full/index.md), or [embedded engine](../installation/spring-boot.md) accordingly.
diff --git a/docs/documentation/reference/db-schema/schema.mermaid b/docs/documentation/reference/db-schema/schema.mermaid
new file mode 100644
index 00000000..014f6b17
--- /dev/null
+++ b/docs/documentation/reference/db-schema/schema.mermaid
@@ -0,0 +1,997 @@
+%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#f5f5f5', 'primaryBorderColor': '#999'}}}%%
+erDiagram
+ classDef default fill:#f5f5f5,stroke:#999,stroke-width:1px
+ classDef ge fill:#d0e4f7,stroke:#4a6fa5,stroke-width:2px
+ classDef re fill:#d4edda,stroke:#2e8b57,stroke-width:2px
+ classDef ru fill:#fff3cd,stroke:#b8860b,stroke-width:2px
+ classDef hi fill:#fde8cc,stroke:#cd853f,stroke-width:2px
+ classDef id fill:#e8d5f5,stroke:#7b5ea7,stroke-width:2px
+
+ %% =========================================================
+ %% GENERAL (GE) — infrastructure tables
+ %% =========================================================
+
+ ACT_GE_PROPERTY {
+ varchar NAME_ PK
+ varchar VALUE_
+ integer REV_
+ }
+
+ ACT_GE_BYTEARRAY {
+ varchar ID_ PK
+ integer REV_
+ varchar NAME_
+ varchar DEPLOYMENT_ID_ FK
+ bytea BYTES_
+ boolean GENERATED_
+ varchar TENANT_ID_
+ integer TYPE_
+ timestamp CREATE_TIME_
+ varchar ROOT_PROC_INST_ID_
+ timestamp REMOVAL_TIME_
+ }
+
+ ACT_GE_SCHEMA_LOG {
+ varchar ID_ PK
+ timestamp TIMESTAMP_
+ varchar VERSION_
+ }
+
+ %% =========================================================
+ %% REPOSITORY (RE) — definitions and deployments
+ %% =========================================================
+
+ ACT_RE_DEPLOYMENT {
+ varchar ID_ PK
+ varchar NAME_
+ timestamp DEPLOY_TIME_
+ varchar SOURCE_
+ varchar TENANT_ID_
+ }
+
+ ACT_RE_PROCDEF {
+ varchar ID_ PK
+ integer REV_
+ varchar CATEGORY_
+ varchar NAME_
+ varchar KEY_
+ integer VERSION_
+ varchar DEPLOYMENT_ID_
+ varchar RESOURCE_NAME_
+ varchar DGRM_RESOURCE_NAME_
+ boolean HAS_START_FORM_KEY_
+ integer SUSPENSION_STATE_
+ varchar TENANT_ID_
+ varchar VERSION_TAG_
+ integer HISTORY_TTL_
+ boolean STARTABLE_
+ }
+
+ ACT_RE_CAMFORMDEF {
+ varchar ID_ PK
+ integer REV_
+ varchar KEY_
+ integer VERSION_
+ varchar DEPLOYMENT_ID_
+ varchar RESOURCE_NAME_
+ varchar TENANT_ID_
+ }
+
+ ACT_RE_CASE_DEF {
+ varchar ID_ PK
+ integer REV_
+ varchar CATEGORY_
+ varchar NAME_
+ varchar KEY_
+ integer VERSION_
+ varchar DEPLOYMENT_ID_
+ varchar RESOURCE_NAME_
+ varchar DGRM_RESOURCE_NAME_
+ varchar TENANT_ID_
+ integer HISTORY_TTL_
+ }
+
+ ACT_RE_DECISION_DEF {
+ varchar ID_ PK
+ integer REV_
+ varchar CATEGORY_
+ varchar NAME_
+ varchar KEY_
+ integer VERSION_
+ varchar DEPLOYMENT_ID_
+ varchar RESOURCE_NAME_
+ varchar DGRM_RESOURCE_NAME_
+ varchar DEC_REQ_ID_ FK
+ varchar DEC_REQ_KEY_
+ varchar TENANT_ID_
+ integer HISTORY_TTL_
+ varchar VERSION_TAG_
+ }
+
+ ACT_RE_DECISION_REQ_DEF {
+ varchar ID_ PK
+ integer REV_
+ varchar CATEGORY_
+ varchar NAME_
+ varchar KEY_
+ integer VERSION_
+ varchar DEPLOYMENT_ID_
+ varchar RESOURCE_NAME_
+ varchar DGRM_RESOURCE_NAME_
+ varchar TENANT_ID_
+ }
+
+ %% =========================================================
+ %% RUNTIME (RU) — active process/case/job state
+ %% =========================================================
+
+ ACT_RU_EXECUTION {
+ varchar ID_ PK
+ integer REV_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_ FK
+ varchar BUSINESS_KEY_
+ varchar PARENT_ID_ FK
+ varchar PROC_DEF_ID_ FK
+ varchar SUPER_EXEC_ FK
+ varchar SUPER_CASE_EXEC_
+ varchar CASE_INST_ID_
+ varchar ACT_ID_
+ varchar ACT_INST_ID_
+ boolean IS_ACTIVE_
+ boolean IS_CONCURRENT_
+ boolean IS_SCOPE_
+ boolean IS_EVENT_SCOPE_
+ integer SUSPENSION_STATE_
+ integer CACHED_ENT_STATE_
+ bigint SEQUENCE_COUNTER_
+ varchar TENANT_ID_
+ varchar PROC_DEF_KEY_
+ }
+
+ ACT_RU_JOB {
+ varchar ID_ PK
+ integer REV_
+ varchar TYPE_
+ timestamp LOCK_EXP_TIME_
+ varchar LOCK_OWNER_
+ boolean EXCLUSIVE_
+ varchar EXECUTION_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROCESS_INSTANCE_ID_
+ varchar PROCESS_DEF_ID_
+ varchar PROCESS_DEF_KEY_
+ integer RETRIES_
+ varchar EXCEPTION_STACK_ID_ FK
+ varchar EXCEPTION_MSG_
+ varchar FAILED_ACT_ID_
+ timestamp DUEDATE_
+ varchar REPEAT_
+ bigint REPEAT_OFFSET_
+ varchar HANDLER_TYPE_
+ varchar HANDLER_CFG_
+ varchar DEPLOYMENT_ID_
+ integer SUSPENSION_STATE_
+ varchar JOB_DEF_ID_
+ bigint PRIORITY_
+ bigint SEQUENCE_COUNTER_
+ varchar TENANT_ID_
+ timestamp CREATE_TIME_
+ varchar LAST_FAILURE_LOG_ID_
+ varchar BATCH_ID_
+ }
+
+ ACT_RU_JOBDEF {
+ varchar ID_ PK
+ integer REV_
+ varchar PROC_DEF_ID_
+ varchar PROC_DEF_KEY_
+ varchar ACT_ID_
+ varchar JOB_TYPE_
+ varchar JOB_CONFIGURATION_
+ integer SUSPENSION_STATE_
+ bigint JOB_PRIORITY_
+ varchar TENANT_ID_
+ varchar DEPLOYMENT_ID_
+ }
+
+ ACT_RU_TASK {
+ varchar ID_ PK
+ integer REV_
+ varchar EXECUTION_ID_ FK
+ varchar PROC_INST_ID_ FK
+ varchar PROC_DEF_ID_ FK
+ varchar CASE_EXECUTION_ID_ FK
+ varchar CASE_INST_ID_
+ varchar CASE_DEF_ID_ FK
+ varchar NAME_
+ varchar PARENT_TASK_ID_
+ varchar DESCRIPTION_
+ varchar TASK_DEF_KEY_
+ varchar OWNER_
+ varchar ASSIGNEE_
+ varchar DELEGATION_
+ integer PRIORITY_
+ timestamp CREATE_TIME_
+ timestamp LAST_UPDATED_
+ timestamp DUE_DATE_
+ timestamp FOLLOW_UP_DATE_
+ integer SUSPENSION_STATE_
+ varchar TENANT_ID_
+ varchar TASK_STATE_
+ }
+
+ ACT_RU_IDENTITYLINK {
+ varchar ID_ PK
+ integer REV_
+ varchar GROUP_ID_
+ varchar TYPE_
+ varchar USER_ID_
+ varchar TASK_ID_ FK
+ varchar PROC_DEF_ID_ FK
+ varchar TENANT_ID_
+ }
+
+ ACT_RU_VARIABLE {
+ varchar ID_ PK
+ integer REV_
+ varchar TYPE_
+ varchar NAME_
+ varchar EXECUTION_ID_ FK
+ varchar PROC_INST_ID_ FK
+ varchar PROC_DEF_ID_
+ varchar CASE_EXECUTION_ID_ FK
+ varchar CASE_INST_ID_ FK
+ varchar TASK_ID_
+ varchar BATCH_ID_ FK
+ varchar BYTEARRAY_ID_ FK
+ double DOUBLE_
+ bigint LONG_
+ varchar TEXT_
+ varchar TEXT2_
+ varchar VAR_SCOPE_
+ bigint SEQUENCE_COUNTER_
+ boolean IS_CONCURRENT_LOCAL_
+ varchar TENANT_ID_
+ }
+
+ ACT_RU_EVENT_SUBSCR {
+ varchar ID_ PK
+ integer REV_
+ varchar EVENT_TYPE_
+ varchar EVENT_NAME_
+ varchar EXECUTION_ID_ FK
+ varchar PROC_INST_ID_
+ varchar ACTIVITY_ID_
+ varchar CONFIGURATION_
+ timestamp CREATED_
+ varchar TENANT_ID_
+ }
+
+ ACT_RU_INCIDENT {
+ varchar ID_ PK
+ integer REV_
+ timestamp INCIDENT_TIMESTAMP_
+ varchar INCIDENT_MSG_
+ varchar INCIDENT_TYPE_
+ varchar EXECUTION_ID_ FK
+ varchar ACTIVITY_ID_
+ varchar FAILED_ACTIVITY_ID_
+ varchar PROC_INST_ID_ FK
+ varchar PROC_DEF_ID_ FK
+ varchar CAUSE_INCIDENT_ID_ FK
+ varchar ROOT_CAUSE_INCIDENT_ID_ FK
+ varchar CONFIGURATION_
+ varchar TENANT_ID_
+ varchar JOB_DEF_ID_ FK
+ varchar ANNOTATION_
+ }
+
+ ACT_RU_AUTHORIZATION {
+ varchar ID_ PK
+ integer REV_
+ integer TYPE_
+ varchar GROUP_ID_
+ varchar USER_ID_
+ integer RESOURCE_TYPE_
+ varchar RESOURCE_ID_
+ integer PERMS_
+ timestamp REMOVAL_TIME_
+ varchar ROOT_PROC_INST_ID_
+ }
+
+ ACT_RU_FILTER {
+ varchar ID_ PK
+ integer REV_
+ varchar RESOURCE_TYPE_
+ varchar NAME_
+ varchar OWNER_
+ text QUERY_
+ text PROPERTIES_
+ }
+
+ ACT_RU_METER_LOG {
+ varchar ID_ PK
+ varchar NAME_
+ varchar REPORTER_
+ bigint VALUE_
+ timestamp TIMESTAMP_
+ bigint MILLISECONDS_
+ }
+
+ ACT_RU_TASK_METER_LOG {
+ varchar ID_ PK
+ bigint ASSIGNEE_HASH_
+ timestamp TIMESTAMP_
+ }
+
+ ACT_RU_EXT_TASK {
+ varchar ID_ PK
+ integer REV_
+ varchar WORKER_ID_
+ varchar TOPIC_NAME_
+ integer RETRIES_
+ varchar ERROR_MSG_
+ varchar ERROR_DETAILS_ID_ FK
+ timestamp LOCK_EXP_TIME_
+ timestamp CREATE_TIME_
+ integer SUSPENSION_STATE_
+ varchar EXECUTION_ID_ FK
+ varchar PROC_INST_ID_
+ varchar PROC_DEF_ID_
+ varchar PROC_DEF_KEY_
+ varchar ACT_ID_
+ varchar ACT_INST_ID_
+ varchar TENANT_ID_
+ bigint PRIORITY_
+ varchar LAST_FAILURE_LOG_ID_
+ }
+
+ ACT_RU_BATCH {
+ varchar ID_ PK
+ integer REV_
+ varchar TYPE_
+ integer TOTAL_JOBS_
+ integer JOBS_CREATED_
+ integer JOBS_PER_SEED_
+ integer INVOCATIONS_PER_JOB_
+ varchar SEED_JOB_DEF_ID_ FK
+ varchar BATCH_JOB_DEF_ID_ FK
+ varchar MONITOR_JOB_DEF_ID_ FK
+ integer SUSPENSION_STATE_
+ varchar CONFIGURATION_
+ varchar TENANT_ID_
+ varchar CREATE_USER_ID_
+ timestamp START_TIME_
+ timestamp EXEC_START_TIME_
+ }
+
+ ACT_RU_CASE_EXECUTION {
+ varchar ID_ PK
+ integer REV_
+ varchar CASE_INST_ID_ FK
+ varchar SUPER_CASE_EXEC_
+ varchar SUPER_EXEC_
+ varchar BUSINESS_KEY_
+ varchar PARENT_ID_ FK
+ varchar CASE_DEF_ID_ FK
+ varchar ACT_ID_
+ integer PREV_STATE_
+ integer CURRENT_STATE_
+ boolean REQUIRED_
+ varchar TENANT_ID_
+ }
+
+ ACT_RU_CASE_SENTRY_PART {
+ varchar ID_ PK
+ integer REV_
+ varchar CASE_INST_ID_ FK
+ varchar CASE_EXEC_ID_ FK
+ varchar SENTRY_ID_
+ varchar TYPE_
+ varchar SOURCE_CASE_EXEC_ID_
+ varchar STANDARD_EVENT_
+ varchar SOURCE_
+ varchar VARIABLE_EVENT_
+ varchar VARIABLE_NAME_
+ boolean SATISFIED_
+ varchar TENANT_ID_
+ }
+
+ %% =========================================================
+ %% HISTORY (HI) — completed/archived records
+ %% =========================================================
+
+ ACT_HI_PROCINST {
+ varchar ID_ PK
+ varchar PROC_INST_ID_ UK
+ varchar BUSINESS_KEY_
+ varchar PROC_DEF_KEY_
+ varchar PROC_DEF_ID_
+ timestamp START_TIME_
+ timestamp END_TIME_
+ timestamp REMOVAL_TIME_
+ bigint DURATION_
+ varchar START_USER_ID_
+ varchar START_ACT_ID_
+ varchar END_ACT_ID_
+ varchar SUPER_PROCESS_INSTANCE_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar SUPER_CASE_INSTANCE_ID_
+ varchar CASE_INST_ID_
+ varchar DELETE_REASON_
+ varchar TENANT_ID_
+ varchar STATE_
+ varchar RESTARTED_PROC_INST_ID_
+ }
+
+ ACT_HI_ACTINST {
+ varchar ID_ PK
+ varchar PARENT_ACT_INST_ID_
+ varchar PROC_DEF_KEY_
+ varchar PROC_DEF_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_
+ varchar EXECUTION_ID_
+ varchar ACT_ID_
+ varchar TASK_ID_
+ varchar CALL_PROC_INST_ID_
+ varchar CALL_CASE_INST_ID_
+ varchar ACT_NAME_
+ varchar ACT_TYPE_
+ varchar ASSIGNEE_
+ timestamp START_TIME_
+ timestamp END_TIME_
+ bigint DURATION_
+ integer ACT_INST_STATE_
+ bigint SEQUENCE_COUNTER_
+ varchar TENANT_ID_
+ timestamp REMOVAL_TIME_
+ }
+
+ ACT_HI_TASKINST {
+ varchar ID_ PK
+ varchar TASK_DEF_KEY_
+ varchar PROC_DEF_KEY_
+ varchar PROC_DEF_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_
+ varchar EXECUTION_ID_
+ varchar CASE_DEF_KEY_
+ varchar CASE_DEF_ID_
+ varchar CASE_INST_ID_
+ varchar CASE_EXECUTION_ID_
+ varchar ACT_INST_ID_
+ varchar NAME_
+ varchar PARENT_TASK_ID_
+ varchar DESCRIPTION_
+ varchar OWNER_
+ varchar ASSIGNEE_
+ timestamp START_TIME_
+ timestamp END_TIME_
+ bigint DURATION_
+ varchar DELETE_REASON_
+ integer PRIORITY_
+ timestamp DUE_DATE_
+ timestamp FOLLOW_UP_DATE_
+ varchar TENANT_ID_
+ timestamp REMOVAL_TIME_
+ varchar TASK_STATE_
+ }
+
+ ACT_HI_VARINST {
+ varchar ID_ PK
+ varchar PROC_DEF_KEY_
+ varchar PROC_DEF_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_
+ varchar EXECUTION_ID_
+ varchar ACT_INST_ID_
+ varchar CASE_DEF_KEY_
+ varchar CASE_DEF_ID_
+ varchar CASE_INST_ID_
+ varchar CASE_EXECUTION_ID_
+ varchar TASK_ID_
+ varchar NAME_
+ varchar VAR_TYPE_
+ timestamp CREATE_TIME_
+ integer REV_
+ varchar BYTEARRAY_ID_
+ double DOUBLE_
+ bigint LONG_
+ varchar TEXT_
+ varchar TEXT2_
+ varchar TENANT_ID_
+ varchar STATE_
+ timestamp REMOVAL_TIME_
+ }
+
+ ACT_HI_DETAIL {
+ varchar ID_ PK
+ varchar TYPE_
+ varchar PROC_DEF_KEY_
+ varchar PROC_DEF_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_
+ varchar EXECUTION_ID_
+ varchar CASE_DEF_KEY_
+ varchar CASE_DEF_ID_
+ varchar CASE_INST_ID_
+ varchar CASE_EXECUTION_ID_
+ varchar TASK_ID_
+ varchar ACT_INST_ID_
+ varchar VAR_INST_ID_
+ varchar NAME_
+ varchar VAR_TYPE_
+ integer REV_
+ timestamp TIME_
+ varchar BYTEARRAY_ID_
+ double DOUBLE_
+ bigint LONG_
+ varchar TEXT_
+ varchar TEXT2_
+ bigint SEQUENCE_COUNTER_
+ varchar TENANT_ID_
+ varchar OPERATION_ID_
+ timestamp REMOVAL_TIME_
+ boolean INITIAL_
+ }
+
+ ACT_HI_IDENTITYLINK {
+ varchar ID_ PK
+ timestamp TIMESTAMP_
+ varchar TYPE_
+ varchar USER_ID_
+ varchar GROUP_ID_
+ varchar TASK_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_DEF_ID_
+ varchar OPERATION_TYPE_
+ varchar ASSIGNER_ID_
+ varchar PROC_DEF_KEY_
+ varchar TENANT_ID_
+ timestamp REMOVAL_TIME_
+ }
+
+ ACT_HI_COMMENT {
+ varchar ID_ PK
+ varchar TYPE_
+ timestamp TIME_
+ varchar USER_ID_
+ varchar TASK_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_
+ varchar ACTION_
+ varchar MESSAGE_
+ bytea FULL_MSG_
+ varchar TENANT_ID_
+ timestamp REMOVAL_TIME_
+ integer REV_
+ }
+
+ ACT_HI_ATTACHMENT {
+ varchar ID_ PK
+ integer REV_
+ varchar USER_ID_
+ varchar NAME_
+ varchar DESCRIPTION_
+ varchar TYPE_
+ varchar TASK_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_
+ varchar URL_
+ varchar CONTENT_ID_
+ varchar TENANT_ID_
+ timestamp CREATE_TIME_
+ timestamp REMOVAL_TIME_
+ }
+
+ ACT_HI_OP_LOG {
+ varchar ID_ PK
+ varchar DEPLOYMENT_ID_
+ varchar PROC_DEF_ID_
+ varchar PROC_DEF_KEY_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_
+ varchar EXECUTION_ID_
+ varchar CASE_DEF_ID_
+ varchar CASE_INST_ID_
+ varchar CASE_EXECUTION_ID_
+ varchar TASK_ID_
+ varchar JOB_ID_
+ varchar JOB_DEF_ID_
+ varchar BATCH_ID_
+ varchar USER_ID_
+ timestamp TIMESTAMP_
+ varchar OPERATION_TYPE_
+ varchar OPERATION_ID_
+ varchar ENTITY_TYPE_
+ varchar PROPERTY_
+ varchar ORG_VALUE_
+ varchar NEW_VALUE_
+ varchar TENANT_ID_
+ timestamp REMOVAL_TIME_
+ varchar CATEGORY_
+ varchar EXTERNAL_TASK_ID_
+ varchar ANNOTATION_
+ }
+
+ ACT_HI_INCIDENT {
+ varchar ID_ PK
+ varchar PROC_DEF_KEY_
+ varchar PROC_DEF_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_INST_ID_
+ varchar EXECUTION_ID_
+ timestamp CREATE_TIME_
+ timestamp END_TIME_
+ varchar INCIDENT_MSG_
+ varchar INCIDENT_TYPE_
+ varchar ACTIVITY_ID_
+ varchar FAILED_ACTIVITY_ID_
+ varchar CAUSE_INCIDENT_ID_
+ varchar ROOT_CAUSE_INCIDENT_ID_
+ varchar CONFIGURATION_
+ varchar HISTORY_CONFIGURATION_
+ integer INCIDENT_STATE_
+ varchar TENANT_ID_
+ varchar JOB_DEF_ID_
+ varchar ANNOTATION_
+ timestamp REMOVAL_TIME_
+ }
+
+ ACT_HI_JOB_LOG {
+ varchar ID_ PK
+ timestamp TIMESTAMP_
+ varchar JOB_ID_
+ timestamp JOB_DUEDATE_
+ integer JOB_RETRIES_
+ bigint JOB_PRIORITY_
+ varchar JOB_EXCEPTION_MSG_
+ varchar JOB_EXCEPTION_STACK_ID_
+ integer JOB_STATE_
+ varchar JOB_DEF_ID_
+ varchar JOB_DEF_TYPE_
+ varchar JOB_DEF_CONFIGURATION_
+ varchar ACT_ID_
+ varchar FAILED_ACT_ID_
+ varchar EXECUTION_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROCESS_INSTANCE_ID_
+ varchar PROCESS_DEF_ID_
+ varchar PROCESS_DEF_KEY_
+ varchar DEPLOYMENT_ID_
+ bigint SEQUENCE_COUNTER_
+ varchar TENANT_ID_
+ varchar HOSTNAME_
+ timestamp REMOVAL_TIME_
+ varchar BATCH_ID_
+ }
+
+ ACT_HI_BATCH {
+ varchar ID_ PK
+ varchar TYPE_
+ integer TOTAL_JOBS_
+ integer JOBS_PER_SEED_
+ integer INVOCATIONS_PER_JOB_
+ varchar SEED_JOB_DEF_ID_
+ varchar MONITOR_JOB_DEF_ID_
+ varchar BATCH_JOB_DEF_ID_
+ varchar TENANT_ID_
+ varchar CREATE_USER_ID_
+ timestamp START_TIME_
+ timestamp END_TIME_
+ timestamp REMOVAL_TIME_
+ timestamp EXEC_START_TIME_
+ }
+
+ ACT_HI_EXT_TASK_LOG {
+ varchar ID_ PK
+ timestamp TIMESTAMP_
+ varchar EXT_TASK_ID_
+ integer RETRIES_
+ varchar TOPIC_NAME_
+ varchar WORKER_ID_
+ bigint PRIORITY_
+ varchar ERROR_MSG_
+ varchar ERROR_DETAILS_ID_
+ varchar ACT_ID_
+ varchar ACT_INST_ID_
+ varchar EXECUTION_ID_
+ varchar PROC_INST_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar PROC_DEF_ID_
+ varchar PROC_DEF_KEY_
+ varchar TENANT_ID_
+ integer STATE_
+ timestamp REMOVAL_TIME_
+ }
+
+ ACT_HI_CASEINST {
+ varchar ID_ PK
+ varchar CASE_INST_ID_ UK
+ varchar BUSINESS_KEY_
+ varchar CASE_DEF_ID_
+ timestamp CREATE_TIME_
+ timestamp CLOSE_TIME_
+ bigint DURATION_
+ integer STATE_
+ varchar CREATE_USER_ID_
+ varchar SUPER_CASE_INSTANCE_ID_
+ varchar SUPER_PROCESS_INSTANCE_ID_
+ varchar TENANT_ID_
+ }
+
+ ACT_HI_CASEACTINST {
+ varchar ID_ PK
+ varchar PARENT_ACT_INST_ID_
+ varchar CASE_DEF_ID_
+ varchar CASE_INST_ID_
+ varchar CASE_ACT_ID_
+ varchar TASK_ID_
+ varchar CALL_PROC_INST_ID_
+ varchar CALL_CASE_INST_ID_
+ varchar CASE_ACT_NAME_
+ varchar CASE_ACT_TYPE_
+ timestamp CREATE_TIME_
+ timestamp END_TIME_
+ bigint DURATION_
+ integer STATE_
+ boolean REQUIRED_
+ varchar TENANT_ID_
+ }
+
+ ACT_HI_DECINST {
+ varchar ID_ PK
+ varchar DEC_DEF_ID_
+ varchar DEC_DEF_KEY_
+ varchar DEC_DEF_NAME_
+ varchar PROC_DEF_KEY_
+ varchar PROC_DEF_ID_
+ varchar PROC_INST_ID_
+ varchar CASE_DEF_KEY_
+ varchar CASE_DEF_ID_
+ varchar CASE_INST_ID_
+ varchar ACT_INST_ID_
+ varchar ACT_ID_
+ timestamp EVAL_TIME_
+ timestamp REMOVAL_TIME_
+ double COLLECT_VALUE_
+ varchar USER_ID_
+ varchar ROOT_DEC_INST_ID_
+ varchar ROOT_PROC_INST_ID_
+ varchar DEC_REQ_ID_
+ varchar DEC_REQ_KEY_
+ varchar TENANT_ID_
+ }
+
+ ACT_HI_DEC_IN {
+ varchar ID_ PK
+ varchar DEC_INST_ID_
+ varchar CLAUSE_ID_
+ varchar CLAUSE_NAME_
+ varchar VAR_TYPE_
+ varchar BYTEARRAY_ID_
+ double DOUBLE_
+ bigint LONG_
+ varchar TEXT_
+ varchar TEXT2_
+ varchar TENANT_ID_
+ timestamp CREATE_TIME_
+ varchar ROOT_PROC_INST_ID_
+ timestamp REMOVAL_TIME_
+ }
+
+ ACT_HI_DEC_OUT {
+ varchar ID_ PK
+ varchar DEC_INST_ID_
+ varchar CLAUSE_ID_
+ varchar CLAUSE_NAME_
+ varchar RULE_ID_
+ integer RULE_ORDER_
+ varchar VAR_NAME_
+ varchar VAR_TYPE_
+ varchar BYTEARRAY_ID_
+ double DOUBLE_
+ bigint LONG_
+ varchar TEXT_
+ varchar TEXT2_
+ varchar TENANT_ID_
+ timestamp CREATE_TIME_
+ varchar ROOT_PROC_INST_ID_
+ timestamp REMOVAL_TIME_
+ }
+
+ %% =========================================================
+ %% IDENTITY (ID) — users, groups, tenants
+ %% =========================================================
+
+ ACT_ID_GROUP {
+ varchar ID_ PK
+ integer REV_
+ varchar NAME_
+ varchar TYPE_
+ }
+
+ ACT_ID_MEMBERSHIP {
+ varchar USER_ID_ PK, FK
+ varchar GROUP_ID_ PK, FK
+ }
+
+ ACT_ID_USER {
+ varchar ID_ PK
+ integer REV_
+ varchar FIRST_
+ varchar LAST_
+ varchar EMAIL_
+ varchar PWD_
+ varchar SALT_
+ timestamp LOCK_EXP_TIME_
+ integer ATTEMPTS_
+ varchar PICTURE_ID_
+ }
+
+ ACT_ID_INFO {
+ varchar ID_ PK
+ integer REV_
+ varchar USER_ID_
+ varchar TYPE_
+ varchar KEY_
+ varchar VALUE_
+ bytea PASSWORD_
+ varchar PARENT_ID_
+ }
+
+ ACT_ID_TENANT {
+ varchar ID_ PK
+ integer REV_
+ varchar NAME_
+ }
+
+ ACT_ID_TENANT_MEMBER {
+ varchar ID_ PK
+ varchar TENANT_ID_ FK
+ varchar USER_ID_ FK
+ varchar GROUP_ID_ FK
+ }
+
+ %% =========================================================
+ %% RELATIONSHIPS — solid (--) lines are SQL FOREIGN KEY constraints;
+ %% dashed (..) lines are logical references without a constraint
+ %% =========================================================
+
+ %% General
+ ACT_GE_BYTEARRAY }o--o| ACT_RE_DEPLOYMENT : "DEPLOYMENT_ID_"
+
+ %% Repository
+ ACT_RE_PROCDEF }o..|| ACT_RE_DEPLOYMENT : "DEPLOYMENT_ID_"
+ ACT_RE_CAMFORMDEF }o..|| ACT_RE_DEPLOYMENT : "DEPLOYMENT_ID_"
+ ACT_RE_CASE_DEF }o..|| ACT_RE_DEPLOYMENT : "DEPLOYMENT_ID_"
+ ACT_RE_DECISION_REQ_DEF }o..|| ACT_RE_DEPLOYMENT : "DEPLOYMENT_ID_"
+ ACT_RE_DECISION_DEF }o..|| ACT_RE_DEPLOYMENT : "DEPLOYMENT_ID_"
+ ACT_RE_DECISION_DEF }o--o| ACT_RE_DECISION_REQ_DEF : "DEC_REQ_ID_"
+
+ %% Runtime — Execution
+ ACT_RU_EXECUTION }o--o| ACT_RU_EXECUTION : "PROC_INST_ID_"
+ ACT_RU_EXECUTION }o--o| ACT_RU_EXECUTION : "PARENT_ID_"
+ ACT_RU_EXECUTION }o--o| ACT_RU_EXECUTION : "SUPER_EXEC_"
+ ACT_RU_EXECUTION }o--|| ACT_RE_PROCDEF : "PROC_DEF_ID_"
+
+ %% Runtime — Task
+ ACT_RU_TASK }o--o| ACT_RU_EXECUTION : "EXECUTION_ID_"
+ ACT_RU_TASK }o--o| ACT_RU_EXECUTION : "PROC_INST_ID_"
+ ACT_RU_TASK }o--o| ACT_RE_PROCDEF : "PROC_DEF_ID_"
+ ACT_RU_TASK }o--o| ACT_RU_CASE_EXECUTION : "CASE_EXECUTION_ID_"
+ ACT_RU_TASK }o--o| ACT_RE_CASE_DEF : "CASE_DEF_ID_"
+
+ %% Runtime — Identity Link
+ ACT_RU_IDENTITYLINK }o--o| ACT_RU_TASK : "TASK_ID_"
+ ACT_RU_IDENTITYLINK }o--o| ACT_RE_PROCDEF : "PROC_DEF_ID_"
+
+ %% Runtime — Variable
+ ACT_RU_VARIABLE }o--o| ACT_RU_EXECUTION : "EXECUTION_ID_"
+ ACT_RU_VARIABLE }o--o| ACT_RU_EXECUTION : "PROC_INST_ID_"
+ ACT_RU_VARIABLE }o--o| ACT_GE_BYTEARRAY : "BYTEARRAY_ID_"
+ ACT_RU_VARIABLE }o--o| ACT_RU_BATCH : "BATCH_ID_"
+ ACT_RU_VARIABLE }o--o| ACT_RU_CASE_EXECUTION : "CASE_EXECUTION_ID_"
+ ACT_RU_VARIABLE }o--o| ACT_RU_CASE_EXECUTION : "CASE_INST_ID_"
+
+ %% Runtime — Job
+ ACT_RU_JOB }o--o| ACT_GE_BYTEARRAY : "EXCEPTION_STACK_ID_"
+ ACT_RU_JOB }o..o| ACT_RU_JOBDEF : "JOB_DEF_ID_"
+
+ %% Runtime — Incident
+ ACT_RU_INCIDENT }o--o| ACT_RU_EXECUTION : "EXECUTION_ID_"
+ ACT_RU_INCIDENT }o--o| ACT_RU_EXECUTION : "PROC_INST_ID_"
+ ACT_RU_INCIDENT }o--o| ACT_RE_PROCDEF : "PROC_DEF_ID_"
+ ACT_RU_INCIDENT }o--o| ACT_RU_INCIDENT : "CAUSE_INCIDENT_ID_"
+ ACT_RU_INCIDENT }o--o| ACT_RU_INCIDENT : "ROOT_CAUSE_INCIDENT_ID_"
+ ACT_RU_INCIDENT }o--o| ACT_RU_JOBDEF : "JOB_DEF_ID_"
+
+ %% Runtime — Event Subscription
+ ACT_RU_EVENT_SUBSCR }o--o| ACT_RU_EXECUTION : "EXECUTION_ID_"
+
+ %% Runtime — External Task
+ ACT_RU_EXT_TASK }o--|| ACT_RU_EXECUTION : "EXECUTION_ID_"
+ ACT_RU_EXT_TASK }o--o| ACT_GE_BYTEARRAY : "ERROR_DETAILS_ID_"
+
+ %% Runtime — Batch
+ ACT_RU_BATCH }o--o| ACT_RU_JOBDEF : "SEED_JOB_DEF_ID_"
+ ACT_RU_BATCH }o--o| ACT_RU_JOBDEF : "MONITOR_JOB_DEF_ID_"
+ ACT_RU_BATCH }o--o| ACT_RU_JOBDEF : "BATCH_JOB_DEF_ID_"
+
+ %% Runtime — Case
+ ACT_RU_CASE_EXECUTION }o--o| ACT_RU_CASE_EXECUTION : "CASE_INST_ID_"
+ ACT_RU_CASE_EXECUTION }o--o| ACT_RU_CASE_EXECUTION : "PARENT_ID_"
+ ACT_RU_CASE_EXECUTION }o--|| ACT_RE_CASE_DEF : "CASE_DEF_ID_"
+ ACT_RU_CASE_SENTRY_PART }o--o| ACT_RU_CASE_EXECUTION : "CASE_INST_ID_"
+ ACT_RU_CASE_SENTRY_PART }o--o| ACT_RU_CASE_EXECUTION : "CASE_EXEC_ID_"
+
+ %% History — Decision
+ ACT_HI_DEC_IN }o..|| ACT_HI_DECINST : "DEC_INST_ID_"
+ ACT_HI_DEC_OUT }o..|| ACT_HI_DECINST : "DEC_INST_ID_"
+
+ %% Identity
+ ACT_ID_MEMBERSHIP }o--|| ACT_ID_GROUP : "GROUP_ID_"
+ ACT_ID_MEMBERSHIP }o--|| ACT_ID_USER : "USER_ID_"
+ ACT_ID_TENANT_MEMBER }o--|| ACT_ID_TENANT : "TENANT_ID_"
+ ACT_ID_TENANT_MEMBER }o--o| ACT_ID_USER : "USER_ID_"
+ ACT_ID_TENANT_MEMBER }o--o| ACT_ID_GROUP : "GROUP_ID_"
+
+ %% =========================================================
+ %% CLASS ASSIGNMENTS — domain colors
+ %% =========================================================
+
+ class ACT_GE_PROPERTY ge
+ class ACT_GE_BYTEARRAY ge
+ class ACT_GE_SCHEMA_LOG ge
+
+ class ACT_RE_DEPLOYMENT re
+ class ACT_RE_PROCDEF re
+ class ACT_RE_CAMFORMDEF re
+ class ACT_RE_CASE_DEF re
+ class ACT_RE_DECISION_DEF re
+ class ACT_RE_DECISION_REQ_DEF re
+
+ class ACT_RU_EXECUTION ru
+ class ACT_RU_JOB ru
+ class ACT_RU_JOBDEF ru
+ class ACT_RU_TASK ru
+ class ACT_RU_IDENTITYLINK ru
+ class ACT_RU_VARIABLE ru
+ class ACT_RU_EVENT_SUBSCR ru
+ class ACT_RU_INCIDENT ru
+ class ACT_RU_AUTHORIZATION ru
+ class ACT_RU_FILTER ru
+ class ACT_RU_METER_LOG ru
+ class ACT_RU_TASK_METER_LOG ru
+ class ACT_RU_EXT_TASK ru
+ class ACT_RU_BATCH ru
+ class ACT_RU_CASE_EXECUTION ru
+ class ACT_RU_CASE_SENTRY_PART ru
+
+ class ACT_HI_PROCINST hi
+ class ACT_HI_ACTINST hi
+ class ACT_HI_TASKINST hi
+ class ACT_HI_VARINST hi
+ class ACT_HI_DETAIL hi
+ class ACT_HI_IDENTITYLINK hi
+ class ACT_HI_COMMENT hi
+ class ACT_HI_ATTACHMENT hi
+ class ACT_HI_OP_LOG hi
+ class ACT_HI_INCIDENT hi
+ class ACT_HI_JOB_LOG hi
+ class ACT_HI_BATCH hi
+ class ACT_HI_EXT_TASK_LOG hi
+ class ACT_HI_CASEINST hi
+ class ACT_HI_CASEACTINST hi
+ class ACT_HI_DECINST hi
+ class ACT_HI_DEC_IN hi
+ class ACT_HI_DEC_OUT hi
+
+ class ACT_ID_GROUP id
+ class ACT_ID_MEMBERSHIP id
+ class ACT_ID_USER id
+ class ACT_ID_INFO id
+ class ACT_ID_TENANT id
+ class ACT_ID_TENANT_MEMBER id
diff --git a/docs/documentation/update/camunda-to-operaton.md b/docs/documentation/update/camunda-to-operaton.md
index 9963ef14..ab197bd6 100644
--- a/docs/documentation/update/camunda-to-operaton.md
+++ b/docs/documentation/update/camunda-to-operaton.md
@@ -38,6 +38,10 @@ Because the Operaton schema is identical to the Camunda 7.24 schema, there is
- Database tables keep the `ACT_` prefix — no tables are renamed.
- Once your application runs on Camunda 7.24, its database is already at the
schema level Operaton expects.
+- Operaton 2.2 and later use schema version 7.25. It has the same tables,
+ columns and indexes as 7.24. Run the `_engine_7.24_to_7.25.sql`
+ upgrade script so that `ACT_GE_SCHEMA_LOG` records the matching version. See
+ [Database schema](../installation/database-schema.md).
- Already-deployed BPMN, DMN, and CMMN models continue to work. The engine
accepts both the `operaton:` and the legacy `camunda:` extension namespaces, so
process definitions deployed under Camunda remain valid.
diff --git a/docs/documentation/user-guide/process-engine/database/database-schema.md b/docs/documentation/user-guide/process-engine/database/database-schema.md
deleted file mode 100644
index 5ce11f0c..00000000
--- a/docs/documentation/user-guide/process-engine/database/database-schema.md
+++ /dev/null
@@ -1,131 +0,0 @@
----
-
-title: 'Database Schema'
-sidebar_position: 10
-menu:
- main:
- identifier: "user-guide-process-engine-database-schema"
- parent: "user-guide-process-engine-database"
-
----
-
-The database schema of the process engine consists of multiple tables.
-The table names all start with ACT. The second part is a two-character
-identification of the use case of the table. This use case will also roughly
-match the service API.
-
-* `ACT_RE_*`: `RE` stands for repository. Tables with this prefix contain 'static' information such as process definitions and process resources (images, rules, etc.).
-* `ACT_RU_*`: `RU` stands for runtime. These are the runtime tables that contain the runtime data of process instances, user tasks, variables, jobs, etc. The engine only stores the runtime data during process instance execution and removes the records when a process instance ends. This keeps the runtime tables small and fast.
-* `ACT_ID_*`: `ID` stands for identity. These tables contain identity information such as users, groups, etc.
-* `ACT_HI_*`: `HI` stands for history. These are the tables that contain historical data such as past process instances, variables, tasks, etc.
-* `ACT_GE_*`: General data, which is used in various use cases.
-
-The main tables of the process engines are the entities of process definitions, executions, tasks, variables and
-event subscriptions. Their relationship is shown in the following UML model.
-
-Database Schema
-
-
-## Process Definitions (`ACT_RE_PROCDEF`)
-
-The `ACT_RE_PROCDEF` table contains all deployed process definitions. It
-includes information like the version details, the resource name or the
-suspension state.
-
-
-## Executions (`ACT_RU_EXECUTION`)
-
-The `ACT_RU_EXECUTION` table contains all current executions. It includes
-information like the process definition, parent execution, business key, the
-current activity and different metadata about the state of the execution.
-
-
-## Tasks (`ACT_RU_TASK`)
-
-The `ACT_RU_TASK` table contains all open tasks of all running process
-instances. It includes information like the corresponding process instance,
-execution and also metadata such as creation time, assignee or due date.
-
-
-## Variables (`ACT_RU_VARIABLE`)
-
-The `ACT_RU_VARIABLE` table contains all currently set process or task
-variables. It includes the names, types and values of the variables and
-information about the corresponding process instance or task.
-
-
-## Event Subscriptions (`ACT_RU_EVENT_SUBSCR`)
-
-The `ACT_RU_EVENT_SUBSCR` table contains all currently existing event
-subscriptions. It includes the type, name and configuration of the expected
-event along with information about the corresponding process instance and
-execution.
-
-## Schema Log (`ACT_GE_SCHEMA_LOG`)
-
-The `ACT_GE_SCHEMA_LOG` table contains a history of the database
-schema version. New entries to the table are written when changes to
-the database schema are made. On database creation the initial entry
-is added. Every update script adds a new entry containing an `id`,
-the `version` the database was updated to and the date and time
-(`timestamp`) of the update.
-
-To retrieve entries from the schema log, the SchemaLogQuery-API can be
-used:
-```java
-List entries = managementService.createSchemaLogQuery().list();
-```
-
-## Metrics Log (ACT_RU_METER_LOG)
-
-The `ACT_RU_METER_LOG` table contains a collection of runtime metrics that can help draw conclusions about usage, load
-and performance of Operaton. Metrics are reported as numbers in the Java `long` range and count the occurrence of
-specific events. Please find detailed information about how metrics are collected in the [Metrics User Guide](../../process-engine/metrics.md).
-
-The default configuration of the [MetricsReporter](../../process-engine/metrics.md#metrics-reporter) will create one row per [metric](../../process-engine/metrics.md#built-in-metrics) in `ACT_RU_METER_LOG` every 15 minutes.
-
-## Task Metrics Log (ACT_RU_TASK_METER_LOG)
-
-The `ACT_RU_TASK_METER_LOG` table contains a collection of task related metrics that can help draw conclusions about usage, load
-and performance of Operaton. Task metrics contain a pseudonymized and fixed-length value of task assignees and their time of appearance. Please find detailed information about how task metrics are collected in the [Metrics User Guide](../../process-engine/metrics.md).
-
-Every assignment of a task to an assignee will create one row in `ACT_RU_TASK_METER_LOG`.
-
-# Entity Relationship Diagrams
-
-:::note
- The database is not part of the **public API**. The database schema may change for MINOR and MAJOR version updates.
-
- **Please note:**
- The following diagrams are based on the MySQL database schema. For other databases the diagram may be slightly different.
-:::
-
-
-The following Entity Relationship Diagrams visualize the database tables and their explicit foreign key constraints, grouped by Engine with focus on BPMN, Engine with focus on DMN, Engine with focus on CMMN, the Engine History and the Identity. Please note that the diagrams do not visualize implicit connections between the tables.
-
-
-## Engine BPMN
-
-BPMN Tables
-
-
-## Engine DMN
-
-DMN Tables
-
-
-## Engine CMMN
-
-CMMN Tables
-
-
-## History
-
-To allow different configurations and to keep the tables more flexible, the history tables contain no foreign key constraints.
-
-History Tables
-
-
-## Identity
-
-Identity Tables
diff --git a/docs/documentation/user-guide/process-engine/database/database-schema/general.md b/docs/documentation/user-guide/process-engine/database/database-schema/general.md
new file mode 100644
index 00000000..bb9eab94
--- /dev/null
+++ b/docs/documentation/user-guide/process-engine/database/database-schema/general.md
@@ -0,0 +1,157 @@
+---
+last_updated: 2026-11-11
+schema_version: 7.25
+---
+
+# General (GE_)
+
+General tables provide shared infrastructure: binary storage, system properties, and schema version tracking. All other domains depend on these tables.
+
+## Tables
+
+- **[`ACT_GE_PROPERTY`](#act_ge_property)** — System configuration key-value store
+- **[`ACT_GE_BYTEARRAY`](#act_ge_bytearray)** — Binary object storage (BLOBs)
+- **[`ACT_GE_SCHEMA_LOG`](#act_ge_schema_log)** — Schema migration history
+
+---
+
+## ACT_GE_PROPERTY
+
+**Purpose:** Key-value store for engine configuration, distributed locks, and ID generation state. Uses optimistic locking (`REV_`) to safely handle concurrent updates across engine nodes.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| NAME_ | VARCHAR(64) | PK NOT NULL | Property name (e.g., `next.dbid`, `historyLevel`) |
+| VALUE_ | VARCHAR(300) | NULL | Property value |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+
+**Standard Properties:**
+
+| Name | Purpose |
+|------|---------|
+| `schema.version` | Legacy marker, always `fox`. It does not hold the schema version; use `ACT_GE_SCHEMA_LOG` instead |
+| `schema.history` | Legacy marker (`create(fox)`) |
+| `next.dbid` | Start of the next ID block handed out by the `DbIdGenerator` |
+| `historyLevel` | ID of the history level the engine was first started with (`0`=none, `1`=activity, `2`=audit, `3`=full) |
+| `deployment.lock` | Exclusive lock row that serializes deployments across cluster nodes |
+| `history.cleanup.job.lock` | Exclusive lock row used when creating the history cleanup jobs |
+| `startup.lock` | Exclusive lock row used during engine bootstrap (e.g., setting the history level) |
+| `installationId.lock` | Exclusive lock row used while generating the installation ID |
+| `operaton.installation.id` | Unique ID of this installation, created on first start |
+
+**Example Queries:**
+
+```sql
+-- Configured history level
+SELECT VALUE_ FROM ACT_GE_PROPERTY WHERE NAME_ = 'historyLevel';
+
+-- All properties with revision
+SELECT NAME_, VALUE_, REV_ FROM ACT_GE_PROPERTY ORDER BY NAME_;
+```
+
+---
+
+## ACT_GE_BYTEARRAY
+
+**Purpose:** Central repository for all binary data — BPMN/DMN/CMMN XML files, process diagrams, form definitions, serialized variable values, job and external task exception stack traces, batch configurations, task attachments, and user pictures. Deployment artifacts are linked via `DEPLOYMENT_ID_`; all other rows are referenced by ID from the owning table (e.g., `ACT_RU_VARIABLE.BYTEARRAY_ID_`).
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Unique identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| NAME_ | VARCHAR(255) | NULL | Resource filename, variable name, or an engine-assigned name (e.g., `job.exceptionByteArray`) |
+| DEPLOYMENT_ID_ | VARCHAR(64) | FK → [ACT_RE_DEPLOYMENT](repository.md#act_re_deployment) | Associated deployment; NULL for runtime and history data |
+| BYTES_ | BYTEA | NULL | Binary content |
+| GENERATED_ | BOOLEAN | NULL | Marks resources generated during deployment rather than deployed by the user; the engine writes `false` for deployment resources and leaves it NULL for runtime and history data |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| TYPE_ | INTEGER | NULL | Resource type: `1`=repository, `2`=runtime, `3`=history |
+| CREATE_TIME_ | TIMESTAMP | NULL | Creation timestamp |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance (set for history data only; used by the history cleanup) |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Time after which the history cleanup deletes the row (history data only) |
+
+**Indexes:**
+
+| Index | Columns | Purpose |
+|-------|---------|---------|
+| ACT_IDX_BYTEAR_DEPL | DEPLOYMENT_ID_ | Resources per deployment |
+| ACT_IDX_BYTEARRAY_ROOT_PI | ROOT_PROC_INST_ID_ | Data per process instance |
+| ACT_IDX_BYTEARRAY_RM_TIME | REMOVAL_TIME_ | History cleanup |
+| ACT_IDX_BYTEARRAY_NAME | NAME_ | Search by name |
+
+**Referenced by:**
+
+- `ACT_RU_VARIABLE.BYTEARRAY_ID_` — binary variable values
+- `ACT_RU_JOB.EXCEPTION_STACK_ID_` — job exception stack traces
+- `ACT_RU_EXT_TASK.ERROR_DETAILS_ID_` — external task error details
+- Without FK constraint: `ACT_RU_BATCH.CONFIGURATION_`, `ACT_HI_VARINST.BYTEARRAY_ID_`, `ACT_HI_DETAIL.BYTEARRAY_ID_`, `ACT_HI_DEC_IN.BYTEARRAY_ID_`, `ACT_HI_DEC_OUT.BYTEARRAY_ID_`, `ACT_HI_JOB_LOG.JOB_EXCEPTION_STACK_ID_`, `ACT_HI_EXT_TASK_LOG.ERROR_DETAILS_ID_`, `ACT_HI_ATTACHMENT.CONTENT_ID_`, and `ACT_ID_INFO.VALUE_` (user picture entry)
+
+**Example Queries:**
+
+```sql
+-- Binary data for a deployment
+SELECT ID_, NAME_, GENERATED_, CREATE_TIME_, octet_length(BYTES_) AS size_bytes
+FROM ACT_GE_BYTEARRAY
+WHERE DEPLOYMENT_ID_ = 'deployment-id'
+ORDER BY CREATE_TIME_ DESC;
+
+-- Number and size of entries per resource type
+SELECT TYPE_, COUNT(*) AS entries, SUM(octet_length(BYTES_)) AS total_bytes
+FROM ACT_GE_BYTEARRAY
+GROUP BY TYPE_;
+
+-- Data scheduled for removal
+SELECT ID_, NAME_, REMOVAL_TIME_
+FROM ACT_GE_BYTEARRAY
+WHERE REMOVAL_TIME_ IS NOT NULL AND REMOVAL_TIME_ > CURRENT_TIMESTAMP
+ORDER BY REMOVAL_TIME_;
+```
+
+---
+
+## ACT_GE_SCHEMA_LOG
+
+**Purpose:** Immutable log of schema migration events. Each row records the schema creation or a version upgrade with a timestamp, enabling operators to verify and audit schema history.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Log entry identifier |
+| TIMESTAMP_ | TIMESTAMP | NULL | When the schema change was applied |
+| VERSION_ | VARCHAR(255) | NULL | Schema version string (e.g., `7.25.0`) |
+
+**Example Queries:**
+
+```sql
+-- Full migration history (newest first)
+SELECT ID_, TIMESTAMP_, VERSION_
+FROM ACT_GE_SCHEMA_LOG
+ORDER BY TIMESTAMP_ DESC;
+
+-- Current schema version
+SELECT VERSION_, TIMESTAMP_
+FROM ACT_GE_SCHEMA_LOG
+ORDER BY TIMESTAMP_ DESC
+LIMIT 1;
+```
+
+---
+
+## Design Notes
+
+- The `next.dbid` property must not be modified manually — the `DbIdGenerator` uses it to hand out unique ID blocks.
+- The `*.lock` properties carry no data. The engine locks these rows to serialize cluster-wide operations.
+- `ACT_GE_BYTEARRAY` serves dual purposes: deployment artifacts (keyed by `DEPLOYMENT_ID_`) and runtime/history data (history rows keyed by `ROOT_PROC_INST_ID_`). Query performance is optimised via separate indexes for each use case.
+- The history cleanup deletes `ACT_GE_BYTEARRAY` rows of history data once their `REMOVAL_TIME_` has passed. Do not delete rows manually.
+
+---
+
+See [Database-Specific Implementation Notes](index.md#database-specific-implementation-notes) for type mappings across PostgreSQL, MySQL/MariaDB, Oracle, MSSQL, H2, and DB2.
+
+---
+
+**Last Updated:** 2026-11-11 | **Schema Version:** 7.25 | **Operaton Versions:** 1.0.0+
diff --git a/docs/documentation/user-guide/process-engine/database/database-schema/history.md b/docs/documentation/user-guide/process-engine/database/database-schema/history.md
new file mode 100644
index 00000000..45b71b74
--- /dev/null
+++ b/docs/documentation/user-guide/process-engine/database/database-schema/history.md
@@ -0,0 +1,729 @@
+---
+last_updated: 2026-11-11
+schema_version: 7.25
+---
+
+# History (HI_)
+
+History tables store immutable audit records of completed processes, tasks, activities, variables, decisions, and operations. They are physically separate from runtime tables for query isolation and independent cleanup. History data is written as events occur and retained according to the `HISTORY_TTL_` configured on each definition.
+
+## Tables
+
+| Table | Purpose |
+|-------|---------|
+| [ACT_HI_PROCINST](#act_hi_procinst) | Historic process instances |
+| [ACT_HI_ACTINST](#act_hi_actinst) | Historic activity instances |
+| [ACT_HI_TASKINST](#act_hi_taskinst) | Historic task instances |
+| [ACT_HI_VARINST](#act_hi_varinst) | Historic variable values |
+| [ACT_HI_DETAIL](#act_hi_detail) | Historic variable change events |
+| [ACT_HI_IDENTITYLINK](#act_hi_identitylink) | Historic identity link events |
+| [ACT_HI_COMMENT](#act_hi_comment) | Task/process comments |
+| [ACT_HI_ATTACHMENT](#act_hi_attachment) | Task/process attachments |
+| [ACT_HI_OP_LOG](#act_hi_op_log) | Operator audit log |
+| [ACT_HI_INCIDENT](#act_hi_incident) | Historic incidents |
+| [ACT_HI_JOB_LOG](#act_hi_job_log) | Job execution log |
+| [ACT_HI_BATCH](#act_hi_batch) | Historic batch operations |
+| [ACT_HI_EXT_TASK_LOG](#act_hi_ext_task_log) | External task execution log |
+| [ACT_HI_CASEINST](#act_hi_caseinst) | Historic case instances (CMMN) |
+| [ACT_HI_CASEACTINST](#act_hi_caseactinst) | Historic case activity instances (CMMN) |
+| [ACT_HI_DECINST](#act_hi_decinst) | Historic decision evaluations (DMN) |
+| [ACT_HI_DEC_IN](#act_hi_dec_in) | Historic decision inputs (DMN) |
+| [ACT_HI_DEC_OUT](#act_hi_dec_out) | Historic decision outputs (DMN) |
+
+---
+
+## ACT_HI_PROCINST
+
+**Purpose:** Lifecycle record of a process instance. Inserted when the instance starts and updated when it ends, so running instances are included. Includes timing metrics for SLA analysis.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | History record ID |
+| PROC_INST_ID_ | VARCHAR(64) | NOT NULL UNIQUE | Runtime process instance ID |
+| BUSINESS_KEY_ | VARCHAR(255) | NULL | External correlation key |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| PROC_DEF_ID_ | VARCHAR(64) | NOT NULL | Process definition ID |
+| START_TIME_ | TIMESTAMP | NOT NULL | Start time |
+| END_TIME_ | TIMESTAMP | NULL | End time (NULL = still active) |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+| DURATION_ | BIGINT | NULL | Duration in milliseconds |
+| START_USER_ID_ | VARCHAR(255) | NULL | User who started the instance |
+| START_ACT_ID_ | VARCHAR(255) | NULL | Start event activity ID |
+| END_ACT_ID_ | VARCHAR(255) | NULL | End event activity ID |
+| SUPER_PROCESS_INSTANCE_ID_ | VARCHAR(64) | NULL | Parent process instance (call activity) |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root of nested subprocess hierarchy |
+| SUPER_CASE_INSTANCE_ID_ | VARCHAR(64) | NULL | Parent case instance |
+| CASE_INST_ID_ | VARCHAR(64) | NULL | Associated case instance |
+| DELETE_REASON_ | VARCHAR(4000) | NULL | Reason when deleted/cancelled |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| STATE_ | VARCHAR(255) | NULL | `ACTIVE`, `SUSPENDED`, `COMPLETED`, `EXTERNALLY_TERMINATED`, `INTERNALLY_TERMINATED` |
+| RESTARTED_PROC_INST_ID_ | VARCHAR(64) | NULL | Original instance if this is a restart |
+
+**Indexes:** `ACT_IDX_HI_PRO_INST_END`, `ACT_IDX_HI_PRO_I_BUSKEY`, `ACT_IDX_HI_PRO_INST_TENANT_ID`, `ACT_IDX_HI_PRO_INST_PROC_DEF_KEY`, `ACT_IDX_HI_PRO_INST_PROC_TIME`, `ACT_IDX_HI_PRO_INST_ROOT_PI`, `ACT_IDX_HI_PRO_INST_RM_TIME`, `ACT_IDX_HI_PI_PDEFID_END_TIME`, `ACT_IDX_HI_PRO_RST_PRO_INST_ID`
+
+**Example Queries:**
+
+```sql
+-- SLA report: completed instances last 30 days
+SELECT PROC_DEF_KEY_, COUNT(*) AS count,
+ AVG(DURATION_) AS avg_ms,
+ MAX(DURATION_) AS max_ms
+FROM ACT_HI_PROCINST
+WHERE STATE_ = 'COMPLETED'
+ AND START_TIME_ >= CURRENT_TIMESTAMP - INTERVAL '30 days'
+GROUP BY PROC_DEF_KEY_
+ORDER BY avg_ms DESC;
+
+-- Instances pending cleanup
+SELECT ID_, PROC_DEF_KEY_, END_TIME_, REMOVAL_TIME_
+FROM ACT_HI_PROCINST
+WHERE REMOVAL_TIME_ < CURRENT_TIMESTAMP
+ORDER BY REMOVAL_TIME_;
+```
+
+---
+
+## ACT_HI_ACTINST
+
+**Purpose:** History record for each individual activity execution (task, gateway, event, subprocess). Created when an activity starts; END_TIME_ set on completion.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Activity instance history ID |
+| PARENT_ACT_INST_ID_ | VARCHAR(64) | NULL | Parent activity instance |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| PROC_DEF_ID_ | VARCHAR(64) | NOT NULL | Process definition ID |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_INST_ID_ | VARCHAR(64) | NOT NULL | Process instance |
+| EXECUTION_ID_ | VARCHAR(64) | NOT NULL | Execution scope |
+| ACT_ID_ | VARCHAR(255) | NOT NULL | Activity element ID |
+| TASK_ID_ | VARCHAR(64) | NULL | Associated task ID |
+| CALL_PROC_INST_ID_ | VARCHAR(64) | NULL | Called process instance (call activity) |
+| CALL_CASE_INST_ID_ | VARCHAR(64) | NULL | Called case instance |
+| ACT_NAME_ | VARCHAR(255) | NULL | Activity display name |
+| ACT_TYPE_ | VARCHAR(255) | NOT NULL | Activity type (userTask, serviceTask, …) |
+| ASSIGNEE_ | VARCHAR(255) | NULL | Assignee (for task activities) |
+| START_TIME_ | TIMESTAMP | NOT NULL | Activity start time |
+| END_TIME_ | TIMESTAMP | NULL | Activity end time |
+| DURATION_ | BIGINT | NULL | Duration in milliseconds |
+| ACT_INST_STATE_ | INTEGER | NULL | `0`=default (e.g. running), `1`=scope complete, `2`=canceled, `4`=ending (left normally via outgoing flow) |
+| SEQUENCE_COUNTER_ | BIGINT | NULL | Ordering counter |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+
+**Indexes:** `ACT_IDX_HI_ACTINST_ROOT_PI`, `ACT_IDX_HI_ACT_INST_START_END`, `ACT_IDX_HI_ACT_INST_END`, `ACT_IDX_HI_ACT_INST_PROCINST`, `ACT_IDX_HI_ACT_INST_COMP`, `ACT_IDX_HI_ACT_INST_STATS`, `ACT_IDX_HI_ACT_INST_TENANT_ID`, `ACT_IDX_HI_ACT_INST_RM_TIME`, `ACT_IDX_HI_ACT_INST_PROC_DEF_KEY`, `ACT_IDX_HI_AI_PDEFID_END_TIME`
+
+**Example Queries:**
+
+```sql
+-- Activity execution stats for a process definition
+SELECT ACT_ID_, ACT_TYPE_, COUNT(*) AS executions,
+ AVG(DURATION_) AS avg_ms, MAX(DURATION_) AS max_ms
+FROM ACT_HI_ACTINST
+WHERE PROC_DEF_KEY_ = 'invoice_approval'
+ AND END_TIME_ IS NOT NULL
+ AND START_TIME_ >= CURRENT_TIMESTAMP - INTERVAL '30 days'
+GROUP BY ACT_ID_, ACT_TYPE_
+ORDER BY avg_ms DESC;
+```
+
+---
+
+## ACT_HI_TASKINST
+
+**Purpose:** Historical record of each task instance. Captures full task lifecycle including assignment, delegation, priority, dates, and completion state.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Task history ID |
+| TASK_DEF_KEY_ | VARCHAR(255) | NULL | Task definition key |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition ID |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| EXECUTION_ID_ | VARCHAR(64) | NULL | Execution scope |
+| CASE_DEF_KEY_ | VARCHAR(255) | NULL | Case definition key (CMMN) |
+| CASE_DEF_ID_ | VARCHAR(64) | NULL | Case definition ID |
+| CASE_INST_ID_ | VARCHAR(64) | NULL | Case instance |
+| CASE_EXECUTION_ID_ | VARCHAR(64) | NULL | Case execution |
+| ACT_INST_ID_ | VARCHAR(64) | NULL | Activity instance reference |
+| NAME_ | VARCHAR(255) | NULL | Task name |
+| PARENT_TASK_ID_ | VARCHAR(64) | NULL | Parent task |
+| DESCRIPTION_ | VARCHAR(4000) | NULL | Task description |
+| OWNER_ | VARCHAR(255) | NULL | Task owner |
+| ASSIGNEE_ | VARCHAR(255) | NULL | Assignee |
+| START_TIME_ | TIMESTAMP | NOT NULL | Task creation time |
+| END_TIME_ | TIMESTAMP | NULL | Task completion time |
+| DURATION_ | BIGINT | NULL | Duration in milliseconds |
+| DELETE_REASON_ | VARCHAR(4000) | NULL | `completed` on normal completion; `deleted` or a custom reason when deleted/cancelled |
+| PRIORITY_ | INTEGER | NULL | Task priority |
+| DUE_DATE_ | TIMESTAMP | NULL | Due date |
+| FOLLOW_UP_DATE_ | TIMESTAMP | NULL | Follow-up date |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+| TASK_STATE_ | VARCHAR(64) | NULL | Lifecycle state: `Init`, `Created`, `Updated`, `Completed`, `Deleted` |
+
+**Indexes:** `ACT_IDX_HI_TASKINST_ROOT_PI`, `ACT_IDX_HI_TASK_INST_TENANT_ID`, `ACT_IDX_HI_TASK_INST_PROC_DEF_KEY`, `ACT_IDX_HI_TASKINST_PROCINST`, `ACT_IDX_HI_TASK_INST_RM_TIME`, `ACT_IDX_HI_TASK_INST_START`, `ACT_IDX_HI_TASK_INST_END`, `ACT_IDX_HI_TASKINSTID_PROCINST`
+
+**Example Queries:**
+
+```sql
+-- Average task duration by definition
+SELECT TASK_DEF_KEY_, COUNT(*) AS completions,
+ AVG(DURATION_) AS avg_ms
+FROM ACT_HI_TASKINST
+WHERE DELETE_REASON_ = 'completed'
+ AND START_TIME_ >= CURRENT_TIMESTAMP - INTERVAL '30 days'
+GROUP BY TASK_DEF_KEY_
+ORDER BY avg_ms DESC;
+
+-- Tasks completed by a specific user
+SELECT ID_, NAME_, PROC_INST_ID_, START_TIME_, END_TIME_, DURATION_
+FROM ACT_HI_TASKINST
+WHERE ASSIGNEE_ = 'john.doe' AND DELETE_REASON_ = 'completed'
+ORDER BY END_TIME_ DESC
+LIMIT 50;
+```
+
+---
+
+## ACT_HI_VARINST
+
+**Purpose:** Snapshot of each variable's current value. Updated when the variable changes; represents the latest known value when history level includes variables.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Variable history ID |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition ID |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| EXECUTION_ID_ | VARCHAR(64) | NULL | Execution scope |
+| ACT_INST_ID_ | VARCHAR(64) | NULL | Activity instance |
+| CASE_DEF_KEY_ | VARCHAR(255) | NULL | Case definition key |
+| CASE_DEF_ID_ | VARCHAR(64) | NULL | Case definition ID |
+| CASE_INST_ID_ | VARCHAR(64) | NULL | Case instance |
+| CASE_EXECUTION_ID_ | VARCHAR(64) | NULL | Case execution |
+| TASK_ID_ | VARCHAR(64) | NULL | Task scope |
+| NAME_ | VARCHAR(255) | NOT NULL | Variable name |
+| VAR_TYPE_ | VARCHAR(100) | NULL | Variable type |
+| CREATE_TIME_ | TIMESTAMP | NULL | When variable was first set |
+| REV_ | INTEGER | NULL | Revision |
+| BYTEARRAY_ID_ | VARCHAR(64) | NULL | Binary value reference |
+| DOUBLE_ | DOUBLE PRECISION | NULL | Float value |
+| LONG_ | BIGINT | NULL | Integer/long/short value; also boolean (`1`/`0`) and date (epoch millis) |
+| TEXT_ | VARCHAR(4000) | NULL | String value; also string form of integer/long/short values, file name for file values |
+| TEXT2_ | VARCHAR(4000) | NULL | Type-specific extra value (object type name, MIME type) |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| STATE_ | VARCHAR(20) | NULL | Variable state (`CREATED`, `DELETED`) |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+
+**Indexes:** `ACT_IDX_HI_VARINST_ROOT_PI`, `ACT_IDX_HI_PROCVAR_PROC_INST`, `ACT_IDX_HI_PROCVAR_NAME_TYPE`, `ACT_IDX_HI_VAR_INST_TENANT_ID`, `ACT_IDX_HI_VARINST_BYTEAR`, `ACT_IDX_HI_VARINST_RM_TIME`, `ACT_IDX_HI_VAR_PI_NAME_TYPE`, `ACT_IDX_HI_VARINST_NAME`, `ACT_IDX_HI_VARINST_ACT_INST_ID`, `ACT_IDX_HI_CASEVAR_CASE_INST`, `ACT_IDX_HI_VAR_INST_PROC_DEF_KEY`
+
+---
+
+## ACT_HI_DETAIL
+
+**Purpose:** Fine-grained variable change events. Each row is a single variable update or form property event and holds the value after the change. Form property events are written from history level `AUDIT`; variable updates only with `FULL`, which gives a complete variable audit trail.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Detail event ID |
+| TYPE_ | VARCHAR(255) | NOT NULL | Event type: `VariableUpdate`, `FormProperty` |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition ID |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| EXECUTION_ID_ | VARCHAR(64) | NULL | Execution scope |
+| CASE_DEF_KEY_ | VARCHAR(255) | NULL | Case definition key |
+| CASE_DEF_ID_ | VARCHAR(64) | NULL | Case definition ID |
+| CASE_INST_ID_ | VARCHAR(64) | NULL | Case instance |
+| CASE_EXECUTION_ID_ | VARCHAR(64) | NULL | Case execution |
+| TASK_ID_ | VARCHAR(64) | NULL | Task scope |
+| ACT_INST_ID_ | VARCHAR(64) | NULL | Activity instance |
+| VAR_INST_ID_ | VARCHAR(64) | NULL | Variable instance reference |
+| NAME_ | VARCHAR(255) | NOT NULL | Variable/property name |
+| VAR_TYPE_ | VARCHAR(64) | NULL | Variable type |
+| REV_ | INTEGER | NULL | Revision |
+| TIME_ | TIMESTAMP | NOT NULL | Event timestamp |
+| BYTEARRAY_ID_ | VARCHAR(64) | NULL | Binary value reference |
+| DOUBLE_ | DOUBLE PRECISION | NULL | Float value |
+| LONG_ | BIGINT | NULL | Integer/long/short value; also boolean (`1`/`0`) and date (epoch millis) |
+| TEXT_ | VARCHAR(4000) | NULL | String value; also string form of integer/long/short values, file name for file values |
+| TEXT2_ | VARCHAR(4000) | NULL | Type-specific extra value (object type name, MIME type) |
+| SEQUENCE_COUNTER_ | BIGINT | NULL | Ordering counter |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| OPERATION_ID_ | VARCHAR(64) | NULL | Linked operation log entry |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+| INITIAL_ | BOOLEAN | NULL | Whether this is the initial value |
+
+**Indexes:** `ACT_IDX_HI_DETAIL_ROOT_PI`, `ACT_IDX_HI_DETAIL_PROC_INST`, `ACT_IDX_HI_DETAIL_ACT_INST`, `ACT_IDX_HI_DETAIL_TIME`, `ACT_IDX_HI_DETAIL_NAME`, `ACT_IDX_HI_DETAIL_TASK_ID`, `ACT_IDX_HI_DETAIL_RM_TIME`, `ACT_IDX_HI_DETAIL_BYTEAR`, `ACT_IDX_HI_DETAIL_VAR_INST_ID`, `ACT_IDX_HI_DETAIL_CASE_INST`, `ACT_IDX_HI_DETAIL_CASE_EXEC`, `ACT_IDX_HI_DETAIL_TENANT_ID`, `ACT_IDX_HI_DETAIL_PROC_DEF_KEY`, `ACT_IDX_HI_DETAIL_TASK_BYTEAR`
+
+---
+
+## ACT_HI_IDENTITYLINK
+
+**Purpose:** Audit log of identity link add/remove events (task assignment, candidate group changes). Each row is a timestamped event, not current state.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Event ID |
+| TIMESTAMP_ | TIMESTAMP | NOT NULL | Event time |
+| TYPE_ | VARCHAR(255) | NULL | Link type |
+| USER_ID_ | VARCHAR(255) | NULL | User |
+| GROUP_ID_ | VARCHAR(255) | NULL | Group |
+| TASK_ID_ | VARCHAR(64) | NULL | Associated task |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition |
+| OPERATION_TYPE_ | VARCHAR(64) | NULL | `add` or `delete` |
+| ASSIGNER_ID_ | VARCHAR(64) | NULL | User who made the change |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+
+**Indexes:** `ACT_IDX_HI_IDENT_LNK_ROOT_PI`, `ACT_IDX_HI_IDENT_LNK_USER`, `ACT_IDX_HI_IDENT_LNK_GROUP`, `ACT_IDX_HI_IDENT_LNK_TENANT_ID`, `ACT_IDX_HI_IDENT_LINK_TASK`, `ACT_IDX_HI_IDENT_LINK_RM_TIME`, `ACT_IDX_HI_IDENT_LNK_TIMESTAMP`, `ACT_IDX_HI_IDENT_LNK_PROC_DEF_KEY`
+
+---
+
+## ACT_HI_COMMENT
+
+**Purpose:** User and system comments on tasks and process instances. `FULL_MSG_` always stores the full comment text as binary; `MESSAGE_` holds a shortened copy for display.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Comment ID |
+| TYPE_ | VARCHAR(255) | NULL | `comment` (the engine writes only this value; `event` is legacy) |
+| TIME_ | TIMESTAMP | NOT NULL | Comment timestamp |
+| USER_ID_ | VARCHAR(255) | NULL | Author user ID |
+| TASK_ID_ | VARCHAR(64) | NULL | Associated task |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| ACTION_ | VARCHAR(255) | NULL | Last action on the comment: `AddComment` or `UpdateComment` |
+| MESSAGE_ | VARCHAR(4000) | NULL | Comment text (truncated) |
+| FULL_MSG_ | BYTEA | NULL | Full comment text (binary) |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+| REV_ | INTEGER | NOT NULL DEFAULT 1 | Revision |
+
+**Indexes:** `ACT_IDX_HI_COMMENT_TASK`, `ACT_IDX_HI_COMMENT_ROOT_PI`, `ACT_IDX_HI_COMMENT_PROCINST`, `ACT_IDX_HI_COMMENT_RM_TIME`
+
+---
+
+## ACT_HI_ATTACHMENT
+
+**Purpose:** Attachments (files, URLs) associated with tasks or process instances.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Attachment ID |
+| REV_ | INTEGER | NULL | Revision |
+| USER_ID_ | VARCHAR(255) | NULL | Not written by the engine (always NULL) |
+| NAME_ | VARCHAR(255) | NULL | Attachment name |
+| DESCRIPTION_ | VARCHAR(4000) | NULL | Description |
+| TYPE_ | VARCHAR(255) | NULL | MIME type or category |
+| TASK_ID_ | VARCHAR(64) | NULL | Associated task |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| URL_ | VARCHAR(4000) | NULL | External URL |
+| CONTENT_ID_ | VARCHAR(64) | NULL | Reference to content in ACT_GE_BYTEARRAY |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| CREATE_TIME_ | TIMESTAMP | NULL | Upload time |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+
+**Indexes:** `ACT_IDX_HI_ATTACHMENT_CONTENT`, `ACT_IDX_HI_ATTACHMENT_ROOT_PI`, `ACT_IDX_HI_ATTACHMENT_PROCINST`, `ACT_IDX_HI_ATTACHMENT_TASK`, `ACT_IDX_HI_ATTACHMENT_RM_TIME`
+
+---
+
+## ACT_HI_OP_LOG
+
+**Purpose:** Operator audit log. Records administrative operations (suspend/activate, delete, migrate, reassign) performed by users (by default only logged when a user is authenticated). Essential for compliance and forensics.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Log entry ID |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Associated deployment |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| EXECUTION_ID_ | VARCHAR(64) | NULL | Execution |
+| CASE_DEF_ID_ | VARCHAR(64) | NULL | Case definition |
+| CASE_INST_ID_ | VARCHAR(64) | NULL | Case instance |
+| CASE_EXECUTION_ID_ | VARCHAR(64) | NULL | Case execution |
+| TASK_ID_ | VARCHAR(64) | NULL | Task |
+| JOB_ID_ | VARCHAR(64) | NULL | Job |
+| JOB_DEF_ID_ | VARCHAR(64) | NULL | Job definition |
+| BATCH_ID_ | VARCHAR(64) | NULL | Batch |
+| USER_ID_ | VARCHAR(255) | NULL | User who performed the operation |
+| TIMESTAMP_ | TIMESTAMP | NOT NULL | When the operation occurred |
+| OPERATION_TYPE_ | VARCHAR(64) | NULL | Operation (e.g., `Suspend`, `Delete`, `Assign`) |
+| OPERATION_ID_ | VARCHAR(64) | NULL | Groups related changes in one operation |
+| ENTITY_TYPE_ | VARCHAR(30) | NULL | Entity class (e.g., `ProcessInstance`, `Task`) |
+| PROPERTY_ | VARCHAR(64) | NULL | Property changed |
+| ORG_VALUE_ | VARCHAR(4000) | NULL | Old value |
+| NEW_VALUE_ | VARCHAR(4000) | NULL | New value |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+| CATEGORY_ | VARCHAR(64) | NULL | Operation category: `Operator`, `Admin`, `TaskWorker` |
+| EXTERNAL_TASK_ID_ | VARCHAR(64) | NULL | External task |
+| ANNOTATION_ | VARCHAR(4000) | NULL | Operator notes |
+
+**Indexes:** `ACT_IDX_HI_OP_LOG_ROOT_PI`, `ACT_IDX_HI_OP_LOG_PROCINST`, `ACT_IDX_HI_OP_LOG_PROCDEF`, `ACT_IDX_HI_OP_LOG_TASK`, `ACT_IDX_HI_OP_LOG_RM_TIME`, `ACT_IDX_HI_OP_LOG_TIMESTAMP`, `ACT_IDX_HI_OP_LOG_USER_ID`, `ACT_IDX_HI_OP_LOG_OP_TYPE`, `ACT_IDX_HI_OP_LOG_ENTITY_TYPE`
+
+**Example Queries:**
+
+```sql
+-- All operations on a process instance
+SELECT TIMESTAMP_, USER_ID_, OPERATION_TYPE_, ENTITY_TYPE_,
+ PROPERTY_, ORG_VALUE_, NEW_VALUE_, ANNOTATION_
+FROM ACT_HI_OP_LOG
+WHERE PROC_INST_ID_ = 'pi-id'
+ORDER BY TIMESTAMP_;
+
+-- Recent admin operations by user
+SELECT TIMESTAMP_, OPERATION_TYPE_, ENTITY_TYPE_, PROC_INST_ID_, TASK_ID_
+FROM ACT_HI_OP_LOG
+WHERE USER_ID_ = 'admin' AND TIMESTAMP_ >= CURRENT_TIMESTAMP - INTERVAL '24 hours'
+ORDER BY TIMESTAMP_ DESC;
+```
+
+---
+
+## ACT_HI_INCIDENT
+
+**Purpose:** Historical record of incidents (resolved and open). Captures the full lifecycle including resolution time and configuration history.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Incident history ID |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition ID |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| EXECUTION_ID_ | VARCHAR(64) | NULL | Execution |
+| CREATE_TIME_ | TIMESTAMP | NOT NULL | Incident creation time |
+| END_TIME_ | TIMESTAMP | NULL | Resolution/deletion time |
+| INCIDENT_MSG_ | VARCHAR(4000) | NULL | Error message |
+| INCIDENT_TYPE_ | VARCHAR(255) | NOT NULL | Incident type |
+| ACTIVITY_ID_ | VARCHAR(255) | NULL | Activity where incident occurred |
+| FAILED_ACTIVITY_ID_ | VARCHAR(255) | NULL | Failed activity |
+| CAUSE_INCIDENT_ID_ | VARCHAR(64) | NULL | Cause incident |
+| ROOT_CAUSE_INCIDENT_ID_ | VARCHAR(64) | NULL | Root cause incident |
+| CONFIGURATION_ | VARCHAR(255) | NULL | Configuration (e.g., job ID) |
+| HISTORY_CONFIGURATION_ | VARCHAR(255) | NULL | ID of the failure log entry (`ACT_HI_JOB_LOG` / `ACT_HI_EXT_TASK_LOG`) that caused the incident |
+| INCIDENT_STATE_ | INTEGER | NULL | `0`=open, `1`=resolved, `2`=deleted |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| JOB_DEF_ID_ | VARCHAR(64) | NULL | Job definition |
+| ANNOTATION_ | VARCHAR(4000) | NULL | Operator notes |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+
+**Indexes:** `ACT_IDX_HI_INCIDENT_TENANT_ID`, `ACT_IDX_HI_INCIDENT_PROC_DEF_KEY`, `ACT_IDX_HI_INCIDENT_ROOT_PI`, `ACT_IDX_HI_INCIDENT_PROCINST`, `ACT_IDX_HI_INCIDENT_RM_TIME`, `ACT_IDX_HI_INCIDENT_CREATE_TIME`, `ACT_IDX_HI_INCIDENT_END_TIME`
+
+---
+
+## ACT_HI_JOB_LOG
+
+**Purpose:** Execution log for background jobs. One row per job event: created, failed (including each retry), successful, or deleted. Essential for debugging asynchronous failures.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Log entry ID |
+| TIMESTAMP_ | TIMESTAMP | NOT NULL | Event timestamp |
+| JOB_ID_ | VARCHAR(64) | NOT NULL | Job that was logged |
+| JOB_DUEDATE_ | TIMESTAMP | NULL | Job due time at event |
+| JOB_RETRIES_ | INTEGER | NULL | Retry count at event |
+| JOB_PRIORITY_ | BIGINT | NOT NULL DEFAULT 0 | Job priority at event |
+| JOB_EXCEPTION_MSG_ | VARCHAR(4000) | NULL | Exception message |
+| JOB_EXCEPTION_STACK_ID_ | VARCHAR(64) | NULL | Stack trace reference |
+| JOB_STATE_ | INTEGER | NULL | `0`=created, `1`=failed, `2`=successful, `3`=deleted |
+| JOB_DEF_ID_ | VARCHAR(64) | NULL | Job definition |
+| JOB_DEF_TYPE_ | VARCHAR(255) | NULL | Job type |
+| JOB_DEF_CONFIGURATION_ | VARCHAR(255) | NULL | Job configuration |
+| ACT_ID_ | VARCHAR(255) | NULL | Activity ID |
+| FAILED_ACT_ID_ | VARCHAR(255) | NULL | Failed activity ID |
+| EXECUTION_ID_ | VARCHAR(64) | NULL | Execution |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROCESS_INSTANCE_ID_ | VARCHAR(64) | NULL | Process instance |
+| PROCESS_DEF_ID_ | VARCHAR(64) | NULL | Process definition ID |
+| PROCESS_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Deployment |
+| SEQUENCE_COUNTER_ | BIGINT | NULL | Ordering counter |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| HOSTNAME_ | VARCHAR(255) | NULL | Engine node hostname |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+| BATCH_ID_ | VARCHAR(64) | NULL | Associated batch |
+
+**Indexes:** `ACT_IDX_HI_JOB_LOG_ROOT_PI`, `ACT_IDX_HI_JOB_LOG_PROCINST`, `ACT_IDX_HI_JOB_LOG_PROCDEF`, `ACT_IDX_HI_JOB_LOG_TENANT_ID`, `ACT_IDX_HI_JOB_LOG_JOB_DEF_ID`, `ACT_IDX_HI_JOB_LOG_EX_STACK`, `ACT_IDX_HI_JOB_LOG_RM_TIME`, `ACT_IDX_HI_JOB_LOG_JOB_CONF`, `ACT_IDX_HI_JOB_LOG_PROC_DEF_KEY`
+
+**Example Queries:**
+
+```sql
+-- All log entries for a job
+SELECT TIMESTAMP_, JOB_STATE_, JOB_RETRIES_, JOB_EXCEPTION_MSG_, HOSTNAME_
+FROM ACT_HI_JOB_LOG
+WHERE JOB_ID_ = 'job-id'
+ORDER BY TIMESTAMP_;
+
+-- Frequently failing jobs
+SELECT PROCESS_DEF_KEY_, ACT_ID_, COUNT(*) AS failures
+FROM ACT_HI_JOB_LOG
+WHERE JOB_STATE_ = 1 -- failed
+ AND TIMESTAMP_ >= CURRENT_TIMESTAMP - INTERVAL '7 days'
+GROUP BY PROCESS_DEF_KEY_, ACT_ID_
+ORDER BY failures DESC;
+```
+
+---
+
+## ACT_HI_BATCH
+
+**Purpose:** Historical record of batch operations. Inserted when the batch starts; `END_TIME_` is set when it completes.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Batch history ID |
+| TYPE_ | VARCHAR(255) | NULL | Batch type |
+| TOTAL_JOBS_ | INTEGER | NULL | Total jobs |
+| JOBS_PER_SEED_ | INTEGER | NULL | Jobs per seed |
+| INVOCATIONS_PER_JOB_ | INTEGER | NULL | Invocations per job |
+| SEED_JOB_DEF_ID_ | VARCHAR(64) | NULL | Seed job definition |
+| MONITOR_JOB_DEF_ID_ | VARCHAR(64) | NULL | Monitor job definition |
+| BATCH_JOB_DEF_ID_ | VARCHAR(64) | NULL | Batch job definition |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| CREATE_USER_ID_ | VARCHAR(255) | NULL | User who started the batch |
+| START_TIME_ | TIMESTAMP | NOT NULL | Start time |
+| END_TIME_ | TIMESTAMP | NULL | End time |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+| EXEC_START_TIME_ | TIMESTAMP | NULL | Execution phase start |
+
+**Indexes:** `ACT_HI_BAT_RM_TIME`
+
+---
+
+## ACT_HI_EXT_TASK_LOG
+
+**Purpose:** Execution log for external tasks. One row per event: created, failed, successful, or deleted. Mirrors `ACT_HI_JOB_LOG` for the external task pattern.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Log entry ID |
+| TIMESTAMP_ | TIMESTAMP | NOT NULL | Event timestamp |
+| EXT_TASK_ID_ | VARCHAR(64) | NOT NULL | External task |
+| RETRIES_ | INTEGER | NULL | Retry count at event |
+| TOPIC_NAME_ | VARCHAR(255) | NULL | Worker topic |
+| WORKER_ID_ | VARCHAR(255) | NULL | Worker ID |
+| PRIORITY_ | BIGINT | NOT NULL DEFAULT 0 | Priority at event |
+| ERROR_MSG_ | VARCHAR(4000) | NULL | Error message |
+| ERROR_DETAILS_ID_ | VARCHAR(64) | NULL | Error detail reference |
+| ACT_ID_ | VARCHAR(255) | NULL | Activity ID |
+| ACT_INST_ID_ | VARCHAR(64) | NULL | Activity instance |
+| EXECUTION_ID_ | VARCHAR(64) | NULL | Execution |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| STATE_ | INTEGER | NULL | `0`=created, `1`=failed, `2`=successful, `3`=deleted |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+
+**Indexes:** `ACT_HI_EXT_TASK_LOG_ROOT_PI`, `ACT_HI_EXT_TASK_LOG_PROCINST`, `ACT_HI_EXT_TASK_LOG_PROCDEF`, `ACT_HI_EXT_TASK_LOG_PROC_DEF_KEY`, `ACT_HI_EXT_TASK_LOG_TENANT_ID`, `ACT_IDX_HI_EXTTASKLOG_ERRORDET`, `ACT_HI_EXT_TASK_LOG_RM_TIME`
+
+---
+
+## ACT_HI_CASEINST
+
+**Purpose:** Historical record of a CMMN case instance lifecycle.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | History record ID |
+| CASE_INST_ID_ | VARCHAR(64) | NOT NULL UNIQUE | Runtime case instance ID |
+| BUSINESS_KEY_ | VARCHAR(255) | NULL | External correlation key |
+| CASE_DEF_ID_ | VARCHAR(64) | NOT NULL | Case definition ID |
+| CREATE_TIME_ | TIMESTAMP | NOT NULL | Case creation time |
+| CLOSE_TIME_ | TIMESTAMP | NULL | Case close time |
+| DURATION_ | BIGINT | NULL | Duration in milliseconds |
+| STATE_ | INTEGER | NULL | Case state: `4`=active, `5`=suspended, `6`=terminated, `7`=completed, `8`=failed, `9`=closed |
+| CREATE_USER_ID_ | VARCHAR(255) | NULL | User who created the case |
+| SUPER_CASE_INSTANCE_ID_ | VARCHAR(64) | NULL | Parent case instance |
+| SUPER_PROCESS_INSTANCE_ID_ | VARCHAR(64) | NULL | Parent process instance |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_HI_CAS_I_CLOSE`, `ACT_IDX_HI_CAS_I_BUSKEY`, `ACT_IDX_HI_CAS_I_TENANT_ID`
+
+---
+
+## ACT_HI_CASEACTINST
+
+**Purpose:** Historical record of each activity (stage, milestone, task) executed within a case.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | History record ID |
+| PARENT_ACT_INST_ID_ | VARCHAR(64) | NULL | Parent activity instance |
+| CASE_DEF_ID_ | VARCHAR(64) | NOT NULL | Case definition ID |
+| CASE_INST_ID_ | VARCHAR(64) | NOT NULL | Case instance |
+| CASE_ACT_ID_ | VARCHAR(255) | NOT NULL | CMMN activity element ID |
+| TASK_ID_ | VARCHAR(64) | NULL | Associated task |
+| CALL_PROC_INST_ID_ | VARCHAR(64) | NULL | Called process instance |
+| CALL_CASE_INST_ID_ | VARCHAR(64) | NULL | Called case instance |
+| CASE_ACT_NAME_ | VARCHAR(255) | NULL | Activity display name |
+| CASE_ACT_TYPE_ | VARCHAR(255) | NULL | Activity type (stage, milestone, …) |
+| CREATE_TIME_ | TIMESTAMP | NOT NULL | Activity start time |
+| END_TIME_ | TIMESTAMP | NULL | Activity end time |
+| DURATION_ | BIGINT | NULL | Duration in milliseconds |
+| STATE_ | INTEGER | NULL | State: `1`=available, `2`=enabled, `3`=disabled, `4`=active, `5`=suspended, `6`=terminated, `7`=completed |
+| REQUIRED_ | BOOLEAN | NULL | Required for case completion |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_HI_CAS_A_I_CREATE`, `ACT_IDX_HI_CAS_A_I_END`, `ACT_IDX_HI_CAS_A_I_COMP`, `ACT_IDX_HI_CAS_A_I_TENANT_ID`
+
+---
+
+## ACT_HI_DECINST
+
+**Purpose:** Records each DMN decision evaluation — which decision was evaluated, when, with what context (process/case/standalone).
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Decision evaluation ID |
+| DEC_DEF_ID_ | VARCHAR(64) | NOT NULL | Decision definition ID |
+| DEC_DEF_KEY_ | VARCHAR(255) | NOT NULL | Decision key |
+| DEC_DEF_NAME_ | VARCHAR(255) | NULL | Decision name |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Calling process key |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Calling process definition |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Calling process instance |
+| CASE_DEF_KEY_ | VARCHAR(255) | NULL | Calling case key |
+| CASE_DEF_ID_ | VARCHAR(64) | NULL | Calling case definition |
+| CASE_INST_ID_ | VARCHAR(64) | NULL | Calling case instance |
+| ACT_INST_ID_ | VARCHAR(64) | NULL | Activity instance that triggered evaluation |
+| ACT_ID_ | VARCHAR(255) | NULL | Activity ID |
+| EVAL_TIME_ | TIMESTAMP | NOT NULL | Evaluation timestamp |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+| COLLECT_VALUE_ | DOUBLE PRECISION | NULL | Aggregated collect value (for collect hit policy) |
+| USER_ID_ | VARCHAR(255) | NULL | Authenticated user who evaluated the decision (standalone evaluations only) |
+| ROOT_DEC_INST_ID_ | VARCHAR(64) | NULL | Root decision instance (for chained evaluations) |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| DEC_REQ_ID_ | VARCHAR(64) | NULL | Decision requirement definition |
+| DEC_REQ_KEY_ | VARCHAR(255) | NULL | Decision requirement key |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_HI_DEC_INST_ID`, `ACT_IDX_HI_DEC_INST_KEY`, `ACT_IDX_HI_DEC_INST_PI`, `ACT_IDX_HI_DEC_INST_TIME`, `ACT_IDX_HI_DEC_INST_TENANT_ID`, `ACT_IDX_HI_DEC_INST_ROOT_PI`, `ACT_IDX_HI_DEC_INST_REQ_ID`, `ACT_IDX_HI_DEC_INST_RM_TIME`, `ACT_IDX_HI_DEC_INST_CI`, `ACT_IDX_HI_DEC_INST_ACT`, `ACT_IDX_HI_DEC_INST_ACT_INST`, `ACT_IDX_HI_DEC_INST_ROOT_ID`, `ACT_IDX_HI_DEC_INST_REQ_KEY`
+
+**Example Queries:**
+
+```sql
+-- Decision evaluation frequency
+SELECT DEC_DEF_KEY_, COUNT(*) AS evaluations,
+ AVG(COLLECT_VALUE_) AS avg_collect
+FROM ACT_HI_DECINST
+WHERE EVAL_TIME_ >= CURRENT_TIMESTAMP - INTERVAL '7 days'
+GROUP BY DEC_DEF_KEY_
+ORDER BY evaluations DESC;
+```
+
+---
+
+## ACT_HI_DEC_IN
+
+**Purpose:** Input clause values used in a specific decision evaluation. One row per input clause per evaluation.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Input record ID |
+| DEC_INST_ID_ | VARCHAR(64) | NOT NULL | Parent decision evaluation (`ACT_HI_DECINST.ID_`, no FK constraint) |
+| CLAUSE_ID_ | VARCHAR(64) | NULL | Input clause element ID |
+| CLAUSE_NAME_ | VARCHAR(255) | NULL | Input clause name |
+| VAR_TYPE_ | VARCHAR(100) | NULL | Variable type |
+| BYTEARRAY_ID_ | VARCHAR(64) | NULL | Binary value reference |
+| DOUBLE_ | DOUBLE PRECISION | NULL | Float value |
+| LONG_ | BIGINT | NULL | Integer/long/short value; also boolean (`1`/`0`) and date (epoch millis) |
+| TEXT_ | VARCHAR(4000) | NULL | String value; also string form of integer/long/short values, file name for file values |
+| TEXT2_ | VARCHAR(4000) | NULL | Type-specific extra value (object type name, MIME type) |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| CREATE_TIME_ | TIMESTAMP | NULL | Creation time |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+
+**Indexes:** `ACT_IDX_HI_DEC_IN_INST`, `ACT_IDX_HI_DEC_IN_CLAUSE`, `ACT_IDX_HI_DEC_IN_ROOT_PI`, `ACT_IDX_HI_DEC_IN_RM_TIME`
+
+---
+
+## ACT_HI_DEC_OUT
+
+**Purpose:** Output clause values produced by a decision evaluation. One row per output clause per matched rule per evaluation (a literal expression decision writes a single row without clause/rule).
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Output record ID |
+| DEC_INST_ID_ | VARCHAR(64) | NOT NULL | Parent decision evaluation (`ACT_HI_DECINST.ID_`, no FK constraint) |
+| CLAUSE_ID_ | VARCHAR(64) | NULL | Output clause element ID |
+| CLAUSE_NAME_ | VARCHAR(255) | NULL | Output clause name |
+| RULE_ID_ | VARCHAR(64) | NULL | Matched rule ID |
+| RULE_ORDER_ | INTEGER | NULL | Position of the rule among the matched rules (1-based) |
+| VAR_NAME_ | VARCHAR(255) | NULL | Output variable name |
+| VAR_TYPE_ | VARCHAR(100) | NULL | Variable type |
+| BYTEARRAY_ID_ | VARCHAR(64) | NULL | Binary value reference |
+| DOUBLE_ | DOUBLE PRECISION | NULL | Float value |
+| LONG_ | BIGINT | NULL | Integer/long/short value; also boolean (`1`/`0`) and date (epoch millis) |
+| TEXT_ | VARCHAR(4000) | NULL | String value; also string form of integer/long/short values, file name for file values |
+| TEXT2_ | VARCHAR(4000) | NULL | Type-specific extra value (object type name, MIME type) |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| CREATE_TIME_ | TIMESTAMP | NULL | Creation time |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Scheduled cleanup time |
+
+**Indexes:** `ACT_IDX_HI_DEC_OUT_INST`, `ACT_IDX_HI_DEC_OUT_RULE`, `ACT_IDX_HI_DEC_OUT_ROOT_PI`, `ACT_IDX_HI_DEC_OUT_RM_TIME`
+
+---
+
+## Design Notes
+
+- **History levels**: The amount of data written to history tables is controlled by the engine's history level: `NONE`, `ACTIVITY`, `AUDIT`, `FULL`. `FULL` writes `ACT_HI_DETAIL` for every variable change.
+- **REMOVAL_TIME_**: With the default removal-time-based cleanup strategy, the engine sets `REMOVAL_TIME_` when the root process instance ends (end time plus `HISTORY_TTL_` of the definition). The history cleanup job deletes rows whose removal time has passed, in batches within the configured cleanup window.
+- **Updates**: Log-style tables (`ACT_HI_DETAIL`, `ACT_HI_JOB_LOG`, `ACT_HI_EXT_TASK_LOG`, `ACT_HI_IDENTITYLINK`, `ACT_HI_OP_LOG`) are append-only, apart from setting `REMOVAL_TIME_` and editing `ACT_HI_OP_LOG.ANNOTATION_`. Instance tables (`ACT_HI_PROCINST`, `ACT_HI_ACTINST`, `ACT_HI_TASKINST`, `ACT_HI_VARINST`, `ACT_HI_INCIDENT`, `ACT_HI_BATCH`, `ACT_HI_CASEINST`, `ACT_HI_CASEACTINST`) are updated while the instance runs.
+- **ACT_HI_PROCINST vs ACT_HI_ACTINST**: `PROCINST` is one row per process instance; `ACTINST` is many rows — one per activity execution within that instance.
+
+---
+
+See [Database-Specific Implementation Notes](index.md#database-specific-implementation-notes) for type mappings.
+
+---
+
+**Last Updated:** 2026-11-11 | **Schema Version:** 7.25 | **Operaton Versions:** 1.0.0+
diff --git a/docs/documentation/user-guide/process-engine/database/database-schema/identity.md b/docs/documentation/user-guide/process-engine/database/database-schema/identity.md
new file mode 100644
index 00000000..5391fbb7
--- /dev/null
+++ b/docs/documentation/user-guide/process-engine/database/database-schema/identity.md
@@ -0,0 +1,216 @@
+---
+last_updated: 2026-11-11
+schema_version: 7.25
+---
+
+# Identity (ID_)
+
+Identity tables manage users, groups, and tenants for the built-in identity provider. These tables are optional — Operaton supports pluggable identity providers (LDAP, Kerberos, custom) that do not use this schema. The `ACT_ID_*` tables are created unless the engine configuration sets `dbIdentityUsed` to `false`; with a different provider they typically stay empty.
+
+## Tables
+
+- **[`ACT_ID_USER`](#act_id_user)** — User accounts
+- **[`ACT_ID_GROUP`](#act_id_group)** — Groups/roles
+- **[`ACT_ID_MEMBERSHIP`](#act_id_membership)** — User↔Group membership
+- **[`ACT_ID_INFO`](#act_id_info)** — Extended user information
+- **[`ACT_ID_TENANT`](#act_id_tenant)** — Tenants
+- **[`ACT_ID_TENANT_MEMBER`](#act_id_tenant_member)** — User/Group↔Tenant membership
+
+---
+
+## ACT_ID_USER
+
+**Purpose:** Stores user accounts for the built-in identity provider, including credentials and account lockout state.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | User identifier (e.g., `john.doe`) |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| FIRST_ | VARCHAR(255) | NULL | First name |
+| LAST_ | VARCHAR(255) | NULL | Last name |
+| EMAIL_ | VARCHAR(255) | NULL | Email address |
+| PWD_ | VARCHAR(255) | NULL | Hashed password |
+| SALT_ | VARCHAR(255) | NULL | Password salt |
+| LOCK_EXP_TIME_ | TIMESTAMP | NULL | End of the temporary login delay after the last failed attempt; NULL after a successful login or unlock |
+| ATTEMPTS_ | INTEGER | NULL | Failed login attempts since last success; the user is locked permanently once it reaches `loginMaxAttempts` (default 10) |
+| PICTURE_ID_ | VARCHAR(64) | NULL | Not used by the engine; user pictures are referenced from `ACT_ID_INFO` (`KEY_` = `picture`) |
+
+**Example Queries:**
+
+```sql
+-- Find locked accounts (10 = default loginMaxAttempts)
+SELECT ID_, FIRST_, LAST_, EMAIL_, LOCK_EXP_TIME_, ATTEMPTS_
+FROM ACT_ID_USER
+WHERE (LOCK_EXP_TIME_ IS NOT NULL AND LOCK_EXP_TIME_ > CURRENT_TIMESTAMP)
+ OR ATTEMPTS_ >= 10
+ORDER BY LOCK_EXP_TIME_;
+
+-- Search by email
+SELECT ID_, FIRST_, LAST_, EMAIL_
+FROM ACT_ID_USER
+WHERE EMAIL_ LIKE '%@example.com'
+ORDER BY LAST_, FIRST_;
+```
+
+---
+
+## ACT_ID_GROUP
+
+**Purpose:** Groups bundle users for authorization and task candidate assignment.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Group identifier (e.g., `managers`, `approvers`) |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| NAME_ | VARCHAR(255) | NULL | Display name |
+| TYPE_ | VARCHAR(255) | NULL | Group type (e.g., `WORKFLOW`, `SYSTEM`) |
+
+**Example Queries:**
+
+```sql
+-- All groups
+SELECT ID_, NAME_, TYPE_ FROM ACT_ID_GROUP ORDER BY TYPE_, NAME_;
+
+-- Groups a user belongs to
+SELECT g.ID_, g.NAME_, g.TYPE_
+FROM ACT_ID_GROUP g
+JOIN ACT_ID_MEMBERSHIP m ON g.ID_ = m.GROUP_ID_
+WHERE m.USER_ID_ = 'john.doe'
+ORDER BY g.NAME_;
+```
+
+---
+
+## ACT_ID_MEMBERSHIP
+
+**Purpose:** Junction table linking users to groups. Composite primary key `(USER_ID_, GROUP_ID_)` enforces unique membership.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| USER_ID_ | VARCHAR(64) | PK, FK → [ACT_ID_USER](#act_id_user) | User member |
+| GROUP_ID_ | VARCHAR(64) | PK, FK → [ACT_ID_GROUP](#act_id_group) | Group being joined |
+
+**Indexes:** `ACT_IDX_MEMB_GROUP` on GROUP_ID_, `ACT_IDX_MEMB_USER` on USER_ID_
+
+**Example Queries:**
+
+```sql
+-- All members of a group
+SELECT USER_ID_ FROM ACT_ID_MEMBERSHIP
+WHERE GROUP_ID_ = 'approvers'
+ORDER BY USER_ID_;
+
+-- Groups a user belongs to (IDs only)
+SELECT GROUP_ID_ FROM ACT_ID_MEMBERSHIP
+WHERE USER_ID_ = 'john.doe';
+```
+
+---
+
+## ACT_ID_INFO
+
+**Purpose:** Extensible key-value store for additional user attributes (e.g., department, phone, external account credentials). Supports hierarchical entries via `PARENT_ID_`.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Entry identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| USER_ID_ | VARCHAR(64) | NULL | Owning user; NULL for account detail rows |
+| TYPE_ | VARCHAR(64) | NULL | Entry type: `userinfo` or `account`; NULL for account detail rows and the user picture entry |
+| KEY_ | VARCHAR(255) | NULL | Attribute key |
+| VALUE_ | VARCHAR(255) | NULL | Attribute value (plain text); for the `picture` entry, the ID of the picture in `ACT_GE_BYTEARRAY` |
+| PASSWORD_ | BYTEA | NULL | Account password as bytes of the string (not encrypted) |
+| PARENT_ID_ | VARCHAR(255) | NULL | `ID_` of the parent `account` entry (for account detail rows) |
+
+**Example Queries:**
+
+```sql
+-- All info entries for a user
+SELECT TYPE_, KEY_, VALUE_
+FROM ACT_ID_INFO
+WHERE USER_ID_ = 'john.doe' AND TYPE_ = 'userinfo'
+ORDER BY KEY_;
+```
+
+---
+
+## ACT_ID_TENANT
+
+**Purpose:** Defines tenants for multi-tenancy isolation. Tenants allow independent data partitioning within a single Operaton installation.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Tenant identifier (e.g., `acme-corp`) |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| NAME_ | VARCHAR(255) | NULL | Display name |
+
+**Example Queries:**
+
+```sql
+SELECT ID_, NAME_ FROM ACT_ID_TENANT ORDER BY NAME_;
+```
+
+---
+
+## ACT_ID_TENANT_MEMBER
+
+**Purpose:** Associates users or groups with tenants. A member may be a user OR a group (not both simultaneously). Unique constraints prevent duplicate membership per combination.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Member entry identifier |
+| TENANT_ID_ | VARCHAR(64) | FK → [ACT_ID_TENANT](#act_id_tenant), NOT NULL | Tenant |
+| USER_ID_ | VARCHAR(64) | FK → [ACT_ID_USER](#act_id_user), NULL | User member (NULL if group) |
+| GROUP_ID_ | VARCHAR(64) | FK → [ACT_ID_GROUP](#act_id_group), NULL | Group member (NULL if user) |
+
+**Unique Constraints:**
+- `ACT_UNIQ_TENANT_MEMB_USER` on `(TENANT_ID_, USER_ID_)`
+- `ACT_UNIQ_TENANT_MEMB_GROUP` on `(TENANT_ID_, GROUP_ID_)`
+
+On DB2 the constraints are unique indexes on the generated helper columns `UNI_USER_ID_` and `UNI_GROUP_ID_`, which replace NULL with `ID_`.
+
+**Indexes:** `ACT_IDX_TENANT_MEMB`, `ACT_IDX_TENANT_MEMB_USER`, `ACT_IDX_TENANT_MEMB_GROUP`
+
+**Example Queries:**
+
+```sql
+-- All members of a tenant
+SELECT COALESCE(USER_ID_, GROUP_ID_) AS member,
+ CASE WHEN USER_ID_ IS NOT NULL THEN 'user' ELSE 'group' END AS member_type
+FROM ACT_ID_TENANT_MEMBER
+WHERE TENANT_ID_ = 'acme-corp'
+ORDER BY member_type, member;
+
+-- Tenants a user belongs to
+SELECT TENANT_ID_ FROM ACT_ID_TENANT_MEMBER
+WHERE USER_ID_ = 'john.doe';
+```
+
+---
+
+## Design Notes
+
+- `ACT_ID_*` tables are only populated when using the **built-in identity provider**.
+- `ACT_RU_AUTHORIZATION.USER_ID_` and `GROUP_ID_` are string references — there are no foreign keys to `ACT_ID_USER`/`ACT_ID_GROUP`. Authorization works with any identity source.
+- Account locking: `LOCK_EXP_TIME_` + `ATTEMPTS_` in `ACT_ID_USER` implement brute-force protection. Unlock a user with `IdentityService.unlockUser(userId)` instead of updating the row directly.
+- `ACT_ID_INFO.PASSWORD_` stores the account password as unencrypted bytes; use the Operaton API to manage account credentials.
+
+---
+
+See [Database-Specific Implementation Notes](index.md#database-specific-implementation-notes) for type mappings.
+
+---
+
+**Last Updated:** 2026-11-11 | **Schema Version:** 7.25 | **Operaton Versions:** 1.0.0+
diff --git a/docs/documentation/user-guide/process-engine/database/database-schema/index.md b/docs/documentation/user-guide/process-engine/database/database-schema/index.md
new file mode 100644
index 00000000..6bb1933c
--- /dev/null
+++ b/docs/documentation/user-guide/process-engine/database/database-schema/index.md
@@ -0,0 +1,446 @@
+---
+
+title: 'Database Schema'
+sidebar_position: 10
+menu:
+ main:
+ identifier: "user-guide-process-engine-database-schema"
+ parent: "user-guide-process-engine-database"
+
+---
+## Schema Version Mapping
+
+| Operaton Version | Schema Version |
+|--------------------|----------------|
+| 1.0, 1.1, 2.0, 2.1 | 7.24 |
+| 2.2 | 7.25 |
+
+Schema 7.25 has the same tables, columns and indexes as 7.24. The upgrade only records the new version in
+[`ACT_GE_SCHEMA_LOG`](general.md#act_ge_schema_log). To check the schema version of a database, read the latest
+entry of that table.
+
+---
+
+## Overview
+
+The database schema of the process engine consists of multiple tables.
+The table names all start with ACT. The second part is a two-character
+identification of the use case of the table. This use case will also roughly
+match the service API.
+
+* `ACT_RE_*`: `RE` stands for [repository](./repository.md). Tables with this prefix contain 'static' information such as process definitions and process resources (images, rules, etc.).
+* `ACT_RU_*`: `RU` stands for [runtime](./runtime.md). These are the runtime tables that contain the runtime data of process instances, user tasks, variables, jobs, etc. The engine only stores the runtime data during process instance execution and removes the records when a process instance ends. This keeps the runtime tables small and fast.
+* `ACT_ID_*`: `ID` stands for [identity](./identity.md). These tables contain identity information such as users, groups, etc.
+* `ACT_HI_*`: `HI` stands for [history](./history.md). These are the tables that contain historical data such as past process instances, variables, tasks, etc.
+* `ACT_GE_*`: [General data](./general.md), which is used in various use cases.
+
+The main tables of the process engines are the entities of process definitions, executions, tasks, variables and
+event subscriptions. Their relationship is shown in the following UML model.
+
+Database Schema
+
+
+## Process Definitions (ACT_RE_PROCDEF)
+
+The [`ACT_RE_PROCDEF`](repository.md#act_re_procdef) table contains all deployed process definitions. It
+includes information like the version details, the resource name or the
+suspension state.
+
+
+## Executions (ACT_RU_EXECUTION)
+
+The [`ACT_RU_EXECUTION`](runtime.md#act_ru_execution) table contains all current executions. It includes information like the process definition, parent execution, business key, the
+current activity and different metadata about the state of the execution.
+
+
+## Tasks (ACT_RU_TASK)
+
+The [`ACT_RU_TASK`](runtime.md#act_ru_task) table contains all open tasks of all running process
+instances. It includes information like the corresponding process instance,
+execution and also metadata such as creation time, assignee or due date.
+
+
+## Variables (ACT_RU_VARIABLE)
+
+The [`ACT_RU_VARIABLE`](runtime.md#act_ru_variable) table contains all currently set process or task
+variables. It includes the names, types and values of the variables and
+information about the corresponding process instance or task.
+
+
+## Event Subscriptions (ACT_RU_EVENT_SUBSCR)
+
+The [`ACT_RU_EVENT_SUBSCR`](runtime.md#act_ru_event_subscr) table contains all currently existing event
+subscriptions. It includes the type, name and configuration of the expected
+event along with information about the corresponding process instance and
+execution.
+
+## Schema Log (ACT_GE_SCHEMA_LOG)
+
+The [`ACT_GE_SCHEMA_LOG`](general.md#act_ge_schema_log) table contains a history of the database
+schema version. New entries to the table are written when changes to
+the database schema are made. On database creation the initial entry
+is added. Every update script adds a new entry containing an `id`,
+the `version` the database was updated to and the date and time
+(`timestamp`) of the update.
+
+To retrieve entries from the schema log, the SchemaLogQuery-API can be
+used:
+```java
+List entries = managementService.createSchemaLogQuery().list();
+```
+
+## Metrics Log (ACT_RU_METER_LOG)
+
+The [`ACT_RU_METER_LOG`](runtime.md#act_ru_meter_log) table contains a collection of runtime metrics that can help draw conclusions about usage, load
+and performance of Operaton. Metrics are reported as numbers in the Java `long` range and count the occurrence of
+specific events. Please find detailed information about how metrics are collected in the [Metrics User Guide](../../metrics.md).
+
+The default configuration of the [MetricsReporter](../../metrics.md#metrics-reporter) will create one row per [metric](../../metrics.md#built-in-metrics) in `ACT_RU_METER_LOG` every 15 minutes.
+
+## Task Metrics Log (ACT_RU_TASK_METER_LOG)
+
+The [`ACT_RU_TASK_METER_LOG`](runtime.md#act_ru_task_meter_log) table contains a collection of task related metrics that can help draw conclusions about usage, load
+and performance of Operaton. Task metrics contain a pseudonymized and fixed-length value of task assignees and their time of appearance. Please find detailed information about how task metrics are collected in the [Metrics User Guide](../../metrics.md).
+
+Every assignment of a task to an assignee will create one row in `ACT_RU_TASK_METER_LOG`.
+
+# Entity Relationship Diagrams
+
+:::note
+ The database is not part of the **public API**. The database schema may change for MINOR and MAJOR version updates.
+
+ **Please note:**
+ The following diagrams are based on the PostgreSQL database schema. For other databases the column types differ slightly.
+:::
+
+
+The following Entity Relationship Diagrams visualize the database tables, grouped by Engine with focus on BPMN, Engine with focus on DMN, Engine with focus on CMMN, the Engine History and the Identity. Solid lines are foreign key constraints. Dashed lines are important references that have no foreign key constraint, such as the `DEPLOYMENT_ID_` of the definition tables. Most other implicit references, for example `PROC_INST_ID_` in the history tables, are not shown.
+
+
+## Engine BPMN
+
+BPMN Tables
+
+
+## Engine DMN
+
+DMN Tables
+
+
+## Engine CMMN
+
+CMMN Tables
+
+
+## History
+
+To allow different configurations and to keep the tables more flexible, the history tables contain no foreign key constraints. The dashed lines show the logical link between decision instances and their inputs and outputs.
+
+History Tables
+
+
+## Identity
+
+Identity Tables
+
+# Quick Reference: All Tables
+
+## General
+
+| Table | Purpose |
+|-----------------------------------------------------|--------------------------------------|
+| [`ACT_GE_PROPERTY`](general.md#act_ge_property) | System configuration key-value store |
+| [`ACT_GE_BYTEARRAY`](general.md#act_ge_bytearray) | Binary object storage (BLOBs) |
+| [`ACT_GE_SCHEMA_LOG`](general.md#act_ge_schema_log) | Schema migration history |
+
+## Repository
+
+| Table | Purpose |
+|--------------------------------------------------------------------|----------------------------------------|
+| [`ACT_RE_CAMFORMDEF`](repository.md#act_re_camformdef) | Operaton form definitions |
+| [`ACT_RE_CASE_DEF`](repository.md#act_re_case_def) | Case definitions (CMMN) |
+| [`ACT_RE_DECISION_DEF`](repository.md#act_re_decision_def) | Decision definitions (DMN) |
+| [`ACT_RE_DECISION_REQ_DEF`](repository.md#act_re_decision_req_def) | Decision requirement definitions (DRG) |
+| [`ACT_RE_DEPLOYMENT`](repository.md#act_re_deployment) | Deployment container |
+| [`ACT_RE_PROCDEF`](repository.md#act_re_procdef) | Process definitions (BPMN) |
+
+## Runtime
+
+| Table | Purpose |
+|-----------------------------------------------------------------|-----------------------------|
+| [`ACT_RU_AUTHORIZATION`](runtime.md#act_ru_authorization) | Permission rules |
+| [`ACT_RU_BATCH`](runtime.md#act_ru_batch) | Batch operation containers |
+| [`ACT_RU_CASE_EXECUTION`](runtime.md#act_ru_case_execution) | CMMN case execution scopes |
+| [`ACT_RU_CASE_SENTRY_PART`](runtime.md#act_ru_case_sentry_part) | CMMN sentry condition parts |
+| [`ACT_RU_EVENT_SUBSCR`](runtime.md#act_ru_event_subscr) | Event subscriptions |
+| [`ACT_RU_EXECUTION`](runtime.md#act_ru_execution) | Process execution scopes |
+| [`ACT_RU_EXT_TASK`](runtime.md#act_ru_ext_task) | External task subscriptions |
+| [`ACT_RU_FILTER`](runtime.md#act_ru_filter) | Saved task list filters |
+| [`ACT_RU_IDENTITYLINK`](runtime.md#act_ru_identitylink) | User/group task assignments |
+| [`ACT_RU_INCIDENT`](runtime.md#act_ru_incident) | Runtime incidents/failures |
+| [`ACT_RU_JOB`](runtime.md#act_ru_job) | Async job instances |
+| [`ACT_RU_JOBDEF`](runtime.md#act_ru_jobdef) | Job execution definitions |
+| [`ACT_RU_METER_LOG`](runtime.md#act_ru_meter_log) | Engine usage metrics |
+| [`ACT_RU_TASK`](runtime.md#act_ru_task) | Active user tasks |
+| [`ACT_RU_TASK_METER_LOG`](runtime.md#act_ru_task_meter_log) | Task assignment metrics |
+| [`ACT_RU_VARIABLE`](runtime.md#act_ru_variable) | Process and task variables |
+
+## History
+
+| Table | Purpose |
+|---------------------------------------------------------|----------------------------------|
+| [`ACT_HI_ACTINST`](history.md#act_hi_actinst) | Historic activity instances |
+| [`ACT_HI_ATTACHMENT`](history.md#act_hi_attachment) | Task/process attachments |
+| [`ACT_HI_BATCH`](history.md#act_hi_batch) | Historic batch records |
+| [`ACT_HI_CASEACTINST`](history.md#act_hi_caseactinst) | Historic case activity instances |
+| [`ACT_HI_CASEINST`](history.md#act_hi_caseinst) | Historic case instances |
+| [`ACT_HI_COMMENT`](history.md#act_hi_comment) | Task/process comments |
+| [`ACT_HI_DEC_IN`](history.md#act_hi_dec_in) | Decision evaluation inputs |
+| [`ACT_HI_DEC_OUT`](history.md#act_hi_dec_out) | Decision evaluation outputs |
+| [`ACT_HI_DECINST`](history.md#act_hi_decinst) | Historic decision evaluations |
+| [`ACT_HI_DETAIL`](history.md#act_hi_detail) | Variable change details |
+| [`ACT_HI_EXT_TASK_LOG`](history.md#act_hi_ext_task_log) | External task execution history |
+| [`ACT_HI_IDENTITYLINK`](history.md#act_hi_identitylink) | Historic identity link changes |
+| [`ACT_HI_INCIDENT`](history.md#act_hi_incident) | Historic incidents |
+| [`ACT_HI_JOB_LOG`](history.md#act_hi_job_log) | Job execution history |
+| [`ACT_HI_OP_LOG`](history.md#act_hi_op_log) | Operator audit log |
+| [`ACT_HI_PROCINST`](history.md#act_hi_procinst) | Historic process instances |
+| [`ACT_HI_TASKINST`](history.md#act_hi_taskinst) | Historic task instances |
+| [`ACT_HI_VARINST`](history.md#act_hi_varinst) | Historic variable values |
+
+## Identity
+
+| Table | Purpose |
+|------------------------------------------------------------|------------------------------|
+| [`ACT_ID_GROUP`](identity.md#act_id_group) | Groups/roles |
+| [`ACT_ID_INFO`](identity.md#act_id_info) | Extended user information |
+| [`ACT_ID_MEMBERSHIP`](identity.md#act_id_membership) | User↔Group membership |
+| [`ACT_ID_TENANT`](identity.md#act_id_tenant) | Tenants |
+| [`ACT_ID_TENANT_MEMBER`](identity.md#act_id_tenant_member) | User/Group↔Tenant membership |
+| [`ACT_ID_USER`](identity.md#act_id_user) | User accounts |
+
+
+## Common Query Patterns
+
+### Find all tasks for a user
+
+```sql
+SELECT t.*
+FROM ACT_RU_TASK t
+ LEFT JOIN ACT_RU_IDENTITYLINK il ON t.ID_ = il.TASK_ID_
+WHERE il.USER_ID_ = 'john.doe'
+ OR t.ASSIGNEE_ = 'john.doe'
+ORDER BY t.CREATE_TIME_ DESC;
+```
+
+See [runtime.md → ACT_RU_TASK](runtime.md#act_ru_task)
+
+### Get process variables
+
+```sql
+SELECT NAME_, TYPE_, TEXT_, LONG_, DOUBLE_
+FROM ACT_RU_VARIABLE
+WHERE PROC_INST_ID_ = 'proc-id';
+```
+
+See [runtime.md → ACT_RU_VARIABLE](runtime.md#act_ru_variable)
+
+### Latest process definition version by key
+
+```sql
+SELECT ID_, KEY_, VERSION_, DEPLOYMENT_ID_
+FROM ACT_RE_PROCDEF
+WHERE KEY_ = 'invoice_approval'
+ORDER BY VERSION_ DESC LIMIT 1;
+```
+
+See [repository.md → ACT_RE_PROCDEF](repository.md#act_re_procdef)
+
+### Authorization rules for a user
+
+```sql
+SELECT RESOURCE_TYPE_, RESOURCE_ID_, PERMS_
+FROM ACT_RU_AUTHORIZATION
+WHERE USER_ID_ = 'john.doe'
+ OR GROUP_ID_ IN (SELECT GROUP_ID_
+ FROM ACT_ID_MEMBERSHIP
+ WHERE USER_ID_ = 'john.doe');
+```
+
+See [runtime.md → ACT_RU_AUTHORIZATION](runtime.md#act_ru_authorization)
+
+### Failed jobs with retry count
+
+```sql
+SELECT j.ID_, j.TYPE_, j.PROCESS_INSTANCE_ID_, j.RETRIES_, j.EXCEPTION_MSG_
+FROM ACT_RU_JOB j
+WHERE j.RETRIES_ = 0
+ORDER BY j.DUEDATE_ DESC;
+```
+
+See [runtime.md → ACT_RU_JOB](runtime.md#act_ru_job)
+
+---
+
+## Key Schema Design Patterns
+
+### Optimistic Locking
+
+Most runtime, repository, identity and general tables include `REV_ INTEGER`. Every UPDATE must match the
+current `REV_` and increment it. A stale read results in a zero-row update, and the engine throws an
+`OptimisticLockingException`. Most history tables, `ACT_RE_DEPLOYMENT`, the membership tables and the meter log
+tables have no `REV_` column.
+
+### Multi-Tenancy
+
+Most tables carry `TENANT_ID_ VARCHAR(64)`. All queries should filter by tenant where data isolation
+is required.
+
+### Removal Time
+
+`REMOVAL_TIME_ TIMESTAMP` marks history rows for deferred cleanup. Besides the history tables, `ACT_GE_BYTEARRAY`
+and `ACT_RU_AUTHORIZATION` carry it. The engine sets it from the end time and the history time to live of the
+definition. With the default removal-time-based cleanup strategy, the history cleanup job deletes rows where
+`REMOVAL_TIME_` has passed.
+Never delete these rows manually while the engine is running.
+
+### Hierarchical Execution
+
+`ACT_RU_EXECUTION` is self-referential: `PARENT_ID_` → parent scope, `PROC_INST_ID_` → root
+execution (when `PROC_INST_ID_ = ID_`, the row is the root), `SUPER_EXEC_` → calling execution in a
+parent process.
+
+### Variable Storage
+
+`ACT_RU_VARIABLE` uses a discriminated-union layout: scalar types use `LONG_`, `DOUBLE_`, or
+`TEXT_`; binary types store a reference in `BYTEARRAY_ID_` pointing to `ACT_GE_BYTEARRAY`.
+
+### Job Priority and Locking
+
+`ACT_RU_JOB.PRIORITY_` controls execution order; `LOCK_OWNER_` + `LOCK_EXP_TIME_` implement
+optimistic distributed locking so multiple engine nodes don't double-execute the same job.
+
+### Incident Chain
+
+`ACT_RU_INCIDENT.CAUSE_INCIDENT_ID_` → direct cause; `ROOT_CAUSE_INCIDENT_ID_` → original root.
+Enables root-cause traversal in failure chains.
+
+---
+
+## Column Naming Conventions
+
+| Suffix | Meaning | Example |
+|-----------------------------|-----------------------|-----------------------------------|
+| `_ID_` | PK or FK identifier | `PROC_DEF_ID_`, `TASK_ID_` |
+| `_KEY_` | Stable business key | `PROC_DEF_KEY_`, `TASK_DEF_KEY_` |
+| `_NAME_` | Human-readable label | `ACT_NAME_`, `TOPIC_NAME_` |
+| `_TIME_` / `_TIMESTAMP_` | Point in time | `CREATE_TIME_`, `LOCK_EXP_TIME_` |
+| `_STATE_` | Status code or name | `SUSPENSION_STATE_`, `STATE_` |
+| `_MSG_` | Text message / error | `EXCEPTION_MSG_`, `INCIDENT_MSG_` |
+| `_CFG_` / `_CONFIGURATION_` | Configuration payload | `HANDLER_CFG_` |
+
+| Prefix | Domain | Contents |
+|-----------|------------|--------------------------------------------------------|
+| `ACT_GE_` | General | Infrastructure: binary storage, properties, schema log |
+| `ACT_RE_` | Repository | Immutable definitions: processes, decisions, forms |
+| `ACT_RU_` | Runtime | Active execution state |
+| `ACT_HI_` | History | Audit trail of completed executions |
+| `ACT_ID_` | Identity | Built-in user/group/tenant store |
+
+---
+
+## Database-Specific Implementation Notes
+
+All supported databases have the same tables, the same columns and the same foreign keys, with the exceptions
+listed below. Column types differ, and so do some index names and the set of indexes. The documentation uses the
+PostgreSQL types and index names.
+
+Column deviations from PostgreSQL:
+
+- `ACT_RU_VARIABLE.VAR_SCOPE_` is `NOT NULL` on all databases except PostgreSQL
+- `ACT_HI_DETAIL.VAR_TYPE_` is `VARCHAR(255)` on all databases except PostgreSQL and Oracle, where it is 64
+ characters long
+
+### PostgreSQL
+
+- `boolean`, `timestamp`, `bytea`, `bigint`, `double precision`
+- `text` for the filter columns `QUERY_` and `PROPERTIES_`
+
+### MySQL / MariaDB
+
+- `TINYINT` for boolean columns
+- `datetime` for timestamps (MariaDB: `datetime(3)`)
+- `LONGBLOB` for binary data; `LONGTEXT` for the filter columns
+- `BOOLEAN` (an alias for `TINYINT(1)`) for `EXCLUSIVE_`, `STARTABLE_`, `INITIAL_`, `REQUIRED_` and `SATISFIED_`
+- `timestamp` (MariaDB: `timestamp(3)`) for `ACT_HI_IDENTITYLINK.TIMESTAMP_`, `ACT_HI_OP_LOG.TIMESTAMP_`,
+ `ACT_HI_EXT_TASK_LOG.TIMESTAMP_` and `ACT_HI_INCIDENT.CREATE_TIME_`/`END_TIME_`
+- Tables use `CHARSET=utf8` with `COLLATE utf8_bin`, so string comparisons are case-sensitive
+- MySQL only: `ACT_HI_EXT_TASK_LOG` has an additional `REV_` column
+- No explicit indexes on foreign key columns (for example `ACT_IDX_EXE_PROCINST` or `ACT_IDX_TASK_EXEC`); InnoDB
+ creates an index for each foreign key itself
+- `ACT_IDX_EXE_ROOT_PI` is named `ACT_IDX_EXEC_ROOT_PI`
+- `ACT_IDX_JOB_HANDLER` is a prefix index on `HANDLER_TYPE_(100), HANDLER_CFG_(155)`
+- Additional index `ACT_IDX_HI_CAS_A_I_CASEINST` on `ACT_HI_CASEACTINST (CASE_INST_ID_, CASE_ACT_ID_)`
+
+### Oracle
+
+- `NVARCHAR2(n)` for text. Columns of length 4000 on other databases are `NVARCHAR2(2000)` on Oracle
+- `NUMBER(19,0)` for `BIGINT`; `NUMBER(*,10)` for `DOUBLE`
+- `NUMBER(1,0)` with a `CHECK (... IN (1,0))` constraint for boolean columns
+- `TIMESTAMP(6)` for timestamps; `BLOB` for binary data; `NCLOB` for the filter columns
+- `ACT_HI_OP_LOG.OPERATION_TYPE_` is `NVARCHAR2(255)`
+- The unique constraints of `ACT_RU_AUTHORIZATION` and `ACT_ID_TENANT_MEMBER` are function-based unique indexes,
+ so rows with `NULL` user or group IDs do not collide
+- Index names are limited to 30 characters, so some are shortened (for example `ACT_IDX_HI_PRO_INST_PROC_KEY`
+ instead of `ACT_IDX_HI_PRO_INST_PROC_DEF_KEY`, `ACT_IDX_EXE_ROOT_PROCINST` instead of `ACT_IDX_EXE_ROOT_PI`)
+- The `TENANT_ID_` indexes are composite indexes on `(TENANT_ID_, 0)`, so rows with a `NULL` tenant are indexed
+- `ACT_IDX_JOB_HANDLER` covers `HANDLER_TYPE_, SUBSTR(HANDLER_CFG_, 1, 1850)`
+
+### Microsoft SQL Server
+
+- `nvarchar(n)` for text; `nvarchar(max)` for the filter columns
+- `datetime2` for timestamps
+- `tinyint` for most boolean columns; `bit` for `EXCLUSIVE_`, `STARTABLE_` and `INITIAL_`
+- `numeric(19,0)` for `BIGINT`; `tinyint` for the `SUSPENSION_STATE_` and some `STATE_` columns
+- `image` for binary data
+- `ACT_RU_AUTHORIZATION.REV_` is nullable
+- The unique constraints of `ACT_RU_AUTHORIZATION` and `ACT_ID_TENANT_MEMBER` are filtered unique indexes
+ (`WHERE USER_ID_ IS NOT NULL`, `WHERE GROUP_ID_ IS NOT NULL`)
+- Several foreign key indexes have other names (for example `ACT_IDX_EXECUTION_PROCINST` instead of
+ `ACT_IDX_EXE_PROCINST`, `ACT_IDX_INCIDENT_CAUSE` instead of `ACT_IDX_INC_CAUSEINCID`)
+- No `ACT_IDX_JOB_HANDLER` and no indexes on the foreign key columns of `ACT_ID_MEMBERSHIP` and
+ `ACT_ID_TENANT_MEMBER`
+- Additional index `ACT_IDX_TASK_PARENT_TASK_ID` on `ACT_RU_TASK (PARENT_TASK_ID_)`
+
+### H2
+
+- `bit` for most boolean columns (`boolean` for `EXCLUSIVE_`, `STARTABLE_` and `INITIAL_`)
+- `blob` for binary data (`longvarbinary` for `ACT_HI_COMMENT.FULL_MSG_` and `ACT_ID_INFO.PASSWORD_`); `CLOB` for
+ the filter columns
+- `integer` for the `SEQUENCE_COUNTER_` columns
+- No explicit indexes on foreign key columns; H2 creates an index for each foreign key itself
+- `ACT_IDX_EXE_ROOT_PI` is named `ACT_IDX_EXEC_ROOT_PI`
+- Intended for development and testing
+
+### DB2
+
+- `smallint` with a `CHECK (... IN (1,0))` constraint for boolean columns
+- `BLOB` for binary data; `CLOB` for the filter columns
+- Unique constraints on nullable columns use generated helper columns: `ACT_RU_AUTHORIZATION` has
+ `UNI_USER_ID_`, `UNI_GROUP_ID_` and `UNI_RESOURCE_ID_`, `ACT_ID_TENANT_MEMBER` has `UNI_USER_ID_` and
+ `UNI_GROUP_ID_`. Each replaces `NULL` with the row's `ID_`.
+- The unique constraints are unique indexes on these helper columns
+- Same index names as Microsoft SQL Server (for example `ACT_IDX_EXECUTION_PROCINST`), except
+ `ACT_IDX_EXECUTION_ROOT_PI` instead of `ACT_IDX_EXE_ROOT_PI`
+- No `ACT_IDX_JOB_HANDLER` and no indexes on the foreign key columns of `ACT_ID_MEMBERSHIP` and
+ `ACT_ID_TENANT_MEMBER`
+
+### Cross-Platform Notes
+
+- **Schema scripts:** The create, drop and upgrade scripts for each database ship in the
+ `operaton-sql-scripts-.tar.gz` asset of each release and in the `operaton-engine` artifact under
+ `org/operaton/bpm/engine/db/`. See [Database schema installation](../../../../installation/database-schema.md).
+- **Collation:** Use UTF-8 character sets in all databases for multi-language process data.
+- **Foreign keys:** The engine deletes dependent rows itself, so delete data through the engine API. Only on
+ MySQL and MariaDB do the self-references `ACT_FK_EXE_PROCINST`, `ACT_FK_INC_CAUSE`, `ACT_FK_INC_RCAUSE` and
+ `ACT_FK_CASE_EXE_CASE_INST` use `ON DELETE CASCADE ON UPDATE CASCADE`.
diff --git a/docs/documentation/user-guide/process-engine/database/database-schema/repository.md b/docs/documentation/user-guide/process-engine/database/database-schema/repository.md
new file mode 100644
index 00000000..d6cbb39c
--- /dev/null
+++ b/docs/documentation/user-guide/process-engine/database/database-schema/repository.md
@@ -0,0 +1,284 @@
+---
+last_updated: 2026-11-11
+schema_version: 7.25
+---
+
+# Repository (RE_)
+
+Repository tables store definitions — process models, case models, decision tables, form definitions, and their deployment containers. The deployed models are never changed; a changed model is deployed as a new version. Only a few attributes, such as the suspension state or the history time to live, can be updated after deployment.
+
+## Tables
+
+- **[`ACT_RE_DEPLOYMENT`](#act_re_deployment)** — Deployment container
+- **[`ACT_RE_PROCDEF`](#act_re_procdef)** — Process definitions (BPMN)
+- **[`ACT_RE_CAMFORMDEF`](#act_re_camformdef)** — Operaton Forms definitions
+- **[`ACT_RE_CASE_DEF`](#act_re_case_def)** — Case definitions (CMMN)
+- **[`ACT_RE_DECISION_DEF`](#act_re_decision_def)** — Decision definitions (DMN)
+- **[`ACT_RE_DECISION_REQ_DEF`](#act_re_decision_req_def)** — Decision requirement definitions (DRG)
+
+---
+
+## ACT_RE_DEPLOYMENT
+
+**Purpose:** Immutable container grouping related artifacts (BPMN, DMN, CMMN, forms) deployed together. All definitions in a deployment share the same `DEPLOYMENT_ID_`.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Deployment identifier |
+| NAME_ | VARCHAR(255) | NULL | Human-readable deployment name |
+| DEPLOY_TIME_ | TIMESTAMP | NULL | When deployment occurred |
+| SOURCE_ | VARCHAR(255) | NULL | Free-text origin set via `DeploymentBuilder.source()` (e.g., `process application`); NULL if not set |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_DEPLOYMENT_NAME`, `ACT_IDX_DEPLOYMENT_TENANT_ID`
+
+**Referenced by:** `ACT_GE_BYTEARRAY` (FK constraint `ACT_FK_BYTEARR_DEPL`). `ACT_RE_PROCDEF`, `ACT_RE_CAMFORMDEF`, `ACT_RE_CASE_DEF`, `ACT_RE_DECISION_DEF`, `ACT_RE_DECISION_REQ_DEF`, `ACT_RU_JOB`, `ACT_RU_JOBDEF`, `ACT_HI_JOB_LOG` and `ACT_HI_OP_LOG` reference it without a constraint.
+
+**Example Queries:**
+
+```sql
+-- All deployments, newest first
+SELECT ID_, NAME_, DEPLOY_TIME_, SOURCE_, TENANT_ID_
+FROM ACT_RE_DEPLOYMENT
+ORDER BY DEPLOY_TIME_ DESC;
+
+-- Deployment with all its process definitions
+SELECT d.ID_, d.NAME_, d.DEPLOY_TIME_,
+ p.ID_ AS procdef_id, p.KEY_, p.NAME_ AS proc_name, p.VERSION_
+FROM ACT_RE_DEPLOYMENT d
+LEFT JOIN ACT_RE_PROCDEF p ON d.ID_ = p.DEPLOYMENT_ID_
+WHERE d.ID_ = 'deployment-id'
+ORDER BY p.KEY_, p.VERSION_;
+
+-- Latest deployment per tenant
+SELECT TENANT_ID_, ID_, NAME_, DEPLOY_TIME_
+FROM ACT_RE_DEPLOYMENT d1
+WHERE DEPLOY_TIME_ = (
+ SELECT MAX(DEPLOY_TIME_) FROM ACT_RE_DEPLOYMENT d2
+ WHERE d2.TENANT_ID_ = d1.TENANT_ID_
+)
+ORDER BY TENANT_ID_;
+```
+
+---
+
+## ACT_RE_PROCDEF
+
+**Purpose:** Stores BPMN process definition versions. Same `KEY_` with incrementing `VERSION_` coexist; running instances reference their definition by `ID_`.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Internal unique ID for this version |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| CATEGORY_ | VARCHAR(255) | NULL | Namespace/category |
+| NAME_ | VARCHAR(255) | NULL | Display name |
+| KEY_ | VARCHAR(255) | NOT NULL | Logical process key |
+| VERSION_ | INTEGER | NOT NULL | Version number |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Containing deployment (logical reference, no FK constraint) |
+| RESOURCE_NAME_ | VARCHAR(4000) | NULL | BPMN resource filename |
+| DGRM_RESOURCE_NAME_ | VARCHAR(4000) | NULL | Diagram resource filename |
+| HAS_START_FORM_KEY_ | BOOLEAN | NULL | Start event defines an `operaton:formKey` (not set for `operaton:formRef`) |
+| SUSPENSION_STATE_ | INTEGER | NULL | `1`=active, `2`=suspended |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| VERSION_TAG_ | VARCHAR(64) | NULL | Optional version label |
+| HISTORY_TTL_ | INTEGER | NULL | History retention in days (NULL=indefinite) |
+| STARTABLE_ | BOOLEAN | NOT NULL DEFAULT TRUE | `operaton:isStartableInTasklist`: whether Tasklist offers the process for starting (does not restrict starting via API) |
+
+**Indexes:** `ACT_IDX_PROCDEF_DEPLOYMENT_ID`, `ACT_IDX_PROCDEF_TENANT_ID`, `ACT_IDX_PROCDEF_VER_TAG`
+
+**Example Queries:**
+
+```sql
+-- Latest active version of all process definitions
+SELECT ID_, KEY_, NAME_, VERSION_, DEPLOYMENT_ID_
+FROM ACT_RE_PROCDEF p1
+WHERE SUSPENSION_STATE_ = 1
+ AND (KEY_, VERSION_) IN (
+ SELECT KEY_, MAX(VERSION_) FROM ACT_RE_PROCDEF
+ WHERE SUSPENSION_STATE_ = 1 GROUP BY KEY_
+ )
+ORDER BY KEY_;
+
+-- Version history for a process key
+SELECT ID_, KEY_, VERSION_, DEPLOYMENT_ID_, VERSION_TAG_, SUSPENSION_STATE_
+FROM ACT_RE_PROCDEF
+WHERE KEY_ = 'invoice_approval'
+ORDER BY VERSION_ DESC;
+
+-- Count running instances per definition
+SELECT p.KEY_, p.VERSION_, COUNT(e.ID_) AS running_instances
+FROM ACT_RE_PROCDEF p
+LEFT JOIN ACT_RU_EXECUTION e ON p.ID_ = e.PROC_DEF_ID_
+ AND e.PROC_INST_ID_ = e.ID_
+WHERE p.SUSPENSION_STATE_ = 1
+GROUP BY p.KEY_, p.VERSION_
+ORDER BY running_instances DESC;
+```
+
+---
+
+## ACT_RE_CAMFORMDEF
+
+**Purpose:** Operaton Forms definitions (`.form` files) referenced via `operaton:formRef` from user tasks and start events. Forms are versioned independently by `KEY_`/`VERSION_` and linked to a deployment.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Form definition identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| KEY_ | VARCHAR(255) | NOT NULL | Form key |
+| VERSION_ | INTEGER | NOT NULL | Version number |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Containing deployment (logical reference, no FK constraint) |
+| RESOURCE_NAME_ | VARCHAR(4000) | NULL | Form resource filename |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Example Queries:**
+
+```sql
+-- Latest version of a form
+SELECT ID_, KEY_, VERSION_, DEPLOYMENT_ID_, RESOURCE_NAME_
+FROM ACT_RE_CAMFORMDEF
+WHERE KEY_ = 'approval_form'
+ORDER BY VERSION_ DESC LIMIT 1;
+
+-- All forms in a deployment
+SELECT ID_, KEY_, VERSION_, RESOURCE_NAME_
+FROM ACT_RE_CAMFORMDEF
+WHERE DEPLOYMENT_ID_ = 'deployment-id'
+ORDER BY KEY_, VERSION_ DESC;
+```
+
+---
+
+## ACT_RE_CASE_DEF
+
+**Purpose:** CMMN case definition versions. Cases support flexible, non-linear execution with stages and milestones.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Internal unique ID |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| CATEGORY_ | VARCHAR(255) | NULL | Namespace/category |
+| NAME_ | VARCHAR(255) | NULL | Display name |
+| KEY_ | VARCHAR(255) | NOT NULL | Logical case key |
+| VERSION_ | INTEGER | NOT NULL | Version number |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Containing deployment (logical reference, no FK constraint) |
+| RESOURCE_NAME_ | VARCHAR(4000) | NULL | CMMN resource filename |
+| DGRM_RESOURCE_NAME_ | VARCHAR(4000) | NULL | Diagram resource filename |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| HISTORY_TTL_ | INTEGER | NULL | History retention in days |
+
+**Indexes:** `ACT_IDX_CASE_DEF_TENANT_ID`
+
+**Example Queries:**
+
+```sql
+-- All case definition versions
+SELECT ID_, KEY_, NAME_, VERSION_, DEPLOYMENT_ID_
+FROM ACT_RE_CASE_DEF
+ORDER BY KEY_, VERSION_ DESC;
+```
+
+---
+
+## ACT_RE_DECISION_DEF
+
+**Purpose:** DMN decision definition versions (decision tables and literal expressions). Decisions are invoked from process/case activities or directly via the decision service.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Internal unique ID |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| CATEGORY_ | VARCHAR(255) | NULL | Namespace/category |
+| NAME_ | VARCHAR(255) | NULL | Display name |
+| KEY_ | VARCHAR(255) | NOT NULL | Logical decision key |
+| VERSION_ | INTEGER | NOT NULL | Version number |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Containing deployment (logical reference, no FK constraint) |
+| RESOURCE_NAME_ | VARCHAR(4000) | NULL | DMN resource filename |
+| DGRM_RESOURCE_NAME_ | VARCHAR(4000) | NULL | Diagram resource filename |
+| DEC_REQ_ID_ | VARCHAR(64) | FK → [ACT_RE_DECISION_REQ_DEF](#act_re_decision_req_def) | Parent DRG (NULL if the DMN resource contains only one decision) |
+| DEC_REQ_KEY_ | VARCHAR(255) | NULL | Parent DRG key (denormalized) |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| HISTORY_TTL_ | INTEGER | NULL | History retention in days |
+| VERSION_TAG_ | VARCHAR(64) | NULL | Optional version label |
+
+**Indexes:** `ACT_IDX_DEC_DEF_TENANT_ID`, `ACT_IDX_DEC_DEF_REQ_ID`
+
+**Example Queries:**
+
+```sql
+-- Latest version of each decision
+SELECT d1.ID_, d1.KEY_, d1.NAME_, d1.VERSION_, d1.DEPLOYMENT_ID_
+FROM ACT_RE_DECISION_DEF d1
+WHERE d1.VERSION_ = (
+ SELECT MAX(d2.VERSION_) FROM ACT_RE_DECISION_DEF d2
+ WHERE d2.KEY_ = d1.KEY_ AND d2.TENANT_ID_ IS NOT DISTINCT FROM d1.TENANT_ID_
+)
+ORDER BY d1.KEY_;
+
+-- Decisions within a DRG
+SELECT ID_, KEY_, NAME_, VERSION_
+FROM ACT_RE_DECISION_DEF
+WHERE DEC_REQ_ID_ = 'drg-id'
+ORDER BY KEY_;
+```
+
+---
+
+## ACT_RE_DECISION_REQ_DEF
+
+**Purpose:** Decision Requirement Graph (DRG) — a collection of related decisions with their dependencies. A DRG groups multiple `ACT_RE_DECISION_DEF` entries; a row is only created when a DMN resource contains more than one decision.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Internal unique ID |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| CATEGORY_ | VARCHAR(255) | NULL | Namespace/category |
+| NAME_ | VARCHAR(255) | NULL | Display name |
+| KEY_ | VARCHAR(255) | NOT NULL | Logical DRG key |
+| VERSION_ | INTEGER | NOT NULL | Version number |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Containing deployment (logical reference, no FK constraint) |
+| RESOURCE_NAME_ | VARCHAR(4000) | NULL | DMN resource filename |
+| DGRM_RESOURCE_NAME_ | VARCHAR(4000) | NULL | Diagram resource filename |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_DEC_REQ_DEF_TENANT_ID`
+
+**Example Queries:**
+
+```sql
+-- DRGs and their decisions
+SELECT r.KEY_ AS drg_key, r.VERSION_ AS drg_version,
+ d.KEY_ AS decision_key, d.VERSION_ AS decision_version
+FROM ACT_RE_DECISION_REQ_DEF r
+JOIN ACT_RE_DECISION_DEF d ON r.ID_ = d.DEC_REQ_ID_
+ORDER BY r.KEY_, d.KEY_;
+```
+
+---
+
+## Design Notes
+
+- **Versioning**: Definitions are immutable; redeployment creates a new row with an incremented `VERSION_`. Running instances always reference their original `ID_`, ensuring definition stability.
+- **Suspension**: `ACT_RE_PROCDEF.SUSPENSION_STATE_ = 2` prevents new instances from being started without deleting the definition.
+- **HISTORY_TTL_**: Retention period in days for history data of the definition. The engine derives `REMOVAL_TIME_` of history rows from it, and the history cleanup job deletes rows after that time.
+- Binary content (BPMN/DMN XML, diagrams) is stored in `ACT_GE_BYTEARRAY`. Match `ACT_GE_BYTEARRAY.NAME_` and `DEPLOYMENT_ID_` with the definition's `RESOURCE_NAME_` and `DEPLOYMENT_ID_`.
+
+---
+
+See [Database-Specific Implementation Notes](index.md#database-specific-implementation-notes) for type mappings.
+
+---
+
+**Last Updated:** 2026-11-11 | **Schema Version:** 7.25 | **Operaton Versions:** 1.0.0+
diff --git a/docs/documentation/user-guide/process-engine/database/database-schema/runtime.md b/docs/documentation/user-guide/process-engine/database/database-schema/runtime.md
new file mode 100644
index 00000000..978e1b94
--- /dev/null
+++ b/docs/documentation/user-guide/process-engine/database/database-schema/runtime.md
@@ -0,0 +1,690 @@
+---
+last_updated: 2026-11-11
+schema_version: 7.25
+---
+
+# Runtime (RU_)
+
+Runtime tables hold the live state of all active process/case executions, tasks, variables, jobs, incidents, and related objects. Rows are deleted or moved to history tables when work completes.
+
+## Tables
+
+| Table | Purpose |
+|-------|---------|
+| [ACT_RU_EXECUTION](#act_ru_execution) | Active process execution scopes |
+| [ACT_RU_TASK](#act_ru_task) | Active user tasks |
+| [ACT_RU_VARIABLE](#act_ru_variable) | Runtime variables |
+| [ACT_RU_IDENTITYLINK](#act_ru_identitylink) | Task/process user-group assignments |
+| [ACT_RU_JOB](#act_ru_job) | Background jobs (timers, async work) |
+| [ACT_RU_JOBDEF](#act_ru_jobdef) | Job definitions |
+| [ACT_RU_INCIDENT](#act_ru_incident) | Active incidents |
+| [ACT_RU_EVENT_SUBSCR](#act_ru_event_subscr) | Event subscriptions |
+| [ACT_RU_EXT_TASK](#act_ru_ext_task) | External task subscriptions |
+| [ACT_RU_BATCH](#act_ru_batch) | Batch operation records |
+| [ACT_RU_AUTHORIZATION](#act_ru_authorization) | Permission rules |
+| [ACT_RU_FILTER](#act_ru_filter) | Saved task filters |
+| [ACT_RU_METER_LOG](#act_ru_meter_log) | Engine metrics |
+| [ACT_RU_TASK_METER_LOG](#act_ru_task_meter_log) | Task worker (assignment) metrics |
+| [ACT_RU_CASE_EXECUTION](#act_ru_case_execution) | Active case executions (CMMN) |
+| [ACT_RU_CASE_SENTRY_PART](#act_ru_case_sentry_part) | Case sentry parts (CMMN) |
+
+---
+
+## ACT_RU_EXECUTION
+
+**Purpose:** Represents one execution scope within a process instance. Executions form a self-referential tree: the root execution (`PROC_INST_ID_ = ID_`) represents the process instance; child executions represent parallel branches, sub-processes, or event scopes.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Execution identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Top-level process instance of the call hierarchy (same for all executions of a process instance and of the instances it calls) |
+| PROC_INST_ID_ | VARCHAR(64) | FK → self | Root execution ID; equals ID_ for root |
+| BUSINESS_KEY_ | VARCHAR(255) | NULL | External correlation key |
+| PARENT_ID_ | VARCHAR(64) | FK → self | Parent execution (NULL for root) |
+| PROC_DEF_ID_ | VARCHAR(64) | FK → [ACT_RE_PROCDEF](repository.md#act_re_procdef) | Process definition |
+| SUPER_EXEC_ | VARCHAR(64) | FK → self | Caller execution (for call activities) |
+| SUPER_CASE_EXEC_ | VARCHAR(64) | NULL | Caller case execution |
+| CASE_INST_ID_ | VARCHAR(64) | NULL | Associated case instance |
+| ACT_ID_ | VARCHAR(255) | NULL | Current activity element ID |
+| ACT_INST_ID_ | VARCHAR(64) | NULL | Current activity instance ID |
+| IS_ACTIVE_ | BOOLEAN | NULL | Whether execution is active |
+| IS_CONCURRENT_ | BOOLEAN | NULL | Parallel branch |
+| IS_SCOPE_ | BOOLEAN | NULL | Creates a new variable scope |
+| IS_EVENT_SCOPE_ | BOOLEAN | NULL | Event scope execution kept after its scope completed, for compensation |
+| SUSPENSION_STATE_ | INTEGER | NULL | `1`=active, `2`=suspended |
+| CACHED_ENT_STATE_ | INTEGER | NULL | Bitmask of related entities present (event subscriptions, tasks, jobs, incidents, variables, sub-process/case instances, external tasks) |
+| SEQUENCE_COUNTER_ | BIGINT | NULL | Ordering counter for events of this execution (inherited by child executions) |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key (denormalized) |
+
+**Indexes:** `ACT_IDX_EXE_ROOT_PI`, `ACT_IDX_EXEC_BUSKEY`, `ACT_IDX_EXE_PROCINST`, `ACT_IDX_EXE_PARENT`, `ACT_IDX_EXE_SUPER`, `ACT_IDX_EXE_PROCDEF`, `ACT_IDX_EXEC_TENANT_ID`
+
+**Example Queries:**
+
+```sql
+-- All scopes in a process instance
+SELECT ID_, PARENT_ID_, ACT_ID_, IS_SCOPE_, IS_CONCURRENT_, SUSPENSION_STATE_
+FROM ACT_RU_EXECUTION
+WHERE PROC_INST_ID_ = 'pi-id'
+ORDER BY SEQUENCE_COUNTER_;
+
+-- Suspended process instances
+SELECT ID_, BUSINESS_KEY_, PROC_DEF_KEY_, SUSPENSION_STATE_
+FROM ACT_RU_EXECUTION
+WHERE PROC_INST_ID_ = ID_ AND SUSPENSION_STATE_ = 2;
+
+-- Execution hierarchy (PostgreSQL recursive)
+WITH RECURSIVE tree AS (
+ SELECT ID_, PARENT_ID_, ACT_ID_, 1 AS depth
+ FROM ACT_RU_EXECUTION WHERE PARENT_ID_ IS NULL AND PROC_INST_ID_ = ID_
+ UNION ALL
+ SELECT e.ID_, e.PARENT_ID_, e.ACT_ID_, t.depth + 1
+ FROM ACT_RU_EXECUTION e JOIN tree t ON e.PARENT_ID_ = t.ID_
+)
+SELECT * FROM tree ORDER BY depth, ID_;
+```
+
+---
+
+## ACT_RU_TASK
+
+**Purpose:** Active user task instance (BPMN user task, CMMN human task, or standalone task created via the API). Tracks assignment, delegation, priority, due dates, and suspension state. Deleted when completed or cancelled; history written to `ACT_HI_TASKINST`.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Task identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| EXECUTION_ID_ | VARCHAR(64) | FK → [ACT_RU_EXECUTION](#act_ru_execution) | Enclosing execution scope |
+| PROC_INST_ID_ | VARCHAR(64) | FK → [ACT_RU_EXECUTION](#act_ru_execution) | Process instance |
+| PROC_DEF_ID_ | VARCHAR(64) | FK → [ACT_RE_PROCDEF](repository.md#act_re_procdef) | Process definition |
+| CASE_EXECUTION_ID_ | VARCHAR(64) | FK → [ACT_RU_CASE_EXECUTION](#act_ru_case_execution) | Case execution (CMMN) |
+| CASE_INST_ID_ | VARCHAR(64) | NULL | Case instance (CMMN) |
+| CASE_DEF_ID_ | VARCHAR(64) | FK → [ACT_RE_CASE_DEF](repository.md#act_re_case_def) | Case definition (CMMN) |
+| NAME_ | VARCHAR(255) | NULL | Task display name |
+| PARENT_TASK_ID_ | VARCHAR(64) | NULL | Parent task for subtask hierarchies |
+| DESCRIPTION_ | VARCHAR(4000) | NULL | Task description |
+| TASK_DEF_KEY_ | VARCHAR(255) | NULL | Activity element ID from the BPMN definition |
+| OWNER_ | VARCHAR(255) | NULL | Task owner user ID |
+| ASSIGNEE_ | VARCHAR(255) | NULL | Currently assigned user ID |
+| DELEGATION_ | VARCHAR(64) | NULL | Delegation state: NULL, `PENDING`, `RESOLVED` |
+| PRIORITY_ | INTEGER | NULL | Priority (higher = more urgent) |
+| CREATE_TIME_ | TIMESTAMP | NULL | Task creation time |
+| LAST_UPDATED_ | TIMESTAMP | NULL | Last modification time |
+| DUE_DATE_ | TIMESTAMP | NULL | Deadline |
+| FOLLOW_UP_DATE_ | TIMESTAMP | NULL | Follow-up reminder date |
+| SUSPENSION_STATE_ | INTEGER | NULL | `1`=active, `2`=suspended |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| TASK_STATE_ | VARCHAR(64) | NULL | Lifecycle state: `Init`, `Created`, `Updated`, `Completed`, `Deleted` |
+
+**Indexes:** `ACT_IDX_TASK_CREATE`, `ACT_IDX_TASK_LAST_UPDATED`, `ACT_IDX_TASK_ASSIGNEE`, `ACT_IDX_TASK_OWNER`, `ACT_IDX_TASK_TENANT_ID`, `ACT_IDX_TASK_EXEC`, `ACT_IDX_TASK_PROCINST`, `ACT_IDX_TASK_PROCDEF`, `ACT_IDX_TASK_CASE_EXEC`, `ACT_IDX_TASK_CASE_DEF_ID`
+
+**Example Queries:**
+
+```sql
+-- Unassigned tasks for a process instance
+SELECT ID_, NAME_, PRIORITY_, CREATE_TIME_, DUE_DATE_
+FROM ACT_RU_TASK
+WHERE PROC_INST_ID_ = 'pi-id' AND ASSIGNEE_ IS NULL AND SUSPENSION_STATE_ = 1
+ORDER BY PRIORITY_ DESC, CREATE_TIME_;
+
+-- Overdue tasks
+SELECT ID_, NAME_, ASSIGNEE_, DUE_DATE_
+FROM ACT_RU_TASK
+WHERE DUE_DATE_ < CURRENT_TIMESTAMP AND SUSPENSION_STATE_ = 1
+ORDER BY DUE_DATE_;
+
+-- Task load per user
+SELECT ASSIGNEE_, COUNT(*) AS tasks,
+ SUM(CASE WHEN DUE_DATE_ < CURRENT_TIMESTAMP THEN 1 ELSE 0 END) AS overdue
+FROM ACT_RU_TASK
+WHERE ASSIGNEE_ IS NOT NULL AND SUSPENSION_STATE_ = 1
+GROUP BY ASSIGNEE_ ORDER BY tasks DESC;
+```
+
+---
+
+## ACT_RU_VARIABLE
+
+**Purpose:** Runtime variables scoped to a process instance, execution, task, case execution, or batch. Stores typed values: scalars in `LONG_`/`DOUBLE_`/`TEXT_`, complex objects via `BYTEARRAY_ID_`. Unique constraint `(VAR_SCOPE_, NAME_)` ensures one variable per name per scope.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Variable identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| TYPE_ | VARCHAR(255) | NOT NULL | Serializer name: `string`, `integer`, `long`, `short`, `double`, `boolean`, `date`, `bytes`, `file`, `null`, `serializable` (Java object), `json`, `xml`, … |
+| NAME_ | VARCHAR(255) | NOT NULL | Variable name |
+| EXECUTION_ID_ | VARCHAR(64) | FK → [ACT_RU_EXECUTION](#act_ru_execution) | Execution scope |
+| PROC_INST_ID_ | VARCHAR(64) | FK → [ACT_RU_EXECUTION](#act_ru_execution) | Process instance |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition (denormalized) |
+| CASE_EXECUTION_ID_ | VARCHAR(64) | FK → [ACT_RU_CASE_EXECUTION](#act_ru_case_execution) | Case execution scope |
+| CASE_INST_ID_ | VARCHAR(64) | FK → [ACT_RU_CASE_EXECUTION](#act_ru_case_execution) | Case instance scope |
+| TASK_ID_ | VARCHAR(64) | NULL | Task scope |
+| BATCH_ID_ | VARCHAR(64) | FK → [ACT_RU_BATCH](#act_ru_batch) | Batch scope |
+| BYTEARRAY_ID_ | VARCHAR(64) | FK → [ACT_GE_BYTEARRAY](general.md#act_ge_bytearray) | Binary value reference |
+| DOUBLE_ | DOUBLE PRECISION | NULL | Float/double value |
+| LONG_ | BIGINT | NULL | Integer/long/boolean/date value |
+| TEXT_ | VARCHAR(4000) | NULL | String value; string form of `Short`/`Integer`/`Long`; file name for `File` |
+| TEXT2_ | VARCHAR(4000) | NULL | Type-specific extra value: object type name for `Object`, MIME type and encoding for `File` |
+| VAR_SCOPE_ | VARCHAR(64) | NULL | Scope key for uniqueness check |
+| SEQUENCE_COUNTER_ | BIGINT | NULL | Update version counter |
+| IS_CONCURRENT_LOCAL_ | BOOLEAN | NULL | Local to a concurrent branch |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Unique Constraint:** `ACT_UNIQ_VARIABLE` on `(VAR_SCOPE_, NAME_)`
+
+**Indexes:** `ACT_IDX_VAR_EXE`, `ACT_IDX_VAR_PROCINST`, `ACT_IDX_VAR_BYTEARRAY`, `ACT_IDX_VARIABLE_TASK_ID`, `ACT_IDX_VARIABLE_TASK_NAME_TYPE`, `ACT_IDX_BATCH_ID`, `ACT_IDX_VAR_CASE_EXE`, `ACT_IDX_VAR_CASE_INST_ID`, `ACT_IDX_VARIABLE_TENANT_ID`
+
+**Variable Type→Column Mapping:**
+
+| Type | Column(s) |
+|------|-----------|
+| String | TEXT_ (limited by the column size) |
+| Boolean, Date | LONG_ |
+| Short, Integer, Long | LONG_, TEXT_ (string form) |
+| Double | DOUBLE_ |
+| Bytes | BYTEARRAY_ID_ |
+| File | BYTEARRAY_ID_ (content), TEXT_ (file name), TEXT2_ (MIME type, encoding) |
+| Object | BYTEARRAY_ID_ (serialized value), TEXT2_ (object type name); serialization format is given by `TYPE_` |
+| JSON, XML | BYTEARRAY_ID_ (serialized value) |
+| Null | all value columns NULL |
+
+**Example Queries:**
+
+```sql
+-- All variables for a process instance
+SELECT NAME_, TYPE_, TEXT_, LONG_, DOUBLE_
+FROM ACT_RU_VARIABLE
+WHERE PROC_INST_ID_ = 'pi-id'
+ORDER BY NAME_;
+
+-- Find processes with variable value
+SELECT DISTINCT PROC_INST_ID_
+FROM ACT_RU_VARIABLE
+WHERE NAME_ = 'status' AND TEXT_ = 'approved';
+
+-- Task variables
+SELECT NAME_, TYPE_, TEXT_, LONG_
+FROM ACT_RU_VARIABLE WHERE TASK_ID_ = 'task-id' ORDER BY NAME_;
+```
+
+---
+
+## ACT_RU_IDENTITYLINK
+
+**Purpose:** Links tasks or process definitions to users/groups. Task links hold candidate users and groups (`TYPE_ = 'candidate'`) and custom link types. Process definition links hold candidate starters, also with `TYPE_ = 'candidate'`. The assignee and owner of a task are stored in `ACT_RU_TASK`, not here.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Link identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| GROUP_ID_ | VARCHAR(255) | NULL | Group identifier |
+| TYPE_ | VARCHAR(255) | NULL | Link type, usually `candidate`; custom types are possible |
+| USER_ID_ | VARCHAR(255) | NULL | User identifier |
+| TASK_ID_ | VARCHAR(64) | FK → [ACT_RU_TASK](#act_ru_task) | Associated task (NULL for process-scoped) |
+| PROC_DEF_ID_ | VARCHAR(64) | FK → [ACT_RE_PROCDEF](repository.md#act_re_procdef) | Process definition (NULL for task-scoped) |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_IDENT_LNK_USER`, `ACT_IDX_IDENT_LNK_GROUP`, `ACT_IDX_TSKASS_TASK`, `ACT_IDX_ATHRZ_PROCEDEF`
+
+**Example Queries:**
+
+```sql
+-- All tasks a user can claim (as candidate)
+SELECT DISTINCT t.ID_, t.NAME_, t.PRIORITY_, t.CREATE_TIME_
+FROM ACT_RU_TASK t
+JOIN ACT_RU_IDENTITYLINK il ON t.ID_ = il.TASK_ID_
+WHERE il.USER_ID_ = 'john.doe' AND il.TYPE_ = 'candidate'
+ AND t.ASSIGNEE_ IS NULL AND t.SUSPENSION_STATE_ = 1;
+
+-- Candidate groups for a task
+SELECT GROUP_ID_ FROM ACT_RU_IDENTITYLINK
+WHERE TASK_ID_ = 'task-id' AND TYPE_ = 'candidate' AND GROUP_ID_ IS NOT NULL;
+```
+
+---
+
+## ACT_RU_JOB
+
+**Purpose:** Background job queue: timers (`TYPE_='timer'`), asynchronous continuations and batch jobs (`TYPE_='message'`), and the history cleanup job (`TYPE_='ever-living'`). Distributed execution uses `LOCK_OWNER_`/`LOCK_EXP_TIME_` for coordination. Failed jobs decrement `RETRIES_` and create incidents.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Job identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| TYPE_ | VARCHAR(255) | NOT NULL | Job type: `message`, `timer`, `ever-living` |
+| LOCK_EXP_TIME_ | TIMESTAMP | NULL | Lock expiry for distributed execution |
+| LOCK_OWNER_ | VARCHAR(255) | NULL | Engine instance holding the lock |
+| EXCLUSIVE_ | BOOLEAN | NULL | Exclusive execution (no parallel) |
+| EXECUTION_ID_ | VARCHAR(64) | NULL | Associated execution |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance |
+| PROCESS_INSTANCE_ID_ | VARCHAR(64) | NULL | Process instance |
+| PROCESS_DEF_ID_ | VARCHAR(64) | NULL | Process definition |
+| PROCESS_DEF_KEY_ | VARCHAR(255) | NULL | Process key (denormalized) |
+| RETRIES_ | INTEGER | NULL | Remaining retry attempts |
+| EXCEPTION_STACK_ID_ | VARCHAR(64) | FK → [ACT_GE_BYTEARRAY](general.md#act_ge_bytearray) | Exception stack trace |
+| EXCEPTION_MSG_ | VARCHAR(4000) | NULL | Last exception message |
+| FAILED_ACT_ID_ | VARCHAR(255) | NULL | Failed activity ID |
+| DUEDATE_ | TIMESTAMP | NULL | Execution due time (for timers) |
+| REPEAT_ | VARCHAR(255) | NULL | Cycle expression of a repeating timer (ISO 8601 `R…` or cron) |
+| REPEAT_OFFSET_ | BIGINT | DEFAULT 0 | Repeat offset |
+| HANDLER_TYPE_ | VARCHAR(255) | NULL | Job handler type (e.g., `async-continuation`, `timer-transition`, `batch-seed-job`) |
+| HANDLER_CFG_ | VARCHAR(4000) | NULL | Handler configuration |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Associated deployment |
+| SUSPENSION_STATE_ | INTEGER | NOT NULL DEFAULT 1 | `1`=active, `2`=suspended |
+| JOB_DEF_ID_ | VARCHAR(64) | NULL | Job definition (logical reference, no FK constraint) |
+| PRIORITY_ | BIGINT | NOT NULL DEFAULT 0 | Execution priority |
+| SEQUENCE_COUNTER_ | BIGINT | NULL | Ordering counter |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| CREATE_TIME_ | TIMESTAMP | NULL | Creation timestamp |
+| LAST_FAILURE_LOG_ID_ | VARCHAR(64) | NULL | Last failure log reference |
+| BATCH_ID_ | VARCHAR(64) | NULL | Associated batch |
+
+**Indexes:** `ACT_IDX_JOB_EXECUTION_ID`, `ACT_IDX_JOB_HANDLER`, `ACT_IDX_JOB_PROCINST`, `ACT_IDX_JOB_ROOT_PROCINST`, `ACT_IDX_JOB_TENANT_ID`, `ACT_IDX_JOB_EXCEPTION`, `ACT_IDX_JOB_JOB_DEF_ID`, `ACT_IDX_JOB_HANDLER_TYPE`
+
+**Example Queries:**
+
+```sql
+-- Jobs ready for execution
+SELECT ID_, TYPE_, HANDLER_TYPE_, PRIORITY_, DUEDATE_, PROCESS_INSTANCE_ID_, RETRIES_
+FROM ACT_RU_JOB
+WHERE SUSPENSION_STATE_ = 1
+ AND RETRIES_ > 0
+ AND (DUEDATE_ IS NULL OR DUEDATE_ <= CURRENT_TIMESTAMP)
+ AND (LOCK_OWNER_ IS NULL OR LOCK_EXP_TIME_ < CURRENT_TIMESTAMP)
+ORDER BY PRIORITY_ DESC, DUEDATE_ ASC;
+
+-- Jobs with failures
+SELECT ID_, TYPE_, EXCEPTION_MSG_, RETRIES_, FAILED_ACT_ID_
+FROM ACT_RU_JOB
+WHERE EXCEPTION_MSG_ IS NOT NULL
+ORDER BY CREATE_TIME_ DESC;
+
+-- Jobs currently locked by job executors
+SELECT LOCK_OWNER_, COUNT(*) AS locked_jobs, MIN(LOCK_EXP_TIME_) AS next_lock_expiry
+FROM ACT_RU_JOB
+WHERE LOCK_OWNER_ IS NOT NULL
+GROUP BY LOCK_OWNER_;
+```
+
+---
+
+## ACT_RU_JOBDEF
+
+**Purpose:** Defines job execution characteristics for an activity (timer event, async continuation) or a batch. Stores default priority, job type, and suspension state that apply to all instances of that activity's jobs.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Job definition identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Associated process definition |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key (denormalized) |
+| ACT_ID_ | VARCHAR(255) | NULL | Activity element ID |
+| JOB_TYPE_ | VARCHAR(255) | NOT NULL | Job handler type (e.g., `async-continuation`, `timer-transition`, `batch-seed-job`) |
+| JOB_CONFIGURATION_ | VARCHAR(255) | NULL | Handler-specific configuration (e.g., `async-before`/`async-after`, `DURATION: PT5M`, or the batch ID) |
+| SUSPENSION_STATE_ | INTEGER | NULL | `1`=active, `2`=suspended |
+| JOB_PRIORITY_ | BIGINT | NULL | Default priority for new jobs |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| DEPLOYMENT_ID_ | VARCHAR(64) | NULL | Associated deployment |
+
+**Indexes:** `ACT_IDX_JOBDEF_TENANT_ID`, `ACT_IDX_JOBDEF_PROC_DEF_ID`
+
+---
+
+## ACT_RU_INCIDENT
+
+**Purpose:** Tracks active failures within a process. When a job exhausts retries, an incident is created. Incidents form a chain: `CAUSE_INCIDENT_ID_` → direct cause, `ROOT_CAUSE_INCIDENT_ID_` → original root cause.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Incident identifier |
+| REV_ | INTEGER | NOT NULL | Revision for optimistic locking |
+| INCIDENT_TIMESTAMP_ | TIMESTAMP | NOT NULL | When the incident occurred |
+| INCIDENT_MSG_ | VARCHAR(4000) | NULL | Error message |
+| INCIDENT_TYPE_ | VARCHAR(255) | NOT NULL | Type: `failedJob`, `failedExternalTask`, … |
+| EXECUTION_ID_ | VARCHAR(64) | FK → [ACT_RU_EXECUTION](#act_ru_execution) | Associated execution |
+| ACTIVITY_ID_ | VARCHAR(255) | NULL | Activity where incident is attached |
+| FAILED_ACTIVITY_ID_ | VARCHAR(255) | NULL | Activity that actually failed |
+| PROC_INST_ID_ | VARCHAR(64) | FK → [ACT_RU_EXECUTION](#act_ru_execution) | Process instance |
+| PROC_DEF_ID_ | VARCHAR(64) | FK → [ACT_RE_PROCDEF](repository.md#act_re_procdef) | Process definition |
+| CAUSE_INCIDENT_ID_ | VARCHAR(64) | FK → self | Direct cause incident |
+| ROOT_CAUSE_INCIDENT_ID_ | VARCHAR(64) | FK → self | Root cause incident |
+| CONFIGURATION_ | VARCHAR(255) | NULL | Configuration (e.g., job ID) |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| JOB_DEF_ID_ | VARCHAR(64) | FK → [ACT_RU_JOBDEF](#act_ru_jobdef) | Related job definition |
+| ANNOTATION_ | VARCHAR(4000) | NULL | Operator notes |
+
+**Indexes:** `ACT_IDX_INC_CONFIGURATION`, `ACT_IDX_INC_TENANT_ID`, `ACT_IDX_INC_EXID`, `ACT_IDX_INC_PROCINSTID`, `ACT_IDX_INC_PROCDEFID`, `ACT_IDX_INC_CAUSEINCID`, `ACT_IDX_INC_ROOTCAUSEINCID`, `ACT_IDX_INC_JOB_DEF`
+
+**Example Queries:**
+
+```sql
+-- Active incidents for a process instance
+SELECT ID_, INCIDENT_TYPE_, INCIDENT_MSG_, ACTIVITY_ID_, ANNOTATION_
+FROM ACT_RU_INCIDENT
+WHERE PROC_INST_ID_ = 'pi-id'
+ORDER BY INCIDENT_TIMESTAMP_ DESC;
+
+-- Incident cause chain
+SELECT e.ID_, e.INCIDENT_TYPE_, e.INCIDENT_MSG_,
+ c.ID_ AS cause_id, c.INCIDENT_TYPE_ AS cause_type
+FROM ACT_RU_INCIDENT e
+LEFT JOIN ACT_RU_INCIDENT c ON e.CAUSE_INCIDENT_ID_ = c.ID_
+WHERE e.ROOT_CAUSE_INCIDENT_ID_ = 'root-incident-id';
+```
+
+---
+
+## ACT_RU_EVENT_SUBSCR
+
+**Purpose:** An active subscription to a message, signal, compensation or conditional event. Created when an execution reaches a catch event or enters a scope with boundary or event sub-process events; deleted when the event is received and execution resumes. Message, signal and conditional start events have subscriptions without an execution.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Subscription identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| EVENT_TYPE_ | VARCHAR(255) | NOT NULL | Type: `message`, `signal`, `compensate`, `conditional` |
+| EVENT_NAME_ | VARCHAR(255) | NULL | Message or signal name |
+| EXECUTION_ID_ | VARCHAR(64) | FK → [ACT_RU_EXECUTION](#act_ru_execution) | Awaiting execution (NULL for start event subscriptions) |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| ACTIVITY_ID_ | VARCHAR(255) | NULL | Catch element activity ID |
+| CONFIGURATION_ | VARCHAR(255) | NULL | Process definition ID for start event subscriptions; event scope execution ID for `compensate` |
+| CREATED_ | TIMESTAMP | NOT NULL | Creation time |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_EVENT_SUBSCR`, `ACT_IDX_EVENT_SUBSCR_CONFIG_`, `ACT_IDX_EVENT_SUBSCR_TENANT_ID`, `ACT_IDX_EVENT_SUBSCR_EVT_NAME`
+
+**Example Queries:**
+
+```sql
+-- All message subscriptions pending correlation
+SELECT ID_, EVENT_NAME_, EXECUTION_ID_, PROC_INST_ID_, CONFIGURATION_
+FROM ACT_RU_EVENT_SUBSCR
+WHERE EVENT_TYPE_ = 'message'
+ORDER BY CREATED_ ASC;
+```
+
+---
+
+## ACT_RU_EXT_TASK
+
+**Purpose:** External task subscription enabling decoupled worker execution. Workers fetch tasks by `TOPIC_NAME_`, acquire a lock via `WORKER_ID_`/`LOCK_EXP_TIME_`, execute, then complete or fail the task.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | External task identifier |
+| REV_ | INTEGER | NOT NULL | Revision for optimistic locking |
+| WORKER_ID_ | VARCHAR(255) | NULL | Worker holding the lock |
+| TOPIC_NAME_ | VARCHAR(255) | NULL | Worker routing topic |
+| RETRIES_ | INTEGER | NULL | Remaining retry attempts |
+| ERROR_MSG_ | VARCHAR(4000) | NULL | Last error message |
+| ERROR_DETAILS_ID_ | VARCHAR(64) | FK → [ACT_GE_BYTEARRAY](general.md#act_ge_bytearray) | Detailed error (serialized) |
+| LOCK_EXP_TIME_ | TIMESTAMP | NULL | Lock expiry |
+| CREATE_TIME_ | TIMESTAMP | NULL | Creation time |
+| SUSPENSION_STATE_ | INTEGER | NULL | `1`=active, `2`=suspended |
+| EXECUTION_ID_ | VARCHAR(64) | FK → [ACT_RU_EXECUTION](#act_ru_execution) | Associated execution |
+| PROC_INST_ID_ | VARCHAR(64) | NULL | Process instance |
+| PROC_DEF_ID_ | VARCHAR(64) | NULL | Process definition |
+| PROC_DEF_KEY_ | VARCHAR(255) | NULL | Process key |
+| ACT_ID_ | VARCHAR(255) | NULL | Activity ID |
+| ACT_INST_ID_ | VARCHAR(64) | NULL | Activity instance ID |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| PRIORITY_ | BIGINT | NOT NULL DEFAULT 0 | Execution priority |
+| LAST_FAILURE_LOG_ID_ | VARCHAR(64) | NULL | Last failure log reference |
+
+**Indexes:** `ACT_IDX_EXT_TASK_TOPIC`, `ACT_IDX_EXT_TASK_TENANT_ID`, `ACT_IDX_EXT_TASK_PRIORITY`, `ACT_IDX_EXT_TASK_ERR_DETAILS`, `ACT_IDX_EXT_TASK_EXEC`
+
+**Example Queries:**
+
+```sql
+-- Available tasks for a worker topic
+SELECT ID_, TOPIC_NAME_, PRIORITY_, EXECUTION_ID_, PROC_INST_ID_
+FROM ACT_RU_EXT_TASK
+WHERE TOPIC_NAME_ = 'payment-processing'
+ AND SUSPENSION_STATE_ = 1
+ AND (RETRIES_ IS NULL OR RETRIES_ > 0)
+ AND (LOCK_EXP_TIME_ IS NULL OR LOCK_EXP_TIME_ <= CURRENT_TIMESTAMP)
+ORDER BY PRIORITY_ DESC, CREATE_TIME_ ASC
+LIMIT 10;
+```
+
+---
+
+## ACT_RU_BATCH
+
+**Purpose:** Coordinates bulk operations (process migration, message correlation, etc.). A batch spawns three job types: seed jobs (create work), batch jobs (do work), and a monitor job (tracks progress).
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Batch identifier |
+| REV_ | INTEGER | NOT NULL | Revision for optimistic locking |
+| TYPE_ | VARCHAR(255) | NULL | Batch type (e.g., `instance-migration`, `correlate-message`) |
+| TOTAL_JOBS_ | INTEGER | NULL | Total jobs to complete |
+| JOBS_CREATED_ | INTEGER | NULL | Jobs created so far |
+| JOBS_PER_SEED_ | INTEGER | NULL | Jobs per seed invocation |
+| INVOCATIONS_PER_JOB_ | INTEGER | NULL | Work units per batch job |
+| SEED_JOB_DEF_ID_ | VARCHAR(64) | FK → [ACT_RU_JOBDEF](#act_ru_jobdef) | Seed job definition |
+| BATCH_JOB_DEF_ID_ | VARCHAR(64) | FK → [ACT_RU_JOBDEF](#act_ru_jobdef) | Batch job definition |
+| MONITOR_JOB_DEF_ID_ | VARCHAR(64) | FK → [ACT_RU_JOBDEF](#act_ru_jobdef) | Monitor job definition |
+| SUSPENSION_STATE_ | INTEGER | NULL | `1`=active, `2`=suspended |
+| CONFIGURATION_ | VARCHAR(255) | NULL | ID of the batch configuration in `ACT_GE_BYTEARRAY` |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+| CREATE_USER_ID_ | VARCHAR(255) | NULL | User who started the batch |
+| START_TIME_ | TIMESTAMP | NULL | Start time |
+| EXEC_START_TIME_ | TIMESTAMP | NULL | Execution phase start time |
+
+**Indexes:** `ACT_IDX_BATCH_SEED_JOB_DEF`, `ACT_IDX_BATCH_MONITOR_JOB_DEF`, `ACT_IDX_BATCH_JOB_DEF`
+
+**Example Queries:**
+
+```sql
+-- Batch job creation progress (seeding)
+SELECT ID_, TYPE_, TOTAL_JOBS_, JOBS_CREATED_,
+ ROUND(100.0 * JOBS_CREATED_ / NULLIF(TOTAL_JOBS_, 0), 1) AS pct_jobs_created
+FROM ACT_RU_BATCH WHERE SUSPENSION_STATE_ = 1;
+```
+
+---
+
+## ACT_RU_AUTHORIZATION
+
+**Purpose:** Fine-grained access control rules. Each row grants or revokes permission(s) to a user or group on a resource type/ID combination. `PERMS_` is a bitmask of permission flags.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Authorization rule identifier |
+| REV_ | INTEGER | NOT NULL | Revision for optimistic locking |
+| TYPE_ | INTEGER | NOT NULL | `0`=global, `1`=grant, `2`=revoke |
+| GROUP_ID_ | VARCHAR(255) | NULL | Target group (mutually exclusive with USER_ID_) |
+| USER_ID_ | VARCHAR(255) | NULL | Target user (mutually exclusive with GROUP_ID_); `*` for global authorizations |
+| RESOURCE_TYPE_ | INTEGER | NOT NULL | Resource type (`0`=application, `1`=user, `2`=group, `6`=process definition, `7`=task, `8`=process instance, …) |
+| RESOURCE_ID_ | VARCHAR(255) | NULL | Specific resource ID; `*` for all resources of the type |
+| PERMS_ | INTEGER | NULL | Permission bitmask (READ=2, UPDATE=4, CREATE=8, DELETE=16, …); for revoke rows a cleared bit means revoked |
+| REMOVAL_TIME_ | TIMESTAMP | NULL | Removal time for authorizations on history data (history cleanup) |
+| ROOT_PROC_INST_ID_ | VARCHAR(64) | NULL | Root process instance reference |
+
+**Unique Constraints:**
+- `ACT_UNIQ_AUTH_USER` on `(TYPE_, USER_ID_, RESOURCE_TYPE_, RESOURCE_ID_)`
+- `ACT_UNIQ_AUTH_GROUP` on `(TYPE_, GROUP_ID_, RESOURCE_TYPE_, RESOURCE_ID_)`
+
+**Indexes:** `ACT_IDX_AUTH_GROUP_ID`, `ACT_IDX_AUTH_RESOURCE_ID`, `ACT_IDX_AUTH_ROOT_PI`, `ACT_IDX_AUTH_RM_TIME`
+
+**Permission Flags:** `NONE=0`, `READ=2`, `UPDATE=4`, `CREATE=8`, `DELETE=16`, `ACCESS=32`, `READ_TASK=64`, `UPDATE_TASK=128`, `CREATE_INSTANCE=256`, `READ_INSTANCE=512`, `UPDATE_INSTANCE=1024`, `DELETE_INSTANCE=2048`, `READ_HISTORY=4096`, `DELETE_HISTORY=8192`, `TASK_WORK=16384`, `TASK_ASSIGN=32768`, `MIGRATE_INSTANCE=65536`; `ALL` sets every bit (`2147483647`). Resource-specific permissions (e.g. `ProcessDefinitionPermissions`) add further flags such as `SUSPEND=1048576`, and may reuse bits (`RETRY_JOB=32`).
+
+**Resource Types:** `APPLICATION=0`, `USER=1`, `GROUP=2`, `GROUP_MEMBERSHIP=3`, `AUTHORIZATION=4`, `FILTER=5`, `PROCESS_DEFINITION=6`, `TASK=7`, `PROCESS_INSTANCE=8`, `DEPLOYMENT=9`, `DECISION_DEFINITION=10`, `TENANT=11`, `TENANT_MEMBERSHIP=12`, `BATCH=13`, `DECISION_REQUIREMENTS_DEFINITION=14`, `REPORT=15`, `DASHBOARD=16`, `OPERATION_LOG_CATEGORY=17`, `OPTIMIZE=18`, `HISTORIC_TASK=19`, `HISTORIC_PROCESS_INSTANCE=20`, `SYSTEM=21`
+
+**Example Queries:**
+
+```sql
+-- All permissions for a user
+SELECT TYPE_, RESOURCE_TYPE_, RESOURCE_ID_, PERMS_
+FROM ACT_RU_AUTHORIZATION
+WHERE USER_ID_ = 'john.doe'
+ORDER BY RESOURCE_TYPE_, RESOURCE_ID_;
+
+-- Grants with READ on a process definition (PostgreSQL/MySQL)
+-- The engine also evaluates group, global and revoke authorizations.
+SELECT ID_, TYPE_, RESOURCE_ID_, PERMS_
+FROM ACT_RU_AUTHORIZATION
+WHERE USER_ID_ = 'john.doe'
+ AND RESOURCE_TYPE_ = 6
+ AND RESOURCE_ID_ IN ('invoice_approval', '*')
+ AND TYPE_ = 1
+ AND (PERMS_ & 2) = 2;
+```
+
+---
+
+## ACT_RU_FILTER
+
+**Purpose:** Saved task filter/query definitions for the Tasklist UI. Each filter stores its query criteria (assignee, priority, process, etc.) as JSON in `QUERY_`.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Filter identifier |
+| REV_ | INTEGER | NOT NULL | Revision for optimistic locking |
+| RESOURCE_TYPE_ | VARCHAR(255) | NOT NULL | Resource type; currently always `Task` |
+| NAME_ | VARCHAR(255) | NOT NULL | Filter display name |
+| OWNER_ | VARCHAR(255) | NULL | Owning user ID |
+| QUERY_ | TEXT | NOT NULL | Filter query (JSON) |
+| PROPERTIES_ | TEXT | NULL | Additional metadata (JSON) |
+
+---
+
+## ACT_RU_METER_LOG
+
+**Purpose:** Engine metrics such as `root-process-instance-start`, `activity-instance-start`, `job-successful` or `executed-decision-elements`. The metrics reporter writes one row per metric and reporting interval.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Log entry identifier |
+| NAME_ | VARCHAR(64) | NOT NULL | Metric name (e.g., `root-process-instance-start`) |
+| REPORTER_ | VARCHAR(255) | NULL | Reporting engine instance ID |
+| VALUE_ | BIGINT | NULL | Metric value |
+| TIMESTAMP_ | TIMESTAMP | NULL | End of the reporting interval |
+| MILLISECONDS_ | BIGINT | DEFAULT 0 | `TIMESTAMP_` as epoch milliseconds (indexed for range queries) |
+
+**Indexes:** `ACT_IDX_METER_LOG_MS`, `ACT_IDX_METER_LOG_NAME_MS`, `ACT_IDX_METER_LOG_REPORT`, `ACT_IDX_METER_LOG_TIME`, `ACT_IDX_METER_LOG`
+
+**Example Queries:**
+
+```sql
+-- Hourly root process instance starts (last 7 days)
+SELECT date_trunc('hour', TIMESTAMP_) AS hour, SUM(VALUE_) AS starts
+FROM ACT_RU_METER_LOG
+WHERE NAME_ = 'root-process-instance-start'
+ AND TIMESTAMP_ >= CURRENT_TIMESTAMP - INTERVAL '7 days'
+GROUP BY 1 ORDER BY 1 DESC;
+```
+
+---
+
+## ACT_RU_TASK_METER_LOG
+
+**Purpose:** Task worker metrics. The engine writes one row each time a task is assigned, with a pseudonymized `ASSIGNEE_HASH_` instead of the user ID. Used to count unique task workers.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Log entry identifier |
+| ASSIGNEE_HASH_ | BIGINT | NULL | Hash of assignee user ID |
+| TIMESTAMP_ | TIMESTAMP | NULL | Time of the assignment |
+
+**Indexes:** `ACT_IDX_TASK_METER_LOG_TIME`
+
+---
+
+## ACT_RU_CASE_EXECUTION
+
+**Purpose:** Active execution scope within a CMMN case instance. Mirrors `ACT_RU_EXECUTION` for cases — root execution is the case instance, child executions are stages and tasks.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Case execution identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| CASE_INST_ID_ | VARCHAR(64) | FK → self | Root case instance (equals ID_ for root) |
+| SUPER_CASE_EXEC_ | VARCHAR(64) | NULL | Caller case execution |
+| SUPER_EXEC_ | VARCHAR(64) | NULL | Caller process execution |
+| BUSINESS_KEY_ | VARCHAR(255) | NULL | External correlation key |
+| PARENT_ID_ | VARCHAR(64) | FK → self | Parent case execution |
+| CASE_DEF_ID_ | VARCHAR(64) | FK → [ACT_RE_CASE_DEF](repository.md#act_re_case_def) | Case definition |
+| ACT_ID_ | VARCHAR(255) | NULL | Current CMMN activity ID |
+| PREV_STATE_ | INTEGER | NULL | Previous state |
+| CURRENT_STATE_ | INTEGER | NULL | Current state (`0`=new, `1`=available, `2`=enabled, `3`=disabled, `4`=active, `5`=suspended, `6`=terminated, `7`=completed, `8`=failed, `9`=closed, `10`–`14`=transient terminating/suspending states) |
+| REQUIRED_ | BOOLEAN | NULL | Whether completion is required for parent |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_CASE_EXEC_BUSKEY`, `ACT_IDX_CASE_EXE_CASE_INST`, `ACT_IDX_CASE_EXE_PARENT`, `ACT_IDX_CASE_EXE_CASE_DEF`, `ACT_IDX_CASE_EXEC_TENANT_ID`
+
+---
+
+## ACT_RU_CASE_SENTRY_PART
+
+**Purpose:** Tracks satisfaction state of individual sentry conditions in a CMMN case. A sentry fires when all its parts are satisfied, enabling or disabling case elements.
+
+**Columns:**
+
+| Column | Type | Constraints | Description |
+|--------|------|-------------|-------------|
+| ID_ | VARCHAR(64) | PK NOT NULL | Sentry part identifier |
+| REV_ | INTEGER | NULL | Revision for optimistic locking |
+| CASE_INST_ID_ | VARCHAR(64) | FK → [ACT_RU_CASE_EXECUTION](#act_ru_case_execution) | Case instance |
+| CASE_EXEC_ID_ | VARCHAR(64) | FK → [ACT_RU_CASE_EXECUTION](#act_ru_case_execution) | Associated case execution |
+| SENTRY_ID_ | VARCHAR(255) | NULL | Sentry element ID |
+| TYPE_ | VARCHAR(255) | NULL | Part type: `planItemOnPart`, `ifPart`, `variableOnPart` |
+| SOURCE_CASE_EXEC_ID_ | VARCHAR(64) | NULL | Source execution for transition conditions |
+| STANDARD_EVENT_ | VARCHAR(255) | NULL | CMMN standard event |
+| SOURCE_ | VARCHAR(255) | NULL | Source plan item activity ID (for planItemOnPart) |
+| VARIABLE_EVENT_ | VARCHAR(255) | NULL | Variable change event (for variableOnPart) |
+| VARIABLE_NAME_ | VARCHAR(255) | NULL | Observed variable name |
+| SATISFIED_ | BOOLEAN | NULL | Whether this part is satisfied |
+| TENANT_ID_ | VARCHAR(64) | NULL | Tenant identifier |
+
+**Indexes:** `ACT_IDX_CASE_SENTRY_CASE_INST`, `ACT_IDX_CASE_SENTRY_CASE_EXEC`
+
+---
+
+## Design Notes
+
+- **Optimistic locking**: The engine checks `REV_` on every update and raises an `OptimisticLockingException` on conflict. Change data through the engine API, not with direct SQL updates.
+- **Suspension**: `SUSPENSION_STATE_` (`1`=active, `2`=suspended) is set on executions, tasks, jobs, job definitions, external tasks and batches. Suspended items cannot progress but are not deleted.
+- **Incident chains**: `CAUSE_INCIDENT_ID_` and `ROOT_CAUSE_INCIDENT_ID_` in `ACT_RU_INCIDENT` enable root cause navigation for cascaded failures.
+- **Job lock expiry**: Locks of crashed engine nodes need no cleanup. Once `LOCK_EXP_TIME_` has passed, any job executor can acquire the job again.
+- **Multi-tenancy**: Always include `TENANT_ID_` predicates in queries on multi-tenant installations.
+
+---
+
+See [Database-Specific Implementation Notes](index.md#database-specific-implementation-notes) for type mappings.
+
+---
+
+**Last Updated:** 2026-11-11 | **Schema Version:** 7.25 | **Operaton Versions:** 1.0.0+
diff --git a/docs/documentation/user-guide/process-engine/process-engine-api.md b/docs/documentation/user-guide/process-engine/process-engine-api.md
index 2e6e70d8..19df26d1 100644
--- a/docs/documentation/user-guide/process-engine/process-engine-api.md
+++ b/docs/documentation/user-guide/process-engine/process-engine-api.md
@@ -247,7 +247,7 @@ The Java Query API is exposed as REST service as well, see the [REST documentati
### Native Queries
-Sometimes you need more powerful queries, e.g., queries using an OR operator or restrictions you cannot express using the Query API. For these cases, we introduced native queries, which allow you to write your own SQL queries. The return type is defined by the Query object you use and the data is mapped into the correct objects, e.g., Task, ProcessInstance, Execution, etc. Since the query will be fired at the database you have to use table and column names as they are defined in the [database schema](../process-engine/database/database-schema.md). This requires some knowledge about the internal data structure and it is recommended to use native queries with care. The table names can be retrieved via the API to keep the dependency as small as possible.
+Sometimes you need more powerful queries, e.g., queries using an OR operator or restrictions you cannot express using the Query API. For these cases, we introduced native queries, which allow you to write your own SQL queries. The return type is defined by the Query object you use and the data is mapped into the correct objects, e.g., Task, ProcessInstance, Execution, etc. Since the query will be fired at the database you have to use table and column names as they are defined in the [database schema](database/database-schema/index.md). This requires some knowledge about the internal data structure and it is recommended to use native queries with care. The table names can be retrieved via the API to keep the dependency as small as possible.
```java
List tasks = taskService.createNativeTaskQuery()
@@ -273,7 +273,7 @@ With a custom query you write the SQL yourself, join the engine tables with your
Custom queries require that the engine tables and your domain tables live in the same database, so that a single SQL statement can join them.
:::warning[Internal Database Schema]
-Custom queries depend on the [database schema](../process-engine/database/database-schema.md) of the engine, which is not part of the public API. While the schema is fairly stable, it may change between versions. Make sure to test your custom queries whenever you upgrade Operaton.
+Custom queries depend on the [database schema](database/database-schema/index.md) of the engine, which is not part of the public API. While the schema is fairly stable, it may change between versions. Make sure to test your custom queries whenever you upgrade Operaton.
:::
#### Set Up a Separate MyBatis Session Factory
@@ -407,4 +407,4 @@ List tasks = customQuerySessionFactory.executeQuery(commandContext -> {
### SQL Queries
-The [table layout](../process-engine/database/database-schema.md) is pretty straightforward - we focused on making it easy to understand. Hence it is OK to do SQL queries for e.g., reporting use cases. Just make sure that you do not mess up the engine data by updating the tables without exactly knowing what you are doing.
+The [table layout](database/database-schema/index.md) is pretty straightforward - we focused on making it easy to understand. Hence it is OK to do SQL queries for e.g., reporting use cases. Just make sure that you do not mess up the engine data by updating the tables without exactly knowing what you are doing.
diff --git a/docs/documentation/user-guide/security.md b/docs/documentation/user-guide/security.md
index 25833cd6..1df4d305 100644
--- a/docs/documentation/user-guide/security.md
+++ b/docs/documentation/user-guide/security.md
@@ -100,7 +100,7 @@ Someone could use brute force to produce arbitrary amounts of log statements and
To perform authentication, Operaton can use two sources: a database or LDAP.
-When using the database, usernames and passwords are stored inside the `ACT_ID_USER` table (see [documentation on database schema](../user-guide/process-engine/database/database-schema.md#identity)). To protect the passwords stored in the database, Operaton uses two concepts:
+When using the database, usernames and passwords are stored inside the `ACT_ID_USER` table (see [documentation on database schema](process-engine/database/database-schema/database-schema.md#identity)). To protect the passwords stored in the database, Operaton uses two concepts:
* **hashing**: instead of storing the password in plain text, a hash is stored. When authenticating, the same hash is generated from the user's input and compared against the hash in the database. If both hashes are equal the authentication attempt is successful. Operaton allows users to configure and customize the hash function used. Please refer the [documentation section on password hashing](../user-guide/process-engine/password-hashing.md) for details.
* **salted hashes** to protect the database against rainbow table attacks, Operaton uses salted hashes. Similar to hashing itself, this function can be configured and extended to a user's needs. Please refer the [documentation section on password hashing](../user-guide/process-engine/password-hashing.md) for details.
diff --git a/package-lock.json b/package-lock.json
index 9b8fb4e4..f60269f2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8483,19 +8483,6 @@
"integrity": "sha512-b6Z/X4MczChMcfhk6kfRmBzPgjoPzuS9KGR4AFsiLulLNRAAqhP+xZTKtMnZGhLuc61I20d5WqlId02AZvcO6g==",
"license": "MIT"
},
- "node_modules/docusaurus-theme-search-typesense/node_modules/@docusaurus/logger": {
- "version": "3.9.2",
- "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.9.2.tgz",
- "integrity": "sha512-/SVCc57ByARzGSU60c50rMyQlBuMIJCjcsJlkphxY6B0GV4UH3tcA1994N8fFfbJ9kX3jIBe/xg3XP5qBtGDbA==",
- "license": "MIT",
- "dependencies": {
- "chalk": "^4.1.2",
- "tslib": "^2.6.0"
- },
- "engines": {
- "node": ">=20.0"
- }
- },
"node_modules/docusaurus-theme-search-typesense/node_modules/typesense": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/typesense/-/typesense-1.8.2.tgz",
diff --git a/scripts/erd_build.py b/scripts/erd_build.py
new file mode 100644
index 00000000..32a9fb93
--- /dev/null
+++ b/scripts/erd_build.py
@@ -0,0 +1,26 @@
+"""Build per-group mermaid ER sub-diagrams from parsed schema data."""
+
+
+def extract_header(text):
+ lines = text.splitlines()
+ init_line = lines[0]
+ classdef_lines = [l for l in lines if l.strip().startswith("classDef")]
+ return init_line, classdef_lines
+
+
+def build_subdiagram(tables, entities, rels, classes, init_line, classdef_lines):
+ out = [init_line, "erDiagram"]
+ out.extend(" " + l.strip() for l in classdef_lines)
+
+ for t in tables:
+ out.append(f" {t} {{{entities[t]}\n }}")
+
+ for a, rel, b, col in rels:
+ if a in tables and b in tables:
+ out.append(f' {a} {rel} {b} : "{col}"')
+
+ for t in tables:
+ if t in classes:
+ out.append(f" class {t} {classes[t]}")
+
+ return "\n".join(out) + "\n"
diff --git a/scripts/erd_schema.py b/scripts/erd_schema.py
new file mode 100644
index 00000000..6419ebd6
--- /dev/null
+++ b/scripts/erd_schema.py
@@ -0,0 +1,54 @@
+"""Parse schema.mermaid into entities, relationships, and class assignments."""
+import re
+
+ENTITY_RE = re.compile(r'^\s{4}(ACT_\w+)\s*\{(.*?)\n\s{4}\}', re.MULTILINE | re.DOTALL)
+REL_RE = re.compile(
+ r'^\s*(ACT_\w+)\s+([}|][o|](?:--|\.\.)[o|][|{])\s+(ACT_\w+)\s*:\s*"([^"]+)"',
+ re.MULTILINE,
+)
+CLASS_RE = re.compile(r'^\s*class\s+(ACT_\w+)\s+(\w+)', re.MULTILINE)
+
+TABLE_GROUPS = {
+ "bpmn": [
+ "ACT_GE_PROPERTY", "ACT_GE_BYTEARRAY", "ACT_GE_SCHEMA_LOG",
+ "ACT_RE_DEPLOYMENT", "ACT_RE_PROCDEF", "ACT_RE_CAMFORMDEF",
+ "ACT_RU_EXECUTION", "ACT_RU_JOB", "ACT_RU_JOBDEF", "ACT_RU_TASK",
+ "ACT_RU_IDENTITYLINK", "ACT_RU_VARIABLE", "ACT_RU_EVENT_SUBSCR",
+ "ACT_RU_INCIDENT", "ACT_RU_AUTHORIZATION", "ACT_RU_FILTER",
+ "ACT_RU_METER_LOG", "ACT_RU_TASK_METER_LOG", "ACT_RU_EXT_TASK",
+ "ACT_RU_BATCH",
+ ],
+ "dmn": ["ACT_RE_DECISION_DEF", "ACT_RE_DECISION_REQ_DEF"],
+ "cmmn": ["ACT_RE_CASE_DEF", "ACT_RU_CASE_EXECUTION", "ACT_RU_CASE_SENTRY_PART"],
+ "history": None,
+ "identity": None,
+}
+
+
+def parse_schema(text):
+ entities = {m.group(1): m.group(2) for m in ENTITY_RE.finditer(text)}
+ rels = [
+ (m.group(1), m.group(2), m.group(3), m.group(4))
+ for m in REL_RE.finditer(text)
+ ]
+ classes = {m.group(1): m.group(2) for m in CLASS_RE.finditer(text)}
+ return entities, rels, classes
+
+
+def resolve_groups(entities):
+ groups = {k: v for k, v in TABLE_GROUPS.items() if v is not None}
+ groups["history"] = sorted(n for n in entities if n.startswith("ACT_HI_"))
+ groups["identity"] = sorted(n for n in entities if n.startswith("ACT_ID_"))
+
+ grouped = [t for tables in groups.values() for t in tables]
+ if len(grouped) != len(set(grouped)):
+ seen, dupes = set(), set()
+ for t in grouped:
+ (dupes if t in seen else seen).add(t)
+ raise ValueError(f"tables assigned to multiple groups: {sorted(dupes)}")
+
+ missing = set(entities) - set(grouped)
+ if missing:
+ raise ValueError(f"tables not assigned to any group: {sorted(missing)}")
+
+ return groups
diff --git a/scripts/generate_erd_diagrams.py b/scripts/generate_erd_diagrams.py
new file mode 100644
index 00000000..92897138
--- /dev/null
+++ b/scripts/generate_erd_diagrams.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+"""Generate grouped ER diagram SVGs from schema.mermaid.
+
+Usage: python3 scripts/generate_erd_diagrams.py
+Requires: npx (Node.js) available on PATH; @mermaid-js/mermaid-cli is
+fetched on demand via `npx -y`, no separate install step needed.
+"""
+import subprocess
+import sys
+import tempfile
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).parent))
+from erd_schema import parse_schema, resolve_groups
+from erd_build import extract_header, build_subdiagram
+
+REPO_ROOT = Path(__file__).parent.parent
+SCHEMA_PATH = REPO_ROOT / "docs/documentation/reference/db-schema/schema.mermaid"
+SCHEMA_VERSION = "725"
+OUT_DIR = REPO_ROOT / "static/img/documentation/user-guide/process-engine/database"
+
+
+def main():
+ text = SCHEMA_PATH.read_text()
+ entities, rels, classes = parse_schema(text)
+ groups = resolve_groups(entities)
+ init_line, classdef_lines = extract_header(text)
+
+ OUT_DIR.mkdir(parents=True, exist_ok=True)
+
+ with tempfile.TemporaryDirectory() as tmp:
+ tmp_path = Path(tmp)
+ for group, tables in groups.items():
+ mmd_content = build_subdiagram(tables, entities, rels, classes, init_line, classdef_lines)
+ mmd_path = tmp_path / f"{group}.mmd"
+ mmd_path.write_text(mmd_content)
+
+ svg_path = OUT_DIR / f"erd_{SCHEMA_VERSION}_{group}.svg"
+ result = subprocess.run(
+ [
+ "npx", "-y", "@mermaid-js/mermaid-cli",
+ "-i", str(mmd_path),
+ "-o", str(svg_path),
+ "-b", "transparent",
+ ],
+ capture_output=True,
+ text=True,
+ )
+ if result.returncode != 0:
+ print(f"FAILED rendering group '{group}':\n{result.stderr}", file=sys.stderr)
+ sys.exit(1)
+ print(f"Generated {svg_path} ({len(tables)} tables)")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/test_erd_build.py b/scripts/test_erd_build.py
new file mode 100644
index 00000000..37f35132
--- /dev/null
+++ b/scripts/test_erd_build.py
@@ -0,0 +1,52 @@
+import unittest
+from pathlib import Path
+from erd_schema import parse_schema
+from erd_build import build_subdiagram, extract_header
+
+SCHEMA_PATH = Path(__file__).parent.parent / "docs/documentation/reference/db-schema/schema.mermaid"
+
+
+class TestExtractHeader(unittest.TestCase):
+ def test_extract_header(self):
+ text = SCHEMA_PATH.read_text()
+ init_line, classdefs = extract_header(text)
+ self.assertTrue(init_line.startswith("%%{init:"))
+ self.assertEqual(len(classdefs), 6)
+ self.assertTrue(all(l.strip().startswith("classDef") for l in classdefs))
+
+
+class TestBuildSubdiagram(unittest.TestCase):
+ def test_identity_subdiagram_contains_only_identity_tables(self):
+ text = SCHEMA_PATH.read_text()
+ entities, rels, classes = parse_schema(text)
+ init_line, classdefs = extract_header(text)
+ identity_tables = sorted(n for n in entities if n.startswith("ACT_ID_"))
+
+ mmd = build_subdiagram(identity_tables, entities, rels, classes, init_line, classdefs)
+
+ self.assertTrue(mmd.startswith("%%{init:"))
+ self.assertIn("erDiagram", mmd)
+ for t in identity_tables:
+ self.assertIn(f"{t} {{", mmd)
+ self.assertNotIn("ACT_RU_EXECUTION", mmd)
+ # relationship internal to identity group must be present
+ self.assertIn('ACT_ID_MEMBERSHIP }o--|| ACT_ID_GROUP : "GROUP_ID_"', mmd)
+ # relationship crossing group boundary must be absent
+ self.assertNotIn("ACT_RE_PROCDEF", mmd)
+
+ def test_no_cross_group_relationship_leaks(self):
+ text = SCHEMA_PATH.read_text()
+ entities, rels, classes = parse_schema(text)
+ init_line, classdefs = extract_header(text)
+ dmn_tables = ["ACT_RE_DECISION_DEF", "ACT_RE_DECISION_REQ_DEF"]
+
+ mmd = build_subdiagram(dmn_tables, entities, rels, classes, init_line, classdefs)
+ # DEC_REQ_ID_ relationship is internal to DMN tables, must be present
+ self.assertIn("ACT_RE_DECISION_DEF", mmd)
+ self.assertIn("ACT_RE_DECISION_REQ_DEF", mmd)
+ # no other tables leak in
+ self.assertNotIn("ACT_HI_", mmd)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/scripts/test_erd_schema.py b/scripts/test_erd_schema.py
new file mode 100644
index 00000000..47dba0ac
--- /dev/null
+++ b/scripts/test_erd_schema.py
@@ -0,0 +1,66 @@
+import unittest
+from pathlib import Path
+from erd_schema import parse_schema, resolve_groups
+
+SCHEMA_PATH = Path(__file__).parent.parent / "docs/documentation/reference/db-schema/schema.mermaid"
+
+
+class TestParseSchema(unittest.TestCase):
+ def test_parses_all_entities(self):
+ text = SCHEMA_PATH.read_text()
+ entities, rels, classes = parse_schema(text)
+ self.assertEqual(len(entities), 49)
+ self.assertIn("ACT_ID_GROUP", entities)
+ self.assertIn("varchar NAME_", entities["ACT_ID_GROUP"])
+
+ def test_parses_relationships(self):
+ text = SCHEMA_PATH.read_text()
+ entities, rels, classes = parse_schema(text)
+ self.assertEqual(len(rels), 50)
+ self.assertIn(
+ ("ACT_ID_MEMBERSHIP", "}o--||", "ACT_ID_GROUP", "GROUP_ID_"),
+ rels,
+ )
+
+ def test_parses_logical_relationships(self):
+ text = SCHEMA_PATH.read_text()
+ entities, rels, classes = parse_schema(text)
+ self.assertIn(
+ ("ACT_RE_PROCDEF", "}o..||", "ACT_RE_DEPLOYMENT", "DEPLOYMENT_ID_"),
+ rels,
+ )
+
+ def test_parses_classes(self):
+ text = SCHEMA_PATH.read_text()
+ entities, rels, classes = parse_schema(text)
+ self.assertEqual(classes["ACT_ID_GROUP"], "id")
+ self.assertEqual(classes["ACT_RU_EXECUTION"], "ru")
+
+
+class TestResolveGroups(unittest.TestCase):
+ def test_every_table_assigned_exactly_once(self):
+ text = SCHEMA_PATH.read_text()
+ entities, _, _ = parse_schema(text)
+ groups = resolve_groups(entities)
+ grouped = [t for tables in groups.values() for t in tables]
+ self.assertEqual(len(grouped), len(set(grouped)), "table in multiple groups")
+ self.assertEqual(set(grouped), set(entities.keys()))
+
+ def test_group_sizes(self):
+ text = SCHEMA_PATH.read_text()
+ entities, _, _ = parse_schema(text)
+ groups = resolve_groups(entities)
+ self.assertEqual(len(groups["bpmn"]), 20)
+ self.assertEqual(len(groups["dmn"]), 2)
+ self.assertEqual(len(groups["cmmn"]), 3)
+ self.assertEqual(len(groups["history"]), 18)
+ self.assertEqual(len(groups["identity"]), 6)
+
+ def test_raises_on_unassigned_table(self):
+ entities = {"ACT_XX_UNKNOWN": "", "ACT_ID_GROUP": ""}
+ with self.assertRaises(ValueError):
+ resolve_groups(entities)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/static/img/documentation/user-guide/process-engine/database/erd_725_bpmn.svg b/static/img/documentation/user-guide/process-engine/database/erd_725_bpmn.svg
new file mode 100644
index 00000000..18a5bb82
--- /dev/null
+++ b/static/img/documentation/user-guide/process-engine/database/erd_725_bpmn.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/img/documentation/user-guide/process-engine/database/erd_725_cmmn.svg b/static/img/documentation/user-guide/process-engine/database/erd_725_cmmn.svg
new file mode 100644
index 00000000..73432146
--- /dev/null
+++ b/static/img/documentation/user-guide/process-engine/database/erd_725_cmmn.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/img/documentation/user-guide/process-engine/database/erd_725_dmn.svg b/static/img/documentation/user-guide/process-engine/database/erd_725_dmn.svg
new file mode 100644
index 00000000..2dc81923
--- /dev/null
+++ b/static/img/documentation/user-guide/process-engine/database/erd_725_dmn.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/img/documentation/user-guide/process-engine/database/erd_725_history.svg b/static/img/documentation/user-guide/process-engine/database/erd_725_history.svg
new file mode 100644
index 00000000..a818aa5f
--- /dev/null
+++ b/static/img/documentation/user-guide/process-engine/database/erd_725_history.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/static/img/documentation/user-guide/process-engine/database/erd_725_identity.svg b/static/img/documentation/user-guide/process-engine/database/erd_725_identity.svg
new file mode 100644
index 00000000..f75feb41
--- /dev/null
+++ b/static/img/documentation/user-guide/process-engine/database/erd_725_identity.svg
@@ -0,0 +1 @@
+
\ No newline at end of file