feat(server,client): announcement channels (D1, closes A-2026-07-01)

Make 'announcement' a real channel type, resolving the contradiction where
it was documented and offered by the admin API but hard-rejected by the
migration-013 DB triggers.

Model: announcement channels are readable like text channels (same
READ_MESSAGES visibility), but posting is restricted to users with
MANAGE_MESSAGES — no new permission bit, migration, or client permission
plumbing needed.

Server:
- migrations/016: recreate the channel-type triggers to allow
  text/voice/announcement/dm.
- service/message.go: checkSendPermission now takes the channel type and
  rejects posts to announcement channels from users lacking MANAGE_MESSAGES
  (SendMessage + CanPost paths). Added a service test.
- Unread counts: ready-payload builder (ws/serve.go) and
  GetChannelUnreadCounts (db) now include announcement channels alongside
  text, so they track unread/last-message like text channels.

Client:
- ChannelSidebar renders announcement channels with a megaphone icon
  (added to the icon set) instead of the '#' text prefix; they otherwise
  behave like text channels (already typed in ChannelType).

Specs + trackers (api.md, protocol.md, schema.md incl. migration 016,
architecture/data-model.md, audit A-2026-07-01, decisions D1) updated.

Verified: go build ./...; go test ./service ./db ./ws ./api ./admin;
sqlc-verify; client tsc + oxlint + prettier clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UA17KPvqGBX3XbXYnMf1rA
This commit is contained in:
Claude
2026-07-19 16:00:18 +00:00
parent f66d6c5274
commit 071426c0d8
14 changed files with 92 additions and 18 deletions
+1 -1
View File
@@ -469,7 +469,7 @@ List all channels the authenticated user has `READ_MESSAGES` permission for. DM
| ----- | ---- | ----------- |
| `id` | int64 | Channel ID |
| `name` | string | Channel name |
| `type` | string | `text` or `voice` (`announcement` is planned; the DB currently rejects it) |
| `type` | string | `text`, `voice`, or `announcement` (announcement channels are read like text but only `MANAGE_MESSAGES` holders can post) |
| `topic` | string | Channel topic/description |
| `category` | string | Category grouping |
| `position` | int | Sort order within category |