Modern UI: React 19 + shadcn rewrite with messenger features (typing, unread, read receipts)#6
Open
iwanmitowski wants to merge 9 commits into
Open
Conversation
- Contracts: RoomReadEvent + chat.room-read topic (kafka-init line; keyed by roomId like the other chat topics) - Realtime hub: Typing() transient broadcast to OthersInGroup; MarkRead() publishes RoomReadEvent (durable) then broadcasts ReadReceipt (live); ReceiveMessage now carries the server-assigned message Id; 1:1 messages additionally push MessageNotification to the peer via Clients.User so unread badges/toasts work without being joined to the room group - Chat: room_reads watermark table (RoomId,UserId -> LastReadAt; deliberately not per-message rows because messages has a composite partitioned PK), RoomReadConsumer (forward-only upsert, naturally idempotent), POST api/chat/summaries (last message + unreadCount + peerLastReadAt per authorized room; peer resolved from the provisioned Room row), message Id added to the history projection - Tests: 4 new (summary math, no-watermark case, authorization omission + public-room null peer read, consumer watermark never regresses) -> 41 total - Smoke test extended: second hub connection as the peer verifies typing, live ReadReceipt, and the Kafka-persisted read state via summaries. Full 24-step run PASSED against the compose stack. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dcn/ui) web/ replaces the CRA app (old tree removed at ship time): - Tailwind v4 CSS-first theme: dark-first oklch tokens, rose->amber brand gradient, Inter, safe-area/gradient utilities; shadcn components incl. the June-2026 chat primitives (message-scroller/message/bubble/attachment/marker) - typed API layer mirroring every service contract (multipart field names Image/NewImages/Images-as-JSON/file preserved), axios with the silent 401->refreshToken replay; auth store keeps the legacy localStorage auth key the interceptor + hub token factory read - app-level SignalR core: one connection per session, events fan into the TanStack Query cache (ReceiveMessage dedupes optimistic bubbles by id, ReadReceipt patches summaries) and sonner (custom match + message toasts that navigate); transient signals (typing/presence) via a tiny typed emitter - app shell: desktop rail + mobile bottom tabs with live unread badge, theme toggle, guards, router (exported instance so toasts can navigate), shared useConversations hook (matches x summaries join) - login page (RHF + zod); stub pages for the parallel feature builds - npm run build green (tsc + vite) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3-step register wizard (account -> about you -> photos & terms) with per-step zod validation, direction-aware motion transitions, geo selects, photo picker with profile-pic star and object-URL hygiene, condensed T&C dialog; verify page (token + resend modes); dual-mode reset page. Same multipart contract as the old app via the typed API client. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
motion v12 fling deck (drag rotation, LIKE/NOPE stamps, velocity/offset thresholds, stacked peek that promotes without remounting), tap-through photo carousel, distance chip, action bar sharing the drag code path, preferences sheet writing live to the persisted store, match overlay with Send-a-message CTA, admin redirect, skeleton/empty states. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Conversation list (matches x summaries: previews, unread badges, live typing flash, communities section) + thread on the shadcn chat primitives: anchored scroller with preserved prepend position, day markers, 5-minute sender grouping, optimistic send swapped for the hub echo, paste/attach image upload-then-send, throttled typing signals, markRead on view with live seen ticks (summaries cache + ReadReceipt events), join/leave markers and presence panel for public rooms, reconnect re-join. Mobile stacked views. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Profile: photo manager (star/trash/add with single profile-pic invariant) + details form, cache-patching save. Admin: stat-card dashboard linking into a users data table with debounced search, All/Banned tabs synced to the URL, infinite pages, ban/unban dialog patching cached rows. Landing: gradient hero, feature cards, advice strip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- web/ multi-stage Dockerfile (node build -> nginx static, SPA fallback, immutable asset caching); compose frontend service now serves nginx on 3000 - smoke-test hub probe moved to a disposable node container on the compose network (the frontend container no longer ships node); full 25-step run PASSED against the new stack - Web-FrontEnd (CRA) deleted; README stack/tests refreshed (41 tests, regenerated capture) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Like/Pass action bar drove the top card through one shared ref, but with AnimatePresence the outgoing card unmounts ~120ms AFTER its successor mounts, so the old card's imperative-handle cleanup nulled the ref the new top card had just populated - every button click after the first swipe hit null and silently did nothing. Replaced with ownership-checked registration: the top card registers a swipe handle on mount and its cleanup only clears the slot if it still owns it. Verified with a Playwright probe against the built container: consecutive Like/Pass clicks both advance the deck; 61fps idle and mid-drag at 4x CPU throttle, zero leaked animations (playwright added as a devDependency). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
About now credits the refactor as a Claude Fable 5 test; new section walks every communication path: SPA->gateway (REST + websocket), the single HTTP fan-out, the Kafka topic table (producer->consumers, keys, outbox/inbox semantics), Redis backplane/presence, database-per-service, external integrations, and local JWT validation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Modernizes the SPA on the current 2026 stack and adds full messenger depth (typing indicators, unread badges, read receipts) on top of the microservices backend from #5. Stacked on
feature/microservices— merge #5 first.Frontend rewrite (
web/, replaces the CRAWeb-FrontEnd/)Stack: Vite + React 19 + TypeScript · Tailwind CSS v4 (CSS-first, oklch tokens) + shadcn/ui incl. the June-2026 chat primitives ·
motionv12 · sonner · TanStack Query v5 (+ react-virtual) · react-router 7 · react-hook-form + zod · Zustand. Served by nginx from a multi-stage Docker build (dev-server container retired).MatchReceivedpush finally has a consumer) and new-message toasts that navigate; live nav unread badge; reconnect indicator.Backend additions (B1)
Typing(transient),MarkRead(Kafka-durable + liveReadReceipt), server messageIdnow included inReceiveMessage, and a directMessageNotificationpush to the 1:1 peer so unread badges work without joining the room group.room_readswatermark table +chat.room-readconsumer (forward-only, idempotent),POST api/chat/summaries(last message, unread count, peer read state per authorized room), messageIdexposed in history.chat.room-readtopic (kafka-init + contracts). 4 new tests → 41 total.Verification
dotnet test LoveNet.sln— 41/41 green.scripts/smoke-test.ps1— extended to 25 steps (typing signal, live read receipt, Kafka-persisted watermark via summaries) — PASSED against the full compose stack with the new nginx frontend.npm run buildclean (tsc strict + vite).🤖 Generated with Claude Code