17 — GlobalChat: Messaging UI (iOS + Web)
UI project 4 of 5 · IOS/TheOne/Main/GlobalChat, app/web-platform/app/globalchat
Stack: SwiftUI + Combine + Core Data; React/Next.js with a transport/store/runtime split
Scope: iOS module 75 Swift files ≈ 9,400 lines · web tier with composer, media, search, webrtc, transport, store
Where this sits. The client half of GlobalChat. Two independent implementations of one realtime protocol — which is exactly the situation where client/server contract discipline stops being theoretical.
The web tier's structure
app/web-platform/app/globalchat/
transport/ wire layer — WebSocket, reconnect, framing
store/ client state, ordering, dedupe
runtime/ lifecycle and orchestration
composer/ message composition, attachments, voice
components/ render layer
media/ attachment handling
search/ message search
webrtc/ callController.ts — the media plane
Separating transport / store / runtime / render is the right decomposition for a realtime client. The transport dies constantly; the store must survive it; the render layer should never know a socket exists.
The iOS module — and the correction worth reading
docs/GLOBALCHAT-MODULE-WIRING.md is a wiring record that opens by
retracting three of its own earlier conclusions. That document is a hiring
artifact in its own right:
"I got these wrong first time and they change the picture materially."
-
"The module was never orphaned — it is load-bearing."
GlobalChatServer.swiftdeclares 13 publishers typed withGlobalChatMessage,GlobalChatReceiptEvent,GlobalChatCallLogEntryand 14 other types — every one declared only inside this module. There is no second copy. The module owns model, persistence and view;GlobalChatServerowns transport. -
"The module has been attached in production all along."
TheOneApp.swift:112applies.attachGlobalChat(...)— committed, not added by this work.GlobalChatStore.attachhad been subscribed to all 13 publishers and mirroring live traffic into Core Data on every install. The data layer was wired; only the view layer was never rendered. -
"The attach modifier never had a crash." The earlier claim that nothing injected
GlobalChatServerwas wrong — "my grep looked for a variable namedserver, and it is namedchat."
The real gap, once the false ones were cleared, was narrow and specific: the
outbound path, where GlobalChatStore held a private weak var attachedServer.
Publicly correcting your own analysis, naming the grep that misled you, and then landing a smaller and correct fix is the single most senior-coded behavior in this entire repository.
Feature surface
Attachments (typed), voice messaging, reactions, edits and deletes, view-once
media, live location, typing indicators, read receipts, search, call log, and
an avatar hexagon treatment migrated across the component set. The dating
variant wraps 18 Dating* components in a DatingChatView facade over the
same GlobalChat engine.
WEB_CHAT_RUNBOOK_AND_GAPS.md carries a WhatsApp feature-parity comparison
(present / partial / missing), and
WEB_CHAT_FEATURE_IMPLEMENTATION_PLAN.md turns the gaps into a phased plan
with code-verified backend status, exact file/wire/store changes, effort
sizing, acceptance criteria, and iOS-parity notes.
Interview surface this opens
- Transport / store / render separation in a realtime client
- Message ordering, dedupe, and gap-fill after a reconnect
- Local persistence (Core Data) as a mirror of a server log
- Two clients, one protocol — and how AsyncAPI keeps them honest
- Retracting an analysis in writing when the evidence goes the other way