Account menu + Settings (change password); per-tree home person; full-width tree

- Sidebar bottom-left now shows the signed-in user; clicking opens a menu with
  Settings and Sign out. New /settings page: account info + change password
  (POST /auth/change-password, re-verifies current password). Export/restore/
  delete are stubbed there for the next pass.
- Per-tree default/home person: tree.home_person_id (migration) + TreeUpdate/
  Read; the tree and family views open focused on it; the person page gets a
  "Set as default" control and "Default person" badge. Cleared if that person
  is deleted. Complements the account-level "this is me" link.
- Tree visualization now fills the content area (AppShell drops the max-width
  column on the /tree route); other pages stay centered.
- Audit records are coerced JSON-safe (UUIDs/enums), so PATCHing UUID fields
  like home_person_id audits cleanly.

50 backend tests pass; migration up/down verified; frontend builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 11:05:04 -04:00
parent a8929c2862
commit 0262ed3d97
19 changed files with 521 additions and 26 deletions
+59
View File
@@ -140,6 +140,23 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/v1/auth/change-password": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/** Change Password */
post: operations["change_password_api_v1_auth_change_password_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/v1/users/me": {
parameters: {
query?: never;
@@ -998,6 +1015,13 @@ export interface components {
* @enum {string}
*/
ParentChildQualifier: "biological" | "adoptive" | "step" | "foster" | "donor" | "guardian";
/** PasswordChange */
PasswordChange: {
/** Current Password */
current_password: string;
/** New Password */
new_password: string;
};
/** PasswordResetConfirm */
PasswordResetConfirm: {
/** Token */
@@ -1253,6 +1277,8 @@ export interface components {
* Format: uuid
*/
owner_id: string;
/** Home Person Id */
home_person_id?: string | null;
/**
* Created At
* Format: date-time
@@ -1266,6 +1292,8 @@ export interface components {
/** Description */
description?: string | null;
visibility?: components["schemas"]["TreeVisibility"] | null;
/** Home Person Id */
home_person_id?: string | null;
};
/**
* TreeVisibility
@@ -1545,6 +1573,37 @@ export interface operations {
};
};
};
change_password_api_v1_auth_change_password_post: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["PasswordChange"];
};
};
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"];
};
};
};
};
read_me_api_v1_users_me_get: {
parameters: {
query?: never;