Alternate names (maiden/married), self-person link, deletion integrity
Names (the genealogy standard: maiden name primary, married/alias as typed
alternates):
- Name model already supported multiple typed names; expose full CRUD —
NameCreate/Read/Update schemas, name_service (one-primary invariant,
promote-on-delete), nested /persons/{id}/names routes.
- Person page gains a Names card: add/edit/delete + "make primary", with a
curated name_type dropdown (birth/maiden, married, alias, nickname, …).
Self-person ("who am I"):
- users.self_person_id FK (use_alter for the users<->persons<->trees cycle)
+ migration; PATCH /users/me/self-person; "This is me" / "This is you"
on the person page. Soft-deleting the linked person clears it.
Deletion integrity (fixes the broken tree view):
- delete_person now soft-deletes the relationships touching the person, so no
dangling edges remain; family-chart also filters links to missing people.
- Optional cascade=true recursively deletes descendants (GEDCOM cleanup);
the person page asks "only this person" vs "with all descendants".
- DELETE returns {deleted: n}.
Family view surfaces "Not connected to anyone" so dangling people aren't lost.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vendored
+325
-4
@@ -157,6 +157,26 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/users/me/self-person": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
/**
|
||||
* Set Self Person
|
||||
* @description Link (or unlink) the Person record that represents this account.
|
||||
*/
|
||||
patch: operations["set_self_person_api_v1_users_me_self_person_patch"];
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/trees": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -240,7 +260,11 @@ export interface paths {
|
||||
get: operations["get_person_api_v1_trees__tree_id__persons__person_id__get"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
/** Delete Person */
|
||||
/**
|
||||
* Delete Person
|
||||
* @description Delete a person. ``cascade=true`` also deletes all descendants. Returns
|
||||
* the number of persons deleted (1 unless cascading).
|
||||
*/
|
||||
delete: operations["delete_person_api_v1_trees__tree_id__persons__person_id__delete"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
@@ -265,6 +289,42 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/trees/{tree_id}/persons/{person_id}/names": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** List Names */
|
||||
get: operations["list_names_api_v1_trees__tree_id__persons__person_id__names_get"];
|
||||
put?: never;
|
||||
/** Create Name */
|
||||
post: operations["create_name_api_v1_trees__tree_id__persons__person_id__names_post"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/trees/{tree_id}/persons/{person_id}/names/{name_id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
/** Delete Name */
|
||||
delete: operations["delete_name_api_v1_trees__tree_id__persons__person_id__names__name_id__delete"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
/** Update Name */
|
||||
patch: operations["update_name_api_v1_trees__tree_id__persons__person_id__names__name_id__patch"];
|
||||
trace?: never;
|
||||
};
|
||||
"/api/v1/trees/{tree_id}/events": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -780,6 +840,85 @@ export interface components {
|
||||
/** Source Id */
|
||||
source_id?: string | null;
|
||||
};
|
||||
/** NameCreate */
|
||||
NameCreate: {
|
||||
/**
|
||||
* Name Type
|
||||
* @default birth
|
||||
*/
|
||||
name_type?: string;
|
||||
/** Given */
|
||||
given?: string | null;
|
||||
/** Surname */
|
||||
surname?: string | null;
|
||||
/** Prefix */
|
||||
prefix?: string | null;
|
||||
/** Suffix */
|
||||
suffix?: string | null;
|
||||
/** Nickname */
|
||||
nickname?: string | null;
|
||||
/**
|
||||
* Is Primary
|
||||
* @default false
|
||||
*/
|
||||
is_primary?: boolean;
|
||||
};
|
||||
/** NameRead */
|
||||
NameRead: {
|
||||
/**
|
||||
* Id
|
||||
* Format: uuid
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Tree Id
|
||||
* Format: uuid
|
||||
*/
|
||||
tree_id: string;
|
||||
/**
|
||||
* Person Id
|
||||
* Format: uuid
|
||||
*/
|
||||
person_id: string;
|
||||
/** Name Type */
|
||||
name_type: string;
|
||||
/** Given */
|
||||
given: string | null;
|
||||
/** Surname */
|
||||
surname: string | null;
|
||||
/** Prefix */
|
||||
prefix: string | null;
|
||||
/** Suffix */
|
||||
suffix: string | null;
|
||||
/** Nickname */
|
||||
nickname: string | null;
|
||||
/** Is Primary */
|
||||
is_primary: boolean;
|
||||
/** Sort Order */
|
||||
sort_order: number;
|
||||
/**
|
||||
* Created At
|
||||
* Format: date-time
|
||||
*/
|
||||
created_at: string;
|
||||
};
|
||||
/** NameUpdate */
|
||||
NameUpdate: {
|
||||
/** Name Type */
|
||||
name_type?: string | null;
|
||||
/** Given */
|
||||
given?: string | null;
|
||||
/** Surname */
|
||||
surname?: string | null;
|
||||
/** Prefix */
|
||||
prefix?: string | null;
|
||||
/** Suffix */
|
||||
suffix?: string | null;
|
||||
/** Nickname */
|
||||
nickname?: string | null;
|
||||
/** Is Primary */
|
||||
is_primary?: boolean | null;
|
||||
};
|
||||
/**
|
||||
* ParentChildQualifier
|
||||
* @description Qualifies a parent_child edge so adoption/donor/blended families are
|
||||
@@ -1074,12 +1213,19 @@ export interface components {
|
||||
display_name: string | null;
|
||||
/** Email Verified At */
|
||||
email_verified_at: string | null;
|
||||
/** Self Person Id */
|
||||
self_person_id?: string | null;
|
||||
/**
|
||||
* Created At
|
||||
* Format: date-time
|
||||
*/
|
||||
created_at: string;
|
||||
};
|
||||
/** UserSelfPersonUpdate */
|
||||
UserSelfPersonUpdate: {
|
||||
/** Self Person Id */
|
||||
self_person_id?: string | null;
|
||||
};
|
||||
/** ValidationError */
|
||||
ValidationError: {
|
||||
/** Location */
|
||||
@@ -1347,6 +1493,39 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
set_self_person_api_v1_users_me_self_person_patch: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["UserSelfPersonUpdate"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["UserRead"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
list_my_trees_api_v1_trees_get: {
|
||||
parameters: {
|
||||
query?: {
|
||||
@@ -1640,7 +1819,9 @@ export interface operations {
|
||||
};
|
||||
delete_person_api_v1_trees__tree_id__persons__person_id__delete: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
query?: {
|
||||
cascade?: boolean;
|
||||
};
|
||||
header?: never;
|
||||
path: {
|
||||
tree_id: string;
|
||||
@@ -1651,11 +1832,15 @@ export interface operations {
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
204: {
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
content: {
|
||||
"application/json": {
|
||||
[key: string]: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
@@ -1736,6 +1921,142 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
list_names_api_v1_trees__tree_id__persons__person_id__names_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
tree_id: string;
|
||||
person_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["NameRead"][];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
create_name_api_v1_trees__tree_id__persons__person_id__names_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
tree_id: string;
|
||||
person_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["NameCreate"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
201: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["NameRead"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
delete_name_api_v1_trees__tree_id__persons__person_id__names__name_id__delete: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
tree_id: string;
|
||||
person_id: string;
|
||||
name_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
204: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
update_name_api_v1_trees__tree_id__persons__person_id__names__name_id__patch: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
tree_id: string;
|
||||
person_id: string;
|
||||
name_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["NameUpdate"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["NameRead"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
list_tree_events_api_v1_trees__tree_id__events_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
Reference in New Issue
Block a user