intermittent commit

This commit is contained in:
2026-07-14 13:22:11 +02:00
parent 3444a4920f
commit 6163c8f733
24 changed files with 2367 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
from __future__ import annotations

View File

@@ -0,0 +1,110 @@
"""v0.1.8 notifications baseline
Revision ID: 5e6f7a8b9c0d
Revises: None
Create Date: 2026-07-13 00:00:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
revision = "5e6f7a8b9c0d"
down_revision = None
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table(
"notification_messages",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("source_module", sa.String(length=100), nullable=False),
sa.Column("source_resource_type", sa.String(length=100), nullable=False),
sa.Column("source_resource_id", sa.String(length=255), nullable=True),
sa.Column("event_kind", sa.String(length=100), nullable=False),
sa.Column("channel", sa.String(length=40), nullable=False),
sa.Column("recipient", sa.String(length=500), nullable=True),
sa.Column("recipient_type", sa.String(length=40), nullable=True),
sa.Column("recipient_id", sa.String(length=255), nullable=True),
sa.Column("recipient_label", sa.String(length=500), nullable=True),
sa.Column("subject", sa.String(length=500), nullable=True),
sa.Column("body_text", sa.Text(), nullable=True),
sa.Column("body_html", sa.Text(), nullable=True),
sa.Column("action_url", sa.String(length=1000), nullable=True),
sa.Column("priority", sa.Integer(), nullable=False),
sa.Column("status", sa.String(length=40), nullable=False),
sa.Column("not_before_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("queued_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("sent_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("failed_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("read_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("acknowledged_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("cancelled_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("attempt_count", sa.Integer(), nullable=False),
sa.Column("last_error", sa.Text(), nullable=True),
sa.Column("external_message_id", sa.String(length=255), nullable=True),
sa.Column("payload", sa.JSON(), nullable=False),
sa.Column("metadata", sa.JSON(), nullable=False),
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_notification_messages")),
)
op.create_index(op.f("ix_notification_messages_channel"), "notification_messages", ["channel"], unique=False)
op.create_index(op.f("ix_notification_messages_deleted_at"), "notification_messages", ["deleted_at"], unique=False)
op.create_index(op.f("ix_notification_messages_event_kind"), "notification_messages", ["event_kind"], unique=False)
op.create_index(op.f("ix_notification_messages_external_message_id"), "notification_messages", ["external_message_id"], unique=False)
op.create_index(op.f("ix_notification_messages_not_before_at"), "notification_messages", ["not_before_at"], unique=False)
op.create_index(op.f("ix_notification_messages_priority"), "notification_messages", ["priority"], unique=False)
op.create_index(op.f("ix_notification_messages_recipient"), "notification_messages", ["recipient"], unique=False)
op.create_index(op.f("ix_notification_messages_recipient_id"), "notification_messages", ["recipient_id"], unique=False)
op.create_index(op.f("ix_notification_messages_recipient_type"), "notification_messages", ["recipient_type"], unique=False)
op.create_index(op.f("ix_notification_messages_source_module"), "notification_messages", ["source_module"], unique=False)
op.create_index(op.f("ix_notification_messages_source_resource_id"), "notification_messages", ["source_resource_id"], unique=False)
op.create_index(op.f("ix_notification_messages_source_resource_type"), "notification_messages", ["source_resource_type"], unique=False)
op.create_index(op.f("ix_notification_messages_status"), "notification_messages", ["status"], unique=False)
op.create_index(op.f("ix_notification_messages_tenant_id"), "notification_messages", ["tenant_id"], unique=False)
op.create_index("ix_notification_messages_due", "notification_messages", ["tenant_id", "status", "not_before_at"], unique=False)
op.create_index("ix_notification_messages_source", "notification_messages", ["tenant_id", "source_module", "source_resource_type", "source_resource_id"], unique=False)
op.create_index("ix_notification_messages_tenant_recipient", "notification_messages", ["tenant_id", "recipient_type", "recipient_id"], unique=False)
op.create_index("ix_notification_messages_tenant_status", "notification_messages", ["tenant_id", "status"], unique=False)
op.create_table(
"notification_delivery_attempts",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("notification_id", sa.String(length=36), nullable=False),
sa.Column("attempt_no", sa.Integer(), nullable=False),
sa.Column("channel", sa.String(length=40), nullable=False),
sa.Column("provider", sa.String(length=100), nullable=True),
sa.Column("status", sa.String(length=40), nullable=False),
sa.Column("started_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("external_message_id", sa.String(length=255), nullable=True),
sa.Column("error", sa.Text(), nullable=True),
sa.Column("details", sa.JSON(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(
["notification_id"],
["notification_messages.id"],
name=op.f("fk_notification_delivery_attempts_notification_id_notification_messages"),
ondelete="CASCADE",
),
sa.PrimaryKeyConstraint("id", name=op.f("pk_notification_delivery_attempts")),
)
op.create_index(op.f("ix_notification_delivery_attempts_channel"), "notification_delivery_attempts", ["channel"], unique=False)
op.create_index(op.f("ix_notification_delivery_attempts_notification_id"), "notification_delivery_attempts", ["notification_id"], unique=False)
op.create_index(op.f("ix_notification_delivery_attempts_provider"), "notification_delivery_attempts", ["provider"], unique=False)
op.create_index(op.f("ix_notification_delivery_attempts_status"), "notification_delivery_attempts", ["status"], unique=False)
op.create_index(op.f("ix_notification_delivery_attempts_tenant_id"), "notification_delivery_attempts", ["tenant_id"], unique=False)
op.create_index("ix_notification_attempts_notification", "notification_delivery_attempts", ["notification_id", "attempt_no"], unique=False)
op.create_index("ix_notification_attempts_tenant_status", "notification_delivery_attempts", ["tenant_id", "status"], unique=False)
def downgrade() -> None:
op.drop_table("notification_delivery_attempts")
op.drop_table("notification_messages")

View File

@@ -0,0 +1,41 @@
"""notification preferences
Revision ID: 6f7a8b9c0d1e
Revises: 5e6f7a8b9c0d
Create Date: 2026-07-13 00:00:00.000000
"""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
revision = "6f7a8b9c0d1e"
down_revision = "5e6f7a8b9c0d"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.create_table(
"notification_preferences",
sa.Column("id", sa.String(length=36), nullable=False),
sa.Column("tenant_id", sa.String(length=36), nullable=False),
sa.Column("user_id", sa.String(length=36), nullable=False),
sa.Column("show_unread_badge", sa.Boolean(), nullable=False),
sa.Column("email_enabled", sa.Boolean(), nullable=False),
sa.Column("email_digest_enabled", sa.Boolean(), nullable=False),
sa.Column("muted_source_modules", sa.JSON(), nullable=False),
sa.Column("metadata", sa.JSON(), nullable=False),
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_notification_preferences")),
sa.UniqueConstraint("tenant_id", "user_id", name="uq_notification_preferences_tenant_user"),
)
op.create_index(op.f("ix_notification_preferences_tenant_id"), "notification_preferences", ["tenant_id"], unique=False)
op.create_index("ix_notification_preferences_tenant_user", "notification_preferences", ["tenant_id", "user_id"], unique=False)
op.create_index(op.f("ix_notification_preferences_user_id"), "notification_preferences", ["user_id"], unique=False)
def downgrade() -> None:
op.drop_table("notification_preferences")

View File

@@ -0,0 +1,2 @@
from __future__ import annotations