Skip to content

Sidebar channel sections are per-user only — no way to share a section layout across a team #5469

Open

Description

@obsidianaddict

Problem

Sidebar channel sections are a per-user construct. channelSectionsSync.ts filters
kinds: [KIND_CHANNEL_SECTIONS], authors: [this.pubkey], so a section layout never
leaves the person who made it.

For a team using Buzz for real project work this is the blocker. We run a self-hosted
relay for a small company (design/AV projects). Each project gets a set of channels —
<project>-design, -quotes, -logistics, -email and so on. One person scaffolds
the project, and every other member then has to recreate the same grouping by hand, one
project at a time. New channels created by a colleague appear ungrouped for everyone
else. In practice people stop grouping at all and the sidebar becomes a flat list of
hundreds of channels.

Proposal

A shared, read-only base layer, with the personal layer kept as an overlay:

  • A designated org/steward identity publishes a sections document in the existing shape.
  • Clients additionally subscribe with authors: [ORG_PUBKEY] and merge: shared sections
    first, personal sections after; a personal assignment or same-id section wins.
  • Writes are unchanged — a user only ever publishes their own document.
  • If no org pubkey is configured, or the document is missing/invalid, behaviour is
    exactly as today.
  • UI hides rename/delete/reorder on shared sections (a per-user "hide" would be fine).

One constraint worth flagging

Personal documents are nip44EncryptToSelf-encrypted, so another author's document
can't be decrypted by anyone else. A shared document therefore needs plaintext content
(still signed by the org identity), or a group-encryption scheme if that's preferred.
That choice seems like a maintainer call, which is why I'm raising an issue rather than
opening a PR.

Willing to contribute

We're building this for our own deployment now and are happy to submit it as a PR if the
approach above is one you'd accept — or to rework it to whatever shape you prefer.

Activity

  1. obsidianaddict commented on Aug 18, 2026

    @obsidianaddict
    Author

    Following up with results, since we went ahead and implemented this downstream. It has been running in production for a week, so here is what we found in case it is useful to the upstream design.

    What we built - client-side only, no relay changes, on top of 119a848:

    A steward/org identity publishes a single kind-30078 sections document. Clients subscribe to their own sections exactly as today and additionally with authors: [ORG_PUBKEY], then merge org-base under personal-overlay: org sections are read-only, a personal section with the same id wins, and a personal channel assignment beats the org one. ORG_PUBKEY is a build constant (VITE_BUZZ_ORG_PUBKEY); when it is unset or malformed the client behaves exactly as upstream does today.

    Two files changed, one added:

    desktop/src/features/sidebar/lib/useChannelSections.ts - shared-layer state, merged output, sharedSectionIds
    desktop/src/features/sidebar/lib/channelSectionsStorage.ts - stop stripping a personal assignment that targets an org section
    desktop/src/features/sidebar/lib/sharedChannelSections.ts (new) - reads the org document and merges; never writes or republishes anything
    The design constraint worth flagging: the shared document has to be published in plaintext. channelSectionsSync.ts uses nip44EncryptToSelf / nip44DecryptFromSelf, so a document published in the personal shape is undecryptable by anyone else. We lost time before spotting that. Any upstream implementation will need a separate unencrypted (or differently-keyed) path for a shared document.

    The bug that cost us the most, and which you may want to fix independently of this feature: the relay rate-limits a client's startup query burst - rate-limited: quota exceeded; retry in 5s. Our first implementation did a single fetch on mount and swallowed the error, so the shared layer stayed empty forever and the feature appeared simply not to work. The fix is retry-with-backoff plus refetch on reconnect, which is what the personal sections path already does. If any other startup subscription in the app does a one-shot fetch, it has the same latent failure - that part is worth a look regardless of what happens to shared sections.

    Status: in daily use by a small team since 11 August. We deliberately kept our build's version string identical to upstream so it upgrades in place and users stay signed in.

    Happy to open a PR if you want it - either the whole feature, or just the rate-limit retry fix if shared sections are heading in a different direction. Equally happy to leave it downstream if you would rather own the design. No expectations either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions