2026-06-03 18:04:47 +02:00
|
|
|
"""Per-user inbox notifications, synced to clients via Zero."""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from datetime import UTC, datetime
|
|
|
|
|
|
|
|
|
|
from sqlalchemy import (
|
|
|
|
|
TIMESTAMP,
|
|
|
|
|
Boolean,
|
|
|
|
|
Column,
|
|
|
|
|
ForeignKey,
|
|
|
|
|
Index,
|
|
|
|
|
Integer,
|
|
|
|
|
String,
|
|
|
|
|
Text,
|
|
|
|
|
text,
|
|
|
|
|
)
|
|
|
|
|
from sqlalchemy.dialects.postgresql import JSONB, UUID
|
|
|
|
|
from sqlalchemy.orm import relationship
|
|
|
|
|
|
|
|
|
|
from app.db import BaseModel, TimestampMixin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Notification(BaseModel, TimestampMixin):
|
|
|
|
|
__tablename__ = "notifications"
|
|
|
|
|
__table_args__ = (
|
|
|
|
|
# Serves unread-count queries.
|
|
|
|
|
Index(
|
|
|
|
|
"ix_notifications_user_read_type_created",
|
|
|
|
|
"user_id",
|
|
|
|
|
"read",
|
|
|
|
|
"type",
|
|
|
|
|
"created_at",
|
|
|
|
|
),
|
|
|
|
|
# Serves the paginated inbox list query.
|
|
|
|
|
Index(
|
2026-06-26 12:12:13 +02:00
|
|
|
"ix_notifications_user_workspace_created",
|
2026-06-03 18:04:47 +02:00
|
|
|
"user_id",
|
2026-06-26 12:12:13 +02:00
|
|
|
"workspace_id",
|
2026-06-03 18:04:47 +02:00
|
|
|
"created_at",
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
user_id = Column(
|
|
|
|
|
UUID(as_uuid=True),
|
|
|
|
|
ForeignKey("user.id", ondelete="CASCADE"),
|
|
|
|
|
nullable=False,
|
|
|
|
|
index=True,
|
|
|
|
|
)
|
2026-06-26 18:20:28 +02:00
|
|
|
workspace_id = Column(
|
2026-06-03 18:04:47 +02:00
|
|
|
Integer,
|
2026-06-26 13:27:16 +02:00
|
|
|
ForeignKey("workspaces.id", ondelete="CASCADE"),
|
2026-06-03 18:04:47 +02:00
|
|
|
nullable=True,
|
|
|
|
|
index=True,
|
|
|
|
|
)
|
|
|
|
|
type = Column(String(50), nullable=False, index=True)
|
|
|
|
|
title = Column(String(200), nullable=False)
|
|
|
|
|
message = Column(Text, nullable=False)
|
|
|
|
|
read = Column(
|
|
|
|
|
Boolean, nullable=False, default=False, server_default=text("false"), index=True
|
|
|
|
|
)
|
|
|
|
|
notification_metadata = Column("metadata", JSONB, nullable=True, default={})
|
|
|
|
|
updated_at = Column(
|
|
|
|
|
TIMESTAMP(timezone=True),
|
|
|
|
|
nullable=True,
|
|
|
|
|
default=lambda: datetime.now(UTC),
|
|
|
|
|
onupdate=lambda: datetime.now(UTC),
|
|
|
|
|
index=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
user = relationship("User", back_populates="notifications")
|
2026-06-26 18:20:28 +02:00
|
|
|
workspace = relationship("Workspace", back_populates="notifications")
|