Files
buzz/schema/tables/public/thread_metadata.sql
Bradley Axen 4da2b9f4e4 feat(read-state): follow intents, threads view, arrival-ordered access paths
Extend the merged /buzz/v1 read-state wire with the minimum the follow
model needs:

- `follow` / `unfollow` intents on a thread target. An unfollow sticks
  until the actor posts in the thread or is mentioned there again.
- `GET /me/threads`: followed threads in joined channels, newest reply
  arrival first, cursor-paged, at most 50 per page.
- Thread rows count `mentions` as direct mentions only.
- Broadcast replies count on the channel timeline and are valid channel
  anchors.
- NIP-11 advertises `capabilities: ["follow","threads"]` and `max_threads`.

Migration 0061 adds `events.read_timeline`, `thread_metadata.received_at`
and `personal_read_frontiers.unfollowed`, plus arrival-ordered partial
indexes so the sidebar and threads view probe an index per channel and
per follow instead of scanning a bounded window. No backfill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
2026-10-11 16:14:33 -07:00

34 lines
1.8 KiB
SQL

-- ── Thread metadata ───────────────────────────────────────────────────────────
-- Conformance: thread lookups filter by community before event matching.
CREATE TABLE thread_metadata (
community_id UUID NOT NULL REFERENCES communities(id),
event_created_at TIMESTAMPTZ NOT NULL,
event_id BYTEA NOT NULL,
channel_id UUID NOT NULL,
parent_event_id BYTEA,
parent_event_created_at TIMESTAMPTZ,
root_event_id BYTEA,
root_event_created_at TIMESTAMPTZ,
depth INT NOT NULL DEFAULT 0,
reply_count INT NOT NULL DEFAULT 0,
descendant_count INT NOT NULL DEFAULT 0,
last_reply_at TIMESTAMPTZ,
broadcast BOOLEAN NOT NULL DEFAULT FALSE,
-- A reply's relay arrival; NULL on root stubs and rows before 0061.
received_at TIMESTAMPTZ,
PRIMARY KEY (community_id, event_created_at, event_id),
FOREIGN KEY (community_id, channel_id) REFERENCES channels (community_id, id)
);
CREATE INDEX idx_thread_metadata_parent ON thread_metadata (community_id, parent_event_id);
CREATE INDEX idx_thread_metadata_root ON thread_metadata (community_id, root_event_id);
CREATE INDEX idx_thread_metadata_window
ON thread_metadata (community_id, root_event_id, event_created_at DESC, event_id ASC);
CREATE INDEX idx_thread_metadata_channel_depth
ON thread_metadata (community_id, channel_id, depth, event_created_at);
CREATE INDEX idx_thread_metadata_event_id ON thread_metadata (community_id, event_id);
CREATE INDEX idx_thread_metadata_read_arrival
ON thread_metadata (community_id, root_event_id, received_at DESC, event_id)
WHERE received_at IS NOT NULL;