Implement governed hybrid campaign delivery
This commit is contained in:
@@ -85,6 +85,7 @@ class JobSendStatus(StrEnum):
|
||||
SENDING = "sending"
|
||||
SMTP_ACCEPTED = "smtp_accepted"
|
||||
POSTBOX_ACCEPTED = "postbox_accepted"
|
||||
PRINT_ACCEPTED = "print_accepted"
|
||||
DELIVERED = "delivered"
|
||||
PARTIALLY_ACCEPTED = "partially_accepted"
|
||||
SENT = "sent" # legacy value retained for existing databases/reports
|
||||
@@ -107,6 +108,15 @@ class JobPostboxStatus(StrEnum):
|
||||
SKIPPED = "skipped"
|
||||
|
||||
|
||||
class JobPrintStatus(StrEnum):
|
||||
NOT_REQUESTED = "not_requested"
|
||||
READY = "ready"
|
||||
ACCEPTING = "accepting"
|
||||
ACCEPTED = "accepted"
|
||||
FAILED = "failed"
|
||||
SKIPPED = "skipped"
|
||||
|
||||
|
||||
class JobImapStatus(StrEnum):
|
||||
NOT_REQUESTED = "not_requested"
|
||||
PENDING = "pending"
|
||||
@@ -295,6 +305,12 @@ class CampaignJob(Base, TimestampMixin):
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
print_status: Mapped[str] = mapped_column(
|
||||
String(50),
|
||||
default=JobPrintStatus.NOT_REQUESTED.value,
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
imap_status: Mapped[str] = mapped_column(String(50), default=JobImapStatus.NOT_REQUESTED.value, nullable=False, index=True)
|
||||
|
||||
attempt_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
||||
@@ -303,6 +319,11 @@ class CampaignJob(Base, TimestampMixin):
|
||||
default=0,
|
||||
nullable=False,
|
||||
)
|
||||
print_attempt_count: Mapped[int] = mapped_column(
|
||||
Integer,
|
||||
default=0,
|
||||
nullable=False,
|
||||
)
|
||||
last_error: Mapped[str | None] = mapped_column(Text)
|
||||
queued_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
claimed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
@@ -314,11 +335,20 @@ class CampaignJob(Base, TimestampMixin):
|
||||
sent_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
|
||||
resolved_recipients: Mapped[dict[str, Any] | None] = mapped_column(JSON, nullable=True)
|
||||
delivery_provenance: Mapped[dict[str, Any]] = mapped_column(
|
||||
JSON,
|
||||
default=dict,
|
||||
nullable=False,
|
||||
)
|
||||
resolved_postbox_targets: Mapped[list[dict[str, Any]]] = mapped_column(
|
||||
JSON,
|
||||
default=list,
|
||||
nullable=False,
|
||||
)
|
||||
resolved_print_output: Mapped[dict[str, Any] | None] = mapped_column(
|
||||
JSON,
|
||||
nullable=True,
|
||||
)
|
||||
resolved_attachments: Mapped[list[dict[str, Any]]] = mapped_column(JSON, default=list)
|
||||
issues_snapshot: Mapped[list[dict[str, Any]]] = mapped_column(JSON, default=list)
|
||||
|
||||
@@ -604,6 +634,39 @@ class PostboxDeliveryAttempt(Base, TimestampMixin):
|
||||
)
|
||||
|
||||
|
||||
class PrintOutputAttempt(Base, TimestampMixin):
|
||||
__tablename__ = "campaign_print_output_attempts"
|
||||
__table_args__ = (
|
||||
UniqueConstraint(
|
||||
"job_id",
|
||||
"attempt_number",
|
||||
name="uq_campaign_print_attempt_job_number",
|
||||
),
|
||||
UniqueConstraint(
|
||||
"tenant_id",
|
||||
"idempotency_key",
|
||||
name="uq_campaign_print_attempt_idempotency",
|
||||
),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
|
||||
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
|
||||
job_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("campaign_jobs.id", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
attempt_number: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False)
|
||||
status: Mapped[str] = mapped_column(String(50), nullable=False, index=True)
|
||||
render_id: Mapped[str | None] = mapped_column(String(36), index=True)
|
||||
artifact_sha256: Mapped[str | None] = mapped_column(String(64), index=True)
|
||||
evidence: Mapped[dict[str, Any]] = mapped_column(JSON, default=dict, nullable=False)
|
||||
error_message: Mapped[str | None] = mapped_column(Text)
|
||||
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
|
||||
|
||||
|
||||
|
||||
__all__ = [
|
||||
@@ -622,9 +685,11 @@ __all__ = [
|
||||
"JobBuildStatus",
|
||||
"JobImapStatus",
|
||||
"JobPostboxStatus",
|
||||
"JobPrintStatus",
|
||||
"JobQueueStatus",
|
||||
"JobSendStatus",
|
||||
"JobValidationStatus",
|
||||
"SendAttempt",
|
||||
"PostboxDeliveryAttempt",
|
||||
"PrintOutputAttempt",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user