Date: 2026-02-27
Version: 0.3.0 (in progress)
Context: See ai-context.md for full project overview
Implemented Backlinks between notes using /link slash command. Two critical bugs from the previous session have been fixed; the feature is now functional end-to-end.
Current State: All working.
Root cause: Vue's reactive proxy wraps the Crepe instance returned by useEditor's get(). Milkdown's Crepe class uses ES private fields (#editor), and accessing the editor getter through a proxy fails because this becomes the proxy, which doesn't own the private field.
Fix:
- Store a raw (non-reactive)
crepeRawreference at Crepe creation time, before Vue wraps it. - Use
crepeRaw.editor.action(replaceAll(...))for programmatic content updates. - Added
force-remountfallback: if the direct update fails,MilkdownEditorCoreemitsforce-remount, which increments an internal key counter inMilkdownEditor.vue, causing a full editor remount with updated content.
Root cause: BacklinksPanel received the filename-based note ID (e.g., 20260227-153000) via currentNoteId, but the backend link index stores everything by frontmatter ID (e.g., ironpad-20260227-153000). The API call never matched.
Fix: Changed BacklinksPanel binding from :note-id="currentNoteId" to :note-id="selectedNote.id", which passes the frontmatter ID that matches the link index.
- Removed excessive
console.logdebug statements from all modified frontend files. - Kept only meaningful error/warning logs.
/linkslash command triggers searchable note picker dropdown- Dropdown shows all project notes with keyboard navigation
- Link insertion creates standard markdown:
[Note Title](note-id) - Link renders immediately in the editor after insertion
- BacklinksPanel shows forward links ("Links To") and backlinks ("Linked From")
- Clicking a link in the panel navigates to the target note
- Backend link index rebuilds on note save and file watcher events
- Auto-save triggers backlinks panel refresh
Frontend:
frontend/src/components/MilkdownEditorCore.vue-- Raw Crepe reference, force-remount emit, logging cleanupfrontend/src/components/MilkdownEditor.vue--effectiveKeywith remount counter,force-remounthandlerfrontend/src/components/BacklinksPanel.vue-- Logging cleanupfrontend/src/components/LinkAutocomplete.vue-- Logging cleanupfrontend/src/views/ProjectNotesView.vue-- PassselectedNote.idto BacklinksPanel, logging cleanup
No backend changes were needed.
Two new critical patterns added to ai-context.md:
-
Crepe Raw Reference -- Always use a raw (non-reactive) Crepe reference for
editor.action()calls. Vue's proxy breaks access to ES private fields. -
Note ID vs Filename -- Project notes have two identifiers: filename (
20260227-153000) for routes, frontmatter ID (ironpad-20260227-153000) for backlinks. Always pass frontmatter ID to backlinks API.
# Backend (from backend/)
cargo run # API server on :3000
cargo check # Check compilation
# Frontend (from frontend/)
npm run dev # Dev server on :5173
npm run build # Production build
npx vue-tsc --noEmit # TypeScript checkai-context.md-- Full project documentationROADMAP.md-- Feature roadmap and statusCHANGELOG.md-- Version history