From 74e68e076cfa852b0fe685a568dace5cf0c2e8f8 Mon Sep 17 00:00:00 2001 From: "Reichenbach, Michael" <755327+Silthus@users.noreply.github.com> Date: Mon, 19 Oct 2026 09:43:46 +0000 Subject: [PATCH] feat(workflows): store shared sandbox tenant state Co-Authored-By: Claude Opus 5.5 --- .github/scripts/check-idor-model-coverage.py | 1 + .../0037_sandbox_sender_tenant_state.py | 32 +++++++++++++++++++ .../backend/migrations/max_migration.txt | 2 +- products/workflows/backend/models/__init__.py | 2 ++ .../models/sandbox_sender_tenant_state.py | 9 ++++++ 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 products/workflows/backend/migrations/0037_sandbox_sender_tenant_state.py create mode 100644 products/workflows/backend/models/sandbox_sender_tenant_state.py diff --git a/.github/scripts/check-idor-model-coverage.py b/.github/scripts/check-idor-model-coverage.py index ffe2c08f1681..aa7d0b87aa9c 100644 --- a/.github/scripts/check-idor-model-coverage.py +++ b/.github/scripts/check-idor-model-coverage.py @@ -324,6 +324,7 @@ def get_scoped_models() -> tuple[dict[str, set[str]], set[str], set[str], set[st "DevStackImageTarget", "DevStackImageAttempt", "License", + "SandboxSenderTenantState", # instance-global mirror of the shared sandbox SES tenant state # --- Deprecated --- "Prompt", "PromptSequence", diff --git a/products/workflows/backend/migrations/0037_sandbox_sender_tenant_state.py b/products/workflows/backend/migrations/0037_sandbox_sender_tenant_state.py new file mode 100644 index 000000000000..1ded7276c510 --- /dev/null +++ b/products/workflows/backend/migrations/0037_sandbox_sender_tenant_state.py @@ -0,0 +1,32 @@ +# Generated by Django 5.2.18 on 2026-10-12 15:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("workflows", "0036_teamworkflowsconfig_email_utm_defaults"), + ] + + operations = [ + migrations.CreateModel( + name="SandboxSenderTenantState", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("tenant_name", models.CharField(max_length=64, unique=True)), + ( + "sending_status", + models.CharField(blank=True, db_default="", default="", max_length=32), + ), + ("synced_at", models.DateTimeField(blank=True, null=True)), + ], + ), + ] diff --git a/products/workflows/backend/migrations/max_migration.txt b/products/workflows/backend/migrations/max_migration.txt index d122755b7922..67cf914e224f 100644 --- a/products/workflows/backend/migrations/max_migration.txt +++ b/products/workflows/backend/migrations/max_migration.txt @@ -1 +1 @@ -0036_teamworkflowsconfig_email_utm_defaults +0037_sandbox_sender_tenant_state diff --git a/products/workflows/backend/models/__init__.py b/products/workflows/backend/models/__init__.py index bbc6b3a22a6c..fdf755e421f6 100644 --- a/products/workflows/backend/models/__init__.py +++ b/products/workflows/backend/models/__init__.py @@ -4,6 +4,7 @@ from .hog_flow_optimization import HogFlowOptimization from .hog_flow_revision import HogFlowRevision from .hog_flow_schedule.hog_flow_schedule import HogFlowSchedule +from .sandbox_sender_tenant_state import SandboxSenderTenantState from .team_workflows_config import TeamWorkflowsConfig from .workflow_idea import WorkflowIdea from .workflow_proposal import WorkflowProposal @@ -15,6 +16,7 @@ "HogFlowRevision", "HogFlowSchedule", "HogFlowTemplate", + "SandboxSenderTenantState", "TeamWorkflowsConfig", "WorkflowIdea", "WorkflowProposal", diff --git a/products/workflows/backend/models/sandbox_sender_tenant_state.py b/products/workflows/backend/models/sandbox_sender_tenant_state.py new file mode 100644 index 000000000000..f6b9172850bc --- /dev/null +++ b/products/workflows/backend/models/sandbox_sender_tenant_state.py @@ -0,0 +1,9 @@ +from django.db import models + + +class SandboxSenderTenantState(models.Model): + """Instance-level mirror of the shared sandbox SES tenant; platform state, not tenant data, so no team_id.""" + + tenant_name = models.CharField(max_length=64, unique=True) + sending_status = models.CharField(max_length=32, blank=True, default="", db_default="") + synced_at = models.DateTimeField(null=True, blank=True)