Files
Warp/server/internal/storage/postgres/migrations/0010_push.sql
T
tajniak81andClaude Opus 5.5 b507753172 Phase 8: push and notifications
Implements PLAN.md Phase 8. internal/pushrules is the rule language: the
spec's default ruleset, all six condition kinds, glob and word-boundary
matching, intentional mentions switching off the legacy body rules, and
rule ordering as Synapse has it. internal/pushserver keeps the rules,
pushers and notifications and talks to push gateways.

Push rules are the m.push_rules account data, written only by the push
server; reads keep the user's own rules and the enabled/actions of each
default and take the rest from the current defaults, so new default rules
reach every user without a migration. PUT account_data/m.push_rules is
refused with 405.

The push server listens on the roomserver's emit stage and evaluates each
event on its own worker for every local member and an invite's target.
Notifications and per-room unread counts are stored in migration 0010;
counts are a seventh sync token stream, so /sync reports
unread_notifications and picks up count changes made after the event or by
a receipt from another device. m.read and m.read.private receipts clear
the counts; leaving a room clears it.

Pushers (http kind only) push through a bounded sender pool with retries,
honour event_id_only, drop push keys the gateway rejects, and go away with
their device. GET /notifications pages the history. New config section
push: enabled, include_content, gateway_timeout, notification_retention.

Account data writes now wake the user's blocked syncs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:43:36 +02:00

71 lines
3.0 KiB
SQL

-- Push: pushers, and the notifications push rules produce.
--
-- Push rules themselves are not here. They are the m.push_rules account
-- data, which is where the spec has clients read them and where /sync
-- already carries account data from; a table of their own would be a
-- second copy to keep in step with that one.
-- The notification count stream: one counter, next to its tables, read
-- with the other streams so that a sync token names one moment in all of
-- them.
CREATE TABLE IF NOT EXISTS push_sequences (
name TEXT NOT NULL PRIMARY KEY,
value BIGINT NOT NULL
);
INSERT INTO push_sequences (name, value) VALUES ('notification', 0) ON CONFLICT (name) DO NOTHING;
-- Pushers. A pusher is one app on one device, named by its app ID and push
-- key; device_id is the session that registered it, so that logging the
-- session out removes it.
CREATE TABLE IF NOT EXISTS push_pushers (
localpart TEXT NOT NULL,
app_id TEXT NOT NULL,
pushkey TEXT NOT NULL,
device_id TEXT NOT NULL DEFAULT '',
kind TEXT NOT NULL,
app_display_name TEXT NOT NULL DEFAULT '',
device_display_name TEXT NOT NULL DEFAULT '',
profile_tag TEXT NOT NULL DEFAULT '',
lang TEXT NOT NULL DEFAULT '',
data_json TEXT NOT NULL,
pushkey_ts_ms BIGINT NOT NULL,
PRIMARY KEY (localpart, app_id, pushkey)
);
CREATE INDEX IF NOT EXISTS push_pushers_key_idx ON push_pushers (app_id, pushkey);
-- One row per event that notified a user. id is the position the row was
-- written at in the notification stream, which also orders a user's
-- notifications for GET /notifications. event_pos is the event's position
-- in the room event stream, which a read receipt is compared against.
CREATE TABLE IF NOT EXISTS push_notifications (
id BIGINT NOT NULL PRIMARY KEY,
user_id TEXT NOT NULL,
room_id TEXT NOT NULL,
event_id TEXT NOT NULL,
event_pos BIGINT NOT NULL,
ts_ms BIGINT NOT NULL,
highlight BOOLEAN NOT NULL DEFAULT FALSE,
actions TEXT NOT NULL,
is_read BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE INDEX IF NOT EXISTS push_notifications_user_idx ON push_notifications (user_id, id);
CREATE INDEX IF NOT EXISTS push_notifications_unread_idx ON push_notifications (user_id, room_id, is_read, event_pos);
CREATE INDEX IF NOT EXISTS push_notifications_prune_idx ON push_notifications (is_read, ts_ms);
-- A user's unread counts in a room, kept current by the writes above
-- rather than counted on every sync, and stamped with the notification
-- stream position of the write that last moved them.
CREATE TABLE IF NOT EXISTS push_room_counts (
user_id TEXT NOT NULL,
room_id TEXT NOT NULL,
notification_count BIGINT NOT NULL,
highlight_count BIGINT NOT NULL,
stream_pos BIGINT NOT NULL,
PRIMARY KEY (user_id, room_id)
);
CREATE INDEX IF NOT EXISTS push_room_counts_stream_idx ON push_room_counts (user_id, stream_pos);