Feature: Messages #8
Labels
No labels
area:api
area:core
area:docs
area:infra
area:ux
dependencies
documentation
duplicate
good first issue
help wanted
invalid
question
rust
status:complete
status:partial
status:planned
type:bug
type:design
type:feature
type:infra
type:refactor
type:research
type:ux
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
icub3d/decentcom#8
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Migrated from GitHub issue icub3d/decentcom#8
Original Author: @icub3d
Original Date: 2026-04-15T14:15:29Z
Feature: Messages
Overview
Messages are the core content of decentcom. This feature implements sending, receiving, editing, and deleting text messages in channels, along with message history retrieval using cursor-based pagination and real-time delivery through the WebSocket gateway.
Background
The storage design (
docs/design/storage.md) identifies messages as append-heavy with high read volume, recommending indexes on(channel_id, created_at)and cursor-based pagination for fetching recent history. Messages are soft-deleted, never truly removed. The architecture doc (docs/design/architecture.md) places message CRUD in the REST API and real-time delivery in the gateway. The server model (docs/design/server-model.md) definesmax_message_lengthas a configurable content policy. This feature depends on storage (feature 3), auth (feature 5), the gateway (feature 6), and channels (feature 7).Requirements
edited_attimestamp.deletedflag is set, row is retained).max_message_lengthsetting.Design
API / Interface Changes
REST endpoints (all under
/api/v1/):POST/channels/:channel_id/messagesGET/channels/:channel_id/messagesGET/channels/:channel_id/messages/:message_idPATCH/channels/:channel_id/messages/:message_idDELETE/channels/:channel_id/messages/:message_idPagination query parameters for
GET /channels/:channel_id/messages:beforeafterlimitRequest/response bodies:
Gateway events:
MESSAGE_CREATEMESSAGE_UPDATEMESSAGE_DELETE{ "id": "...", "channel_id": "..." }Data Model Changes
messagestable:idchannel_idauthor_pubkeycontentcreated_atedited_atdeleted_atIndexes:
(channel_id, id)-- Primary query path for paginated history (ULID is time-ordered so this is equivalent to ordering by time).(author_pubkey)-- For fetching a user's messages (future use: moderation).Component Changes
New files/modules (server):
server/src/messages/mod.rs-- Module root.server/src/messages/handlers.rs-- axum handlers for message CRUD and history.server/src/messages/models.rs--Message,CreateMessage,UpdateMessage,MessagePagestructs.Storage layer:
server/src/storage/message_store.rs--MessageStoretrait:create_message,get_message,list_messages(with cursor params),update_message,delete_message.server/src/storage/sqlite/messages.rs-- SQLite implementation ofMessageStore.Shared types crate:
shared/src/messages.rs-- Message types and gateway event payloads.Migrations:
server/migrations/NNNN_create_messages.sql-- Createsmessagestable with indexes.Modified files:
server/src/main.rs-- Add message routes to the router.shared/src/gateway.rs-- AddMESSAGE_CREATE,MESSAGE_UPDATE,MESSAGE_DELETEto theOpenum.Task List
Phase A: Data model and storage
messagestable in001_initial.sqlwith index on(channel_id, created_at).Messagemodel struct inserver/src/storage/models.rs.MessageStoretrait inserver/src/storage/traits.rswithbefore-cursor pagination.server/src/storage/sqlite/messages.rs.Phase B: REST API
POST /channels/{channel_id}/messages— validate, insert, broadcastMESSAGE_CREATE.GET /channels/{channel_id}/messages—before/limitpagination withhas_more.GET /channels/{channel_id}/messages/{message_id}— get single message.PATCH /channels/{channel_id}/messages/{message_id}— owner-only edit, broadcastMESSAGE_UPDATE.DELETE /channels/{channel_id}/messages/{message_id}— owner-only soft-delete, broadcastMESSAGE_DELETE.server/src/main.rs(router is composed directly inapp(), noroutes/mod.rsfile exists).Phase C: Shared types and gateway integration
MESSAGE_CREATE,MESSAGE_UPDATE,MESSAGE_DELETEops already in sharedOpenum.Test List
MessageStoreSQLite — create a message, fetch by ID, verify all fields.MessageStorecursor pagination — insert messages, fetch withbeforecursor.MessageStoreaftercursor — deferred (onlybeforeimplemented for now).MessageStoresoft-delete —deletedflag set, row retained, preserved in list as a tombstone.MessageStoreedit — update content, verifyedited_atis set.edited_at; unauthorized edit returns 403.has_more=truewhen more messages exist.has_more: false.MESSAGE_CREATE— deferred.Implementation Notes
server/src/messages/handlers.rsand router wiring is inserver/src/messages/mod.rs+server/src/main.rs.content.max_message_length.aftercursor input is accepted by schema but currently returns HTTP 400 with a clear error (afternot implemented yet); onlybeforeis supported per test plan.AuthUser.user_idwithmessage.author_id; unauthorized edits/deletes return HTTP 403.deleted=1and clearscontentto""; rows remain queryable so pagination cursors remain valid and tombstones are preserved in history.gateway.broadcast_to_channelfor create/update/delete events.Open Questions