Send text message (composer, Enter, status indicator) #9

Open
opened 2026-05-14 23:17:16 +02:00 by arne · 0 comments
Owner

Parent

#2

What to build

A textarea composer pinned to the bottom of the thread. Enter sends; Shift+Enter inserts newline. Empty/whitespace input is a no-op. Submitting POSTs through chat.posta.no to posta-server's POST /api/v1/messages with a posta.text/v1 payload. The new bubble renders inline from the response. Outbound bubble shows the pending status indicator (clock); later states (delivered, failed-*) will animate in once Slice 8's SSE arrives. Idempotency-Key header is generated per send to make retries safe.

Acceptance criteria

  • Composer textarea visible in /c/<peer> views, focused on page load
  • Enter submits; Shift+Enter inserts newline
  • Empty/whitespace input is a no-op (no request)
  • Submit POSTs to chat.posta.no, which calls posta-server POST /api/v1/messages with {peer, payload:{kind:"posta.text/v1", body}}
  • Idempotency-Key header generated client-side per send (UUID v4)
  • On 202 from posta-server, an outbound bubble appears in the thread with pending status indicator
  • On 4xx/5xx, an inline error appears under the composer; textarea retains content
  • Status indicators: pending/sending → clock; delivered → check; failed-permanent → red triangle; failed-pending-user → orange triangle
  • Status indicator only on the last outbound bubble in a 2-minute cluster
  • internal/posta client implements SendMessage(ctx, token, serverURL, peer, payload, idempotencyKey)

Blocked by

## Parent #2 ## What to build A textarea composer pinned to the bottom of the thread. Enter sends; Shift+Enter inserts newline. Empty/whitespace input is a no-op. Submitting POSTs through chat.posta.no to posta-server's `POST /api/v1/messages` with a `posta.text/v1` payload. The new bubble renders inline from the response. Outbound bubble shows the `pending` status indicator (clock); later states (`delivered`, `failed-*`) will animate in once Slice 8's SSE arrives. Idempotency-Key header is generated per send to make retries safe. ## Acceptance criteria - [ ] Composer textarea visible in `/c/<peer>` views, focused on page load - [ ] Enter submits; Shift+Enter inserts newline - [ ] Empty/whitespace input is a no-op (no request) - [ ] Submit POSTs to chat.posta.no, which calls posta-server `POST /api/v1/messages` with `{peer, payload:{kind:"posta.text/v1", body}}` - [ ] `Idempotency-Key` header generated client-side per send (UUID v4) - [ ] On 202 from posta-server, an outbound bubble appears in the thread with `pending` status indicator - [ ] On 4xx/5xx, an inline error appears under the composer; textarea retains content - [ ] Status indicators: `pending`/`sending` → clock; `delivered` → check; `failed-permanent` → red triangle; `failed-pending-user` → orange triangle - [ ] Status indicator only on the last outbound bubble in a 2-minute cluster - [ ] `internal/posta` client implements `SendMessage(ctx, token, serverURL, peer, payload, idempotencyKey)` ## Blocked by - #8
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
posta/chat#9
No description provided.