feat(api): expose budget state (#1640)

* feat(api): expose budget state

* fix(api): guard malformed budget ids

* fix(api): address budget state review

* fix(api): address budget state review

* fix(api): document budget id formats

* fix(api): align budget category docs auth

* fix(api): lighten budget category index payload

* fix(api): use shared pagination clamp

* fix(api): centralize budget filter handling
This commit is contained in:
ghost
2026-05-06 12:50:46 -06:00
committed by GitHub
parent 4b93bdb447
commit 2d38cfb011
18 changed files with 1442 additions and 20 deletions

View File

@@ -460,6 +460,276 @@ components:
updated_at:
type: string
format: date-time
BudgetSummary:
type: object
required:
- id
- start_date
- end_date
- name
- currency
- initialized
- current
- created_at
- updated_at
properties:
id:
type: string
format: uuid
start_date:
type: string
format: date
end_date:
type: string
format: date
name:
type: string
currency:
type: string
initialized:
type: boolean
current:
type: boolean
budgeted_spending:
type: string
nullable: true
budgeted_spending_cents:
type: integer
nullable: true
expected_income:
type: string
nullable: true
expected_income_cents:
type: integer
nullable: true
allocated_spending:
type: string
allocated_spending_cents:
type: integer
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
Budget:
type: object
required:
- id
- start_date
- end_date
- name
- currency
- initialized
- current
- created_at
- updated_at
properties:
id:
type: string
format: uuid
start_date:
type: string
format: date
end_date:
type: string
format: date
name:
type: string
currency:
type: string
initialized:
type: boolean
current:
type: boolean
budgeted_spending:
type: string
nullable: true
budgeted_spending_cents:
type: integer
nullable: true
expected_income:
type: string
nullable: true
expected_income_cents:
type: integer
nullable: true
allocated_spending:
type: string
allocated_spending_cents:
type: integer
actual_spending:
type: string
actual_spending_cents:
type: integer
actual_income:
type: string
actual_income_cents:
type: integer
available_to_spend:
type: string
available_to_spend_cents:
type: integer
available_to_allocate:
type: string
available_to_allocate_cents:
type: integer
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
BudgetCollection:
type: object
required:
- budgets
- pagination
properties:
budgets:
type: array
items:
"$ref": "#/components/schemas/BudgetSummary"
pagination:
"$ref": "#/components/schemas/Pagination"
BudgetCategorySummary:
type: object
required:
- id
- budget_id
- currency
- subcategory
- inherits_parent_budget
- category
- created_at
- updated_at
properties:
id:
type: string
format: uuid
budget_id:
type: string
format: uuid
currency:
type: string
subcategory:
type: boolean
inherits_parent_budget:
type: boolean
budgeted_spending:
type: string
budgeted_spending_cents:
type: integer
display_budgeted_spending:
type: string
display_budgeted_spending_cents:
type: integer
category:
type: object
required:
- id
- name
- color
- lucide_icon
properties:
id:
type: string
format: uuid
name:
type: string
color:
type: string
lucide_icon:
type: string
parent_id:
type: string
format: uuid
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
BudgetCategory:
type: object
required:
- id
- budget_id
- currency
- subcategory
- inherits_parent_budget
- category
- created_at
- updated_at
properties:
id:
type: string
format: uuid
budget_id:
type: string
format: uuid
currency:
type: string
subcategory:
type: boolean
inherits_parent_budget:
type: boolean
budgeted_spending:
type: string
budgeted_spending_cents:
type: integer
display_budgeted_spending:
type: string
display_budgeted_spending_cents:
type: integer
actual_spending:
type: string
actual_spending_cents:
type: integer
available_to_spend:
type: string
available_to_spend_cents:
type: integer
category:
type: object
required:
- id
- name
- color
- lucide_icon
properties:
id:
type: string
format: uuid
name:
type: string
color:
type: string
lucide_icon:
type: string
parent_id:
type: string
format: uuid
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
BudgetCategoryCollection:
type: object
required:
- budget_categories
- pagination
properties:
budget_categories:
type: array
items:
"$ref": "#/components/schemas/BudgetCategorySummary"
pagination:
"$ref": "#/components/schemas/Pagination"
Balance:
type: object
required:
@@ -2774,6 +3044,220 @@ paths:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
"/api/v1/budget_categories":
get:
summary: List budget categories
tags:
- Budget Categories
security:
- apiKeyAuth: []
parameters:
- name: page
in: query
required: false
description: 'Page number (default: 1)'
schema:
type: integer
- name: per_page
in: query
required: false
description: 'Items per page (default: 25, max: 100)'
schema:
type: integer
- name: budget_id
in: query
required: false
schema:
type: string
format: uuid
description: Filter by budget ID
- name: category_id
in: query
required: false
schema:
type: string
format: uuid
description: Filter by category ID
- name: start_date
in: query
required: false
schema:
type: string
format: date
description: Filter budget categories whose budget starts on or after this
date
- name: end_date
in: query
required: false
schema:
type: string
format: date
description: Filter budget categories whose budget ends on or before this
date
responses:
'200':
description: budget categories listed
content:
application/json:
schema:
"$ref": "#/components/schemas/BudgetCategoryCollection"
'401':
description: unauthorized
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'403':
description: insufficient scope
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'422':
description: invalid filter
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
"/api/v1/budget_categories/{id}":
parameters:
- name: id
in: path
required: true
description: Budget category ID
schema:
type: string
format: uuid
get:
summary: Retrieve a budget category
tags:
- Budget Categories
security:
- apiKeyAuth: []
responses:
'200':
description: budget category retrieved
content:
application/json:
schema:
"$ref": "#/components/schemas/BudgetCategory"
'401':
description: unauthorized
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'403':
description: insufficient scope
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'404':
description: budget category not found
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
"/api/v1/budgets":
get:
summary: List budgets
tags:
- Budgets
security:
- apiKeyAuth: []
parameters:
- name: page
in: query
required: false
description: 'Page number (default: 1)'
schema:
type: integer
- name: per_page
in: query
required: false
description: 'Items per page (default: 25, max: 100)'
schema:
type: integer
- name: start_date
in: query
required: false
schema:
type: string
format: date
description: Filter budgets starting on or after this date
- name: end_date
in: query
required: false
schema:
type: string
format: date
description: Filter budgets ending on or before this date
responses:
'200':
description: budgets listed
content:
application/json:
schema:
"$ref": "#/components/schemas/BudgetCollection"
'401':
description: unauthorized
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'403':
description: insufficient scope
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'422':
description: invalid date filter
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
"/api/v1/budgets/{id}":
parameters:
- name: id
in: path
required: true
description: Budget ID
schema:
type: string
format: uuid
get:
summary: Retrieve a budget
tags:
- Budgets
security:
- apiKeyAuth: []
responses:
'200':
description: budget retrieved
content:
application/json:
schema:
"$ref": "#/components/schemas/Budget"
'401':
description: unauthorized
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'403':
description: insufficient scope
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
'404':
description: budget not found
content:
application/json:
schema:
"$ref": "#/components/schemas/ErrorResponse"
"/api/v1/categories":
get:
summary: List categories