From 36bd7e04148679008e130fb194030ed17e745063 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 28 May 2026 19:55:30 +0200 Subject: [PATCH] chore(stammbaum): add /api/network capture script + canonical fixture (#361) Local-only developer utility that authenticates against the running backend, captures the current /api/network snapshot, and writes it to src/lib/person/genealogy/__fixtures__/stammbaum.json. Sanity gates exit non-zero on a vacuous capture (< 50 nodes, < 5 generations, 0 SPOUSE_OF edges). Fixture and script land together so the fixture is reproducible from the script that generated it. Captured snapshot: 62 nodes, 43 edges, 28 SPOUSE_OF (0 with fromYear), generations G0-G4. Albert de Gruyter is the canonical multi-spouse case with 4 marriages. Co-Authored-By: Claude Opus 4.7 --- frontend/scripts/README.md | 22 + frontend/scripts/capture-network-fixture.mjs | 121 ++ .../person/genealogy/__fixtures__/README.md | 25 + .../genealogy/__fixtures__/stammbaum.json | 1147 +++++++++++++++++ 4 files changed, 1315 insertions(+) create mode 100644 frontend/scripts/README.md create mode 100644 frontend/scripts/capture-network-fixture.mjs create mode 100644 frontend/src/lib/person/genealogy/__fixtures__/README.md create mode 100644 frontend/src/lib/person/genealogy/__fixtures__/stammbaum.json diff --git a/frontend/scripts/README.md b/frontend/scripts/README.md new file mode 100644 index 00000000..f8387321 --- /dev/null +++ b/frontend/scripts/README.md @@ -0,0 +1,22 @@ +# `frontend/scripts/` + +One-off developer utilities. Each script is local-only and never invoked from +CI. Re-run intentionally when needed; commit any generated artefacts as a +separate, atomic commit. + +| Script | Purpose | +| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `capture-network-fixture.mjs` | Capture the canonical `GET /api/network` response into `src/lib/person/genealogy/__fixtures__/stammbaum.json`. Used by `buildLayout.test.ts`. Re-capture when the production family graph grows a new structural case (new edge type, new marriage configuration). | + +## Usage + +```bash +cd frontend +node scripts/capture-network-fixture.mjs +``` + +Defaults to `BACKEND_URL=http://localhost:8080` and the dev admin credentials. +Override via env vars (`BACKEND_URL`, `CAPTURE_EMAIL`, `CAPTURE_PASSWORD`). + +The script exits non-zero if the captured fixture would be vacuous (fewer than +100 nodes, fewer than 5 generations, or zero `SPOUSE_OF` edges). diff --git a/frontend/scripts/capture-network-fixture.mjs b/frontend/scripts/capture-network-fixture.mjs new file mode 100644 index 00000000..95fd9504 --- /dev/null +++ b/frontend/scripts/capture-network-fixture.mjs @@ -0,0 +1,121 @@ +#!/usr/bin/env node +// Local-only. Never invoked from CI. Re-run intentionally; commit the +// resulting JSON in one atomic commit. +// +// Captures the current /api/network response into the canonical fixture used +// by buildLayout.test.ts. Asserts a minimum shape so a silently-empty backend +// can't write a vacuous fixture. + +import { writeFileSync, mkdirSync } from 'node:fs'; +import { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { randomUUID } from 'node:crypto'; + +const BACKEND_URL = process.env.BACKEND_URL ?? 'http://localhost:8080'; +const EMAIL = process.env.CAPTURE_EMAIL ?? 'admin@familyarchive.local'; +const PASSWORD = process.env.CAPTURE_PASSWORD ?? 'admin123'; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const FIXTURE_PATH = `${HERE}/../src/lib/person/genealogy/__fixtures__/stammbaum.json`; + +// Sanity floors — calibrated against the canonical dataset (May 2026: 62 +// nodes, 5 generations, 28 SPOUSE_OF edges). The point is catching a silently +// empty backend, not strict size validation; raise these only if the +// canonical graph grows substantially. +const MIN_NODES = 50; +const MIN_GENERATIONS = 5; +const MIN_SPOUSE_OF_EDGES = 1; + +function parseSetCookies(headers) { + const out = new Map(); + const raw = headers.getSetCookie?.() ?? []; + for (const line of raw) { + const [pair] = line.split(';'); + const eq = pair.indexOf('='); + if (eq < 0) continue; + out.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim()); + } + return out; +} + +function serialiseCookies(jar) { + return [...jar.entries()].map(([k, v]) => `${k}=${v}`).join('; '); +} + +async function login(jar) { + const xsrf = randomUUID(); + jar.set('XSRF-TOKEN', xsrf); + const res = await fetch(`${BACKEND_URL}/api/auth/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-XSRF-TOKEN': xsrf, + Cookie: serialiseCookies(jar) + }, + body: JSON.stringify({ email: EMAIL, password: PASSWORD }) + }); + if (!res.ok) { + throw new Error(`Login failed: ${res.status} ${await res.text()}`); + } + for (const [k, v] of parseSetCookies(res.headers)) jar.set(k, v); +} + +async function fetchNetwork(jar) { + const res = await fetch(`${BACKEND_URL}/api/network`, { + headers: { Cookie: serialiseCookies(jar) } + }); + if (!res.ok) { + throw new Error(`GET /api/network failed: ${res.status} ${await res.text()}`); + } + return res.json(); +} + +function validate(network) { + const nodes = Array.isArray(network.nodes) ? network.nodes : []; + const edges = Array.isArray(network.edges) ? network.edges : []; + const spouseEdges = edges.filter((e) => e.relationType === 'SPOUSE_OF'); + const generations = new Set(nodes.map((n) => n.generation).filter((g) => g != null)); + + const failures = []; + if (nodes.length < MIN_NODES) { + failures.push(`expected >= ${MIN_NODES} nodes, got ${nodes.length}`); + } + if (generations.size < MIN_GENERATIONS) { + failures.push(`expected >= ${MIN_GENERATIONS} distinct generations, got ${generations.size}`); + } + if (spouseEdges.length < MIN_SPOUSE_OF_EDGES) { + failures.push(`expected >= ${MIN_SPOUSE_OF_EDGES} SPOUSE_OF edges, got ${spouseEdges.length}`); + } + if (failures.length > 0) { + throw new Error(`Sanity gates failed:\n - ${failures.join('\n - ')}`); + } + + return { + nodes: nodes.length, + edges: edges.length, + spouseEdges: spouseEdges.length, + generations: [...generations].sort((a, b) => a - b) + }; +} + +function writeFixture(network) { + mkdirSync(dirname(FIXTURE_PATH), { recursive: true }); + writeFileSync(FIXTURE_PATH, JSON.stringify(network, null, '\t') + '\n', 'utf8'); +} + +async function main() { + const jar = new Map(); + console.error(`Capturing /api/network from ${BACKEND_URL} as ${EMAIL} ...`); + await login(jar); + const network = await fetchNetwork(jar); + const stats = validate(network); + writeFixture(network); + console.error( + `Wrote ${FIXTURE_PATH}\n nodes: ${stats.nodes}\n edges: ${stats.edges}\n SPOUSE_OF edges: ${stats.spouseEdges}\n generations: G${stats.generations.join(', G')}` + ); +} + +main().catch((err) => { + console.error(err.message); + process.exit(1); +}); diff --git a/frontend/src/lib/person/genealogy/__fixtures__/README.md b/frontend/src/lib/person/genealogy/__fixtures__/README.md new file mode 100644 index 00000000..1a5dee8d --- /dev/null +++ b/frontend/src/lib/person/genealogy/__fixtures__/README.md @@ -0,0 +1,25 @@ +# `__fixtures__/` + +Pinned real-data fixtures used by Stammbaum layout tests. + +## `stammbaum.json` + +Snapshot of `GET /api/network` against the canonical Familienarchiv dataset. +Captured by `frontend/scripts/capture-network-fixture.mjs`. + +### Lifecycle + +The fixture is **pinned**, not auto-tracked. Tests assert _structural_ +properties (e.g. "a person with ≥ 2 spouses exists") rather than identity +("Albert has exactly 4 spouses"), so the fixture survives data growth without +mechanical edits. + +Re-capture and update the affected tests in a single intentional commit when a +new structural case appears in the production graph (new edge type, new +marriage configuration, new generation range). + +### PII + +The repository is private and the fixture contains real family names. If the +repository ever opens, scrubbing is a one-shot migration commit, not a +permanent test-authoring constraint. diff --git a/frontend/src/lib/person/genealogy/__fixtures__/stammbaum.json b/frontend/src/lib/person/genealogy/__fixtures__/stammbaum.json new file mode 100644 index 00000000..7544f313 --- /dev/null +++ b/frontend/src/lib/person/genealogy/__fixtures__/stammbaum.json @@ -0,0 +1,1147 @@ +{ + "nodes": [ + { + "id": "e382b0ef-247a-460c-80da-b442b17702c2", + "displayName": "Elsgard Allemeyer", + "birthYear": 1920, + "deathYear": 1999, + "generation": 3, + "familyMember": true + }, + { + "id": "afde2dfd-8f0c-4e49-b0c9-8aaeb869024f", + "displayName": "Werner Allemeyer", + "birthYear": null, + "deathYear": 1984, + "generation": 3, + "familyMember": true + }, + { + "id": "32eada1c-a4b9-4248-beee-3c0696d750d6", + "displayName": "Else Bohrmann", + "birthYear": 1888, + "deathYear": 1953, + "generation": 2, + "familyMember": true + }, + { + "id": "75305039-130a-432e-b1a7-80d6733e71d0", + "displayName": "Kurt Bohrmann", + "birthYear": 1925, + "deathYear": null, + "generation": 3, + "familyMember": true + }, + { + "id": "84893538-cee7-4797-a706-cdffc2d53cd4", + "displayName": "Ludwig Bohrmann", + "birthYear": 1879, + "deathYear": 1971, + "generation": 2, + "familyMember": true + }, + { + "id": "957d4b32-c1d4-48db-ad08-0bd4f31852db", + "displayName": "Ruth Bohrmann", + "birthYear": null, + "deathYear": null, + "generation": 3, + "familyMember": true + }, + { + "id": "a8e2f568-5ac4-43ab-ad6c-3229dba2b633", + "displayName": "Ellen Burkhard- Meier", + "birthYear": 1900, + "deathYear": 1992, + "generation": 2, + "familyMember": true + }, + { + "id": "c995a48f-4f9b-4a8c-ba0e-769ff0d1c703", + "displayName": "Alma Cram", + "birthYear": 1884, + "deathYear": 1956, + "generation": 2, + "familyMember": true + }, + { + "id": "082389a9-9869-48c2-9d35-794e6afd6302", + "displayName": "Clara Cram", + "birthYear": 1891, + "deathYear": 1984, + "generation": 2, + "familyMember": true + }, + { + "id": "5c1d4717-ec54-4c50-b8b1-b3d714cf6ef1", + "displayName": "Doris Cram", + "birthYear": 1967, + "deathYear": null, + "generation": 4, + "familyMember": true + }, + { + "id": "0bc6a050-662f-41ee-a5fd-b3be8d55b649", + "displayName": "Erna Cram", + "birthYear": 1901, + "deathYear": 1989, + "generation": 2, + "familyMember": true + }, + { + "id": "b7ebbeb0-6831-4e3a-b7ea-bb41f779c809", + "displayName": "Gisela Cram", + "birthYear": 1931, + "deathYear": 2023, + "generation": 3, + "familyMember": true + }, + { + "id": "9a30d3ce-09d2-4077-8746-e16666c2b7aa", + "displayName": "Hans Cram", + "birthYear": 1886, + "deathYear": 1962, + "generation": 2, + "familyMember": true + }, + { + "id": "bd7da036-e306-427d-8208-fc8440d31004", + "displayName": "Herbert Cram", + "birthYear": 1890, + "deathYear": 1967, + "generation": 2, + "familyMember": true + }, + { + "id": "aed48d4d-c405-4bbe-8fa3-cdd9c8f136bf", + "displayName": "Ilse Cram", + "birthYear": 1931, + "deathYear": null, + "generation": 3, + "familyMember": true + }, + { + "id": "83163451-0582-4956-a1b4-1411de2fbe18", + "displayName": "John James ( Juan) Cram", + "birthYear": 1855, + "deathYear": 1936, + "generation": 1, + "familyMember": true + }, + { + "id": "025fec69-6007-4023-a8fb-c77d72c85495", + "displayName": "Jutta Cram", + "birthYear": 1959, + "deathYear": null, + "generation": 4, + "familyMember": true + }, + { + "id": "ff922515-cdf2-4e47-a8d5-d51424d56e33", + "displayName": "Kurt-Georg Cram", + "birthYear": 1920, + "deathYear": null, + "generation": 3, + "familyMember": true + }, + { + "id": "3b8bdf39-2a1d-41af-acd6-41c82f56bd99", + "displayName": "Marie Cram", + "birthYear": 1863, + "deathYear": 1936, + "generation": 1, + "familyMember": true + }, + { + "id": "9a6939c4-798e-4d61-8798-2b64baa76917", + "displayName": "Martin Cram", + "birthYear": 1956, + "deathYear": null, + "generation": 4, + "familyMember": true + }, + { + "id": "c3c3041e-dcbc-49f2-b796-7573d47982c2", + "displayName": "Otto (Herbert) Cram", + "birthYear": 1931, + "deathYear": 2005, + "generation": 3, + "familyMember": true + }, + { + "id": "f0876cbf-cdd7-4ebe-ab6a-c0b0158f8b95", + "displayName": "Ralph Cram", + "birthYear": 1892, + "deathYear": 1982, + "generation": 2, + "familyMember": true + }, + { + "id": "4663ec14-17c3-4695-b1fb-ce2b84b5ca6a", + "displayName": "Walter (John) Cram", + "birthYear": 1925, + "deathYear": 1974, + "generation": 3, + "familyMember": true + }, + { + "id": "820fe7ce-0a0a-4597-bead-cc7899aa099b", + "displayName": "Ingrid Cram Heydrich", + "birthYear": 1935, + "deathYear": null, + "generation": 3, + "familyMember": true + }, + { + "id": "dd91a302-984a-401f-bb2e-62266fb0a8db", + "displayName": "Karl-August Crisolli", + "birthYear": 1900, + "deathYear": 1935, + "generation": 2, + "familyMember": true + }, + { + "id": "1763587e-ca6d-4d44-975c-6063953fc5eb", + "displayName": "Dolores (Dodo) Duncker", + "birthYear": 1928, + "deathYear": 1987, + "generation": 3, + "familyMember": true + }, + { + "id": "7f38df5d-afb5-47f9-bff5-d4d9e32e9a2e", + "displayName": "Max Duncker", + "birthYear": 1909, + "deathYear": 1998, + "generation": 3, + "familyMember": true + }, + { + "id": "13eb7b71-3a68-406a-90c9-63998cc643c1", + "displayName": "Bernhard Duvenbeck", + "birthYear": 1917, + "deathYear": 1997, + "generation": 3, + "familyMember": true + }, + { + "id": "e94a4554-448f-4cd6-8fd6-1c30fc5b057c", + "displayName": "Birgitta Duvenbeck", + "birthYear": 1946, + "deathYear": null, + "generation": 4, + "familyMember": true + }, + { + "id": "d973b7ef-5da9-43ec-aabd-dc0523d6ef18", + "displayName": "Lili Duvenbeck", + "birthYear": 1916, + "deathYear": 2012, + "generation": 3, + "familyMember": true + }, + { + "id": "7e6cc8a5-40a5-40de-a40e-884127c0d555", + "displayName": "Alexander Lippstadt Kisker", + "birthYear": null, + "deathYear": null, + "generation": 0, + "familyMember": true + }, + { + "id": "8fc32481-b2ee-487f-8e86-d595b1a26d96", + "displayName": "Clara Kisker", + "birthYear": 1860, + "deathYear": 1941, + "generation": 0, + "familyMember": true + }, + { + "id": "6c45bfbd-8910-481f-8a32-b22e7cb14a56", + "displayName": "Emilie Liebrecht", + "birthYear": 1837, + "deathYear": 1864, + "generation": 0, + "familyMember": true + }, + { + "id": "7fcbcfb3-7ed4-4fbf-b58c-b09a628f5f82", + "displayName": "Eugenie Müller", + "birthYear": 1834, + "deathYear": 1904, + "generation": 0, + "familyMember": true + }, + { + "id": "6cf0e64f-e47b-4e8c-b328-bbc6986099fc", + "displayName": "Reinhard Müller", + "birthYear": 1825, + "deathYear": 1899, + "generation": 0, + "familyMember": true + }, + { + "id": "fe500d37-a12e-45c6-88a3-398a7fd753b3", + "displayName": "Hermann Ober", + "birthYear": 1926, + "deathYear": 2006, + "generation": 3, + "familyMember": true + }, + { + "id": "f4afc3d6-ee5d-414a-8f9c-a7fc5589a75b", + "displayName": "Inge Ober", + "birthYear": 1924, + "deathYear": 2007, + "generation": 3, + "familyMember": true + }, + { + "id": "37d9319d-33f0-4bf9-a4c9-df232ce36be8", + "displayName": "Emil Quast", + "birthYear": 1849, + "deathYear": 1922, + "generation": 1, + "familyMember": true + }, + { + "id": "8d2d90d2-c432-46a5-9eb8-96c6adf8762f", + "displayName": "Mary Quast", + "birthYear": 1851, + "deathYear": 1914, + "generation": 1, + "familyMember": true + }, + { + "id": "41741eda-b829-497a-a1e7-143dbc2a2609", + "displayName": "Harald (Bimchen) Roehr-Schefold", + "birthYear": 1931, + "deathYear": 1945, + "generation": 3, + "familyMember": true + }, + { + "id": "56e74621-6d1b-4228-810b-c34bb6f3827e", + "displayName": "Marlise(Marie Luise) Ross", + "birthYear": 1936, + "deathYear": 2019, + "generation": 3, + "familyMember": true + }, + { + "id": "8fab2df1-ca9d-4c73-8696-aac982f46499", + "displayName": "Adolf Schefold", + "birthYear": 1867, + "deathYear": 1953, + "generation": 1, + "familyMember": true + }, + { + "id": "f4fed60e-ad9e-44f5-9e92-47e6ba091804", + "displayName": "Mieze (Maria) Schefold", + "birthYear": 1900, + "deathYear": 1986, + "generation": 2, + "familyMember": true + }, + { + "id": "d0ef4291-3471-4e06-a030-5d122837ec69", + "displayName": "Bertha Schröder", + "birthYear": null, + "deathYear": null, + "generation": 0, + "familyMember": true + }, + { + "id": "c1c64f8f-085f-4db4-9282-7d45ac0b366b", + "displayName": "Emil Lennep Schröder", + "birthYear": null, + "deathYear": null, + "generation": 1, + "familyMember": true + }, + { + "id": "1fcc36c7-4339-42a3-be12-15407b08b14d", + "displayName": "Clara-Eugenie Seils", + "birthYear": 1927, + "deathYear": 2016, + "generation": 3, + "familyMember": true + }, + { + "id": "9f3fc274-0c97-41ec-9617-fa706674f97d", + "displayName": "Peter (Ernst Albert) Seils", + "birthYear": 1928, + "deathYear": 2021, + "generation": 3, + "familyMember": true + }, + { + "id": "aec81778-1efd-41e2-8777-927d322986d2", + "displayName": "Günther Siebert", + "birthYear": 1920, + "deathYear": 1991, + "generation": 3, + "familyMember": true + }, + { + "id": "a720e226-3994-48f5-b4d6-caa3e2d682b9", + "displayName": "Hannemarie sen. Siebert", + "birthYear": 1921, + "deathYear": 2016, + "generation": 3, + "familyMember": true + }, + { + "id": "9555355c-c9d5-4f71-8bc8-2c20791fade1", + "displayName": "Magdalena (Leni) Siebert", + "birthYear": 1892, + "deathYear": 1983, + "generation": 2, + "familyMember": true + }, + { + "id": "c5240f32-1439-4bad-b6e5-d060e30fcf0f", + "displayName": "Bärbel Thiel", + "birthYear": null, + "deathYear": null, + "generation": 4, + "familyMember": true + }, + { + "id": "1b0d9ca9-d708-415c-ba83-dab151cf6185", + "displayName": "Helga Thiel", + "birthYear": 1917, + "deathYear": null, + "generation": 3, + "familyMember": true + }, + { + "id": "25946c95-d7f8-4387-b030-81593902f6c7", + "displayName": "Anita Wöhler", + "birthYear": 1885, + "deathYear": 1948, + "generation": 2, + "familyMember": true + }, + { + "id": "5f2e148a-df21-4b21-83bd-c3cf5b0c8519", + "displayName": "Oskar Wöhler", + "birthYear": 1879, + "deathYear": 1945, + "generation": 2, + "familyMember": true + }, + { + "id": "10603175-16e1-4a06-9934-65d43c9c8d75", + "displayName": "Albert de Gruyter", + "birthYear": 1829, + "deathYear": 1900, + "generation": 0, + "familyMember": true + }, + { + "id": "568d6264-845d-45c3-9e0d-f02c65059aec", + "displayName": "Clara de Gruyter", + "birthYear": 1845, + "deathYear": 1892, + "generation": 0, + "familyMember": true + }, + { + "id": "7f8e6b61-110c-49a9-8427-5ae294cfa8aa", + "displayName": "Emilie de Gruyter", + "birthYear": 1837, + "deathYear": 1864, + "generation": 0, + "familyMember": true + }, + { + "id": "0ad77a4e-af10-49a2-89eb-6f345386e434", + "displayName": "Eugenie de Gruyter", + "birthYear": 1869, + "deathYear": 1950, + "generation": 1, + "familyMember": true + }, + { + "id": "07c49d34-1024-4afc-b62d-958ae1949cbf", + "displayName": "Hans de Gruyter", + "birthYear": 1889, + "deathYear": 1917, + "generation": 2, + "familyMember": true + }, + { + "id": "df8d41ca-b856-4978-85be-14e4b70ed7a2", + "displayName": "Hilde de Gruyter", + "birthYear": 1892, + "deathYear": 1975, + "generation": 2, + "familyMember": true + }, + { + "id": "97d58e98-2228-43b8-82ba-d0a4c0d9713e", + "displayName": "Ursula de Gruyter", + "birthYear": 1907, + "deathYear": 1989, + "generation": 2, + "familyMember": true + }, + { + "id": "f3158bf8-b3c8-43dd-a7dc-520f9ada7436", + "displayName": "Walter de Gruyter", + "birthYear": 1862, + "deathYear": 1923, + "generation": 1, + "familyMember": true + } + ], + "edges": [ + { + "id": "e284b55b-844d-414e-8d8e-eb172bf27dc3", + "personId": "957d4b32-c1d4-48db-ad08-0bd4f31852db", + "relatedPersonId": "75305039-130a-432e-b1a7-80d6733e71d0", + "personDisplayName": "Ruth Bohrmann", + "personBirthYear": null, + "personDeathYear": null, + "relatedPersonDisplayName": "Kurt Bohrmann", + "relatedPersonBirthYear": 1925, + "relatedPersonDeathYear": null, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "eaaf3846-e578-4160-8b2d-0d7108a3ef4a", + "personId": "c995a48f-4f9b-4a8c-ba0e-769ff0d1c703", + "relatedPersonId": "9a30d3ce-09d2-4077-8746-e16666c2b7aa", + "personDisplayName": "Alma Cram", + "personBirthYear": 1884, + "personDeathYear": 1956, + "relatedPersonDisplayName": "Hans Cram", + "relatedPersonBirthYear": 1886, + "relatedPersonDeathYear": 1962, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "341468e1-92f1-4919-9640-b76bff2c9738", + "personId": "f3158bf8-b3c8-43dd-a7dc-520f9ada7436", + "relatedPersonId": "082389a9-9869-48c2-9d35-794e6afd6302", + "personDisplayName": "Walter de Gruyter", + "personBirthYear": 1862, + "personDeathYear": 1923, + "relatedPersonDisplayName": "Clara Cram", + "relatedPersonBirthYear": 1891, + "relatedPersonDeathYear": 1984, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "f7e93b48-76e0-431a-9e73-a7cc8d2dacc7", + "personId": "0ad77a4e-af10-49a2-89eb-6f345386e434", + "relatedPersonId": "082389a9-9869-48c2-9d35-794e6afd6302", + "personDisplayName": "Eugenie de Gruyter", + "personBirthYear": 1869, + "personDeathYear": 1950, + "relatedPersonDisplayName": "Clara Cram", + "relatedPersonBirthYear": 1891, + "relatedPersonDeathYear": 1984, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "c6f51bd5-bd92-4794-a627-4083b92a7ece", + "personId": "83163451-0582-4956-a1b4-1411de2fbe18", + "relatedPersonId": "bd7da036-e306-427d-8208-fc8440d31004", + "personDisplayName": "John James ( Juan) Cram", + "personBirthYear": 1855, + "personDeathYear": 1936, + "relatedPersonDisplayName": "Herbert Cram", + "relatedPersonBirthYear": 1890, + "relatedPersonDeathYear": 1967, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "63908546-50b5-4679-8440-e3197a47f817", + "personId": "082389a9-9869-48c2-9d35-794e6afd6302", + "relatedPersonId": "bd7da036-e306-427d-8208-fc8440d31004", + "personDisplayName": "Clara Cram", + "personBirthYear": 1891, + "personDeathYear": 1984, + "relatedPersonDisplayName": "Herbert Cram", + "relatedPersonBirthYear": 1890, + "relatedPersonDeathYear": 1967, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "2c06caec-b4c1-47cf-9ff2-0773f3583ae7", + "personId": "0bc6a050-662f-41ee-a5fd-b3be8d55b649", + "relatedPersonId": "f0876cbf-cdd7-4ebe-ab6a-c0b0158f8b95", + "personDisplayName": "Erna Cram", + "personBirthYear": 1901, + "personDeathYear": 1989, + "relatedPersonDisplayName": "Ralph Cram", + "relatedPersonBirthYear": 1892, + "relatedPersonDeathYear": 1982, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "6a4d3d0e-2cbe-49e0-b7e0-b52b5bd637aa", + "personId": "b7ebbeb0-6831-4e3a-b7ea-bb41f779c809", + "relatedPersonId": "ff922515-cdf2-4e47-a8d5-d51424d56e33", + "personDisplayName": "Gisela Cram", + "personBirthYear": 1931, + "personDeathYear": 2023, + "relatedPersonDisplayName": "Kurt-Georg Cram", + "relatedPersonBirthYear": 1920, + "relatedPersonDeathYear": null, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "6fbf2881-d448-4845-a544-f53d611206fa", + "personId": "aed48d4d-c405-4bbe-8fa3-cdd9c8f136bf", + "relatedPersonId": "c3c3041e-dcbc-49f2-b796-7573d47982c2", + "personDisplayName": "Ilse Cram", + "personBirthYear": 1931, + "personDeathYear": null, + "relatedPersonDisplayName": "Otto (Herbert) Cram", + "relatedPersonBirthYear": 1931, + "relatedPersonDeathYear": 2005, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "0dfa5341-91a2-4287-86d4-765f577f7295", + "personId": "83163451-0582-4956-a1b4-1411de2fbe18", + "relatedPersonId": "3b8bdf39-2a1d-41af-acd6-41c82f56bd99", + "personDisplayName": "John James ( Juan) Cram", + "personBirthYear": 1855, + "personDeathYear": 1936, + "relatedPersonDisplayName": "Marie Cram", + "relatedPersonBirthYear": 1863, + "relatedPersonDeathYear": 1936, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "414b8bcb-f50b-4b83-a617-ddf6e7fb163b", + "personId": "025fec69-6007-4023-a8fb-c77d72c85495", + "relatedPersonId": "9a6939c4-798e-4d61-8798-2b64baa76917", + "personDisplayName": "Jutta Cram", + "personBirthYear": 1959, + "personDeathYear": null, + "relatedPersonDisplayName": "Martin Cram", + "relatedPersonBirthYear": 1956, + "relatedPersonDeathYear": null, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "bfb03284-a79b-4430-894c-848a3a2ec576", + "personId": "4663ec14-17c3-4695-b1fb-ce2b84b5ca6a", + "relatedPersonId": "820fe7ce-0a0a-4597-bead-cc7899aa099b", + "personDisplayName": "Walter (John) Cram", + "personBirthYear": 1925, + "personDeathYear": 1974, + "relatedPersonDisplayName": "Ingrid Cram Heydrich", + "relatedPersonBirthYear": 1935, + "relatedPersonDeathYear": null, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "318b904e-5578-4224-8e26-56622b61ddd5", + "personId": "dd91a302-984a-401f-bb2e-62266fb0a8db", + "relatedPersonId": "a8e2f568-5ac4-43ab-ad6c-3229dba2b633", + "personDisplayName": "Karl-August Crisolli", + "personBirthYear": 1900, + "personDeathYear": 1935, + "relatedPersonDisplayName": "Ellen Burkhard- Meier", + "relatedPersonBirthYear": 1900, + "relatedPersonDeathYear": 1992, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "4b395c1b-ee67-44cc-be53-bd0615dd3453", + "personId": "d0ef4291-3471-4e06-a030-5d122837ec69", + "relatedPersonId": "0ad77a4e-af10-49a2-89eb-6f345386e434", + "personDisplayName": "Bertha Schröder", + "personBirthYear": null, + "personDeathYear": null, + "relatedPersonDisplayName": "Eugenie de Gruyter", + "relatedPersonBirthYear": 1869, + "relatedPersonDeathYear": 1950, + "relationType": "SIBLING_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "3d1b9184-9a7b-4191-b735-97c50d273487", + "personId": "6cf0e64f-e47b-4e8c-b328-bbc6986099fc", + "relatedPersonId": "0ad77a4e-af10-49a2-89eb-6f345386e434", + "personDisplayName": "Reinhard Müller", + "personBirthYear": 1825, + "personDeathYear": 1899, + "relatedPersonDisplayName": "Eugenie de Gruyter", + "relatedPersonBirthYear": 1869, + "relatedPersonDeathYear": 1950, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "6ed33482-e100-46cf-93d0-da9bdf8b3a51", + "personId": "7fcbcfb3-7ed4-4fbf-b58c-b09a628f5f82", + "relatedPersonId": "0ad77a4e-af10-49a2-89eb-6f345386e434", + "personDisplayName": "Eugenie Müller", + "personBirthYear": 1834, + "personDeathYear": 1904, + "relatedPersonDisplayName": "Eugenie de Gruyter", + "relatedPersonBirthYear": 1869, + "relatedPersonDeathYear": 1950, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "f76c1dbe-2c0f-421f-bdf0-9a15c251fca2", + "personId": "c3c3041e-dcbc-49f2-b796-7573d47982c2", + "relatedPersonId": "5c1d4717-ec54-4c50-b8b1-b3d714cf6ef1", + "personDisplayName": "Otto (Herbert) Cram", + "personBirthYear": 1931, + "personDeathYear": 2005, + "relatedPersonDisplayName": "Doris Cram", + "relatedPersonBirthYear": 1967, + "relatedPersonDeathYear": null, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "a96bb001-d03b-486b-95f0-18b1b03aaa32", + "personId": "07c49d34-1024-4afc-b62d-958ae1949cbf", + "relatedPersonId": "df8d41ca-b856-4978-85be-14e4b70ed7a2", + "personDisplayName": "Hans de Gruyter", + "personBirthYear": 1889, + "personDeathYear": 1917, + "relatedPersonDisplayName": "Hilde de Gruyter", + "relatedPersonBirthYear": 1892, + "relatedPersonDeathYear": 1975, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "f86a0b4e-372d-4fe2-bbb8-2e2ff27e492d", + "personId": "13eb7b71-3a68-406a-90c9-63998cc643c1", + "relatedPersonId": "d973b7ef-5da9-43ec-aabd-dc0523d6ef18", + "personDisplayName": "Bernhard Duvenbeck", + "personBirthYear": 1917, + "personDeathYear": 1997, + "relatedPersonDisplayName": "Lili Duvenbeck", + "relatedPersonBirthYear": 1916, + "relatedPersonDeathYear": 2012, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "6125b3e2-9c72-46ca-aeab-dec96dca43e3", + "personId": "df8d41ca-b856-4978-85be-14e4b70ed7a2", + "relatedPersonId": "d973b7ef-5da9-43ec-aabd-dc0523d6ef18", + "personDisplayName": "Hilde de Gruyter", + "personBirthYear": 1892, + "personDeathYear": 1975, + "relatedPersonDisplayName": "Lili Duvenbeck", + "relatedPersonBirthYear": 1916, + "relatedPersonDeathYear": 2012, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "516fe0b9-da7e-4ceb-8339-a48e968631a7", + "personId": "7e6cc8a5-40a5-40de-a40e-884127c0d555", + "relatedPersonId": "8fc32481-b2ee-487f-8e86-d595b1a26d96", + "personDisplayName": "Alexander Lippstadt Kisker", + "personBirthYear": null, + "personDeathYear": null, + "relatedPersonDisplayName": "Clara Kisker", + "relatedPersonBirthYear": 1860, + "relatedPersonDeathYear": 1941, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "6625c3ff-1d62-439a-9241-43c21bacc81c", + "personId": "7fcbcfb3-7ed4-4fbf-b58c-b09a628f5f82", + "relatedPersonId": "6cf0e64f-e47b-4e8c-b328-bbc6986099fc", + "personDisplayName": "Eugenie Müller", + "personBirthYear": 1834, + "personDeathYear": 1904, + "relatedPersonDisplayName": "Reinhard Müller", + "relatedPersonBirthYear": 1825, + "relatedPersonDeathYear": 1899, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "48844923-ffc5-4096-865a-a0e28cfbc91f", + "personId": "fe500d37-a12e-45c6-88a3-398a7fd753b3", + "relatedPersonId": "f4afc3d6-ee5d-414a-8f9c-a7fc5589a75b", + "personDisplayName": "Hermann Ober", + "personBirthYear": 1926, + "personDeathYear": 2006, + "relatedPersonDisplayName": "Inge Ober", + "relatedPersonBirthYear": 1924, + "relatedPersonDeathYear": 2007, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "0ad043a4-6017-4641-a61f-a61d7a71bd3e", + "personId": "8d2d90d2-c432-46a5-9eb8-96c6adf8762f", + "relatedPersonId": "37d9319d-33f0-4bf9-a4c9-df232ce36be8", + "personDisplayName": "Mary Quast", + "personBirthYear": 1851, + "personDeathYear": 1914, + "relatedPersonDisplayName": "Emil Quast", + "relatedPersonBirthYear": 1849, + "relatedPersonDeathYear": 1922, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "004cccbd-cf31-46c5-898c-fbad84ddf541", + "personId": "13eb7b71-3a68-406a-90c9-63998cc643c1", + "relatedPersonId": "e94a4554-448f-4cd6-8fd6-1c30fc5b057c", + "personDisplayName": "Bernhard Duvenbeck", + "personBirthYear": 1917, + "personDeathYear": 1997, + "relatedPersonDisplayName": "Birgitta Duvenbeck", + "relatedPersonBirthYear": 1946, + "relatedPersonDeathYear": null, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "80180325-13ff-4b25-b165-093ca2f9c8c3", + "personId": "f4fed60e-ad9e-44f5-9e92-47e6ba091804", + "relatedPersonId": "41741eda-b829-497a-a1e7-143dbc2a2609", + "personDisplayName": "Mieze (Maria) Schefold", + "personBirthYear": 1900, + "personDeathYear": 1986, + "relatedPersonDisplayName": "Harald (Bimchen) Roehr-Schefold", + "relatedPersonBirthYear": 1931, + "relatedPersonDeathYear": 1945, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "071f2f90-1021-47ea-8a38-ea7279748bc5", + "personId": "f0876cbf-cdd7-4ebe-ab6a-c0b0158f8b95", + "relatedPersonId": "56e74621-6d1b-4228-810b-c34bb6f3827e", + "personDisplayName": "Ralph Cram", + "personBirthYear": 1892, + "personDeathYear": 1982, + "relatedPersonDisplayName": "Marlise(Marie Luise) Ross", + "relatedPersonBirthYear": 1936, + "relatedPersonDeathYear": 2019, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "085e06fa-914d-474c-93a4-7d5ea4057914", + "personId": "1fcc36c7-4339-42a3-be12-15407b08b14d", + "relatedPersonId": "9f3fc274-0c97-41ec-9617-fa706674f97d", + "personDisplayName": "Clara-Eugenie Seils", + "personBirthYear": 1927, + "personDeathYear": 2016, + "relatedPersonDisplayName": "Peter (Ernst Albert) Seils", + "relatedPersonBirthYear": 1928, + "relatedPersonDeathYear": 2021, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "ee58f307-78c7-4de3-aade-bd486cfc1395", + "personId": "9555355c-c9d5-4f71-8bc8-2c20791fade1", + "relatedPersonId": "aec81778-1efd-41e2-8777-927d322986d2", + "personDisplayName": "Magdalena (Leni) Siebert", + "personBirthYear": 1892, + "personDeathYear": 1983, + "relatedPersonDisplayName": "Günther Siebert", + "relatedPersonBirthYear": 1920, + "relatedPersonDeathYear": 1991, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "f071f5ab-7946-43c8-b86f-4180beb9aea9", + "personId": "a720e226-3994-48f5-b4d6-caa3e2d682b9", + "relatedPersonId": "aec81778-1efd-41e2-8777-927d322986d2", + "personDisplayName": "Hannemarie sen. Siebert", + "personBirthYear": 1921, + "personDeathYear": 2016, + "relatedPersonDisplayName": "Günther Siebert", + "relatedPersonBirthYear": 1920, + "relatedPersonDeathYear": 1991, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "5b128499-334e-4751-a745-606df664e0d0", + "personId": "25946c95-d7f8-4387-b030-81593902f6c7", + "relatedPersonId": "5f2e148a-df21-4b21-83bd-c3cf5b0c8519", + "personDisplayName": "Anita Wöhler", + "personBirthYear": 1885, + "personDeathYear": 1948, + "relatedPersonDisplayName": "Oskar Wöhler", + "relatedPersonBirthYear": 1879, + "relatedPersonDeathYear": 1945, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "77b410df-e31c-4c68-ac2c-1c8c2ce68545", + "personId": "8fab2df1-ca9d-4c73-8696-aac982f46499", + "relatedPersonId": "f4fed60e-ad9e-44f5-9e92-47e6ba091804", + "personDisplayName": "Adolf Schefold", + "personBirthYear": 1867, + "personDeathYear": 1953, + "relatedPersonDisplayName": "Mieze (Maria) Schefold", + "relatedPersonBirthYear": 1900, + "relatedPersonDeathYear": 1986, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "b48b5eb1-8ef0-4856-bf45-a09fedaa8123", + "personId": "1b0d9ca9-d708-415c-ba83-dab151cf6185", + "relatedPersonId": "c5240f32-1439-4bad-b6e5-d060e30fcf0f", + "personDisplayName": "Helga Thiel", + "personBirthYear": 1917, + "personDeathYear": null, + "relatedPersonDisplayName": "Bärbel Thiel", + "relatedPersonBirthYear": null, + "relatedPersonDeathYear": null, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "feea2073-5a25-4908-a116-9a5a9ceae9fa", + "personId": "e382b0ef-247a-460c-80da-b442b17702c2", + "relatedPersonId": "afde2dfd-8f0c-4e49-b0c9-8aaeb869024f", + "personDisplayName": "Elsgard Allemeyer", + "personBirthYear": 1920, + "personDeathYear": 1999, + "relatedPersonDisplayName": "Werner Allemeyer", + "relatedPersonBirthYear": null, + "relatedPersonDeathYear": 1984, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "ba55c368-1dd1-45e4-8e84-8a654e1b1024", + "personId": "32eada1c-a4b9-4248-beee-3c0696d750d6", + "relatedPersonId": "84893538-cee7-4797-a706-cdffc2d53cd4", + "personDisplayName": "Else Bohrmann", + "personBirthYear": 1888, + "personDeathYear": 1953, + "relatedPersonDisplayName": "Ludwig Bohrmann", + "relatedPersonBirthYear": 1879, + "relatedPersonDeathYear": 1971, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "7b60e480-eaf0-4be2-ba77-29f7bccf998a", + "personId": "6c45bfbd-8910-481f-8a32-b22e7cb14a56", + "relatedPersonId": "10603175-16e1-4a06-9934-65d43c9c8d75", + "personDisplayName": "Emilie Liebrecht", + "personBirthYear": 1837, + "personDeathYear": 1864, + "relatedPersonDisplayName": "Albert de Gruyter", + "relatedPersonBirthYear": 1829, + "relatedPersonDeathYear": 1900, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "8f0bcbbb-fdd4-492c-8db6-5c5bb40bdc0a", + "personId": "97d58e98-2228-43b8-82ba-d0a4c0d9713e", + "relatedPersonId": "10603175-16e1-4a06-9934-65d43c9c8d75", + "personDisplayName": "Ursula de Gruyter", + "personBirthYear": 1907, + "personDeathYear": 1989, + "relatedPersonDisplayName": "Albert de Gruyter", + "relatedPersonBirthYear": 1829, + "relatedPersonDeathYear": 1900, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "6711bf1f-1573-415c-b058-f5faa60ce900", + "personId": "7f8e6b61-110c-49a9-8427-5ae294cfa8aa", + "relatedPersonId": "10603175-16e1-4a06-9934-65d43c9c8d75", + "personDisplayName": "Emilie de Gruyter", + "personBirthYear": 1837, + "personDeathYear": 1864, + "relatedPersonDisplayName": "Albert de Gruyter", + "relatedPersonBirthYear": 1829, + "relatedPersonDeathYear": 1900, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "4177b3b0-a185-4325-aa1c-4f06488f7502", + "personId": "568d6264-845d-45c3-9e0d-f02c65059aec", + "relatedPersonId": "10603175-16e1-4a06-9934-65d43c9c8d75", + "personDisplayName": "Clara de Gruyter", + "personBirthYear": 1845, + "personDeathYear": 1892, + "relatedPersonDisplayName": "Albert de Gruyter", + "relatedPersonBirthYear": 1829, + "relatedPersonDeathYear": 1900, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "f88b969a-c10a-4bfc-ab02-6fbded29a1a3", + "personId": "10603175-16e1-4a06-9934-65d43c9c8d75", + "relatedPersonId": "f3158bf8-b3c8-43dd-a7dc-520f9ada7436", + "personDisplayName": "Albert de Gruyter", + "personBirthYear": 1829, + "personDeathYear": 1900, + "relatedPersonDisplayName": "Walter de Gruyter", + "relatedPersonBirthYear": 1862, + "relatedPersonDeathYear": 1923, + "relationType": "PARENT_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "d0622311-974d-468d-9df6-2f31d0cd302a", + "personId": "0ad77a4e-af10-49a2-89eb-6f345386e434", + "relatedPersonId": "f3158bf8-b3c8-43dd-a7dc-520f9ada7436", + "personDisplayName": "Eugenie de Gruyter", + "personBirthYear": 1869, + "personDeathYear": 1950, + "relatedPersonDisplayName": "Walter de Gruyter", + "relatedPersonBirthYear": 1862, + "relatedPersonDeathYear": 1923, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "67058d27-6c58-4ee8-956d-48a61686cb9c", + "personId": "7f38df5d-afb5-47f9-bff5-d4d9e32e9a2e", + "relatedPersonId": "1763587e-ca6d-4d44-975c-6063953fc5eb", + "personDisplayName": "Max Duncker", + "personBirthYear": 1909, + "personDeathYear": 1998, + "relatedPersonDisplayName": "Dolores (Dodo) Duncker", + "relatedPersonBirthYear": 1928, + "relatedPersonDeathYear": 1987, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + }, + { + "id": "e047e96a-be48-4c81-8ac6-524fb9504422", + "personId": "c1c64f8f-085f-4db4-9282-7d45ac0b366b", + "relatedPersonId": "d0ef4291-3471-4e06-a030-5d122837ec69", + "personDisplayName": "Emil Lennep Schröder", + "personBirthYear": null, + "personDeathYear": null, + "relatedPersonDisplayName": "Bertha Schröder", + "relatedPersonBirthYear": null, + "relatedPersonDeathYear": null, + "relationType": "SPOUSE_OF", + "fromYear": null, + "toYear": null, + "notes": null + } + ] +}