From 58e338246f644187190355335e0942913397ef24 Mon Sep 17 00:00:00 2001 From: Myx Date: Sat, 11 Apr 2026 13:39:27 +0200 Subject: [PATCH] refactor: stricter domain: attachments --- toju-app/src/app/domains/attachment/README.md | 45 ++++++++++--------- .../application/attachment.facade.ts | 2 +- .../attachment-manager.service.ts | 12 ++--- .../attachment-persistence.service.ts | 12 ++--- .../attachment-runtime.store.ts | 2 +- .../attachment-transfer-transport.service.ts | 8 ++-- .../attachment-transfer.service.ts | 16 +++---- .../attachment/domain/attachment.logic.ts | 4 +- .../attachment-transfer.constants.ts | 0 .../{ => constants}/attachment.constants.ts | 0 .../attachment-transfer.models.ts | 4 +- .../domain/{ => models}/attachment.models.ts | 2 +- toju-app/src/app/domains/attachment/index.ts | 4 +- .../attachment-storage.service.ts | 6 +-- .../attachment-storage.util.ts} | 0 15 files changed, 60 insertions(+), 57 deletions(-) rename toju-app/src/app/domains/attachment/application/{ => services}/attachment-manager.service.ts (93%) rename toju-app/src/app/domains/attachment/application/{ => services}/attachment-persistence.service.ts (93%) rename toju-app/src/app/domains/attachment/application/{ => services}/attachment-runtime.store.ts (98%) rename toju-app/src/app/domains/attachment/application/{ => services}/attachment-transfer-transport.service.ts (89%) rename toju-app/src/app/domains/attachment/application/{ => services}/attachment-transfer.service.ts (96%) rename toju-app/src/app/domains/attachment/domain/{ => constants}/attachment-transfer.constants.ts (100%) rename toju-app/src/app/domains/attachment/domain/{ => constants}/attachment.constants.ts (100%) rename toju-app/src/app/domains/attachment/domain/{ => models}/attachment-transfer.models.ts (90%) rename toju-app/src/app/domains/attachment/domain/{ => models}/attachment.models.ts (79%) rename toju-app/src/app/domains/attachment/infrastructure/{ => services}/attachment-storage.service.ts (93%) rename toju-app/src/app/domains/attachment/infrastructure/{attachment-storage.helpers.ts => util/attachment-storage.util.ts} (100%) diff --git a/toju-app/src/app/domains/attachment/README.md b/toju-app/src/app/domains/attachment/README.md index c69f966..a39811d 100644 --- a/toju-app/src/app/domains/attachment/README.md +++ b/toju-app/src/app/domains/attachment/README.md @@ -7,25 +7,28 @@ Handles file sharing between peers over WebRTC data channels. Files are announce ``` attachment/ ├── application/ -│ ├── attachment.facade.ts Thin entry point, delegates to manager -│ ├── attachment-manager.service.ts Orchestrates lifecycle, auto-download, peer listeners -│ ├── attachment-transfer.service.ts P2P file transfer protocol (announce/request/chunk/cancel) -│ ├── attachment-transfer-transport.service.ts Base64 encode/decode, chunked streaming -│ ├── attachment-persistence.service.ts DB + filesystem persistence, migration from localStorage -│ └── attachment-runtime.store.ts In-memory signal-based state (Maps for attachments, chunks, pending) +│ ├── attachment.facade.ts Thin entry point, delegates to manager +│ └── services/ +│ ├── attachment-manager.service.ts Orchestrates lifecycle, auto-download, peer listeners +│ ├── attachment-transfer.service.ts P2P file transfer protocol (announce/request/chunk/cancel) +│ ├── attachment-transfer-transport.service.ts Base64 encode/decode, chunked streaming +│ ├── attachment-persistence.service.ts DB + filesystem persistence, migration from localStorage +│ └── attachment-runtime.store.ts In-memory signal-based state (Maps for attachments, chunks, pending) │ ├── domain/ -│ ├── attachment.models.ts Attachment type extending AttachmentMeta with runtime state -│ ├── attachment.logic.ts isAttachmentMedia, shouldAutoRequestWhenWatched, shouldPersistDownloadedAttachment -│ ├── attachment.constants.ts MAX_AUTO_SAVE_SIZE_BYTES = 10 MB -│ ├── attachment-transfer.models.ts Protocol event types (file-announce, file-chunk, file-request, ...) -│ └── attachment-transfer.constants.ts FILE_CHUNK_SIZE_BYTES = 64 KB, EWMA weights, error messages +│ ├── attachment.logic.ts isAttachmentMedia, shouldAutoRequestWhenWatched, shouldPersistDownloadedAttachment +│ ├── models/ +│ │ ├── attachment.models.ts Attachment type extending AttachmentMeta with runtime state +│ │ └── attachment-transfer.models.ts Protocol event types (file-announce, file-chunk, file-request, ...) +│ └── constants/ +│ ├── attachment.constants.ts MAX_AUTO_SAVE_SIZE_BYTES = 10 MB +│ └── attachment-transfer.constants.ts FILE_CHUNK_SIZE_BYTES = 64 KB, EWMA weights, error messages │ ├── infrastructure/ -│ ├── attachment-storage.service.ts Electron filesystem access (save / read / delete) -│ └── attachment-storage.helpers.ts sanitizeAttachmentRoomName, resolveAttachmentStorageBucket +│ ├── attachment-storage.service.ts Electron filesystem access (save / read / delete) +│ └── attachment-storage.util.ts sanitizeAttachmentRoomName, resolveAttachmentStorageBucket │ -└── index.ts Barrel exports +└── index.ts Barrel exports ``` ## Service composition @@ -52,16 +55,16 @@ graph TD Transfer --> Store Persistence --> Storage Persistence --> Store - Storage --> Helpers[attachment-storage.helpers] + Storage --> Helpers[attachment-storage.util] click Facade "application/attachment.facade.ts" "Thin entry point" _blank - click Manager "application/attachment-manager.service.ts" "Orchestrates lifecycle" _blank - click Transfer "application/attachment-transfer.service.ts" "P2P file transfer protocol" _blank - click Transport "application/attachment-transfer-transport.service.ts" "Base64 encode/decode, chunked streaming" _blank - click Persistence "application/attachment-persistence.service.ts" "DB + filesystem persistence" _blank - click Store "application/attachment-runtime.store.ts" "In-memory signal-based state" _blank + click Manager "application/services/attachment-manager.service.ts" "Orchestrates lifecycle" _blank + click Transfer "application/services/attachment-transfer.service.ts" "P2P file transfer protocol" _blank + click Transport "application/services/attachment-transfer-transport.service.ts" "Base64 encode/decode, chunked streaming" _blank + click Persistence "application/services/attachment-persistence.service.ts" "DB + filesystem persistence" _blank + click Store "application/services/attachment-runtime.store.ts" "In-memory signal-based state" _blank click Storage "infrastructure/attachment-storage.service.ts" "Electron filesystem access" _blank - click Helpers "infrastructure/attachment-storage.helpers.ts" "Path helpers" _blank + click Helpers "infrastructure/attachment-storage.util.ts" "Path helpers" _blank click Logic "domain/attachment.logic.ts" "Pure decision functions" _blank ``` diff --git a/toju-app/src/app/domains/attachment/application/attachment.facade.ts b/toju-app/src/app/domains/attachment/application/attachment.facade.ts index 137527f..19fd43b 100644 --- a/toju-app/src/app/domains/attachment/application/attachment.facade.ts +++ b/toju-app/src/app/domains/attachment/application/attachment.facade.ts @@ -1,5 +1,5 @@ import { Injectable, inject } from '@angular/core'; -import { AttachmentManagerService } from './attachment-manager.service'; +import { AttachmentManagerService } from './services/attachment-manager.service'; @Injectable({ providedIn: 'root' }) export class AttachmentFacade { diff --git a/toju-app/src/app/domains/attachment/application/attachment-manager.service.ts b/toju-app/src/app/domains/attachment/application/services/attachment-manager.service.ts similarity index 93% rename from toju-app/src/app/domains/attachment/application/attachment-manager.service.ts rename to toju-app/src/app/domains/attachment/application/services/attachment-manager.service.ts index fc4e730..136e145 100644 --- a/toju-app/src/app/domains/attachment/application/attachment-manager.service.ts +++ b/toju-app/src/app/domains/attachment/application/services/attachment-manager.service.ts @@ -4,18 +4,18 @@ import { inject } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; -import { RealtimeSessionFacade } from '../../../core/realtime'; -import { DatabaseService } from '../../../infrastructure/persistence'; -import { ROOM_URL_PATTERN } from '../../../core/constants'; -import { shouldAutoRequestWhenWatched } from '../domain/attachment.logic'; -import type { Attachment, AttachmentMeta } from '../domain/attachment.models'; +import { RealtimeSessionFacade } from '../../../../core/realtime'; +import { DatabaseService } from '../../../../infrastructure/persistence'; +import { ROOM_URL_PATTERN } from '../../../../core/constants'; +import { shouldAutoRequestWhenWatched } from '../../domain/attachment.logic'; +import type { Attachment, AttachmentMeta } from '../../domain/models/attachment.models'; import type { FileAnnouncePayload, FileCancelPayload, FileChunkPayload, FileNotFoundPayload, FileRequestPayload -} from '../domain/attachment-transfer.models'; +} from '../../domain/models/attachment-transfer.models'; import { AttachmentPersistenceService } from './attachment-persistence.service'; import { AttachmentRuntimeStore } from './attachment-runtime.store'; import { AttachmentTransferService } from './attachment-transfer.service'; diff --git a/toju-app/src/app/domains/attachment/application/attachment-persistence.service.ts b/toju-app/src/app/domains/attachment/application/services/attachment-persistence.service.ts similarity index 93% rename from toju-app/src/app/domains/attachment/application/attachment-persistence.service.ts rename to toju-app/src/app/domains/attachment/application/services/attachment-persistence.service.ts index 329e38e..315f62b 100644 --- a/toju-app/src/app/domains/attachment/application/attachment-persistence.service.ts +++ b/toju-app/src/app/domains/attachment/application/services/attachment-persistence.service.ts @@ -1,12 +1,12 @@ import { Injectable, inject } from '@angular/core'; import { take } from 'rxjs'; import { Store } from '@ngrx/store'; -import { selectCurrentRoomName } from '../../../store/rooms/rooms.selectors'; -import { DatabaseService } from '../../../infrastructure/persistence'; -import { AttachmentStorageService } from '../infrastructure/attachment-storage.service'; -import type { Attachment, AttachmentMeta } from '../domain/attachment.models'; -import { MAX_AUTO_SAVE_SIZE_BYTES } from '../domain/attachment.constants'; -import { LEGACY_ATTACHMENTS_STORAGE_KEY } from '../domain/attachment-transfer.constants'; +import { selectCurrentRoomName } from '../../../../store/rooms/rooms.selectors'; +import { DatabaseService } from '../../../../infrastructure/persistence'; +import { AttachmentStorageService } from '../../infrastructure/services/attachment-storage.service'; +import type { Attachment, AttachmentMeta } from '../../domain/models/attachment.models'; +import { MAX_AUTO_SAVE_SIZE_BYTES } from '../../domain/constants/attachment.constants'; +import { LEGACY_ATTACHMENTS_STORAGE_KEY } from '../../domain/constants/attachment-transfer.constants'; import { AttachmentRuntimeStore } from './attachment-runtime.store'; @Injectable({ providedIn: 'root' }) diff --git a/toju-app/src/app/domains/attachment/application/attachment-runtime.store.ts b/toju-app/src/app/domains/attachment/application/services/attachment-runtime.store.ts similarity index 98% rename from toju-app/src/app/domains/attachment/application/attachment-runtime.store.ts rename to toju-app/src/app/domains/attachment/application/services/attachment-runtime.store.ts index 482b981..3c717b4 100644 --- a/toju-app/src/app/domains/attachment/application/attachment-runtime.store.ts +++ b/toju-app/src/app/domains/attachment/application/services/attachment-runtime.store.ts @@ -1,5 +1,5 @@ import { Injectable, signal } from '@angular/core'; -import type { Attachment } from '../domain/attachment.models'; +import type { Attachment } from '../../domain/models/attachment.models'; @Injectable({ providedIn: 'root' }) export class AttachmentRuntimeStore { diff --git a/toju-app/src/app/domains/attachment/application/attachment-transfer-transport.service.ts b/toju-app/src/app/domains/attachment/application/services/attachment-transfer-transport.service.ts similarity index 89% rename from toju-app/src/app/domains/attachment/application/attachment-transfer-transport.service.ts rename to toju-app/src/app/domains/attachment/application/services/attachment-transfer-transport.service.ts index d7b0494..33ec81b 100644 --- a/toju-app/src/app/domains/attachment/application/attachment-transfer-transport.service.ts +++ b/toju-app/src/app/domains/attachment/application/services/attachment-transfer-transport.service.ts @@ -1,8 +1,8 @@ import { Injectable, inject } from '@angular/core'; -import { RealtimeSessionFacade } from '../../../core/realtime'; -import { AttachmentStorageService } from '../infrastructure/attachment-storage.service'; -import { FILE_CHUNK_SIZE_BYTES } from '../domain/attachment-transfer.constants'; -import { FileChunkEvent } from '../domain/attachment-transfer.models'; +import { RealtimeSessionFacade } from '../../../../core/realtime'; +import { AttachmentStorageService } from '../../infrastructure/services/attachment-storage.service'; +import { FILE_CHUNK_SIZE_BYTES } from '../../domain/constants/attachment-transfer.constants'; +import { FileChunkEvent } from '../../domain/models/attachment-transfer.models'; @Injectable({ providedIn: 'root' }) export class AttachmentTransferTransportService { diff --git a/toju-app/src/app/domains/attachment/application/attachment-transfer.service.ts b/toju-app/src/app/domains/attachment/application/services/attachment-transfer.service.ts similarity index 96% rename from toju-app/src/app/domains/attachment/application/attachment-transfer.service.ts rename to toju-app/src/app/domains/attachment/application/services/attachment-transfer.service.ts index 724d5a5..435f0cb 100644 --- a/toju-app/src/app/domains/attachment/application/attachment-transfer.service.ts +++ b/toju-app/src/app/domains/attachment/application/services/attachment-transfer.service.ts @@ -1,17 +1,17 @@ import { Injectable, inject } from '@angular/core'; -import { recordDebugNetworkFileChunk } from '../../../infrastructure/realtime/logging/debug-network-metrics'; -import { RealtimeSessionFacade } from '../../../core/realtime'; -import { AttachmentStorageService } from '../infrastructure/attachment-storage.service'; -import { MAX_AUTO_SAVE_SIZE_BYTES } from '../domain/attachment.constants'; -import { shouldPersistDownloadedAttachment } from '../domain/attachment.logic'; -import type { Attachment, AttachmentMeta } from '../domain/attachment.models'; +import { recordDebugNetworkFileChunk } from '../../../../infrastructure/realtime/logging/debug-network-metrics'; +import { RealtimeSessionFacade } from '../../../../core/realtime'; +import { AttachmentStorageService } from '../../infrastructure/services/attachment-storage.service'; +import { MAX_AUTO_SAVE_SIZE_BYTES } from '../../domain/constants/attachment.constants'; +import { shouldPersistDownloadedAttachment } from '../../domain/attachment.logic'; +import type { Attachment, AttachmentMeta } from '../../domain/models/attachment.models'; import { ATTACHMENT_TRANSFER_EWMA_CURRENT_WEIGHT, ATTACHMENT_TRANSFER_EWMA_PREVIOUS_WEIGHT, DEFAULT_ATTACHMENT_MIME_TYPE, FILE_NOT_FOUND_REQUEST_ERROR, NO_CONNECTED_PEERS_REQUEST_ERROR -} from '../domain/attachment-transfer.constants'; +} from '../../domain/constants/attachment-transfer.constants'; import { type FileAnnounceEvent, type FileAnnouncePayload, @@ -23,7 +23,7 @@ import { type FileRequestEvent, type FileRequestPayload, type LocalFileWithPath -} from '../domain/attachment-transfer.models'; +} from '../../domain/models/attachment-transfer.models'; import { AttachmentPersistenceService } from './attachment-persistence.service'; import { AttachmentRuntimeStore } from './attachment-runtime.store'; import { AttachmentTransferTransportService } from './attachment-transfer-transport.service'; diff --git a/toju-app/src/app/domains/attachment/domain/attachment.logic.ts b/toju-app/src/app/domains/attachment/domain/attachment.logic.ts index 1cad4d1..f29eec5 100644 --- a/toju-app/src/app/domains/attachment/domain/attachment.logic.ts +++ b/toju-app/src/app/domains/attachment/domain/attachment.logic.ts @@ -1,5 +1,5 @@ -import { MAX_AUTO_SAVE_SIZE_BYTES } from './attachment.constants'; -import type { Attachment } from './attachment.models'; +import { MAX_AUTO_SAVE_SIZE_BYTES } from './constants/attachment.constants'; +import type { Attachment } from './models/attachment.models'; export function isAttachmentMedia(attachment: Pick): boolean { return attachment.mime.startsWith('image/') || diff --git a/toju-app/src/app/domains/attachment/domain/attachment-transfer.constants.ts b/toju-app/src/app/domains/attachment/domain/constants/attachment-transfer.constants.ts similarity index 100% rename from toju-app/src/app/domains/attachment/domain/attachment-transfer.constants.ts rename to toju-app/src/app/domains/attachment/domain/constants/attachment-transfer.constants.ts diff --git a/toju-app/src/app/domains/attachment/domain/attachment.constants.ts b/toju-app/src/app/domains/attachment/domain/constants/attachment.constants.ts similarity index 100% rename from toju-app/src/app/domains/attachment/domain/attachment.constants.ts rename to toju-app/src/app/domains/attachment/domain/constants/attachment.constants.ts diff --git a/toju-app/src/app/domains/attachment/domain/attachment-transfer.models.ts b/toju-app/src/app/domains/attachment/domain/models/attachment-transfer.models.ts similarity index 90% rename from toju-app/src/app/domains/attachment/domain/attachment-transfer.models.ts rename to toju-app/src/app/domains/attachment/domain/models/attachment-transfer.models.ts index 26a5a57..9ac4ef5 100644 --- a/toju-app/src/app/domains/attachment/domain/attachment-transfer.models.ts +++ b/toju-app/src/app/domains/attachment/domain/models/attachment-transfer.models.ts @@ -1,5 +1,5 @@ -import type { ChatEvent } from '../../../shared-kernel'; -import type { ChatAttachmentAnnouncement } from '../../../shared-kernel'; +import type { ChatEvent } from '../../../../shared-kernel'; +import type { ChatAttachmentAnnouncement } from '../../../../shared-kernel'; export type FileAnnounceEvent = ChatEvent & { type: 'file-announce'; diff --git a/toju-app/src/app/domains/attachment/domain/attachment.models.ts b/toju-app/src/app/domains/attachment/domain/models/attachment.models.ts similarity index 79% rename from toju-app/src/app/domains/attachment/domain/attachment.models.ts rename to toju-app/src/app/domains/attachment/domain/models/attachment.models.ts index e838d90..377333d 100644 --- a/toju-app/src/app/domains/attachment/domain/attachment.models.ts +++ b/toju-app/src/app/domains/attachment/domain/models/attachment.models.ts @@ -1,4 +1,4 @@ -import type { ChatAttachmentMeta } from '../../../shared-kernel'; +import type { ChatAttachmentMeta } from '../../../../shared-kernel'; export type AttachmentMeta = ChatAttachmentMeta; diff --git a/toju-app/src/app/domains/attachment/index.ts b/toju-app/src/app/domains/attachment/index.ts index c96e739..5d44444 100644 --- a/toju-app/src/app/domains/attachment/index.ts +++ b/toju-app/src/app/domains/attachment/index.ts @@ -1,3 +1,3 @@ export * from './application/attachment.facade'; -export * from './domain/attachment.constants'; -export * from './domain/attachment.models'; +export * from './domain/constants/attachment.constants'; +export * from './domain/models/attachment.models'; diff --git a/toju-app/src/app/domains/attachment/infrastructure/attachment-storage.service.ts b/toju-app/src/app/domains/attachment/infrastructure/services/attachment-storage.service.ts similarity index 93% rename from toju-app/src/app/domains/attachment/infrastructure/attachment-storage.service.ts rename to toju-app/src/app/domains/attachment/infrastructure/services/attachment-storage.service.ts index f1c7218..26cd69a 100644 --- a/toju-app/src/app/domains/attachment/infrastructure/attachment-storage.service.ts +++ b/toju-app/src/app/domains/attachment/infrastructure/services/attachment-storage.service.ts @@ -1,11 +1,11 @@ import { Injectable, inject } from '@angular/core'; -import { ElectronBridgeService } from '../../../core/platform/electron/electron-bridge.service'; -import type { Attachment } from '../domain/attachment.models'; +import { ElectronBridgeService } from '../../../../core/platform/electron/electron-bridge.service'; +import type { Attachment } from '../../domain/models/attachment.models'; import { resolveAttachmentStorageBucket, resolveAttachmentStoredFilename, sanitizeAttachmentRoomName -} from './attachment-storage.helpers'; +} from '../util/attachment-storage.util'; @Injectable({ providedIn: 'root' }) export class AttachmentStorageService { diff --git a/toju-app/src/app/domains/attachment/infrastructure/attachment-storage.helpers.ts b/toju-app/src/app/domains/attachment/infrastructure/util/attachment-storage.util.ts similarity index 100% rename from toju-app/src/app/domains/attachment/infrastructure/attachment-storage.helpers.ts rename to toju-app/src/app/domains/attachment/infrastructure/util/attachment-storage.util.ts