Submatter/.convoys/workspace-chat-foundation/brief-3-chat-ui.md

55 lines
3.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
brief: 3
convoy: workspace-chat-foundation
role: role-implementer
title: Chat workspace UI and left-rail navigation
status: blocked
priority: P1
slice_dependencies:
- brief-1-chat-persistence
- brief-2-chat-realtime
recommended_model: auto/coding
model_tier: standard
---
# Brief 3 — `Task-chat-ui-and-navigation.md`
## Goal
Expose workspace chat through the existing application shell with accessible channel navigation, durable history/read state, and realtime updates.
## Files
Expected scope; confirm conventions against nearby workspace routes and UI components.
- `apps/web/app/(app)/[workspaceSlug]/chat/page.tsx` — channel selection/redirect or empty state.
- `apps/web/app/(app)/[workspaceSlug]/chat/[channelSlug]/page.tsx` — channel conversation route.
- `apps/web/components/layout/icon-rail.tsx` — Chat destination and accessible unread/mention badge.
- `apps/web/components/chat/` — channel list, paginated message feed, composer, thread affordance, connection state, and retry UI.
- `apps/web/components/providers/` or focused hooks — realtime event reconciliation with tRPC/React Query caches.
- Adjacent component/unit tests.
## Required design
- Server state is authoritative; realtime events invalidate or reconcile durable query data. Foundation UI supports workspace-context channels only; project/object entry points wait for the context authorization task. Never expose unauthorized titles/previews, mention candidates or counts; purge inaccessible cached conversations on denial/revocation. Mention UI must not promise agent addition/execution before its reviewed membership flow exists.
- Ordinary unread activity uses a dot. In this convoy, the numeric badge is computed from persisted message-mention rows above each channel read cursor plus unread direct-channel activity. The later notifications epic adds unified inbox projections without changing the rail contract.
- Unread means a channel's highest message sequence is greater than the member's last-read sequence. Opening a channel does not mark unseen content read until the client intentionally advances the visible boundary.
- Direct-channel unread activity contributes to the numeric Chat badge; ordinary public/private channel activity contributes only the unread dot unless the user is mentioned.
- Optimistic messages and thread replies have deterministic pending, committed, failed, and retry states keyed by the idempotency key.
- History and thread history use per-channel sequence cursor pagination and preserve scroll position while loading older messages.
- Realtime read-state invalidations reconcile rail/channel badges across the user's devices.
- Keyboard and screen-reader behavior cover navigation, unread indicators, composer, threads, and failures.
- Use existing Radix/Tailwind primitives and the current right-panel pattern for a minimally complete thread list/reply surface.
## Acceptance
- A user can enter Chat from the left rail, switch channels, send/retry messages and thread replies, intentionally advance the read boundary, and reload without losing state.
- Realtime messages and replies appear once and per-channel reconnect catch-up converges to server truth.
- Rail/channel unread, direct-message, and mention indicators update across devices after durable mark-read operations.
- Loading, empty, unauthorized, archived, offline, and failed-send states are handled.
- Responsive layout and keyboard navigation work without inaccessible color-only signals.
- `pnpm lint && pnpm type-check && pnpm test` pass.
## Prompt
Read the workspace layout, icon rail, right panel, UI primitives, tRPC provider, and the APIs/events produced by briefs 1–2. Do not add a separate design system or raw internal fetch calls. Keep notification inbox and agent participation out of this slice.