From c7b0103a10291cdc8912f6b0cbf24040bbf7a9aa Mon Sep 17 00:00:00 2001 From: Schalli Date: Sat, 27 Jun 2026 00:06:24 +0200 Subject: [PATCH] docs(07-02): complete DKV inbox-access layer plan - 07-02-SUMMARY.md: interface + IMAP + Exchange providers, all 3 DTOs, self-check passed - STATE.md: advance to Plan 3/6, record 3 decisions, update session to 2026-06-27 - ROADMAP.md: mark 07-01 and 07-02 complete, Phase 7 progress 2/6 --- .planning/ROADMAP.md | 6 +- .planning/STATE.md | 21 +-- .../07-dkv-fleet-module/07-02-SUMMARY.md | 122 ++++++++++++++++++ 3 files changed, 137 insertions(+), 12 deletions(-) create mode 100644 .planning/phases/07-dkv-fleet-module/07-02-SUMMARY.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index c4fec0e..a2aee58 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -228,11 +228,11 @@ Decimal phases appear between their surrounding integers in numeric order. **Wave 0** -- [ ] 07-01-PLAN.md -- Backend foundation: deps install, Prisma models, ScheduleModule, crypto export, validated DKV PDF parser (DKV-02) +- [x] 07-01-PLAN.md -- Backend foundation: deps install, Prisma models, ScheduleModule, crypto export, validated DKV PDF parser (DKV-02) **Wave 1** *(blocked on Wave 0 completion)* -- [ ] 07-02-PLAN.md -- Inbox-access layer: InboxProvider interface, IMAP + Exchange providers, config/vehicle/history DTOs (DKV-01) +- [x] 07-02-PLAN.md -- Inbox-access layer: InboxProvider interface, IMAP + Exchange providers, config/vehicle/history DTOs (DKV-01) - [ ] 07-03-PLAN.md -- Export + delivery + SMTP backend: SettingsModule (SMTP CRUD + test), DkvExportService (xlsx + prune), DkvMailService, MailModule DB-SMTP migration (DKV-04/05, D-06) **Wave 2** *(blocked on Wave 1 completion)* @@ -256,4 +256,4 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 | 4. Marketplace & Portal Navigation | 0/4 | Not started | - | | 5. Dashboard & Calendar | 5/5 | Complete | 2026-06-24 | | 6. Desktop Client & CI/CD | 2/3 | In Progress| | -| 7. DKV Fleet Module | 0/6 | Not started | - | +| 7. DKV Fleet Module | 2/6 | In Progress | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 39a177e..c351a00 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,9 +3,9 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: executing -stopped_at: Phase 07 Plan 01 complete -last_updated: "2026-06-26T17:36:00.000Z" -last_activity: 2026-06-26 -- Phase 07 Plan 01 completed (DKV backend foundation) +stopped_at: Phase 07 Plan 02 complete +last_updated: "2026-06-27T00:10:00.000Z" +last_activity: 2026-06-27 -- Phase 07 Plan 02 completed (DKV inbox-access layer) progress: total_phases: 7 completed_phases: 5 @@ -26,9 +26,9 @@ See: .planning/PROJECT.md (updated 2026-06-18) ## Current Position Phase: 07 (dkv-fleet-module) — EXECUTING -Plan: 2 of 6 -Status: Executing Phase 07 (Plan 01 complete) -Last activity: 2026-06-26 -- Phase 07 Plan 01 completed (DKV backend foundation) +Plan: 3 of 6 +Status: Executing Phase 07 (Plan 02 complete) +Last activity: 2026-06-27 -- Phase 07 Plan 02 completed (DKV inbox-access layer) Progress: [██████████] 100% @@ -99,6 +99,9 @@ Recent decisions affecting current work: - [07-01]: DKV PDF uses two extraction formats: single-tx (tab-separated) vs multi-tx (columnar) — both handled in DkvParserService - [07-01]: Research Pattern 4 regex replaced with empirical dual-format tab/columnar parser after testing against real invoice.pdf - [07-01]: CalendarCryptoService exported from CalendarModule for DKV credential encryption reuse +- [07-02]: Max attachment size 25MB enforced in both ImapProvider and ExchangeInboxProvider before buffering (T-07-05) +- [07-02]: ExchangeInboxProvider uses WellKnownFolderName.Inbox + FindItems (not FindAppointments — email vs calendar EWS API) +- [07-02]: export type {} required for type-only re-exports under isolatedModules TypeScript setting ### Pending Todos @@ -118,6 +121,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-06-26T17:36:00.000Z -Stopped at: Phase 07 Plan 01 complete (DKV backend foundation) -Resume file: .planning/phases/07-dkv-fleet-module/07-02-PLAN.md +Last session: 2026-06-27T00:10:00.000Z +Stopped at: Phase 07 Plan 02 complete (DKV inbox-access layer) +Resume file: .planning/phases/07-dkv-fleet-module/07-03-PLAN.md diff --git a/.planning/phases/07-dkv-fleet-module/07-02-SUMMARY.md b/.planning/phases/07-dkv-fleet-module/07-02-SUMMARY.md new file mode 100644 index 0000000..d4085c2 --- /dev/null +++ b/.planning/phases/07-dkv-fleet-module/07-02-SUMMARY.md @@ -0,0 +1,122 @@ +--- +phase: 07-dkv-fleet-module +plan: 02 +subsystem: dkv-inbox-access-layer +tags: [dkv, imap, ews, exchange, imapflow, inbox-provider, dto, class-validator] +dependency_graph: + requires: [dkv.types.ts (Plan 01), CalendarModule (ews-javascript-api installed)] + provides: [InboxProvider interface, ImapProvider, ExchangeInboxProvider, DkvConfigDto, CreateVehicleDto, UpdateVehicleDto, DkvHistoryQueryDto] + affects: + - apps/api/src/dkv/providers/inbox-provider.interface.ts + - apps/api/src/dkv/providers/imap.provider.ts + - apps/api/src/dkv/providers/exchange-inbox.provider.ts + - apps/api/src/dkv/dto/dkv-config.dto.ts + - apps/api/src/dkv/dto/dkv-vehicle.dto.ts + - apps/api/src/dkv/dto/dkv-history.dto.ts +tech_stack: + added: [] + patterns: + - "imapflow: fetchAll() before any download() — avoids IMAP connection deadlock (Pitfall 1)" + - "imapflow: logger:false in ImapFlow constructor — credential safety (T-07-03)" + - "imapflow: collectPdfParts() recursive MIME tree traversal for application/pdf parts" + - "ews-javascript-api: dynamic import as any, WellKnownFolderName.Inbox + FindItems (not FindAppointments)" + - "ews-javascript-api: SearchFilter.ContainsSubstring for server-side sender filtering" + - "25MB MAX_ATTACHMENT_BYTES guard in both providers — PDF-bomb mitigation (T-07-05)" + - "export type { ... } required for isolatedModules TypeScript setting" + - "class-validator: @IsEmail() on senderFilter/exportRecipient, @Min(5) on pollIntervalMin, @IsInt @Min(1) on pagination" +key_files: + created: + - apps/api/src/dkv/providers/inbox-provider.interface.ts + - apps/api/src/dkv/providers/imap.provider.ts + - apps/api/src/dkv/providers/exchange-inbox.provider.ts + - apps/api/src/dkv/dto/dkv-config.dto.ts + - apps/api/src/dkv/dto/dkv-vehicle.dto.ts + - apps/api/src/dkv/dto/dkv-history.dto.ts + modified: [] +decisions: + - "Max attachment size limit set to 25MB (26_214_400 bytes) — covers all realistic DKV invoices; larger files are skipped with a warning log" + - "ExchangeInboxProvider uses server-side SearchFilter.ContainsSubstring for sender filtering plus client-side verification (handles case-insensitivity differences)" + - "InboxProvider re-exports dkv.types.ts shapes using export type {} (isolatedModules requirement)" + - "EWS attachment download: attachment.Load() then Buffer.from(attachment.Content) — no streaming interface available in ews-javascript-api" + - "ExchangeInboxProvider buildService() uses WebCredentials with empty string fallback (avoids undefined credential error when username/password absent)" +metrics: + duration: 5min + completed: "2026-06-27T00:05:00Z" + tasks: 3 + files_created: 6 + files_modified: 0 +--- + +# Phase 07 Plan 02: DKV Inbox Access Layer — Interface + IMAP + Exchange Providers Summary + +Interchangeable inbox-access layer built: InboxProvider interface contract, ImapProvider (imapflow with fetchAll-before-download deadlock avoidance, logger:false credential safety, 25MB PDF-bomb guard) and ExchangeInboxProvider (dynamic ews-javascript-api import, WellKnownFolderName.Inbox + FindItems — not FindAppointments, SearchFilter sender filtering, same 25MB guard). All three class-validator DTOs defined with security constraints from Research V5. + +## Tasks Completed + +| Task | Name | Commit | Key Files | +|------|------|--------|-----------| +| 1 | InboxProvider interface + config/vehicle/history DTOs | 86ec896 | inbox-provider.interface.ts, dkv-config.dto.ts, dkv-vehicle.dto.ts, dkv-history.dto.ts | +| 2 | ImapProvider (imapflow) | b3f21a8 | providers/imap.provider.ts | +| 3 | ExchangeInboxProvider (ews-javascript-api) | 924de76 | providers/exchange-inbox.provider.ts | + +## Verification Results + +- `pnpm --filter @tessera/api type-check` exits 0: PASS +- `grep -q "fetchAll"` imap.provider.ts: PASS +- `grep -q "logger: false"` imap.provider.ts: PASS +- `grep -q "WellKnownFolderName.Inbox"` exchange-inbox.provider.ts: PASS +- `grep -q "import('ews-javascript-api')"` exchange-inbox.provider.ts: PASS +- `grep -q "IsEmail"` dkv-config.dto.ts: PASS +- `grep -q "InboxProvider"` inbox-provider.interface.ts: PASS +- Both providers > 40 lines: imap.provider.ts (224 lines), exchange-inbox.provider.ts (228 lines): PASS +- No download() inside fetch() async iterator: PASS (fetchAll pattern used) +- 25MB attachment size guard present in both providers: PASS + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] export type required for isolatedModules TypeScript setting** +- **Found during:** Task 1 type-check +- **Issue:** `inbox-provider.interface.ts` used `export { InboxAttachment, InboxConfig, InboxEmail }` (value export syntax). The TypeScript project has `isolatedModules: true`, which requires `export type { ... }` for type-only re-exports (TS1205 error). +- **Fix:** Changed to `export type { InboxAttachment, InboxConfig, InboxEmail }` +- **Files modified:** apps/api/src/dkv/providers/inbox-provider.interface.ts +- **Commit:** 86ec896 + +### EWS Adjustments vs Calendar ExchangeProvider + +| Aspect | CalendarExchangeProvider | ExchangeInboxProvider | +|--------|--------------------------|----------------------| +| Folder | `WellKnownFolderName.Calendar` | `WellKnownFolderName.Inbox` | +| Find method | `FindAppointments` + `CalendarView` | `FindItems` + `ItemView` | +| Bind method | Direct from findResults.Items | `EmailMessage.Bind` with PropertySet | +| Sender filter | Not applicable (calendar) | `SearchFilter.ContainsSubstring` (server) + client-side verification | +| Attachment handling | Not applicable (calendar) | `FileAttachment.Load()` + `Content` → Buffer | +| Error path | returns `[]` | returns `[]` (consistent) | + +## Known Stubs + +None — all functionality in this plan is fully implemented. Neither provider contains placeholder comments or TODO items that would block Plan 04 orchestration. + +## Threat Flags + +None. All STRIDE threats in this plan's threat register were mitigated: +- T-07-03: `logger: false` in ImapFlow constructor; generic error messages in all catch blocks; credentials never appear in log strings +- T-07-04: senderFilter validated with `@IsEmail()`, port with `@Min(1)@Max(65535)`, protocol/encryption with `@IsIn()` +- T-07-05: `MAX_ATTACHMENT_BYTES = 25MB` guard applied before buffering in both ImapProvider (streamToBuffer) and ExchangeInboxProvider (extractPdfAttachments) +- T-07-06: `DkvHistoryQueryDto` exposes `page` and `limit` with `@IsInt() @Min(1)` + +## Self-Check: PASSED + +Files verified present: +- apps/api/src/dkv/providers/inbox-provider.interface.ts ✓ +- apps/api/src/dkv/providers/imap.provider.ts ✓ +- apps/api/src/dkv/providers/exchange-inbox.provider.ts ✓ +- apps/api/src/dkv/dto/dkv-config.dto.ts ✓ +- apps/api/src/dkv/dto/dkv-vehicle.dto.ts ✓ +- apps/api/src/dkv/dto/dkv-history.dto.ts ✓ + +Commits verified in git log: +- 86ec896 ✓ (feat(07-02): InboxProvider interface + config/vehicle/history DTOs) +- b3f21a8 ✓ (feat(07-02): ImapProvider — IMAP inbox access via imapflow) +- 924de76 ✓ (feat(07-02): ExchangeInboxProvider — EWS email inbox access)