mirror of
https://github.com/panatgithub/AnkiHeadingSync.git
synced 2026-07-22 06:51:43 +00:00
中文: 基于真实代码审查整理插件可完善方向、风险点和后续开发优先级。 English: Reviews plugin improvement opportunities, risks, and prioritized next steps based on real code inspection.
257 lines
No EOL
10 KiB
Markdown
257 lines
No EOL
10 KiB
Markdown
# Plugin Improvement Audit Architecture Map
|
||
|
||
## Scope
|
||
|
||
This map is based on the current production runtime path in the repository as inspected on 2026-04-26. It focuses on active code, active wiring, and code paths that materially affect user-visible sync behavior.
|
||
|
||
## 1. Active Entry Points
|
||
|
||
### Runtime entry
|
||
|
||
- `main.ts`
|
||
- Exports `src/presentation/AnkiHeadingSyncPlugin.ts` as the plugin entry.
|
||
|
||
### Plugin composition root
|
||
|
||
- `src/presentation/AnkiHeadingSyncPlugin.ts :: onload()`
|
||
- Creates persistence adapters:
|
||
- `src/infrastructure/obsidian/ObsidianPluginDataStore.ts`
|
||
- `src/infrastructure/persistence/DataJsonPluginConfigRepository.ts`
|
||
- `src/infrastructure/persistence/DataJsonPluginStateRepository.ts`
|
||
- Creates external gateways:
|
||
- `src/infrastructure/anki/AnkiConnectGateway.ts`
|
||
- `src/infrastructure/obsidian/ObsidianVaultGateway.ts`
|
||
- Creates main use cases:
|
||
- `ManualSyncCurrentFileUseCase`
|
||
- `ManualSyncVaultUseCase`
|
||
- `RebuildCardIndexUseCase`
|
||
- `ClearCurrentFileSyncedCardsUseCase`
|
||
- `CleanupEmptyDecksUseCase`
|
||
- Registers commands through `src/presentation/commands/registerCommands.ts`
|
||
- Registers the settings UI through `src/presentation/settings/PluginSettingTab.ts`
|
||
|
||
### User-visible command surface
|
||
|
||
- `src/presentation/commands/registerCommands.ts`
|
||
- Registers 4 commands:
|
||
- sync current file
|
||
- sync vault
|
||
- clear current file synced cards
|
||
- cleanup empty decks
|
||
|
||
### User-visible settings surface
|
||
|
||
- `src/presentation/settings/PluginSettingTab.ts`
|
||
- Active cards:
|
||
- card types
|
||
- sync content
|
||
- deck
|
||
- scope
|
||
- commands
|
||
|
||
## 2. Active Runtime Layers
|
||
|
||
### Presentation
|
||
|
||
- `src/presentation/AnkiHeadingSyncPlugin.ts`
|
||
- Plugin lifecycle, command callbacks, notices, settings update entry.
|
||
- `src/presentation/settings/PluginSettingTab.ts`
|
||
- Settings rendering, note-type cache loading, field-mapping editing, folder-scope editing, deck template insertion button.
|
||
- `src/presentation/notices/NoticeService.ts`
|
||
- User-facing success/error summaries.
|
||
- `src/presentation/modals/EmptyDeckSelectionModal.ts`
|
||
- Deck cleanup modal.
|
||
- `src/presentation/i18n/*`
|
||
- Locale detection and message lookup.
|
||
|
||
### Application
|
||
|
||
- `src/application/use-cases/*`
|
||
- Thin user-action entry points over services.
|
||
- `src/application/services/ManualSyncService.ts`
|
||
- Main orchestration service for file sync, vault sync, and rebuild index.
|
||
- `src/application/services/FileIndexerService.ts`
|
||
- Scope filtering, incremental scan decisions, state-assisted restore of unchanged cards.
|
||
- `src/application/services/AnkiBatchExecutor.ts`
|
||
- Batched Anki note create/update/model-migrate/tag-sync/deck-change/media-upload.
|
||
- `src/application/services/QaGroupSyncService.ts`
|
||
- QA Group note sync, slot preservation, model mismatch handling, GI marker generation.
|
||
- `src/application/services/MarkdownWriteBackService.ts`
|
||
- File-grouped marker writes, conflict capture, pending write-back generation.
|
||
- `src/application/services/RenderConfigService.ts`
|
||
- Deck resolution, note-model selection, render-config hashing.
|
||
- `src/application/services/NoteFieldMappingService.ts`
|
||
- Saved mapping validation and rendered-field projection.
|
||
- `src/application/services/QaGroupFieldMappingService.ts`
|
||
- QA Group slot derivation and validation.
|
||
|
||
### Domain
|
||
|
||
- `src/domain/manual-sync/services/CardIndexingService.ts`
|
||
- Heading scanning, card-type detection, ID/GI marker recovery, QA Group and semantic QA parsing.
|
||
- `src/domain/manual-sync/services/DiffPlannerService.ts`
|
||
- Create/update/change-deck/rewrite-marker/orphan planning.
|
||
- `src/domain/manual-sync/services/CardMarkerService.ts`
|
||
- Card ID marker parse/create/validate/apply.
|
||
- `src/domain/manual-sync/services/GroupMarkerService.ts`
|
||
- GI marker parse/create/validate/apply.
|
||
- `src/domain/manual-sync/services/DeckExtractionService.ts`
|
||
- YAML/body deck declaration parsing.
|
||
- `src/domain/manual-sync/services/DeckResolutionService.ts`
|
||
- Folder/file/default deck resolution and warning generation.
|
||
- `src/domain/manual-sync/services/QaGroupBlockParser.ts`
|
||
- QA Group block parsing.
|
||
- `src/domain/manual-sync/services/SemanticQaListParser.ts`
|
||
- Semantic QA list parsing.
|
||
|
||
### Infrastructure
|
||
|
||
- `src/infrastructure/anki/AnkiConnectGateway.ts`
|
||
- AnkiConnect HTTP adapter and `multi` request batching.
|
||
- `src/infrastructure/obsidian/ObsidianVaultGateway.ts`
|
||
- Vault reads, compare-and-swap writes, folder tree, backlinks, media resolution.
|
||
- `src/infrastructure/persistence/DataJsonPluginConfigRepository.ts`
|
||
- Settings load/save normalization and validation.
|
||
- `src/infrastructure/persistence/DataJsonPluginStateRepository.ts`
|
||
- Plugin state load/save and migration.
|
||
|
||
## 3. Main Data Flow
|
||
|
||
### Manual sync: current file
|
||
|
||
1. Command callback in `registerCommands()` calls `AnkiHeadingSyncPlugin.runSyncCurrentFile()`.
|
||
2. `ManualSyncCurrentFileUseCase.execute()` forwards to `ManualSyncService.syncFile()`.
|
||
3. `ManualSyncService.syncFile()` validates settings and scope, then loads plugin state.
|
||
4. `FileIndexerService.indexFile()` reads the target Markdown file and delegates parsing to `CardIndexingService.index()`.
|
||
5. `DiffPlannerService.plan()` compares indexed cards with persisted state.
|
||
6. `AnkiBatchExecutor.execute()` syncs ordinary/basic/cloze/semantic cards.
|
||
7. `QaGroupSyncService.sync()` syncs QA Group blocks separately.
|
||
8. `MarkdownWriteBackService.write()` writes card ID markers and GI markers back into Markdown.
|
||
9. `ManualSyncService.buildNextState()` saves files/cards/groupBlocks/pending write-back into plugin state.
|
||
10. `NoticeService.showSyncSummary()` renders a localized summary.
|
||
|
||
### Manual sync: vault
|
||
|
||
1. `ManualSyncVaultUseCase.execute()` forwards to `ManualSyncService.syncVault()`.
|
||
2. `FileIndexerService.indexVault()` uses `ScanScopeService` plus `ObsidianVaultGateway.listMarkdownFileRefs()` to enumerate in-scope files.
|
||
3. Incremental decisions are made per file using file stamp, deck-rule fingerprint, missing known cards, and pending write-back state.
|
||
4. Remaining flow matches current-file sync.
|
||
|
||
### Rebuild index
|
||
|
||
1. `RebuildCardIndexUseCase.execute()` forwards to `ManualSyncService.rebuildIndex()`.
|
||
2. Vault is reindexed with `forceReadAll = true`.
|
||
3. No Anki note create/update occurs.
|
||
4. Existing markers can still be rewritten if enough identity exists.
|
||
5. Persisted state is rebuilt from indexed files plus recovered QA Group state.
|
||
|
||
### Clear current file synced cards
|
||
|
||
1. `ClearCurrentFileSyncedCardsUseCase.hasTrackedCards()` checks local state for current file.
|
||
2. `execute()` loads note IDs/group IDs from local state.
|
||
3. Anki notes are deleted through `AnkiGateway.deleteNotes()`.
|
||
4. Markdown markers are removed through `MarkdownSyncedMarkerRemovalService`.
|
||
5. Local state is rewritten without that file’s cards/groups.
|
||
|
||
## 4. Critical State Objects
|
||
|
||
### Settings
|
||
|
||
- `src/application/config/PluginSettings.ts :: PluginSettings`
|
||
- Controls note-type selection, field mapping caches, deck logic, scope logic, backlink behavior, tag sync, and AnkiConnect URL.
|
||
- Contains both current `cardTypeConfigs` and legacy mirrored note-type fields.
|
||
|
||
### Persisted plugin state
|
||
|
||
- `src/domain/manual-sync/entities/PluginState.ts :: PluginState`
|
||
- `files`
|
||
- Per-file index metadata: `fileHash`, `fileStamp`, `deckRulesFingerprint`, `noteIds`, `groupIds`.
|
||
- `cards`
|
||
- Per-note synced card snapshot keyed by note ID.
|
||
- `groupBlocks`
|
||
- Per-QA-group synced snapshot keyed by group ID.
|
||
- `pendingWriteBack`
|
||
- Deferred marker writes intended for conflict recovery.
|
||
|
||
### Scan-time objects
|
||
|
||
- `IndexedCard`
|
||
- `IndexedGroupCardBlock`
|
||
- `IndexedFile`
|
||
|
||
### Plan-time objects
|
||
|
||
- `src/domain/manual-sync/value-objects/ManualSyncPlan.ts :: ManualSyncPlan`
|
||
- `toCreate`
|
||
- `toUpdate`
|
||
- `toVerifyDeck`
|
||
- `toChangeDeck`
|
||
- `toRewriteMarker`
|
||
- `toOrphan`
|
||
|
||
## 5. Main External API Boundaries
|
||
|
||
### Obsidian APIs
|
||
|
||
- `Plugin.loadData()` / `Plugin.saveData()` through `ObsidianPluginDataStore`
|
||
- Vault file enumeration through `ObsidianVaultGateway.listMarkdownFileRefs()`
|
||
- Compare-and-swap write boundary through `ObsidianVaultGateway.replaceMarkdownFile()`
|
||
- Metadata and tag extraction through `getAllTags()` and cached metadata
|
||
- Obsidian notices and settings controls in presentation layer
|
||
|
||
### AnkiConnect
|
||
|
||
- All network calls are centralized in `AnkiConnectGateway.invoke()` / `invokeMulti()`.
|
||
- The adapter uses AnkiConnect action names directly (`modelNames`, `deckNamesAndIds`, `getDeckStats`, `addNote`, `updateNoteFields`, `changeDeck`, `deleteDecks`, `storeMediaFile`, `multi`, etc.).
|
||
|
||
## 6. Active Code vs Likely Legacy / Dormant Remnants
|
||
|
||
### Clearly active
|
||
|
||
- `main.ts`
|
||
- `src/presentation/AnkiHeadingSyncPlugin.ts`
|
||
- `src/presentation/settings/PluginSettingTab.ts`
|
||
- `src/application/services/ManualSyncService.ts`
|
||
- `src/application/services/FileIndexerService.ts`
|
||
- `src/application/services/AnkiBatchExecutor.ts`
|
||
- `src/application/services/QaGroupSyncService.ts`
|
||
- `src/infrastructure/anki/AnkiConnectGateway.ts`
|
||
- `src/infrastructure/obsidian/ObsidianVaultGateway.ts`
|
||
|
||
### Generated or packaging artifacts
|
||
|
||
- `main.js`
|
||
- Root-level generated bundle copy written by `esbuild.config.mjs`.
|
||
- `dist/plugin/*`
|
||
- Staged package output used for release/manual sync.
|
||
|
||
### Debug / manual inspection scripts
|
||
|
||
- `query_note.js`
|
||
- `query_notes.js`
|
||
- Direct HTTP scripts with hard-coded note IDs and no repository call sites.
|
||
|
||
### Likely dormant or legacy architectural branches
|
||
|
||
- `src/application/services/QaGroupModelService.ts`
|
||
- `src/application/services/QaGroupModelDefinition.ts`
|
||
- `src/application/config/ManagedNoteModels.ts`
|
||
- These define and test a managed `ObsiAnki QA Group 12` model, but no production runtime call site invokes `QaGroupModelService.ensureModel()`.
|
||
- The active runtime QA Group path instead uses user-selected note types plus `QaGroupFieldMappingService`.
|
||
|
||
- `src/presentation/AnkiHeadingSyncPlugin.ts :: runRebuildCardIndex()`
|
||
- Wired in plugin initialization, but not surfaced by `registerCommands()` and not listed in the settings command card.
|
||
|
||
- Legacy mirrored settings fields in `PluginSettings`
|
||
- `qaHeadingLevel`, `clozeHeadingLevel`, `qaGroupMarker`, `qaNoteType`, `clozeNoteType`, `semanticQaMarker`, `semanticQaNoteType`
|
||
- Still exist and are derived from `cardTypeConfigs`, which indicates an unfinished migration rather than a clean single source of truth.
|
||
|
||
## 7. Audit Notes
|
||
|
||
- The active sync engine is stateful and layered.
|
||
- The highest-value audit attention should stay on:
|
||
- pending write-back persistence
|
||
- QA Group authority split
|
||
- semantic QA runtime/UI parity
|
||
- AnkiConnect failure handling
|
||
- hidden rebuild/recovery surface |