"""Outbox delivery model for per-consumer delivery tracking.""" from __future__ import annotations import uuid from datetime import datetime from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, UniqueConstraint, func from sqlalchemy.dialects.postgresql import UUID as PGUUID from sqlalchemy.orm import Mapped, mapped_column from app.core.db import Base class OutboxDelivery(Base): """Tracks per-consumer delivery status for outbox events. Each row represents one consumer (event handler) processing one outbox event. An event is only fully 'published' when all mandatory deliveries succeed. """ __tablename__ = "outbox_deliveries" __table_args__ = ( UniqueConstraint("event_id", "consumer_name", name="uq_outbox_deliveries_event_consumer"), ) id: Mapped[uuid.UUID] = mapped_column( PGUUID(as_uuid=True), primary_key=True, server_default=func.gen_random_uuid(), ) event_id: Mapped[uuid.UUID] = mapped_column( PGUUID(as_uuid=True), ForeignKey("event_outbox.id", ondelete="CASCADE"), nullable=False, ) consumer_name: Mapped[str] = mapped_column(String(150), nullable=False) status: Mapped[str] = mapped_column( String(30), nullable=False, server_default="pending", ) attempt_count: Mapped[int] = mapped_column( Integer, nullable=False, server_default="0", ) next_attempt_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, ) last_error: Mapped[str | None] = mapped_column(Text, nullable=True) processed_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True, ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), )