feat(notifications): TODO 7 — draft decision toast + email + bell badge
This commit is contained in:
+56
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog
|
||||
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.27.xsd">
|
||||
|
||||
<!--
|
||||
notification_read_state — tracks which notification_log rows have been read
|
||||
by a given user, enabling the "unread count" and per-item read flag in
|
||||
GET /api/v1/me/notifications.
|
||||
|
||||
Design decisions:
|
||||
- Separate table keeps notification_log append-only (no mutable columns there).
|
||||
- PK = (user_id, notification_id) — no surrogate id needed; natural composite
|
||||
is unique and small enough for index coverage.
|
||||
- user_id stores Keycloak subject (VARCHAR 128, matching user_display_cache.sub).
|
||||
- notification_id references notification_log.id (BIGINT). FK not declared to
|
||||
avoid blocking DELETE on notification_log retention sweeps.
|
||||
- ON CONFLICT DO NOTHING in INSERT — idempotent re-read.
|
||||
-->
|
||||
|
||||
<changeSet id="0024-1-notification-read-state" author="ordinis">
|
||||
<comment>notification_read_state — per-user read tracking for notification_log rows</comment>
|
||||
<createTable tableName="notification_read_state">
|
||||
<!-- Keycloak subject — same shape as user_display_cache.sub -->
|
||||
<column name="user_id" type="VARCHAR(128)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<!-- References notification_log.id — no FK to allow independent retention sweep -->
|
||||
<column name="notification_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="read_at" type="TIMESTAMPTZ" defaultValueComputed="NOW()">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<sql>
|
||||
ALTER TABLE notification_read_state
|
||||
ADD CONSTRAINT notification_read_state_pkey
|
||||
PRIMARY KEY (user_id, notification_id);
|
||||
</sql>
|
||||
|
||||
<!-- Index for "how many unread does user X have" query:
|
||||
SELECT COUNT(*) FROM notification_log nl
|
||||
WHERE nl.recipient = ?
|
||||
AND NOT EXISTS (SELECT 1 FROM notification_read_state rs
|
||||
WHERE rs.user_id = ? AND rs.notification_id = nl.id)
|
||||
-->
|
||||
<createIndex indexName="idx_notif_read_state_user" tableName="notification_read_state">
|
||||
<column name="user_id"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -33,5 +33,6 @@
|
||||
<include file="changes/0021-notifications.xml" relativeToChangelogFile="true"/>
|
||||
<include file="changes/0022-schema-workflow.xml" relativeToChangelogFile="true"/>
|
||||
<include file="changes/0023-user-display-cache.xml" relativeToChangelogFile="true"/>
|
||||
<include file="changes/0024-notification-read-state.xml" relativeToChangelogFile="true"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
||||
Reference in New Issue
Block a user