From eb668fd5c848dd226d4992eae268a0cc8d9bea80 Mon Sep 17 00:00:00 2001 From: Schalli Date: Thu, 23 Jul 2026 13:02:15 +0200 Subject: [PATCH] refactor(14-01): extract DKV inbox providers into shared inbox/ module - Move ImapProvider, ExchangeInboxProvider, InboxProvider into apps/api/src/inbox/ - Move InboxConfig/InboxAttachment/InboxEmail into new inbox.types.ts - dkv.types.ts re-exports the moved types so existing DKV imports keep compiling - DKV switches import paths to ../inbox/... and imports InboxModule - Pure move + import-path swap: fetchPdfAttachments and all DKV logic unchanged (D-01/D-02) Co-Authored-By: Claude Opus 4.8 --- apps/api/src/dkv/dkv.module.ts | 11 +-- apps/api/src/dkv/dkv.service.ts | 4 +- apps/api/src/dkv/dkv.types.ts | 48 ++---------- .../exchange-inbox.provider.ts | 0 .../{dkv/providers => inbox}/imap.provider.ts | 0 .../inbox-provider.interface.ts | 2 +- apps/api/src/inbox/inbox.module.ts | 19 +++++ apps/api/src/inbox/inbox.types.ts | 73 +++++++++++++++++++ 8 files changed, 106 insertions(+), 51 deletions(-) rename apps/api/src/{dkv/providers => inbox}/exchange-inbox.provider.ts (100%) rename apps/api/src/{dkv/providers => inbox}/imap.provider.ts (100%) rename apps/api/src/{dkv/providers => inbox}/inbox-provider.interface.ts (94%) create mode 100644 apps/api/src/inbox/inbox.module.ts create mode 100644 apps/api/src/inbox/inbox.types.ts diff --git a/apps/api/src/dkv/dkv.module.ts b/apps/api/src/dkv/dkv.module.ts index ead5268..666e292 100644 --- a/apps/api/src/dkv/dkv.module.ts +++ b/apps/api/src/dkv/dkv.module.ts @@ -2,6 +2,7 @@ import { Logger, Module, OnModuleInit } from '@nestjs/common'; import { ModuleRegistryModule } from '../module-registry/module-registry.module'; import { ModuleRegistryService } from '../module-registry/module-registry.service'; import { CalendarModule } from '../calendar/calendar.module'; +import { InboxModule } from '../inbox/inbox.module'; import { SettingsModule } from '../settings/settings.module'; import { DkvController } from './dkv.controller'; import { DkvExportService } from './dkv-export.service'; @@ -9,8 +10,6 @@ import { DkvMailService } from './dkv-mail.service'; import { DkvParserService } from './dkv-parser.service'; import { DkvSchedulerService } from './dkv-scheduler.service'; import { DkvService } from './dkv.service'; -import { ExchangeInboxProvider } from './providers/exchange-inbox.provider'; -import { ImapProvider } from './providers/imap.provider'; import { seedDkvModule } from './dkv.seed'; /** @@ -22,12 +21,15 @@ import { seedDkvModule } from './dkv.seed'; * - DkvParserService: pdf-parse v2 text extraction + DKV-specific regex * - DkvExportService: xlsx buffer generation + user-files/ management * - DkvMailService: nodemailer.createTransport() at send time - * - ImapProvider / ExchangeInboxProvider: inbox access providers + * - ImapProvider / ExchangeInboxProvider: inbox access providers, now imported + * from the shared InboxModule (D-01, Phase 14 inbox extraction) * * Imports: * - ModuleRegistryModule: for registry self-seed on init * - CalendarModule: provides CalendarCryptoService (AES-256-GCM encryption) * re-exported from CalendarModule.exports — no re-declaration needed here. + * - InboxModule: exports ImapProvider / ExchangeInboxProvider (shared connection + * mechanics — DKV's own mailbox config stays independent, D-03) * * PrismaModule is global (no explicit import needed). * ScheduleModule.forRoot() was registered in AppModule by Plan 01. @@ -40,6 +42,7 @@ import { seedDkvModule } from './dkv.seed'; imports: [ ModuleRegistryModule, CalendarModule, + InboxModule, SettingsModule, ], controllers: [DkvController], @@ -49,8 +52,6 @@ import { seedDkvModule } from './dkv.seed'; DkvParserService, DkvExportService, DkvMailService, - ImapProvider, - ExchangeInboxProvider, ], exports: [DkvService], }) diff --git a/apps/api/src/dkv/dkv.service.ts b/apps/api/src/dkv/dkv.service.ts index 61a352c..d9e18e4 100644 --- a/apps/api/src/dkv/dkv.service.ts +++ b/apps/api/src/dkv/dkv.service.ts @@ -13,8 +13,8 @@ import { DkvMailService } from './dkv-mail.service'; import { DkvParserService } from './dkv-parser.service'; import { DkvConfigDto } from './dto/dkv-config.dto'; import { CreateVehicleDto, UpdateVehicleDto } from './dto/dkv-vehicle.dto'; -import { ExchangeInboxProvider } from './providers/exchange-inbox.provider'; -import { ImapProvider } from './providers/imap.provider'; +import { ExchangeInboxProvider } from '../inbox/exchange-inbox.provider'; +import { ImapProvider } from '../inbox/imap.provider'; import type { DkvVehicleBlock, InboxConfig, InboxEmail } from './dkv.types'; /** diff --git a/apps/api/src/dkv/dkv.types.ts b/apps/api/src/dkv/dkv.types.ts index 2560d95..53ac82a 100644 --- a/apps/api/src/dkv/dkv.types.ts +++ b/apps/api/src/dkv/dkv.types.ts @@ -41,50 +41,12 @@ export interface DkvVehicleBlock { } /** - * Inbox connection configuration (supports IMAP and Exchange). - * Mirrors DkvModuleConfig from Prisma but with decrypted credentials. + * Inbox connection types (InboxConfig/InboxAttachment/InboxEmail) moved to + * the shared apps/api/src/inbox/ module (D-01, Phase 14 inbox extraction). + * Re-exported here so every existing DKV import path keeps compiling + * unchanged — DKV behavior is byte-identical after the move. */ -export interface InboxConfig { - /** 'imap' | 'exchange' */ - protocol: string; - host: string; - port: number; - /** Optional username (may be empty for anonymous or Exchange-with-integrated-auth) */ - username?: string; - /** Decrypted password (never persisted in this form) */ - password?: string; - /** 'none' | 'starttls' | 'ssl-tls' */ - encryption: string; - /** IMAP folder to monitor (e.g., "INBOX") */ - folder: string; - /** Sender filter: only process emails from this address */ - senderFilter?: string; - /** Exchange only: Windows domain (e.g. "CONTOSO") */ - domain?: string; -} - -/** - * A single email attachment, already downloaded as a Buffer. - */ -export interface InboxAttachment { - filename: string; - contentType: string; - buffer: Buffer; -} - -/** - * A fetched email message with its PDF attachments. - */ -export interface InboxEmail { - /** IMAP UID or Exchange item ID */ - uid: number | string; - /** RFC 2822 Message-ID header */ - messageId: string; - subject: string; - from: string; - date: Date; - attachments: InboxAttachment[]; -} +export type { InboxConfig, InboxAttachment, InboxEmail } from '../inbox/inbox.types'; /** * A single row in the Excel export (5 columns per D-13). diff --git a/apps/api/src/dkv/providers/exchange-inbox.provider.ts b/apps/api/src/inbox/exchange-inbox.provider.ts similarity index 100% rename from apps/api/src/dkv/providers/exchange-inbox.provider.ts rename to apps/api/src/inbox/exchange-inbox.provider.ts diff --git a/apps/api/src/dkv/providers/imap.provider.ts b/apps/api/src/inbox/imap.provider.ts similarity index 100% rename from apps/api/src/dkv/providers/imap.provider.ts rename to apps/api/src/inbox/imap.provider.ts diff --git a/apps/api/src/dkv/providers/inbox-provider.interface.ts b/apps/api/src/inbox/inbox-provider.interface.ts similarity index 94% rename from apps/api/src/dkv/providers/inbox-provider.interface.ts rename to apps/api/src/inbox/inbox-provider.interface.ts index e372da7..ca0205b 100644 --- a/apps/api/src/dkv/providers/inbox-provider.interface.ts +++ b/apps/api/src/inbox/inbox-provider.interface.ts @@ -1,4 +1,4 @@ -import { InboxAttachment, InboxConfig, InboxEmail } from '../dkv.types'; +import { InboxAttachment, InboxConfig, InboxEmail } from './inbox.types'; // Re-export types for downstream consumers that import from this module export type { InboxAttachment, InboxConfig, InboxEmail }; diff --git a/apps/api/src/inbox/inbox.module.ts b/apps/api/src/inbox/inbox.module.ts new file mode 100644 index 0000000..feb944a --- /dev/null +++ b/apps/api/src/inbox/inbox.module.ts @@ -0,0 +1,19 @@ +import { Module } from '@nestjs/common'; +import { ExchangeInboxProvider } from './exchange-inbox.provider'; +import { ImapProvider } from './imap.provider'; + +/** + * Shared inbox-connection module (IMAP/Exchange). + * + * Extracted out of DKV (D-01, 14-CONTEXT.md) so any module that needs to + * poll a mailbox — e.g. the Phase-14 EmailAlertAdapter (Plan 14-03) — can + * import InboxModule and inject ImapProvider / ExchangeInboxProvider without + * depending on DKV. DKV imports this module unchanged in behavior; each + * module keeps its own, independent mailbox configuration (D-03) — only the + * connection code is shared. + */ +@Module({ + providers: [ImapProvider, ExchangeInboxProvider], + exports: [ImapProvider, ExchangeInboxProvider], +}) +export class InboxModule {} diff --git a/apps/api/src/inbox/inbox.types.ts b/apps/api/src/inbox/inbox.types.ts new file mode 100644 index 0000000..688b5ce --- /dev/null +++ b/apps/api/src/inbox/inbox.types.ts @@ -0,0 +1,73 @@ +/** + * Shared types for the inbox module (IMAP/Exchange connection mechanics). + * + * Moved verbatim out of apps/api/src/dkv/dkv.types.ts as part of the + * Phase 14 inbox-module extraction (D-01/D-02, 14-CONTEXT.md). DKV re-exports + * these from ../inbox/inbox.types so existing DKV imports keep compiling. + */ + +/** + * Inbox connection configuration (supports IMAP and Exchange). + * Mirrors DkvModuleConfig from Prisma but with decrypted credentials. + */ +export interface InboxConfig { + /** 'imap' | 'exchange' */ + protocol: string; + host: string; + port: number; + /** Optional username (may be empty for anonymous or Exchange-with-integrated-auth) */ + username?: string; + /** Decrypted password (never persisted in this form) */ + password?: string; + /** 'none' | 'starttls' | 'ssl-tls' */ + encryption: string; + /** IMAP folder to monitor (e.g., "INBOX") */ + folder: string; + /** Sender filter: only process emails from this address */ + senderFilter?: string; + /** Exchange only: Windows domain (e.g. "CONTOSO") */ + domain?: string; +} + +/** + * A single email attachment, already downloaded as a Buffer. + */ +export interface InboxAttachment { + filename: string; + contentType: string; + buffer: Buffer; +} + +/** + * A fetched email message with its PDF attachments. + */ +export interface InboxEmail { + /** IMAP UID or Exchange item ID */ + uid: number | string; + /** RFC 2822 Message-ID header */ + messageId: string; + subject: string; + from: string; + date: Date; + attachments: InboxAttachment[]; +} + +/** + * A single fetched message with subject + HTML/text body (no attachments). + * + * Added additively (D-02) as the seam Plan 14-03's EmailAlertAdapter consumes + * via InboxProvider.fetchMessages — DKV's fetchPdfAttachments is unaffected. + */ +export interface InboxMessage { + /** IMAP UID or Exchange item ID */ + uid: number | string; + /** RFC 2822 Message-ID header */ + messageId: string; + subject: string; + from: string; + date: Date; + /** HTML body part, or null when the message has no text/html part */ + bodyHtml: string | null; + /** Plain-text body part; empty string when the message has no text/plain part */ + bodyText: string; +}