diff --git a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts
index 83e7a40f9..b5666ee0f 100644
--- a/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts
+++ b/src-ui/src/app/components/common/edit-dialog/workflow-edit-dialog/workflow-edit-dialog.component.ts
@@ -120,6 +120,10 @@ export const WORKFLOW_TYPE_OPTIONS = [
id: WorkflowTriggerType.Scheduled,
name: $localize`Scheduled`,
},
+ {
+ id: WorkflowTriggerType.VersionAdded,
+ name: $localize`Version Added`,
+ },
]
export const WORKFLOW_ACTION_OPTIONS = [
diff --git a/src-ui/src/app/data/workflow-trigger.ts b/src-ui/src/app/data/workflow-trigger.ts
index 2bc89f188..b959457e3 100644
--- a/src-ui/src/app/data/workflow-trigger.ts
+++ b/src-ui/src/app/data/workflow-trigger.ts
@@ -12,6 +12,7 @@ export enum WorkflowTriggerType {
DocumentAdded = 2,
DocumentUpdated = 3,
Scheduled = 4,
+ VersionAdded = 5,
}
export enum ScheduleDateField {
diff --git a/src/documents/apps.py b/src/documents/apps.py
index c14f56ee4..e3ea991e3 100644
--- a/src/documents/apps.py
+++ b/src/documents/apps.py
@@ -15,6 +15,7 @@ class DocumentsConfig(AppConfig):
from documents.signals.handlers import add_to_index
from documents.signals.handlers import run_workflows_added
from documents.signals.handlers import run_workflows_updated
+ from documents.signals.handlers import run_workflows_version_added
from documents.signals.handlers import send_websocket_document_updated
from documents.signals.handlers import set_correspondent
from documents.signals.handlers import set_document_type
@@ -28,6 +29,7 @@ class DocumentsConfig(AppConfig):
document_consumption_finished.connect(set_storage_path)
document_consumption_finished.connect(add_to_index)
document_consumption_finished.connect(run_workflows_added)
+ document_consumption_finished.connect(run_workflows_version_added)
document_consumption_finished.connect(add_or_update_document_in_llm_index)
document_updated.connect(run_workflows_updated)
document_updated.connect(send_websocket_document_updated)
diff --git a/src/documents/matching.py b/src/documents/matching.py
index e023adae7..b1c5c7231 100644
--- a/src/documents/matching.py
+++ b/src/documents/matching.py
@@ -689,6 +689,7 @@ def document_matches_workflow(
trigger_type == WorkflowTrigger.WorkflowTriggerType.DOCUMENT_ADDED
or trigger_type == WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED
or trigger_type == WorkflowTrigger.WorkflowTriggerType.SCHEDULED
+ or trigger_type == WorkflowTrigger.WorkflowTriggerType.VERSION_ADDED
):
trigger_matched, reason = existing_document_matches_workflow(
document,
diff --git a/src/documents/migrations/0014_alter_workflowtrigger_type.py b/src/documents/migrations/0014_alter_workflowtrigger_type.py
new file mode 100644
index 000000000..6304cac54
--- /dev/null
+++ b/src/documents/migrations/0014_alter_workflowtrigger_type.py
@@ -0,0 +1,28 @@
+# Generated by Django 5.2.7 on 2026-03-02 00:00
+
+from django.db import migrations
+from django.db import models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("documents", "0013_document_root_document"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="workflowtrigger",
+ name="type",
+ field=models.PositiveSmallIntegerField(
+ choices=[
+ (1, "Consumption Started"),
+ (2, "Document Added"),
+ (3, "Document Updated"),
+ (4, "Scheduled"),
+ (5, "Version Added"),
+ ],
+ default=1,
+ verbose_name="Workflow Trigger Type",
+ ),
+ ),
+ ]
diff --git a/src/documents/models.py b/src/documents/models.py
index 6147ac001..ba97e2690 100644
--- a/src/documents/models.py
+++ b/src/documents/models.py
@@ -1174,6 +1174,7 @@ class WorkflowTrigger(models.Model):
DOCUMENT_ADDED = 2, _("Document Added")
DOCUMENT_UPDATED = 3, _("Document Updated")
SCHEDULED = 4, _("Scheduled")
+ VERSION_ADDED = 5, _("Version Added")
class DocumentSourceChoices(models.IntegerChoices):
CONSUME_FOLDER = DocumentSource.ConsumeFolder.value, _("Consume Folder")
diff --git a/src/documents/signals/handlers.py b/src/documents/signals/handlers.py
index 81dd3ddd9..7f5f9cd35 100644
--- a/src/documents/signals/handlers.py
+++ b/src/documents/signals/handlers.py
@@ -783,6 +783,25 @@ def run_workflows_added(
)
+def run_workflows_version_added(
+ sender,
+ document: Document,
+ logging_group: uuid.UUID | None = None,
+ original_file=None,
+ **kwargs,
+) -> None:
+ if document.root_document is None:
+ return
+
+ run_workflows(
+ trigger_type=WorkflowTrigger.WorkflowTriggerType.VERSION_ADDED,
+ document=document.root_document,
+ logging_group=logging_group,
+ overrides=None,
+ original_file=original_file,
+ )
+
+
def run_workflows_updated(
sender,
document: Document,
diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py
index 78d42437d..b3d2ead8c 100644
--- a/src/documents/tests/test_workflows.py
+++ b/src/documents/tests/test_workflows.py
@@ -1786,6 +1786,89 @@ class TestWorkflows(
).exists(),
)
+ def test_version_added_workflow_runs_on_root_document(self) -> None:
+ trigger = WorkflowTrigger.objects.create(
+ type=WorkflowTrigger.WorkflowTriggerType.VERSION_ADDED,
+ )
+ action = WorkflowAction.objects.create(
+ assign_title="Updated by version",
+ assign_owner=self.user2,
+ )
+ workflow = Workflow.objects.create(
+ name="Version workflow",
+ order=0,
+ )
+ workflow.triggers.add(trigger)
+ workflow.actions.add(action)
+
+ root_doc = Document.objects.create(
+ title="root",
+ correspondent=self.c,
+ original_filename="root.pdf",
+ )
+ version_doc = Document.objects.create(
+ title="version",
+ correspondent=self.c,
+ original_filename="version.pdf",
+ root_document=root_doc,
+ )
+
+ document_consumption_finished.send(
+ sender=self.__class__,
+ document=version_doc,
+ )
+
+ root_doc.refresh_from_db()
+ version_doc.refresh_from_db()
+
+ self.assertEqual(root_doc.title, "Updated by version")
+ self.assertEqual(root_doc.owner, self.user2)
+ self.assertIsNone(version_doc.owner)
+ self.assertEqual(
+ WorkflowRun.objects.filter(
+ workflow=workflow,
+ type=WorkflowTrigger.WorkflowTriggerType.VERSION_ADDED,
+ document=root_doc,
+ ).count(),
+ 1,
+ )
+
+ def test_version_added_workflow_ignored_for_root_documents(self) -> None:
+ trigger = WorkflowTrigger.objects.create(
+ type=WorkflowTrigger.WorkflowTriggerType.VERSION_ADDED,
+ )
+ action = WorkflowAction.objects.create(
+ assign_title="Should not run",
+ )
+ workflow = Workflow.objects.create(
+ name="Version workflow",
+ order=0,
+ )
+ workflow.triggers.add(trigger)
+ workflow.actions.add(action)
+
+ root_doc = Document.objects.create(
+ title="root",
+ correspondent=self.c,
+ original_filename="root.pdf",
+ )
+
+ document_consumption_finished.send(
+ sender=self.__class__,
+ document=root_doc,
+ )
+
+ root_doc.refresh_from_db()
+
+ self.assertEqual(root_doc.title, "root")
+ self.assertFalse(
+ WorkflowRun.objects.filter(
+ workflow=workflow,
+ type=WorkflowTrigger.WorkflowTriggerType.VERSION_ADDED,
+ document=root_doc,
+ ).exists(),
+ )
+
def test_document_updated_workflow(self) -> None:
trigger = WorkflowTrigger.objects.create(
type=WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED,