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 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 13:02:15 +02:00
parent 9dd5038575
commit eb668fd5c8
8 changed files with 106 additions and 51 deletions
+6 -5
View File
@@ -2,6 +2,7 @@ import { Logger, Module, OnModuleInit } from '@nestjs/common';
import { ModuleRegistryModule } from '../module-registry/module-registry.module'; import { ModuleRegistryModule } from '../module-registry/module-registry.module';
import { ModuleRegistryService } from '../module-registry/module-registry.service'; import { ModuleRegistryService } from '../module-registry/module-registry.service';
import { CalendarModule } from '../calendar/calendar.module'; import { CalendarModule } from '../calendar/calendar.module';
import { InboxModule } from '../inbox/inbox.module';
import { SettingsModule } from '../settings/settings.module'; import { SettingsModule } from '../settings/settings.module';
import { DkvController } from './dkv.controller'; import { DkvController } from './dkv.controller';
import { DkvExportService } from './dkv-export.service'; import { DkvExportService } from './dkv-export.service';
@@ -9,8 +10,6 @@ import { DkvMailService } from './dkv-mail.service';
import { DkvParserService } from './dkv-parser.service'; import { DkvParserService } from './dkv-parser.service';
import { DkvSchedulerService } from './dkv-scheduler.service'; import { DkvSchedulerService } from './dkv-scheduler.service';
import { DkvService } from './dkv.service'; import { DkvService } from './dkv.service';
import { ExchangeInboxProvider } from './providers/exchange-inbox.provider';
import { ImapProvider } from './providers/imap.provider';
import { seedDkvModule } from './dkv.seed'; import { seedDkvModule } from './dkv.seed';
/** /**
@@ -22,12 +21,15 @@ import { seedDkvModule } from './dkv.seed';
* - DkvParserService: pdf-parse v2 text extraction + DKV-specific regex * - DkvParserService: pdf-parse v2 text extraction + DKV-specific regex
* - DkvExportService: xlsx buffer generation + user-files/ management * - DkvExportService: xlsx buffer generation + user-files/ management
* - DkvMailService: nodemailer.createTransport() at send time * - 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: * Imports:
* - ModuleRegistryModule: for registry self-seed on init * - ModuleRegistryModule: for registry self-seed on init
* - CalendarModule: provides CalendarCryptoService (AES-256-GCM encryption) * - CalendarModule: provides CalendarCryptoService (AES-256-GCM encryption)
* re-exported from CalendarModule.exports — no re-declaration needed here. * 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). * PrismaModule is global (no explicit import needed).
* ScheduleModule.forRoot() was registered in AppModule by Plan 01. * ScheduleModule.forRoot() was registered in AppModule by Plan 01.
@@ -40,6 +42,7 @@ import { seedDkvModule } from './dkv.seed';
imports: [ imports: [
ModuleRegistryModule, ModuleRegistryModule,
CalendarModule, CalendarModule,
InboxModule,
SettingsModule, SettingsModule,
], ],
controllers: [DkvController], controllers: [DkvController],
@@ -49,8 +52,6 @@ import { seedDkvModule } from './dkv.seed';
DkvParserService, DkvParserService,
DkvExportService, DkvExportService,
DkvMailService, DkvMailService,
ImapProvider,
ExchangeInboxProvider,
], ],
exports: [DkvService], exports: [DkvService],
}) })
+2 -2
View File
@@ -13,8 +13,8 @@ import { DkvMailService } from './dkv-mail.service';
import { DkvParserService } from './dkv-parser.service'; import { DkvParserService } from './dkv-parser.service';
import { DkvConfigDto } from './dto/dkv-config.dto'; import { DkvConfigDto } from './dto/dkv-config.dto';
import { CreateVehicleDto, UpdateVehicleDto } from './dto/dkv-vehicle.dto'; import { CreateVehicleDto, UpdateVehicleDto } from './dto/dkv-vehicle.dto';
import { ExchangeInboxProvider } from './providers/exchange-inbox.provider'; import { ExchangeInboxProvider } from '../inbox/exchange-inbox.provider';
import { ImapProvider } from './providers/imap.provider'; import { ImapProvider } from '../inbox/imap.provider';
import type { DkvVehicleBlock, InboxConfig, InboxEmail } from './dkv.types'; import type { DkvVehicleBlock, InboxConfig, InboxEmail } from './dkv.types';
/** /**
+5 -43
View File
@@ -41,50 +41,12 @@ export interface DkvVehicleBlock {
} }
/** /**
* Inbox connection configuration (supports IMAP and Exchange). * Inbox connection types (InboxConfig/InboxAttachment/InboxEmail) moved to
* Mirrors DkvModuleConfig from Prisma but with decrypted credentials. * 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 { export type { InboxConfig, InboxAttachment, InboxEmail } from '../inbox/inbox.types';
/** '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 row in the Excel export (5 columns per D-13). * A single row in the Excel export (5 columns per D-13).
@@ -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 // Re-export types for downstream consumers that import from this module
export type { InboxAttachment, InboxConfig, InboxEmail }; export type { InboxAttachment, InboxConfig, InboxEmail };
+19
View File
@@ -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 {}
+73
View File
@@ -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;
}