mirror of
https://github.com/block/buzz.git
synced 2026-11-01 06:51:17 +00:00
feat(sections): add workspace contract and persistence
Signed-off-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -160,6 +160,108 @@ CREATE TABLE channel_members (
|
||||
CREATE INDEX idx_channel_members_pubkey ON channel_members (community_id, pubkey)
|
||||
WHERE removed_at IS NULL;
|
||||
|
||||
-- ── Section workspaces ───────────────────────────────────────────────────────
|
||||
|
||||
CREATE TABLE section_workspaces (
|
||||
community_id UUID NOT NULL REFERENCES communities(id),
|
||||
owner_pubkey BYTEA NOT NULL CHECK (length(owner_pubkey) = 32),
|
||||
revision BIGINT NOT NULL DEFAULT 0 CHECK (revision >= 0),
|
||||
layout_revision BIGINT NOT NULL DEFAULT 0 CHECK (layout_revision >= 0),
|
||||
key_epoch BIGINT NOT NULL DEFAULT 0 CHECK (key_epoch >= 0),
|
||||
migrated_at TIMESTAMPTZ,
|
||||
migration_source_event_id BYTEA CHECK (migration_source_event_id IS NULL OR length(migration_source_event_id) = 32),
|
||||
migration_source_hash BYTEA CHECK (migration_source_hash IS NULL OR length(migration_source_hash) = 32),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (community_id, owner_pubkey),
|
||||
CHECK ((migrated_at IS NULL) = (migration_source_event_id IS NULL)),
|
||||
CHECK ((migrated_at IS NULL) = (migration_source_hash IS NULL)),
|
||||
CHECK ((migrated_at IS NULL) = (revision = 0))
|
||||
);
|
||||
|
||||
CREATE TABLE section_grants (
|
||||
community_id UUID NOT NULL,
|
||||
owner_pubkey BYTEA NOT NULL CHECK (length(owner_pubkey) = 32),
|
||||
actor_pubkey BYTEA NOT NULL CHECK (length(actor_pubkey) = 32),
|
||||
role TEXT NOT NULL CHECK (role IN ('viewer', 'mover', 'manager')),
|
||||
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'revoked')),
|
||||
granted_by BYTEA NOT NULL CHECK (length(granted_by) = 32),
|
||||
granted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
revoked_at TIMESTAMPTZ,
|
||||
PRIMARY KEY (community_id, owner_pubkey, actor_pubkey),
|
||||
FOREIGN KEY (community_id, owner_pubkey)
|
||||
REFERENCES section_workspaces(community_id, owner_pubkey) ON DELETE CASCADE,
|
||||
CHECK (actor_pubkey <> owner_pubkey),
|
||||
CHECK ((status = 'revoked') = (revoked_at IS NOT NULL))
|
||||
);
|
||||
CREATE INDEX section_grants_actor_active
|
||||
ON section_grants (community_id, actor_pubkey, owner_pubkey)
|
||||
WHERE status = 'active';
|
||||
|
||||
CREATE TABLE section_key_envelopes (
|
||||
community_id UUID NOT NULL,
|
||||
owner_pubkey BYTEA NOT NULL CHECK (length(owner_pubkey) = 32),
|
||||
reader_pubkey BYTEA NOT NULL CHECK (length(reader_pubkey) = 32),
|
||||
key_epoch BIGINT NOT NULL CHECK (key_epoch > 0),
|
||||
envelope TEXT NOT NULL CHECK (octet_length(envelope) BETWEEN 1 AND 4096),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (community_id, owner_pubkey, reader_pubkey, key_epoch),
|
||||
FOREIGN KEY (community_id, owner_pubkey)
|
||||
REFERENCES section_workspaces(community_id, owner_pubkey) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE sections (
|
||||
community_id UUID NOT NULL,
|
||||
owner_pubkey BYTEA NOT NULL CHECK (length(owner_pubkey) = 32),
|
||||
section_id UUID NOT NULL CHECK (section_id <> '00000000-0000-0000-0000-000000000000'::uuid),
|
||||
encrypted_label TEXT NOT NULL CHECK (octet_length(encrypted_label) BETWEEN 1 AND 65535),
|
||||
encrypted_icon TEXT CHECK (encrypted_icon IS NULL OR octet_length(encrypted_icon) BETWEEN 1 AND 65535),
|
||||
rank INTEGER NOT NULL CHECK (rank BETWEEN 0 AND 99),
|
||||
revision BIGINT NOT NULL CHECK (revision > 0),
|
||||
deleted_at TIMESTAMPTZ,
|
||||
PRIMARY KEY (community_id, owner_pubkey, section_id),
|
||||
FOREIGN KEY (community_id, owner_pubkey)
|
||||
REFERENCES section_workspaces(community_id, owner_pubkey) ON DELETE CASCADE
|
||||
);
|
||||
CREATE UNIQUE INDEX sections_active_rank
|
||||
ON sections (community_id, owner_pubkey, rank) WHERE deleted_at IS NULL;
|
||||
|
||||
CREATE TABLE section_assignments (
|
||||
community_id UUID NOT NULL,
|
||||
owner_pubkey BYTEA NOT NULL CHECK (length(owner_pubkey) = 32),
|
||||
channel_id UUID NOT NULL,
|
||||
section_id UUID NOT NULL,
|
||||
revision BIGINT NOT NULL CHECK (revision > 0),
|
||||
updated_by BYTEA NOT NULL CHECK (length(updated_by) = 32),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (community_id, owner_pubkey, channel_id),
|
||||
FOREIGN KEY (community_id, owner_pubkey, section_id)
|
||||
REFERENCES sections(community_id, owner_pubkey, section_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (community_id, channel_id)
|
||||
REFERENCES channels(community_id, id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE section_actions (
|
||||
community_id UUID NOT NULL,
|
||||
owner_pubkey BYTEA NOT NULL CHECK (length(owner_pubkey) = 32),
|
||||
action_id UUID NOT NULL,
|
||||
actor_pubkey BYTEA NOT NULL CHECK (length(actor_pubkey) = 32),
|
||||
command_kind TEXT NOT NULL CHECK (command_kind IN (
|
||||
'import_v1', 'grant', 'revoke', 'assign_channel', 'unassign_channel',
|
||||
'create_section', 'rename_section', 'delete_section', 'reorder_sections'
|
||||
)),
|
||||
command_event_id BYTEA NOT NULL CHECK (length(command_event_id) = 32),
|
||||
signed_event_json JSONB NOT NULL CHECK (jsonb_typeof(signed_event_json) = 'object'),
|
||||
command_hash BYTEA NOT NULL CHECK (length(command_hash) = 32),
|
||||
resulting_revision BIGINT NOT NULL CHECK (resulting_revision > 0),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (community_id, owner_pubkey, action_id),
|
||||
FOREIGN KEY (community_id, owner_pubkey)
|
||||
REFERENCES section_workspaces(community_id, owner_pubkey) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
|
||||
|
||||
-- ── Users ─────────────────────────────────────────────────────────────────────
|
||||
-- Conformance: "Users, profiles, NIP-05, and user search". One profile per
|
||||
-- (community, pubkey): the same key reposts kind:0 in each community it joins.
|
||||
@@ -1662,6 +1764,12 @@ SELECT attach_community_write_fence('reactions');
|
||||
SELECT attach_community_write_fence('relay_invites');
|
||||
SELECT attach_community_write_fence('relay_members');
|
||||
SELECT attach_community_write_fence('scheduled_workflow_fires');
|
||||
SELECT attach_community_write_fence('section_actions');
|
||||
SELECT attach_community_write_fence('section_assignments');
|
||||
SELECT attach_community_write_fence('section_grants');
|
||||
SELECT attach_community_write_fence('section_key_envelopes');
|
||||
SELECT attach_community_write_fence('section_workspaces');
|
||||
SELECT attach_community_write_fence('sections');
|
||||
SELECT attach_community_write_fence('subscriptions');
|
||||
SELECT attach_community_write_fence('thread_metadata');
|
||||
SELECT attach_community_write_fence('users');
|
||||
|
||||
Reference in New Issue
Block a user