prism-models 0.7.6__tar.gz → 0.7.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {prism_models-0.7.6 → prism_models-0.7.7}/PKG-INFO +1 -1
  2. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/__init__.py +3 -0
  3. prism_models-0.7.7/prism_models/migration/versions/2026_01_29_1312_ed197421f25a_add_notification_tables.py +87 -0
  4. prism_models-0.7.7/prism_models/notification.py +142 -0
  5. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models.egg-info/PKG-INFO +1 -1
  6. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models.egg-info/SOURCES.txt +3 -1
  7. {prism_models-0.7.6 → prism_models-0.7.7}/pyproject.toml +1 -1
  8. {prism_models-0.7.6 → prism_models-0.7.7}/README.md +0 -0
  9. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/agent_profile.py +0 -0
  10. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/base.py +0 -0
  11. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/chat.py +0 -0
  12. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/config.py +0 -0
  13. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/content.py +0 -0
  14. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/feedback.py +0 -0
  15. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/README +0 -0
  16. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/__init__.py +0 -0
  17. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/env.py +0 -0
  18. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/script.py.mako +0 -0
  19. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_11_1516_161f8829d93f_initial_schema.py +0 -0
  20. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_11_1558_5e011849ea76_changes_for_feedback.py +0 -0
  21. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_14_2243_059af231c2b2_profile_entities.py +0 -0
  22. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_15_1646_3219fec0bb10_agent_changes.py +0 -0
  23. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_16_1627_f2013b08daac_rename_metadata_to_additional_data.py +0 -0
  24. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_17_1147_327febbf555f_display_name_added.py +0 -0
  25. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_18_1106_b0bcb7ca1dc9_add_support_for_profile_on_create_convo.py +0 -0
  26. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_18_1511_bbc1955191e6_preview_mode.py +0 -0
  27. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_26_1115_6eb70e848451_added_publish_status_to_document.py +0 -0
  28. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_26_1240_f8b0ea2e743c_drop_unique_title_version_on_document.py +0 -0
  29. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_26_1505_07dc8c2589e0_added_chunk_id_and_vector_embeddings_to_.py +0 -0
  30. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_09_29_1220_46ba2693b883_add_markdown_markdown_file_path_s3_.py +0 -0
  31. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_02_1520_bf1472a9b021_removed_doc_id_from_config_table_and_.py +0 -0
  32. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_02_1525_6c0e63e0fef8_removed_doc_id_from_config_table_.py +0 -0
  33. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_02_1608_1b3eb48f5017_config_id_on_delete_will_be_set_to_null.py +0 -0
  34. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_03_1109_ac85b606d8a4_added_docling_hybrid_to_chunkstrategy.py +0 -0
  35. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_03_1204_7d1cb343a63f_added_s3_bucket_and_s3_dir_in_source_.py +0 -0
  36. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_03_1452_f9c750ec2a0b_1_to_1_relationship_between_collection_.py +0 -0
  37. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_07_1722_5cfa0c462948_added_travel_advisory_enum.py +0 -0
  38. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_08_1304_c91eb8e38cc7_added_destination_report_and_event_.py +0 -0
  39. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_09_1308_796b720ea35f_added_qa_id_to_vovetor.py +0 -0
  40. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_16_1611_663c66268631_added_sharepoint_drive_item_id_as_an_.py +0 -0
  41. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_23_1228_919d07a93f83_added_sharepoint_directory_in_source.py +0 -0
  42. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_27_1331_ff3be2c4311f_added_agentcollectionaccess_table.py +0 -0
  43. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_10_28_1333_b789e61df26a_ad_enum_and_field_added.py +0 -0
  44. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_03_1633_cc27b20a106e_removed_collection_from_source_.py +0 -0
  45. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_03_1653_bf5c2ce928e3_removed_collection_from_source_.py +0 -0
  46. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_03_1738_b733b48d78b5_remove_source.py +0 -0
  47. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_06_1450_8a7e56260eba_added_collection_ids_sync_enabled_and_.py +0 -0
  48. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_06_1626_4c4148ac2d21_removed_qna_related_columns_from_.py +0 -0
  49. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_06_1648_b228888a01ee_added_chunk_config_to_source.py +0 -0
  50. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_06_1656_7d0982bae4db_added_chunk_config_to_source_again_last_.py +0 -0
  51. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_12_1727_b9663951b5c1_removed_un_used_fields_from_feedback.py +0 -0
  52. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_12_1749_3d37806383a2_simplified_feedback.py +0 -0
  53. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_12_1838_8c3c862b565e_removed_is_upvoted_from_message.py +0 -0
  54. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_12_1841_54a2f12a1573_added_vote_field.py +0 -0
  55. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_13_1215_fa00286fe6cd_add_type_column_to_chunk_table.py +0 -0
  56. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_14_1216_2c62317520f9_add_rerieved_and_created_chunks_and_.py +0 -0
  57. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_17_1259_a3bc4e4c08a0_agent_and_profile_entity_changes.py +0 -0
  58. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_17_1325_df5b1cdc2c36_agentprofile_contact_entity_changes.py +0 -0
  59. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_17_1716_ed91cdf82ef3_adding_feedback_enum.py +0 -0
  60. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_20_0008_80f5954656f0_feedback_chunk_entity_added.py +0 -0
  61. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_20_0109_58be389d0ed7_feedback_chunks_changes.py +0 -0
  62. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_20_0158_98eb0c87e65e_feedback_chunk_chnages.py +0 -0
  63. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_21_1207_bbee88729aae_add_feedback_columns.py +0 -0
  64. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_21_1625_8c50f64287fe_added_sequence_column_to_chunk_table_.py +0 -0
  65. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_21_1654_e7ae98ce2121_removed_sync_enabled.py +0 -0
  66. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_21_1758_24b3f480777b_refactor_feedback_analysis_for_unified_.py +0 -0
  67. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_21_1801_5a52fb845dc0_refactor_feedback_analysis_for_unified_.py +0 -0
  68. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_24_1124_dc57fb290621_added_conversation_context_to_.py +0 -0
  69. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_11_25_1847_c6c36663acd5_added_user_preferences_table.py +0 -0
  70. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_12_07_2236_88f01df468f2_added_sparse_embeddings_field_in_vector_.py +0 -0
  71. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_12_09_1146_6abdd3f001ab_adding_orchestrator_model_to_profile_.py +0 -0
  72. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2025_12_17_1220_4d9291a3acb1_removed_qa_pair_chunk.py +0 -0
  73. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2026_01_14_1742_147509a82af8_changed_user_role_enums.py +0 -0
  74. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2026_01_15_1010_3b7d0b2e9f5a_add_contact_profile_table.py +0 -0
  75. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/migration/versions/2026_01_26_1648_53d6d0b55f11_feedback_changes.py +0 -0
  76. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models/qdrant.py +0 -0
  77. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models.egg-info/dependency_links.txt +0 -0
  78. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models.egg-info/requires.txt +0 -0
  79. {prism_models-0.7.6 → prism_models-0.7.7}/prism_models.egg-info/top_level.txt +0 -0
  80. {prism_models-0.7.6 → prism_models-0.7.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prism-models
3
- Version: 0.7.6
3
+ Version: 0.7.7
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: sqlalchemy[asyncio]>=2.0.0
6
6
  Requires-Dist: alembic>=1.16.0
@@ -17,6 +17,7 @@ from prism_models.chat import Contact, Conversation, ConversationMessage, Conver
17
17
  from prism_models.content import Chunk, ChunkConfig, Collection, CollectionDocument, Document, IntegrationConfig, Source, Vector
18
18
  from prism_models.feedback import Augmentation, Feedback, FeedbackAnalysis, FeedbackStatus, FeedbackType
19
19
  from prism_models.qdrant import QdrantVectorPayload, DestinationVectorPayload, PydanticType
20
+ from prism_models.notification import NotificationTarget, NotificationOutbox
20
21
 
21
22
  __all__ = [
22
23
  "POSTGRES_NAMING_CONVENTION",
@@ -51,4 +52,6 @@ __all__ = [
51
52
  "Source",
52
53
  "TimestampMixin",
53
54
  "Vector",
55
+ "NotificationTarget",
56
+ "NotificationOutbox",
54
57
  ]
@@ -0,0 +1,87 @@
1
+ """add notification tables
2
+
3
+ Revision ID: ed197421f25a
4
+ Revises: 53d6d0b55f11
5
+ Create Date: 2026-01-29 13:12:33.275063
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+ from sqlalchemy.dialects import postgresql
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = 'ed197421f25a'
16
+ down_revision: Union[str, Sequence[str], None] = '53d6d0b55f11'
17
+ branch_labels: Union[str, Sequence[str], None] = None
18
+ depends_on: Union[str, Sequence[str], None] = None
19
+
20
+
21
+ def upgrade() -> None:
22
+ """Upgrade schema."""
23
+ # ### commands auto generated by Alembic - please adjust! ###
24
+ op.create_table('notification_target',
25
+ sa.Column('provider', sa.String(length=50), nullable=False),
26
+ sa.Column('target_key', sa.String(length=100), nullable=False),
27
+ sa.Column('display_name', sa.String(length=255), nullable=True),
28
+ sa.Column('webhook_url', sa.Text(), nullable=False),
29
+ sa.Column('is_enabled', sa.Boolean(), nullable=False),
30
+ sa.Column('id', sa.Integer(), nullable=False),
31
+ sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
32
+ sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
33
+ sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
34
+ sa.PrimaryKeyConstraint('id', name=op.f('notification_target_pkey')),
35
+ sa.UniqueConstraint('provider', 'target_key', name='uq_notification_target_provider_key')
36
+ )
37
+ op.create_index(op.f('notification_target_id_idx'), 'notification_target', ['id'], unique=False)
38
+ op.create_table('notification_outbox',
39
+ sa.Column('provider', sa.String(length=50), nullable=False),
40
+ sa.Column('target_key', sa.String(length=100), nullable=False),
41
+ sa.Column('event_type', sa.String(length=100), nullable=False),
42
+ sa.Column('severity', sa.String(length=20), nullable=True),
43
+ sa.Column('dedupe_key', sa.String(length=255), nullable=False),
44
+ sa.Column('correlation_id', sa.String(length=100), nullable=True),
45
+ sa.Column('entity_type', sa.String(length=50), nullable=True),
46
+ sa.Column('entity_id', sa.String(length=100), nullable=True),
47
+ sa.Column('payload', postgresql.JSONB(astext_type=sa.Text()), nullable=False),
48
+ sa.Column('status', sa.String(length=20), nullable=False),
49
+ sa.Column('priority', sa.Integer(), nullable=False),
50
+ sa.Column('attempts', sa.Integer(), nullable=False),
51
+ sa.Column('max_attempts', sa.Integer(), nullable=False),
52
+ sa.Column('next_attempt_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
53
+ sa.Column('last_error', sa.Text(), nullable=True),
54
+ sa.Column('sent_at', sa.DateTime(timezone=True), nullable=True),
55
+ sa.Column('expires_at', sa.DateTime(timezone=True), nullable=True),
56
+ sa.Column('locked_by', sa.String(length=100), nullable=True),
57
+ sa.Column('locked_at', sa.DateTime(timezone=True), nullable=True),
58
+ sa.Column('id', sa.Integer(), nullable=False),
59
+ sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
60
+ sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
61
+ sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True),
62
+ sa.ForeignKeyConstraint(['provider', 'target_key'], ['notification_target.provider', 'notification_target.target_key'], name='fk_notification_outbox_target'),
63
+ sa.PrimaryKeyConstraint('id', name=op.f('notification_outbox_pkey')),
64
+ sa.UniqueConstraint('dedupe_key', name=op.f('notification_outbox_dedupe_key_key'))
65
+ )
66
+ op.create_index('ix_notification_outbox_entity', 'notification_outbox', ['entity_type', 'entity_id'], unique=False)
67
+ op.create_index('ix_notification_outbox_ready', 'notification_outbox', ['status', 'priority', 'next_attempt_at'], unique=False)
68
+ op.create_index(op.f('notification_outbox_correlation_id_idx'), 'notification_outbox', ['correlation_id'], unique=False)
69
+ op.create_index(op.f('notification_outbox_expires_at_idx'), 'notification_outbox', ['expires_at'], unique=False)
70
+ op.create_index(op.f('notification_outbox_id_idx'), 'notification_outbox', ['id'], unique=False)
71
+ op.create_index(op.f('notification_outbox_status_idx'), 'notification_outbox', ['status'], unique=False)
72
+ # ### end Alembic commands ###
73
+
74
+
75
+ def downgrade() -> None:
76
+ """Downgrade schema."""
77
+ # ### commands auto generated by Alembic - please adjust! ###
78
+ op.drop_index(op.f('notification_outbox_status_idx'), table_name='notification_outbox')
79
+ op.drop_index(op.f('notification_outbox_id_idx'), table_name='notification_outbox')
80
+ op.drop_index(op.f('notification_outbox_expires_at_idx'), table_name='notification_outbox')
81
+ op.drop_index(op.f('notification_outbox_correlation_id_idx'), table_name='notification_outbox')
82
+ op.drop_index('ix_notification_outbox_ready', table_name='notification_outbox')
83
+ op.drop_index('ix_notification_outbox_entity', table_name='notification_outbox')
84
+ op.drop_table('notification_outbox')
85
+ op.drop_index(op.f('notification_target_id_idx'), table_name='notification_target')
86
+ op.drop_table('notification_target')
87
+ # ### end Alembic commands ###
@@ -0,0 +1,142 @@
1
+ """Notification models for outbox-based delivery to Teams channels."""
2
+
3
+ import enum
4
+ from datetime import datetime
5
+ from typing import Optional
6
+
7
+ from sqlalchemy import (
8
+ Boolean,
9
+ DateTime,
10
+ ForeignKeyConstraint,
11
+ Index,
12
+ Integer,
13
+ String,
14
+ Text,
15
+ UniqueConstraint,
16
+ func,
17
+ )
18
+ from sqlalchemy.dialects.postgresql import JSONB
19
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
20
+
21
+ from prism_models.base import Base, BaseModel, TimestampMixin
22
+
23
+
24
+ # ─────────────────────────────────────────────────────────────────────────────
25
+ # Enums
26
+ # ─────────────────────────────────────────────────────────────────────────────
27
+
28
+
29
+ class NotificationStatus(str, enum.Enum):
30
+ """Lifecycle states for outbox notifications."""
31
+
32
+ PENDING = "pending"
33
+ SENDING = "sending"
34
+ SENT = "sent"
35
+ FAILED = "failed"
36
+
37
+
38
+ class NotificationSeverity(str, enum.Enum):
39
+ """Severity levels for notification prioritization and formatting."""
40
+
41
+ INFO = "info"
42
+ WARN = "warn"
43
+ ERROR = "error"
44
+ CRITICAL = "critical"
45
+
46
+
47
+ class NotificationProvider(str, enum.Enum):
48
+ """Supported notification providers (only Teams for now)."""
49
+
50
+ TEAMS = "teams"
51
+
52
+ class NotificationTarget(BaseModel):
53
+ """
54
+ Webhook destinations for notifications.
55
+
56
+ Each target represents a Teams channel webhook.
57
+ Multiple event types can route to the same target.
58
+ """
59
+
60
+ __tablename__ = "notification_target"
61
+
62
+ provider: Mapped[str] = mapped_column(String(50), nullable=False)
63
+ target_key: Mapped[str] = mapped_column(String(100), nullable=False)
64
+ display_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
65
+ webhook_url: Mapped[str] = mapped_column(Text, nullable=False)
66
+ is_enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
67
+
68
+ outbox_entries: Mapped[list["NotificationOutbox"]] = relationship(
69
+ back_populates="target",
70
+ foreign_keys="[NotificationOutbox.provider, NotificationOutbox.target_key]",
71
+ )
72
+
73
+ __table_args__ = (
74
+ UniqueConstraint("provider", "target_key", name="uq_notification_target_provider_key"),
75
+ )
76
+
77
+ def __repr__(self):
78
+ return f"<NotificationTarget(id={self.id}, provider='{self.provider}', key='{self.target_key}')>"
79
+
80
+
81
+ class NotificationOutbox(BaseModel):
82
+ """
83
+ Transactional outbox for reliable notification delivery.
84
+
85
+ Design notes:
86
+ - dedupe_key: Prevents duplicate sends at insert time
87
+ - entity_type + entity_id: Polymorphic reference to source entity
88
+ - locked_by + locked_at: Enables safe multi-worker polling
89
+ - priority: Critical alerts jump ahead of digests
90
+ - max_attempts: Per-notification retry limit
91
+ - expires_at: Auto-expire stale notifications
92
+ """
93
+
94
+ __tablename__ = "notification_outbox"
95
+
96
+ provider: Mapped[str] = mapped_column(String(50), nullable=False)
97
+ target_key: Mapped[str] = mapped_column(String(100), nullable=False)
98
+ event_type: Mapped[str] = mapped_column(String(100), nullable=False)
99
+ severity: Mapped[str | None] = mapped_column(String(20), nullable=True)
100
+
101
+ dedupe_key: Mapped[str] = mapped_column(String(255), nullable=False, unique=True)
102
+ correlation_id: Mapped[str | None] = mapped_column(String(100), nullable=True, index=True)
103
+
104
+ entity_type: Mapped[str | None] = mapped_column(String(50), nullable=True)
105
+ entity_id: Mapped[str | None] = mapped_column(String(100), nullable=True)
106
+
107
+ payload: Mapped[dict] = mapped_column(JSONB, nullable=False)
108
+
109
+ status: Mapped[str] = mapped_column(
110
+ String(20), default=NotificationStatus.PENDING.value, nullable=False, index=True
111
+ )
112
+ priority: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
113
+ attempts: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
114
+ max_attempts: Mapped[int] = mapped_column(Integer, default=5, nullable=False)
115
+ next_attempt_at: Mapped[datetime] = mapped_column(
116
+ DateTime(timezone=True), server_default=func.now(), nullable=False
117
+ )
118
+ last_error: Mapped[str | None] = mapped_column(Text, nullable=True)
119
+ sent_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
120
+
121
+ expires_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
122
+
123
+ locked_by: Mapped[str | None] = mapped_column(String(100), nullable=True)
124
+ locked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
125
+
126
+ target: Mapped[Optional["NotificationTarget"]] = relationship(
127
+ back_populates="outbox_entries",
128
+ foreign_keys=[provider, target_key],
129
+ )
130
+
131
+ __table_args__ = (
132
+ ForeignKeyConstraint(
133
+ ["provider", "target_key"],
134
+ ["notification_target.provider", "notification_target.target_key"],
135
+ name="fk_notification_outbox_target",
136
+ ),
137
+ Index("ix_notification_outbox_ready", "status", "priority", "next_attempt_at"),
138
+ Index("ix_notification_outbox_entity", "entity_type", "entity_id"),
139
+ )
140
+
141
+ def __repr__(self):
142
+ return f"<NotificationOutbox(id={self.id}, event='{self.event_type}', status='{self.status}')>"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prism-models
3
- Version: 0.7.6
3
+ Version: 0.7.7
4
4
  Requires-Python: >=3.12
5
5
  Requires-Dist: sqlalchemy[asyncio]>=2.0.0
6
6
  Requires-Dist: alembic>=1.16.0
@@ -7,6 +7,7 @@ prism_models/chat.py
7
7
  prism_models/config.py
8
8
  prism_models/content.py
9
9
  prism_models/feedback.py
10
+ prism_models/notification.py
10
11
  prism_models/qdrant.py
11
12
  prism_models.egg-info/PKG-INFO
12
13
  prism_models.egg-info/SOURCES.txt
@@ -73,4 +74,5 @@ prism_models/migration/versions/2025_12_09_1146_6abdd3f001ab_adding_orchestrator
73
74
  prism_models/migration/versions/2025_12_17_1220_4d9291a3acb1_removed_qa_pair_chunk.py
74
75
  prism_models/migration/versions/2026_01_14_1742_147509a82af8_changed_user_role_enums.py
75
76
  prism_models/migration/versions/2026_01_15_1010_3b7d0b2e9f5a_add_contact_profile_table.py
76
- prism_models/migration/versions/2026_01_26_1648_53d6d0b55f11_feedback_changes.py
77
+ prism_models/migration/versions/2026_01_26_1648_53d6d0b55f11_feedback_changes.py
78
+ prism_models/migration/versions/2026_01_29_1312_ed197421f25a_add_notification_tables.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "prism-models"
7
- version = "0.7.6"
7
+ version = "0.7.7"
8
8
  requires-python = ">=3.12"
9
9
  dependencies = [
10
10
  "sqlalchemy[asyncio]>=2.0.0",
File without changes
File without changes