Root cause of the blank Jung tree: a child double-linked to the same parent
(and, generally, any cycle) made family-chart recurse forever.
Backend (the real fix):
- create_relationship now rejects an equivalent existing edge → 409.
parent_child is directional (parent→child); partnership/sibling match the
pair in either order. So you can't link the same two people the same way
twice. (GEDCOM import already deduped; manual creates didn't.)
Frontend (defense in depth so data can never blank the view):
- Tree view sanitizes the graph before rendering: dedupes parents/spouses,
drops self-links, and greedily breaks ancestor cycles (a person can't be
their own ancestor); children are derived from the kept edges. The render is
wrapped in try/catch and shows a note instead of a blank canvas, telling you
which conflicting links were skipped.
- Person page surfaces the 409 ("They're already linked that way.").
59 backend tests pass (incl. dup-rejection + reverse-parent-child allowed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the rule #8 gap at the API layer: PATCH endpoints + service updates for Tree (name/description/visibility), Source, Citation (page/detail/confidence), Relationship (qualifier/notes), and Media (title/attachment) — editor-gated and audited. Every core entity now has create/read/update/delete. Edit UIs for these land in the frontend batch. 37 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
Tree and person soft-delete + restore (owner-only for trees, editor for people) with recovery listings (?deleted=true); the worker already purges past the 30-day window. Adds tree-wide GET /relationships and /events so the family/pedigree view loads the whole graph in a few calls. 27 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
Events (create/list-per-person/soft-delete) and relationships (create/list-per-person/soft-delete) through the layered stack: editor-gated writes, privacy-engine reads, audit on every change. Events carry exactly one subject (person XOR partnership); relationships are typed qualified edges (parent_child gets a biological/adoptive/step/foster/donor/guardian qualifier). Adds a single-person GET. 18 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>