Files
SubMiner/backlog/tasks/task-27.3 - Refactor-anki-integration.ts-into-domain-specific-service-modules.md

4.7 KiB

id, title, status, assignee, created_date, updated_date, labels, dependencies, references, documentation, parent_task_id, priority
id title status assignee created_date updated_date labels dependencies references documentation parent_task_id priority
TASK-27.3 Refactor anki-integration.ts into domain-specific service modules Done
backend
2026-02-13 17:13 2026-02-15 04:23
owner:backend
TASK-27.1
src/anki-integration.ts
docs/architecture.md
TASK-27 high

Description

Split anki-integration.ts (2,679 LOC, 60+ methods) into cohesive modules with clear handoff contracts. Keep a stable facade API to avoid broad call-site churn.

Target Decomposition (7 modules)

Based on method clustering analysis:

  1. polling/lifecycle (~250 LOC) — start, stop, poll, pollOnce, processNewCard
  2. card-creation (~350 LOC) — createSentenceCard, setCardTypeFields, extractFields, processSentence, field resolution helpers
  3. media-generation (~200 LOC) — generateAudio, generateImage, filename generation, generateMediaForMerge
  4. field-grouping (~900 LOC) — triggerFieldGroupingForLastAddedCard, applyFieldGrouping, computeFieldGroupingMergedFields, buildFieldGroupingPreview, performFieldGroupingMerge, handleFieldGroupingAuto, handleFieldGroupingManual, plus ~15 span/parse/normalize helpers
  5. duplicate-detection (~100 LOC) — findDuplicateNote, findFirstExactDuplicateNoteId, search escaping
  6. ai-translation (~100 LOC) — translateSentenceWithAi, extractAiText, normalizeOpenAiBaseUrl
  7. ui-feedback (~150 LOC) — progress tracking, OSD notifications, status notifications

Plus a facade (src/anki-integration/index.ts) that re-exports the public API for backward compatibility.

Acceptance Criteria

  • #1 Extract at least 6 modules matching the decomposition map above (7 recommended).
  • #2 Keep a stable facade API in src/anki-integration/index.ts so external callers (main.ts, mining-service) don't change.
  • #3 Field grouping cluster (~900 LOC) is extracted as its own module — it's the largest single concern.
  • #4 AI/translation integration is extracted separately from card creation.
  • #5 Each module defines explicit input/output types; no module exceeds 400 LOC unless justified in a TODO comment.
  • #6 The 15 private state fields (pollingInterval, backoffMs, progressTimer, etc.) are managed through a shared internal state object or passed explicitly — not scattered across files as module-level lets.
  • #7 Preserve existing external behavior for all config keys and session flow.
  • #8 All existing tests pass; add focused unit tests for at least the field-grouping and card-creation modules.

Implementation Notes

Execution Notes

This task is self-contained — anki-integration.ts is a single class with a clear public API consumed by main.ts and mining-service. Internal restructuring doesn't affect other files as long as the facade is maintained.

Should run first in Phase 2 because:

  • It's the largest file (2,679 LOC vs 1,392 for main.ts)
  • Its public API is narrow (class constructor + ~5 public methods)
  • main.ts instantiates AnkiIntegration, so stabilizing its API before splitting main.ts avoids double-refactoring

Key Risk

The class has 15 private state fields that create implicit coupling between methods. The updateLastAddedFromClipboard method alone is ~230 lines and touches polling state, media generation, and card updates. Extraction order matters: start with the leaf clusters (ai-translation, ui-feedback, duplicate-detection) and work inward toward the stateful core (polling, card-creation, field-grouping).

Started TASK-27.3 with a surgical extraction of the duplicate-detection cluster into src/anki-integration-duplicate.ts and refactoring AnkiIntegration.findDuplicateNote() to delegate all deck query, search escaping, and normalization logic to the new module while preserving behavior. This reduces anki-integration.ts by removing three private duplicate-parsing methods and keeps callsites unchanged. Remaining decomposition work still needed across polling/card-creation/field-grouping/notification clusters from the task map.

Second extraction pass completed: moved sentence-translation decision + AI fallback behavior out of createSentenceCard into src/anki-integration/ai.ts as resolveSentenceBackText(...), with AnkiIntegration now delegating translation result generation to this function. This further isolates AI concerns from card-creation flow while keeping behavior and defaults intact.

Refactor for TASK-27.3 is complete and build passes after cleanup of ui-feedback delegation (src/anki-integration.ts, src/anki-integration-ui-feedback.ts).