import uuid from sqlalchemy import ForeignKey, Integer, String from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.orm import Mapped, mapped_column from app.core.db import Base from app.models.mixins import TimestampMixin, UUIDPrimaryKeyMixin class IdempotencyRecord(UUIDPrimaryKeyMixin, TimestampMixin, Base): __tablename__ = "idempotency_records" idempotency_key: Mapped[str] = mapped_column(String(128), unique=True, nullable=False) booking_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("bookings.id"), nullable=False ) # SHA-256 of the canonical request body. Replaying a key with a *different* body is # a client bug and must be rejected instead of silently answered with the old result. request_fingerprint: Mapped[str | None] = mapped_column(String(64), nullable=True) response_status: Mapped[int] = mapped_column(Integer, nullable=False) response_body: Mapped[dict] = mapped_column(JSONB, nullable=False)