Files
provenance/frontend/openapi.json
T
justin a5a79f01a7 Scaffold Next.js frontend with generated OpenAPI client and core views
Next.js (App Router) + React 19 + TypeScript + Tailwind v4, with shadcn-style UI primitives (Button, Input, Card, Label via cva/tailwind-merge). A typed API client is generated from the backend OpenAPI spec with openapi-typescript + openapi-fetch (npm run gen:api); the committed openapi.json/schema.d.ts are the snapshot.

Views: landing, login, register, tree list + create, and tree detail with person list + create. Auth rides the same-origin HttpOnly session cookie the backend sets (Caddy proxies /api/*), so no token handling in JS. Built as a standalone container. Mobile-first; next build is clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
2026-06-06 11:03:07 -04:00

936 lines
22 KiB
JSON

{
"openapi": "3.1.0",
"info": {
"title": "Provenance",
"description": "Provenance API \u2014 family and land provenance.",
"version": "0.0.0"
},
"paths": {
"/health": {
"get": {
"tags": [
"health"
],
"summary": "Health",
"operationId": "health_health_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"additionalProperties": true,
"type": "object",
"title": "Response Health Health Get"
}
}
}
}
}
}
},
"/health/ready": {
"get": {
"tags": [
"health"
],
"summary": "Ready",
"operationId": "ready_health_ready_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"additionalProperties": true,
"type": "object",
"title": "Response Ready Health Ready Get"
}
}
}
}
}
}
},
"/api/v1/auth/register": {
"post": {
"tags": [
"auth"
],
"summary": "Register",
"operationId": "register_api_v1_auth_register_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RegisterRequest"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SessionRead"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/v1/auth/login": {
"post": {
"tags": [
"auth"
],
"summary": "Login",
"operationId": "login_api_v1_auth_login_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SessionRead"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/v1/auth/logout": {
"post": {
"tags": [
"auth"
],
"summary": "Logout",
"operationId": "logout_api_v1_auth_logout_post",
"responses": {
"204": {
"description": "Successful Response"
}
}
}
},
"/api/v1/auth/verify-email": {
"post": {
"tags": [
"auth"
],
"summary": "Verify Email",
"operationId": "verify_email_api_v1_auth_verify_email_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TokenRequest"
}
}
},
"required": true
},
"responses": {
"204": {
"description": "Successful Response"
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/v1/auth/request-password-reset": {
"post": {
"tags": [
"auth"
],
"summary": "Request Password Reset",
"operationId": "request_password_reset_api_v1_auth_request_password_reset_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PasswordResetRequest"
}
}
},
"required": true
},
"responses": {
"202": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"additionalProperties": true,
"type": "object",
"title": "Response Request Password Reset Api V1 Auth Request Password Reset Post"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/v1/auth/reset-password": {
"post": {
"tags": [
"auth"
],
"summary": "Reset Password",
"operationId": "reset_password_api_v1_auth_reset_password_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PasswordResetConfirm"
}
}
},
"required": true
},
"responses": {
"204": {
"description": "Successful Response"
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/v1/users/me": {
"get": {
"tags": [
"users"
],
"summary": "Read Me",
"operationId": "read_me_api_v1_users_me_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserRead"
}
}
}
}
}
}
},
"/api/v1/trees": {
"get": {
"tags": [
"trees"
],
"summary": "List My Trees",
"operationId": "list_my_trees_api_v1_trees_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/TreeRead"
},
"type": "array",
"title": "Response List My Trees Api V1 Trees Get"
}
}
}
}
}
},
"post": {
"tags": [
"trees"
],
"summary": "Create Tree",
"operationId": "create_tree_api_v1_trees_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TreeCreate"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TreeRead"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/v1/trees/{tree_id}": {
"get": {
"tags": [
"trees"
],
"summary": "Get Tree",
"operationId": "get_tree_api_v1_trees__tree_id__get",
"parameters": [
{
"name": "tree_id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid",
"title": "Tree Id"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TreeRead"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/v1/trees/{tree_id}/persons": {
"post": {
"tags": [
"persons"
],
"summary": "Create Person",
"operationId": "create_person_api_v1_trees__tree_id__persons_post",
"parameters": [
{
"name": "tree_id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid",
"title": "Tree Id"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PersonCreate"
}
}
}
},
"responses": {
"201": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PersonRead"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
},
"get": {
"tags": [
"persons"
],
"summary": "List Persons",
"operationId": "list_persons_api_v1_trees__tree_id__persons_get",
"parameters": [
{
"name": "tree_id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid",
"title": "Tree Id"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PersonRead"
},
"title": "Response List Persons Api V1 Trees Tree Id Persons Get"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
},
"LoginRequest": {
"properties": {
"email": {
"type": "string",
"title": "Email"
},
"password": {
"type": "string",
"title": "Password"
}
},
"type": "object",
"required": [
"email",
"password"
],
"title": "LoginRequest"
},
"PasswordResetConfirm": {
"properties": {
"token": {
"type": "string",
"title": "Token"
},
"new_password": {
"type": "string",
"minLength": 8,
"title": "New Password"
}
},
"type": "object",
"required": [
"token",
"new_password"
],
"title": "PasswordResetConfirm"
},
"PasswordResetRequest": {
"properties": {
"email": {
"type": "string",
"title": "Email"
}
},
"type": "object",
"required": [
"email"
],
"title": "PasswordResetRequest"
},
"PersonCreate": {
"properties": {
"given": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Given"
},
"surname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Surname"
},
"gender": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Gender"
},
"is_living": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Is Living"
},
"privacy": {
"$ref": "#/components/schemas/PersonPrivacy",
"default": "inherit"
},
"notes": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Notes"
}
},
"type": "object",
"title": "PersonCreate"
},
"PersonPrivacy": {
"type": "string",
"enum": [
"inherit",
"private",
"public"
],
"title": "PersonPrivacy",
"description": "Per-person override of the tree's visibility (PRD US-041)."
},
"PersonRead": {
"properties": {
"id": {
"type": "string",
"format": "uuid",
"title": "Id"
},
"tree_id": {
"type": "string",
"format": "uuid",
"title": "Tree Id"
},
"primary_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Primary Name"
},
"gender": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Gender"
},
"is_living": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Is Living"
},
"privacy": {
"$ref": "#/components/schemas/PersonPrivacy"
},
"created_at": {
"type": "string",
"format": "date-time",
"title": "Created At"
}
},
"type": "object",
"required": [
"id",
"tree_id",
"gender",
"is_living",
"privacy",
"created_at"
],
"title": "PersonRead"
},
"RegisterRequest": {
"properties": {
"email": {
"type": "string",
"title": "Email"
},
"password": {
"type": "string",
"minLength": 8,
"title": "Password"
},
"display_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Display Name"
}
},
"type": "object",
"required": [
"email",
"password"
],
"title": "RegisterRequest"
},
"SessionRead": {
"properties": {
"user": {
"$ref": "#/components/schemas/UserRead"
},
"token": {
"type": "string",
"title": "Token"
},
"expires_at": {
"type": "string",
"format": "date-time",
"title": "Expires At"
}
},
"type": "object",
"required": [
"user",
"token",
"expires_at"
],
"title": "SessionRead"
},
"TokenRequest": {
"properties": {
"token": {
"type": "string",
"title": "Token"
}
},
"type": "object",
"required": [
"token"
],
"title": "TokenRequest"
},
"TreeCreate": {
"properties": {
"name": {
"type": "string",
"title": "Name"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"visibility": {
"$ref": "#/components/schemas/TreeVisibility",
"default": "private"
}
},
"type": "object",
"required": [
"name"
],
"title": "TreeCreate"
},
"TreeRead": {
"properties": {
"id": {
"type": "string",
"format": "uuid",
"title": "Id"
},
"name": {
"type": "string",
"title": "Name"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Description"
},
"visibility": {
"$ref": "#/components/schemas/TreeVisibility"
},
"owner_id": {
"type": "string",
"format": "uuid",
"title": "Owner Id"
},
"created_at": {
"type": "string",
"format": "date-time",
"title": "Created At"
}
},
"type": "object",
"required": [
"id",
"name",
"description",
"visibility",
"owner_id",
"created_at"
],
"title": "TreeRead"
},
"TreeVisibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"private"
],
"title": "TreeVisibility"
},
"UserRead": {
"properties": {
"id": {
"type": "string",
"format": "uuid",
"title": "Id"
},
"email": {
"type": "string",
"title": "Email"
},
"display_name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Display Name"
},
"email_verified_at": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"title": "Email Verified At"
},
"created_at": {
"type": "string",
"format": "date-time",
"title": "Created At"
}
},
"type": "object",
"required": [
"id",
"email",
"display_name",
"email_verified_at",
"created_at"
],
"title": "UserRead"
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
},
"input": {
"title": "Input"
},
"ctx": {
"type": "object",
"title": "Context"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
}
}
}
}