Files
Synapse/docs/adr/0022-remove-ui-db-and-refactor-editor-first.md
Dasemu 40631362b3 Initial import of LogDarioSeq baseline
Establishes version control for the personal Logseq DB fork before
starting the server-client architecture migration and domain features
described in docs/agent-guide and the approved implementation plan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 15:32:15 +02:00

118 lines
5.3 KiB
Markdown

# ADR 0022: Remove the UI DataScript DB and Refactor Editor First
Date: 2026-07-08
Status: Accepted
## Context
The db worker is the durable owner of graph data, but the renderer has still
kept a second DataScript connection as a UI read model. That split makes graph
reads harder to reason about because UI code can read stale renderer entities,
perform reverse lookups locally, or depend on lazy entity navigation that does
not exist when the worker database is the only graph database.
The renderer has used this UI DB through several shapes:
- direct `d/entity`, `d/pull`, `d/q`, `db/entity`, `db/pull`, and
`db-model/*` calls;
- reverse lookup attributes such as `:block/_alias` and `:block/_refs`;
- nested entity or pull-map reads such as reading fields from
`(:block/parent block)`;
- handler code that performs graph-backed editor calculations before
dispatching worker transactions.
The editor is the highest-risk migration surface because it combines block
tree reads, sibling and parent selection, paste, delete, merge, quick-add,
navigation, undo metadata, DOM focus, and outliner transactions. Removing the
UI DB without simplifying editor ownership would preserve the same complexity
behind async worker calls.
## Decision
Remove the renderer-owned DataScript database as a graph read model.
The db worker is the only owner of graph facts. UI code must not depend on
DataScript entities, lazy entity navigation, reverse lookup attributes, or
renderer-side pull maps for graph computation.
Refactor editor ownership first:
1. Move graph-backed editor calculations to worker APIs.
2. Add worker editor namespaces where editor-specific graph operations need a
clear home.
3. Keep UI editor handlers thin: they dispatch user intent, coordinate DOM and
focus state, and consume explicit worker payloads.
4. Return plain data from worker APIs with explicit fields needed by the UI.
Do not rely on entity identity, lazy nested refs, or reverse attributes.
5. Keep components focused on rendering and event dispatch. Component
migration comes after handler/editor contracts are explicit.
Do not add a renderer cache to replace the UI DB. If a cache becomes necessary,
it must have a narrowly documented owner, invalidation rule, and test case.
The default design is no cache.
Do not keep a compatibility layer that lets UI code continue to call
renderer-style DB helpers. Compatibility wrappers may remain only while their
call sites are being removed, and they must not hide a second graph database.
## Migration Shape
1. Add guard tests that count and reject direct UI DB reads, reverse lookups,
and nested entity or pull-map assumptions in frontend UI code.
2. Remove direct `d/entity`, `d/pull`, `d/q`, `db/entity`, `db/pull`,
`db-model/*`, and renderer `conn/get-db` reads from handlers and events.
3. Move editor calculations to worker APIs before converting component-heavy
surfaces.
4. Replace reverse lookup usage with worker-owned queries that return explicit
result fields.
5. Replace nested entity reads with explicit worker payloads, for example
parent ids, page ids, children, aliases, refs, or sibling blocks.
6. Keep outliner writes on worker-backed transaction paths and keep UI code
out of DB transaction assembly when the worker can own the calculation.
7. Convert components last so they render worker-shaped data and dispatch UI
events without graph reads.
8. Run focused tests after each migration batch, then run the broader test and
e2e suites when the UI DB removal is complete.
## Consequences
UI code becomes more explicit. It must ask the worker for the graph data or
editor decision it needs instead of navigating a local entity graph.
Worker APIs increase during the migration, especially around editor behavior.
That is intentional when the API represents a real graph-backed editor
operation. APIs should stay narrow and return plain data.
Editor behavior needs stronger focused coverage because many previously local
reads become async worker calls. Tests should cover insert, delete, merge,
paste, quick-add, sibling navigation, focused-root behavior, and reverse lookup
replacement paths.
Component migration is delayed until handler and editor worker contracts are
stable. This keeps rendering code simpler and avoids moving complex graph
calculation into components.
The removal may temporarily leave old helper namespaces in place while call
sites are drained, but the target architecture has no renderer-owned graph DB.
## Rejected Alternatives
### Keep a Renderer Read Cache
A renderer cache would preserve much of the old split-brain behavior and would
need invalidation logic for every worker transaction, sync update, import,
undo, redo, and rebase path. That adds complexity without solving ownership.
### Convert Components Before Editor
Component-first migration would move the easiest render reads first while
leaving the most complex graph-backed behavior in handlers. Editor behavior
would continue to depend on old assumptions, and later changes would force a
second pass through component contracts.
### Preserve Entity-shaped Worker Results
Returning entity-like maps with nested refs would keep the renderer coupled to
DataScript navigation semantics. Explicit worker payloads are easier to test,
serialize, and reason about across thread boundaries.