Move toju-app into own its folder
This commit is contained in:
143
toju-app/src/app/domains/chat/README.md
Normal file
143
toju-app/src/app/domains/chat/README.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Chat Domain
|
||||
|
||||
Text messaging, reactions, GIF search, typing indicators, and the user list. All UI is under `feature/`; application services handle GIF integration; domain rules govern message editing, deletion, and sync.
|
||||
|
||||
## Module map
|
||||
|
||||
```
|
||||
chat/
|
||||
├── application/
|
||||
│ └── klipy.service.ts GIF search via the KLIPY API (proxied through the server)
|
||||
│
|
||||
├── domain/
|
||||
│ ├── message.rules.ts canEditMessage, normaliseDeletedMessage, getMessageTimestamp
|
||||
│ └── message-sync.rules.ts Inventory-based sync: chunkArray, findMissingIds, limits
|
||||
│
|
||||
├── feature/
|
||||
│ ├── chat-messages/ Main chat view (orchestrates composer, list, overlays)
|
||||
│ │ ├── chat-messages.component.ts Root component: replies, GIF picker, reactions, drag-drop
|
||||
│ │ ├── components/
|
||||
│ │ │ ├── message-composer/ Markdown toolbar, file drag-drop, send
|
||||
│ │ │ ├── message-item/ Single message bubble with edit/delete/react
|
||||
│ │ │ ├── message-list/ Paginated list (50 msgs/page), auto-scroll, Prism highlighting
|
||||
│ │ │ └── message-overlays/ Context menus, reaction picker, reply preview
|
||||
│ │ ├── models/ View models for messages
|
||||
│ │ └── services/
|
||||
│ │ └── chat-markdown.service.ts Markdown-to-HTML rendering
|
||||
│ │
|
||||
│ ├── klipy-gif-picker/ GIF search/browse picker panel
|
||||
│ ├── typing-indicator/ "X is typing..." display (3 s TTL, max 4 names)
|
||||
│ └── user-list/ Online user sidebar
|
||||
│
|
||||
└── index.ts Barrel exports
|
||||
```
|
||||
|
||||
## Component composition
|
||||
|
||||
`ChatMessagesComponent` is the root of the chat view. It renders the message list, composer, and overlays as child components and coordinates cross-cutting interactions like replying to a message or inserting a GIF.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Chat[ChatMessagesComponent]
|
||||
List[MessageListComponent]
|
||||
Composer[MessageComposerComponent]
|
||||
Overlays[MessageOverlays]
|
||||
Item[MessageItemComponent]
|
||||
GIF[KlipyGifPickerComponent]
|
||||
Typing[TypingIndicatorComponent]
|
||||
Users[UserListComponent]
|
||||
|
||||
Chat --> List
|
||||
Chat --> Composer
|
||||
Chat --> Overlays
|
||||
Chat --> GIF
|
||||
List --> Item
|
||||
Item --> Overlays
|
||||
|
||||
click Chat "feature/chat-messages/chat-messages.component.ts" "Root chat view" _blank
|
||||
click List "feature/chat-messages/components/message-list/" "Paginated message list" _blank
|
||||
click Composer "feature/chat-messages/components/message-composer/" "Markdown toolbar + send" _blank
|
||||
click Overlays "feature/chat-messages/components/message-overlays/" "Context menus, reaction picker" _blank
|
||||
click Item "feature/chat-messages/components/message-item/" "Single message bubble" _blank
|
||||
click GIF "feature/klipy-gif-picker/" "GIF search panel" _blank
|
||||
click Typing "feature/typing-indicator/" "Typing indicator" _blank
|
||||
click Users "feature/user-list/" "Online user sidebar" _blank
|
||||
```
|
||||
|
||||
## Message lifecycle
|
||||
|
||||
Messages are created in the composer, broadcast to peers over the data channel, and rendered in the list. Editing and deletion are sender-only operations.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Composer as MessageComposer
|
||||
participant Store as NgRx Store
|
||||
participant DC as Data Channel
|
||||
participant Peer as Remote Peer
|
||||
|
||||
User->>Composer: Type + send
|
||||
Composer->>Store: dispatch addMessage
|
||||
Composer->>DC: broadcastMessage(chat-message)
|
||||
DC->>Peer: chat-message event
|
||||
|
||||
Note over User: Edit
|
||||
User->>Store: dispatch editMessage
|
||||
User->>DC: broadcastMessage(edit-message)
|
||||
|
||||
Note over User: Delete
|
||||
User->>Store: dispatch deleteMessage (normaliseDeletedMessage)
|
||||
User->>DC: broadcastMessage(delete-message)
|
||||
```
|
||||
|
||||
## Message sync
|
||||
|
||||
When a peer connects (or reconnects), both sides exchange an inventory of their recent messages so each can request anything it missed. The inventory is capped at 1 000 messages and sent in chunks of 200.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant A as Peer A
|
||||
participant B as Peer B
|
||||
|
||||
A->>B: inventory (up to 1000 msg IDs + timestamps)
|
||||
B->>B: findMissingIds(remote, local)
|
||||
B->>A: request missing message IDs
|
||||
A->>B: message payloads (chunked, 200/batch)
|
||||
```
|
||||
|
||||
`findMissingIds` compares each remote item's timestamp and reaction/attachment counts against the local map. Any item that is missing, newer, or has different counts is requested.
|
||||
|
||||
## GIF integration
|
||||
|
||||
`KlipyService` checks availability on the active server, then proxies search requests through the server API. Images are rendered via an image proxy endpoint to avoid mixed-content issues.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Picker[KlipyGifPickerComponent]
|
||||
Klipy[KlipyService]
|
||||
SD[ServerDirectoryFacade]
|
||||
API[Server API]
|
||||
|
||||
Picker --> Klipy
|
||||
Klipy --> SD
|
||||
Klipy --> API
|
||||
|
||||
click Picker "feature/klipy-gif-picker/" "GIF search panel" _blank
|
||||
click Klipy "application/klipy.service.ts" "GIF search via KLIPY API" _blank
|
||||
click SD "../server-directory/application/server-directory.facade.ts" "Resolves API base URL" _blank
|
||||
```
|
||||
|
||||
## Domain rules
|
||||
|
||||
| Function | Purpose |
|
||||
|---|---|
|
||||
| `canEditMessage(msg, userId)` | Only the sender can edit their own message |
|
||||
| `normaliseDeletedMessage(msg)` | Strips content and reactions from deleted messages |
|
||||
| `getMessageTimestamp(msg)` | Returns `editedAt` if present, otherwise `timestamp` |
|
||||
| `getLatestTimestamp(msgs)` | Max timestamp across a batch, used for sync ordering |
|
||||
| `chunkArray(items, size)` | Splits arrays into fixed-size chunks for batched transfer |
|
||||
| `findMissingIds(remote, local)` | Compares inventories and returns IDs to request |
|
||||
|
||||
## Typing indicator
|
||||
|
||||
`TypingIndicatorComponent` listens for typing events from peers. Each event resets a 3-second TTL timer. If no new event arrives within 3 seconds, the user is removed from the typing list. At most 4 names are shown; beyond that it displays "N users are typing".
|
||||
Reference in New Issue
Block a user