# `PhoenixKitKnowledgeBase.Web.VaultLive`
[🔗](https://github.com/BeamLabEU/phoenix_kit_knowledge_base/blob/v0.1.0/lib/phoenix_kit_knowledge_base/web/vault_live.ex#L1)

The vault workspace — one LiveView serving three routes, so moving between
notes patches the note pane instead of remounting the sidebar:

  * `:index` — the vault with no note open
  * `:show`  — a note open (read or edit)
  * `:new`   — the "this note doesn't exist yet" page an unresolved
    `[[wiki-link]]` points at

## Editing

Obsidian's model, and only that: clicking a note puts you in the editor, the
editor is already a rendered view, and there is no second "reading" surface to
switch to. That editor is [Leaf](https://hex.pm/packages/leaf) — the same one
PhoenixKit uses elsewhere — in **hybrid mode**, its Obsidian-style live
preview, where formatting renders inline while the source markers stay
editable. Someone with read-only access gets the same surface, not a different
one.

`[[wiki-links]]` render as link tokens in the editor itself. Leaf decorates
them and asks which targets exist — only this module knows that — and the
answer goes back through the same resolver and same-folder tie-break that
built the stored link index, so a link never renders as pointing somewhere
the backlinks panel disagrees with. An unresolved target is styled distinctly
and points at the create page.

Leaf never navigates on a click; it reports one and leaves the destination to
us. The right-hand panel still lists outgoing links, which is the path for a
reader who wants the whole set rather than the one under the cursor.

Visual and HTML modes are denied. Both round-trip the document through HTML,
and a note's YAML front matter is `---`-delimited — which survives that trip
as a horizontal rule and a paragraph, silently destroying every property on
the note. Hybrid and markdown modes edit the source directly and are safe.

Edits autosave: Leaf debounces, the save writes the file and reindexes it,
and the status pill reports where that got to.

## `[[` and `#` autocomplete

Leaf's inline-suggestion triggers do the real thing — a caret-anchored popup,
arrow keys to move, Enter or Tab to accept, Escape to dismiss, and it works
mid-paragraph because the client knows where the caret is.

`[[` completes note titles and `#` completes tags. Both allow creating what
does not exist yet, so you can link ahead of yourself exactly as in Obsidian.
A suggestion whose title several notes share is inserted **path-qualified**,
so the link says which note it meant rather than leaving it to the tie-break.

# `editor_id`

```elixir
@spec editor_id(map() | nil) :: String.t()
```

The Leaf component id for a note.

Keyed to the note, and both halves of that matter.

Leaf's editing surfaces are `phx-update="ignore"`, so LiveView never patches
them after mount and a changed `content` assign does nothing to the DOM.
Under a constant id, patching from note A to note B reused the same
component and the same hook, and the editor went on showing A's text while
the server believed it was showing B's — every note opened with whatever was
loaded first.

Keying the id to the note makes LiveView tear the old component down and
mount a fresh one, and it makes a *stale* message identifiable: Leaf
debounces, so a `:leaf_changed` for the note you just left can arrive after
you have switched, and saving it would write A's text into B's file.

# `save_decision`

```elixir
@spec save_decision(map(), map() | nil, String.t()) :: :save | :stale | :unchanged
```

Whether a `{:leaf_changed, …}` payload should be written to disk.

Pure, and public, because it is the whole of the fix for two bugs that were
invisible from the server's point of view — a stale editor writing into the
wrong note, and an untouched note being rewritten just for being opened.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
