refactor: stricter domain: chat

This commit is contained in:
2026-04-11 14:01:19 +02:00
parent 39b85e2e3a
commit 98ed8eeb68
16 changed files with 34 additions and 29 deletions

View File

@@ -7,11 +7,14 @@ Text messaging, reactions, GIF search, typing indicators, and the user list. All
```
chat/
├── application/
│ └── klipy.service.ts GIF search via the KLIPY API (proxied through the server)
│ └── services/
│ ├── klipy.service.ts GIF search via the KLIPY API (proxied through the server)
│ └── link-metadata.service.ts Link preview metadata fetching
├── domain/
── message.rules.ts canEditMessage, normaliseDeletedMessage, getMessageTimestamp
── message-sync.rules.ts Inventory-based sync: chunkArray, findMissingIds, limits
── rules/
── 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)
@@ -25,6 +28,7 @@ chat/
│ │ └── services/
│ │ └── chat-markdown.service.ts Markdown-to-HTML rendering
│ │
│ ├── chat-image-proxy-fallback.directive.ts Image proxy fallback for broken URLs
│ ├── 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
@@ -129,7 +133,7 @@ graph LR
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 Klipy "application/services/klipy.service.ts" "GIF search via KLIPY API" _blank
click SD "../server-directory/application/server-directory.facade.ts" "Resolves API base URL" _blank
```

View File

@@ -13,7 +13,7 @@ import {
throwError
} from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { ServerDirectoryFacade } from '../../server-directory';
import { ServerDirectoryFacade } from '../../../server-directory';
export interface KlipyGif {
id: string;

View File

@@ -1,8 +1,8 @@
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';
import { ServerDirectoryFacade } from '../../server-directory';
import { LinkMetadata } from '../../../shared-kernel';
import { ServerDirectoryFacade } from '../../../server-directory';
import { LinkMetadata } from '../../../../shared-kernel';
const URL_PATTERN = /https?:\/\/[^\s<>)"']+/g;

View File

@@ -1,4 +1,4 @@
import { DELETED_MESSAGE_CONTENT, type Message } from '../../../shared-kernel';
import { DELETED_MESSAGE_CONTENT, type Message } from '../../../../shared-kernel';
/** Extracts the effective timestamp from a message (editedAt takes priority). */
export function getMessageTimestamp(msg: Message): number {

View File

@@ -7,7 +7,7 @@ import {
input,
signal
} from '@angular/core';
import { KlipyService } from '../application/klipy.service';
import { KlipyService } from '../application/services/klipy.service';
@Directive({
selector: 'img[appChatImageProxyFallback]',

View File

@@ -11,7 +11,7 @@ import { Store } from '@ngrx/store';
import { ElectronBridgeService } from '../../../../core/platform/electron/electron-bridge.service';
import { RealtimeSessionFacade } from '../../../../core/realtime';
import { Attachment, AttachmentFacade } from '../../../attachment';
import { KlipyGif } from '../../application/klipy.service';
import { KlipyGif } from '../../application/services/klipy.service';
import { MessagesActions } from '../../../../store/messages/messages.actions';
import {
selectAllMessages,
@@ -33,7 +33,7 @@ import {
ChatMessageImageContextMenuEvent,
ChatMessageReactionEvent,
ChatMessageReplyEvent
} from './models/chat-messages.models';
} from './models/chat-messages.model';
@Component({
selector: 'app-chat-messages',

View File

@@ -21,12 +21,12 @@ import {
} from '@ng-icons/lucide';
import type { ClipboardFilePayload } from '../../../../../../core/platform/electron/electron-api.models';
import { ElectronBridgeService } from '../../../../../../core/platform/electron/electron-bridge.service';
import { KlipyGif, KlipyService } from '../../../../application/klipy.service';
import { KlipyGif, KlipyService } from '../../../../application/services/klipy.service';
import { Message } from '../../../../../../shared-kernel';
import { ChatImageProxyFallbackDirective } from '../../../chat-image-proxy-fallback.directive';
import { TypingIndicatorComponent } from '../../../typing-indicator/typing-indicator.component';
import { ChatMarkdownService } from '../../services/chat-markdown.service';
import { ChatMessageComposerSubmitEvent } from '../../models/chat-messages.models';
import { ChatMessageComposerSubmitEvent } from '../../models/chat-messages.model';
type LocalFileWithPath = File & {
path?: string;

View File

@@ -29,7 +29,7 @@ import {
AttachmentFacade,
MAX_AUTO_SAVE_SIZE_BYTES
} from '../../../../../attachment';
import { KlipyService } from '../../../../application/klipy.service';
import { KlipyService } from '../../../../application/services/klipy.service';
import { DELETED_MESSAGE_CONTENT, Message } from '../../../../../../shared-kernel';
import {
ChatAudioPlayerComponent,
@@ -45,7 +45,7 @@ import {
ChatMessageImageContextMenuEvent,
ChatMessageReactionEvent,
ChatMessageReplyEvent
} from '../../models/chat-messages.models';
} from '../../models/chat-messages.model';
const COMMON_EMOJIS = [
'👍',

View File

@@ -13,7 +13,7 @@ import {
signal
} from '@angular/core';
import { Attachment } from '../../../../../attachment';
import { getMessageTimestamp } from '../../../../domain/message.rules';
import { getMessageTimestamp } from '../../../../domain/rules/message.rules';
import { Message } from '../../../../../../shared-kernel';
import {
ChatMessageDeleteEvent,
@@ -22,7 +22,7 @@ import {
ChatMessageImageContextMenuEvent,
ChatMessageReactionEvent,
ChatMessageReplyEvent
} from '../../models/chat-messages.models';
} from '../../models/chat-messages.model';
import { ChatMessageItemComponent } from '../message-item/chat-message-item.component';
interface PrismGlobal {

View File

@@ -12,7 +12,7 @@ import {
} from '@ng-icons/lucide';
import { Attachment } from '../../../../../attachment';
import { ContextMenuComponent } from '../../../../../../shared';
import { ChatMessageImageContextMenuEvent } from '../../models/chat-messages.models';
import { ChatMessageImageContextMenuEvent } from '../../models/chat-messages.model';
@Component({
selector: 'app-chat-message-overlays',

View File

@@ -20,7 +20,7 @@ import {
lucideSearch,
lucideX
} from '@ng-icons/lucide';
import { KlipyGif, KlipyService } from '../../application/klipy.service';
import { KlipyGif, KlipyService } from '../../application/services/klipy.service';
import { ChatImageProxyFallbackDirective } from '../chat-image-proxy-fallback.directive';
const KLIPY_CARD_MIN_WIDTH = 140;

View File

@@ -1,6 +1,7 @@
export * from './application/klipy.service';
export * from './domain/message.rules';
export * from './domain/message-sync.rules';
export * from './application/services/klipy.service';
export * from './application/services/link-metadata.service';
export * from './domain/rules/message.rules';
export * from './domain/rules/message-sync.rules';
export { ChatMessagesComponent } from './feature/chat-messages/chat-messages.component';
export { TypingIndicatorComponent } from './feature/typing-indicator/typing-indicator.component';
export { KlipyGifPickerComponent } from './feature/klipy-gif-picker/klipy-gif-picker.component';