feat: extract headless workflow engine
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Workflow database migrations."""
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
"""v0.1.14 module Workflow standards and contribution provenance
|
||||
|
||||
Revision ID: 0b4e7c9a2d6f
|
||||
Revises: f1b7d3e5a9c2
|
||||
Create Date: 2026-07-31 00:00:00.000000
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = "0b4e7c9a2d6f"
|
||||
down_revision = "f1b7d3e5a9c2"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
with op.batch_alter_table("workflow_definitions") as batch:
|
||||
batch.add_column(
|
||||
sa.Column("standard_origin_module_id", sa.String(120), nullable=True)
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column("standard_definition_key", sa.String(120), nullable=True)
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column(
|
||||
"standard_origin_module_version",
|
||||
sa.String(40),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column(
|
||||
"standard_contribution_schema_version",
|
||||
sa.String(40),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column("standard_contribution_hash", sa.String(64), nullable=True)
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column(
|
||||
"standard_reconciled_at",
|
||||
sa.DateTime(timezone=True),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch.create_index(
|
||||
"ix_workflow_definitions_standard_origin_module_id",
|
||||
["standard_origin_module_id"],
|
||||
)
|
||||
batch.create_index(
|
||||
"ix_workflow_definitions_standard_definition_key",
|
||||
["standard_definition_key"],
|
||||
)
|
||||
batch.create_index(
|
||||
"ix_workflow_definitions_standard_contribution_hash",
|
||||
["standard_contribution_hash"],
|
||||
)
|
||||
batch.create_index(
|
||||
"uq_workflow_standard_origin_scope",
|
||||
[
|
||||
"scope_key",
|
||||
"standard_origin_module_id",
|
||||
"standard_definition_key",
|
||||
],
|
||||
unique=True,
|
||||
)
|
||||
|
||||
with op.batch_alter_table("workflow_definition_revisions") as batch:
|
||||
batch.add_column(
|
||||
sa.Column(
|
||||
"contribution_origin_module_version",
|
||||
sa.String(40),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column(
|
||||
"contribution_schema_version",
|
||||
sa.String(40),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column("contribution_hash", sa.String(64), nullable=True)
|
||||
)
|
||||
batch.add_column(
|
||||
sa.Column("contribution_metadata", sa.JSON(), nullable=True)
|
||||
)
|
||||
batch.create_index(
|
||||
"ix_workflow_definition_revisions_contribution_hash",
|
||||
["contribution_hash"],
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
with op.batch_alter_table("workflow_definition_revisions") as batch:
|
||||
batch.drop_index(
|
||||
"ix_workflow_definition_revisions_contribution_hash"
|
||||
)
|
||||
batch.drop_column("contribution_metadata")
|
||||
batch.drop_column("contribution_hash")
|
||||
batch.drop_column("contribution_schema_version")
|
||||
batch.drop_column("contribution_origin_module_version")
|
||||
|
||||
with op.batch_alter_table("workflow_definitions") as batch:
|
||||
batch.drop_index("uq_workflow_standard_origin_scope")
|
||||
batch.drop_index(
|
||||
"ix_workflow_definitions_standard_contribution_hash"
|
||||
)
|
||||
batch.drop_index("ix_workflow_definitions_standard_definition_key")
|
||||
batch.drop_index(
|
||||
"ix_workflow_definitions_standard_origin_module_id"
|
||||
)
|
||||
batch.drop_column("standard_reconciled_at")
|
||||
batch.drop_column("standard_contribution_hash")
|
||||
batch.drop_column("standard_contribution_schema_version")
|
||||
batch.drop_column("standard_origin_module_version")
|
||||
batch.drop_column("standard_definition_key")
|
||||
batch.drop_column("standard_origin_module_id")
|
||||
@@ -0,0 +1 @@
|
||||
"""Workflow Alembic revisions."""
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
"""v0.1.14 Workflow definitions
|
||||
|
||||
Revision ID: a7c4e2f9b1d3
|
||||
Revises: None
|
||||
Create Date: 2026-07-28 00:00:00.000000
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = "a7c4e2f9b1d3"
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
"workflow_definitions",
|
||||
sa.Column("id", sa.String(length=36), nullable=False),
|
||||
sa.Column("tenant_id", sa.String(length=36), nullable=False),
|
||||
sa.Column("definition_key", sa.String(length=120), nullable=False),
|
||||
sa.Column("name", sa.String(length=300), nullable=False),
|
||||
sa.Column("description", sa.Text(), nullable=True),
|
||||
sa.Column("status", sa.String(length=32), nullable=False),
|
||||
sa.Column("current_revision", sa.Integer(), nullable=False),
|
||||
sa.Column("active_revision", sa.Integer(), nullable=True),
|
||||
sa.Column("metadata", sa.JSON(), nullable=False),
|
||||
sa.Column("created_by", sa.String(length=255), nullable=True),
|
||||
sa.Column("updated_by", sa.String(length=255), nullable=True),
|
||||
sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.PrimaryKeyConstraint("id", name=op.f("pk_workflow_definitions")),
|
||||
sa.UniqueConstraint(
|
||||
"tenant_id",
|
||||
"definition_key",
|
||||
name="uq_workflow_definition_key",
|
||||
),
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definitions_created_by"),
|
||||
"workflow_definitions",
|
||||
["created_by"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definitions_deleted_at"),
|
||||
"workflow_definitions",
|
||||
["deleted_at"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definitions_status"),
|
||||
"workflow_definitions",
|
||||
["status"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definitions_tenant_id"),
|
||||
"workflow_definitions",
|
||||
["tenant_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definitions_updated_by"),
|
||||
"workflow_definitions",
|
||||
["updated_by"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_workflow_definitions_tenant_status",
|
||||
"workflow_definitions",
|
||||
["tenant_id", "status"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_workflow_definitions_tenant_updated",
|
||||
"workflow_definitions",
|
||||
["tenant_id", "updated_at"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
op.create_table(
|
||||
"workflow_definition_revisions",
|
||||
sa.Column("id", sa.String(length=36), nullable=False),
|
||||
sa.Column("tenant_id", sa.String(length=36), nullable=False),
|
||||
sa.Column("definition_id", sa.String(length=36), nullable=False),
|
||||
sa.Column("revision", sa.Integer(), nullable=False),
|
||||
sa.Column("schema_version", sa.Integer(), nullable=False),
|
||||
sa.Column("graph", sa.JSON(), nullable=False),
|
||||
sa.Column("content_hash", sa.String(length=64), nullable=False),
|
||||
sa.Column("library_id", sa.String(length=100), nullable=False),
|
||||
sa.Column("library_version", sa.String(length=40), nullable=False),
|
||||
sa.Column("created_by", sa.String(length=255), nullable=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["definition_id"],
|
||||
["workflow_definitions.id"],
|
||||
name=op.f(
|
||||
"fk_workflow_definition_revisions_definition_id_workflow_definitions"
|
||||
),
|
||||
ondelete="CASCADE",
|
||||
),
|
||||
sa.PrimaryKeyConstraint(
|
||||
"id",
|
||||
name=op.f("pk_workflow_definition_revisions"),
|
||||
),
|
||||
sa.UniqueConstraint(
|
||||
"definition_id",
|
||||
"revision",
|
||||
name="uq_workflow_definition_revision",
|
||||
),
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definition_revisions_created_by"),
|
||||
"workflow_definition_revisions",
|
||||
["created_by"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definition_revisions_definition_id"),
|
||||
"workflow_definition_revisions",
|
||||
["definition_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definition_revisions_tenant_id"),
|
||||
"workflow_definition_revisions",
|
||||
["tenant_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_workflow_definition_revisions_content_hash",
|
||||
"workflow_definition_revisions",
|
||||
["tenant_id", "content_hash"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_workflow_definition_revisions_tenant_definition",
|
||||
"workflow_definition_revisions",
|
||||
["tenant_id", "definition_id"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(
|
||||
"ix_workflow_definition_revisions_tenant_definition",
|
||||
table_name="workflow_definition_revisions",
|
||||
)
|
||||
op.drop_index(
|
||||
"ix_workflow_definition_revisions_content_hash",
|
||||
table_name="workflow_definition_revisions",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definition_revisions_tenant_id"),
|
||||
table_name="workflow_definition_revisions",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definition_revisions_definition_id"),
|
||||
table_name="workflow_definition_revisions",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definition_revisions_created_by"),
|
||||
table_name="workflow_definition_revisions",
|
||||
)
|
||||
op.drop_table("workflow_definition_revisions")
|
||||
|
||||
op.drop_index(
|
||||
"ix_workflow_definitions_tenant_updated",
|
||||
table_name="workflow_definitions",
|
||||
)
|
||||
op.drop_index(
|
||||
"ix_workflow_definitions_tenant_status",
|
||||
table_name="workflow_definitions",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definitions_updated_by"),
|
||||
table_name="workflow_definitions",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definitions_tenant_id"),
|
||||
table_name="workflow_definitions",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definitions_status"),
|
||||
table_name="workflow_definitions",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definitions_deleted_at"),
|
||||
table_name="workflow_definitions",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definitions_created_by"),
|
||||
table_name="workflow_definitions",
|
||||
)
|
||||
op.drop_table("workflow_definitions")
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
"""v0.1.14 governed Workflow definitions
|
||||
|
||||
Revision ID: c6d8f1a3e5b7
|
||||
Revises: a7c4e2f9b1d3
|
||||
Create Date: 2026-07-28 00:00:00.000000
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = "c6d8f1a3e5b7"
|
||||
down_revision = "a7c4e2f9b1d3"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
with op.batch_alter_table("workflow_definitions") as batch_op:
|
||||
batch_op.drop_constraint(
|
||||
"uq_workflow_definition_key",
|
||||
type_="unique",
|
||||
)
|
||||
batch_op.alter_column(
|
||||
"tenant_id",
|
||||
existing_type=sa.String(length=36),
|
||||
nullable=True,
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"scope_type",
|
||||
sa.String(length=20),
|
||||
nullable=False,
|
||||
server_default="tenant",
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column("scope_id", sa.String(length=36), nullable=True)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"scope_key",
|
||||
sa.String(length=80),
|
||||
nullable=False,
|
||||
server_default="tenant:legacy",
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"definition_kind",
|
||||
sa.String(length=20),
|
||||
nullable=False,
|
||||
server_default="flow",
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"inherit_to_lower_scopes",
|
||||
sa.Boolean(),
|
||||
nullable=False,
|
||||
server_default=sa.false(),
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"allow_start",
|
||||
sa.Boolean(),
|
||||
nullable=False,
|
||||
server_default=sa.true(),
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"allow_reuse",
|
||||
sa.Boolean(),
|
||||
nullable=False,
|
||||
server_default=sa.false(),
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"allow_automation",
|
||||
sa.Boolean(),
|
||||
nullable=False,
|
||||
server_default=sa.false(),
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"derived_from_definition_id",
|
||||
sa.String(length=36),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column("derived_from_revision", sa.Integer(), nullable=True)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"derived_from_hash",
|
||||
sa.String(length=64),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"derivation_provenance",
|
||||
sa.JSON(),
|
||||
nullable=False,
|
||||
server_default=sa.text("'{}'"),
|
||||
)
|
||||
)
|
||||
op.execute(
|
||||
sa.text(
|
||||
"UPDATE workflow_definitions "
|
||||
"SET scope_id = tenant_id, "
|
||||
"scope_key = 'tenant:' || tenant_id "
|
||||
"WHERE tenant_id IS NOT NULL"
|
||||
)
|
||||
)
|
||||
with op.batch_alter_table("workflow_definitions") as batch_op:
|
||||
batch_op.create_unique_constraint(
|
||||
"uq_workflow_definition_key",
|
||||
["scope_key", "definition_key"],
|
||||
)
|
||||
for column in (
|
||||
"scope_type",
|
||||
"scope_id",
|
||||
"scope_key",
|
||||
"definition_kind",
|
||||
"derived_from_definition_id",
|
||||
):
|
||||
op.create_index(
|
||||
op.f(f"ix_workflow_definitions_{column}"),
|
||||
"workflow_definitions",
|
||||
[column],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
with op.batch_alter_table(
|
||||
"workflow_definition_revisions"
|
||||
) as batch_op:
|
||||
batch_op.alter_column(
|
||||
"tenant_id",
|
||||
existing_type=sa.String(length=36),
|
||||
nullable=True,
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute(
|
||||
sa.text(
|
||||
"UPDATE workflow_definition_revisions "
|
||||
"SET tenant_id = COALESCE(tenant_id, 'system')"
|
||||
)
|
||||
)
|
||||
with op.batch_alter_table(
|
||||
"workflow_definition_revisions"
|
||||
) as batch_op:
|
||||
batch_op.alter_column(
|
||||
"tenant_id",
|
||||
existing_type=sa.String(length=36),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
for column in (
|
||||
"derived_from_definition_id",
|
||||
"definition_kind",
|
||||
"scope_key",
|
||||
"scope_id",
|
||||
"scope_type",
|
||||
):
|
||||
op.drop_index(
|
||||
op.f(f"ix_workflow_definitions_{column}"),
|
||||
table_name="workflow_definitions",
|
||||
)
|
||||
op.execute(
|
||||
sa.text(
|
||||
"UPDATE workflow_definitions "
|
||||
"SET tenant_id = COALESCE(tenant_id, 'system')"
|
||||
)
|
||||
)
|
||||
with op.batch_alter_table("workflow_definitions") as batch_op:
|
||||
batch_op.drop_constraint(
|
||||
"uq_workflow_definition_key",
|
||||
type_="unique",
|
||||
)
|
||||
batch_op.create_unique_constraint(
|
||||
"uq_workflow_definition_key",
|
||||
["tenant_id", "definition_key"],
|
||||
)
|
||||
batch_op.drop_column("derivation_provenance")
|
||||
batch_op.drop_column("derived_from_hash")
|
||||
batch_op.drop_column("derived_from_revision")
|
||||
batch_op.drop_column("derived_from_definition_id")
|
||||
batch_op.drop_column("allow_automation")
|
||||
batch_op.drop_column("allow_reuse")
|
||||
batch_op.drop_column("allow_start")
|
||||
batch_op.drop_column("inherit_to_lower_scopes")
|
||||
batch_op.drop_column("definition_kind")
|
||||
batch_op.drop_column("scope_key")
|
||||
batch_op.drop_column("scope_id")
|
||||
batch_op.drop_column("scope_type")
|
||||
batch_op.alter_column(
|
||||
"tenant_id",
|
||||
existing_type=sa.String(length=36),
|
||||
nullable=False,
|
||||
)
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
"""v0.1.14 Workflow instances and resumable handoffs
|
||||
|
||||
Revision ID: d8f2a5c7e1b4
|
||||
Revises: c6d8f1a3e5b7
|
||||
Create Date: 2026-07-30 00:00:00.000000
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = "d8f2a5c7e1b4"
|
||||
down_revision = "c6d8f1a3e5b7"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
"workflow_instances",
|
||||
sa.Column("id", sa.String(length=36), nullable=False),
|
||||
sa.Column("tenant_id", sa.String(length=36), nullable=False),
|
||||
sa.Column("definition_id", sa.String(length=36), nullable=False),
|
||||
sa.Column(
|
||||
"definition_revision_id",
|
||||
sa.String(length=36),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column("status", sa.String(length=30), nullable=False),
|
||||
sa.Column("idempotency_key", sa.String(length=255), nullable=False),
|
||||
sa.Column("correlation_id", sa.String(length=128), nullable=True),
|
||||
sa.Column("current_step_id", sa.String(length=36), nullable=True),
|
||||
sa.Column("input", sa.JSON(), nullable=False),
|
||||
sa.Column("context", sa.JSON(), nullable=False),
|
||||
sa.Column("output", sa.JSON(), nullable=False),
|
||||
sa.Column("authorization", sa.JSON(), nullable=False),
|
||||
sa.Column("started_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column(
|
||||
"cancellation_requested_at",
|
||||
sa.DateTime(timezone=True),
|
||||
nullable=True,
|
||||
),
|
||||
sa.Column("error", sa.Text(), nullable=True),
|
||||
sa.Column("created_by", sa.String(length=255), nullable=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["definition_id"],
|
||||
["workflow_definitions.id"],
|
||||
ondelete="CASCADE",
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["definition_revision_id"],
|
||||
["workflow_definition_revisions.id"],
|
||||
ondelete="RESTRICT",
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint(
|
||||
"tenant_id",
|
||||
"definition_id",
|
||||
"idempotency_key",
|
||||
name="uq_workflow_instance_idempotency",
|
||||
),
|
||||
)
|
||||
for column in (
|
||||
"tenant_id",
|
||||
"definition_id",
|
||||
"definition_revision_id",
|
||||
"status",
|
||||
"idempotency_key",
|
||||
"correlation_id",
|
||||
"current_step_id",
|
||||
"created_by",
|
||||
):
|
||||
op.create_index(
|
||||
op.f(f"ix_workflow_instances_{column}"),
|
||||
"workflow_instances",
|
||||
[column],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_workflow_instances_tenant_status",
|
||||
"workflow_instances",
|
||||
["tenant_id", "status"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_workflow_instances_reconcile",
|
||||
"workflow_instances",
|
||||
["status", "updated_at"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
op.create_table(
|
||||
"workflow_instance_steps",
|
||||
sa.Column("id", sa.String(length=36), nullable=False),
|
||||
sa.Column("tenant_id", sa.String(length=36), nullable=False),
|
||||
sa.Column("instance_id", sa.String(length=36), nullable=False),
|
||||
sa.Column("sequence", sa.Integer(), nullable=False),
|
||||
sa.Column("node_id", sa.String(length=120), nullable=False),
|
||||
sa.Column("node_type", sa.String(length=120), nullable=False),
|
||||
sa.Column("status", sa.String(length=30), nullable=False),
|
||||
sa.Column("attempt", sa.Integer(), nullable=False),
|
||||
sa.Column("idempotency_key", sa.String(length=255), nullable=False),
|
||||
sa.Column("input", sa.JSON(), nullable=False),
|
||||
sa.Column("output", sa.JSON(), nullable=False),
|
||||
sa.Column("handoff", sa.JSON(), nullable=False),
|
||||
sa.Column("external_ref", sa.String(length=500), nullable=True),
|
||||
sa.Column("started_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("error", sa.Text(), nullable=True),
|
||||
sa.Column("completed_by", sa.String(length=255), nullable=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["instance_id"],
|
||||
["workflow_instances.id"],
|
||||
ondelete="CASCADE",
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint(
|
||||
"instance_id",
|
||||
"sequence",
|
||||
name="uq_workflow_instance_step_sequence",
|
||||
),
|
||||
)
|
||||
for column in (
|
||||
"tenant_id",
|
||||
"instance_id",
|
||||
"node_id",
|
||||
"node_type",
|
||||
"status",
|
||||
"external_ref",
|
||||
):
|
||||
op.create_index(
|
||||
op.f(f"ix_workflow_instance_steps_{column}"),
|
||||
"workflow_instance_steps",
|
||||
[column],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_workflow_instance_steps_tenant_status",
|
||||
"workflow_instance_steps",
|
||||
["tenant_id", "status"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
op.create_table(
|
||||
"workflow_instance_events",
|
||||
sa.Column("id", sa.String(length=36), nullable=False),
|
||||
sa.Column("tenant_id", sa.String(length=36), nullable=False),
|
||||
sa.Column("instance_id", sa.String(length=36), nullable=False),
|
||||
sa.Column("step_id", sa.String(length=36), nullable=True),
|
||||
sa.Column("sequence", sa.Integer(), nullable=False),
|
||||
sa.Column("kind", sa.String(length=120), nullable=False),
|
||||
sa.Column("actor_id", sa.String(length=255), nullable=True),
|
||||
sa.Column("payload", sa.JSON(), nullable=False),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["instance_id"],
|
||||
["workflow_instances.id"],
|
||||
ondelete="CASCADE",
|
||||
),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
sa.UniqueConstraint(
|
||||
"instance_id",
|
||||
"sequence",
|
||||
name="uq_workflow_instance_event_sequence",
|
||||
),
|
||||
)
|
||||
for column in (
|
||||
"tenant_id",
|
||||
"instance_id",
|
||||
"step_id",
|
||||
"kind",
|
||||
"actor_id",
|
||||
):
|
||||
op.create_index(
|
||||
op.f(f"ix_workflow_instance_events_{column}"),
|
||||
"workflow_instance_events",
|
||||
[column],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_workflow_instance_events_tenant_created",
|
||||
"workflow_instance_events",
|
||||
["tenant_id", "created_at"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(
|
||||
"ix_workflow_instance_events_tenant_created",
|
||||
table_name="workflow_instance_events",
|
||||
)
|
||||
op.drop_table("workflow_instance_events")
|
||||
op.drop_index(
|
||||
"ix_workflow_instance_steps_tenant_status",
|
||||
table_name="workflow_instance_steps",
|
||||
)
|
||||
op.drop_table("workflow_instance_steps")
|
||||
op.drop_index(
|
||||
"ix_workflow_instances_reconcile",
|
||||
table_name="workflow_instances",
|
||||
)
|
||||
op.drop_index(
|
||||
"ix_workflow_instances_tenant_status",
|
||||
table_name="workflow_instances",
|
||||
)
|
||||
op.drop_table("workflow_instances")
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
"""v0.1.14 normalized BPMN revision artifacts
|
||||
|
||||
Revision ID: e9a4c6b8d2f1
|
||||
Revises: d8f2a5c7e1b4
|
||||
Create Date: 2026-07-30 00:00:00.000000
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = "e9a4c6b8d2f1"
|
||||
down_revision = "d8f2a5c7e1b4"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
with op.batch_alter_table("workflow_definition_revisions") as batch_op:
|
||||
batch_op.add_column(sa.Column("bpmn_xml", sa.Text(), nullable=True))
|
||||
batch_op.add_column(
|
||||
sa.Column("bpmn_hash", sa.String(length=64), nullable=True)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"bpmn_adapter_id",
|
||||
sa.String(length=120),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"bpmn_adapter_version",
|
||||
sa.String(length=40),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"bpmn_runtime_kind",
|
||||
sa.String(length=20),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column("bpmn_executable", sa.Boolean(), nullable=True)
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_workflow_definition_revisions_bpmn_hash"),
|
||||
"workflow_definition_revisions",
|
||||
["bpmn_hash"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index(
|
||||
op.f("ix_workflow_definition_revisions_bpmn_hash"),
|
||||
table_name="workflow_definition_revisions",
|
||||
)
|
||||
with op.batch_alter_table("workflow_definition_revisions") as batch_op:
|
||||
batch_op.drop_column("bpmn_executable")
|
||||
batch_op.drop_column("bpmn_runtime_kind")
|
||||
batch_op.drop_column("bpmn_adapter_version")
|
||||
batch_op.drop_column("bpmn_adapter_id")
|
||||
batch_op.drop_column("bpmn_hash")
|
||||
batch_op.drop_column("bpmn_xml")
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
"""v0.1.14 workflow execution modes and focused Views
|
||||
|
||||
Revision ID: f1b7d3e5a9c2
|
||||
Revises: e9a4c6b8d2f1
|
||||
Create Date: 2026-07-30 00:00:00.000000
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = "f1b7d3e5a9c2"
|
||||
down_revision = "e9a4c6b8d2f1"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
with op.batch_alter_table("workflow_definition_revisions") as batch_op:
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"execution_mode",
|
||||
sa.String(length=20),
|
||||
nullable=False,
|
||||
server_default="hybrid",
|
||||
)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column("view_id", sa.String(length=36), nullable=True)
|
||||
)
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"view_revision_id",
|
||||
sa.String(length=36),
|
||||
nullable=True,
|
||||
)
|
||||
)
|
||||
with op.batch_alter_table("workflow_instances") as batch_op:
|
||||
batch_op.add_column(
|
||||
sa.Column(
|
||||
"start_origin",
|
||||
sa.String(length=30),
|
||||
nullable=False,
|
||||
server_default="user",
|
||||
)
|
||||
)
|
||||
batch_op.create_index(
|
||||
"ix_workflow_instances_start_origin",
|
||||
["start_origin"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
with op.batch_alter_table("workflow_instances") as batch_op:
|
||||
batch_op.drop_index("ix_workflow_instances_start_origin")
|
||||
batch_op.drop_column("start_origin")
|
||||
with op.batch_alter_table("workflow_definition_revisions") as batch_op:
|
||||
batch_op.drop_column("view_revision_id")
|
||||
batch_op.drop_column("view_id")
|
||||
batch_op.drop_column("execution_mode")
|
||||
Reference in New Issue
Block a user