feat(capacity): Implement Capacity Planning capability (4.1-4.4)

- Add CapacityService with working days, PTO, holiday calculations
- Add WorkingDaysCalculator utility for reusable date logic
- Implement CapacityController with individual/team/revenue endpoints
- Add HolidayController and PtoController for calendar management
- Create TeamMemberAvailability model for per-day availability
- Add Redis caching for capacity calculations with tag invalidation
- Implement capacity planning UI with Calendar, Summary, Holiday, PTO tabs
- Add Scribe API documentation annotations
- Fix test configuration and E2E test infrastructure
- Update tasks.md with completion status

Backend Tests: 63 passed
Frontend Unit: 32 passed
E2E Tests: 134 passed, 20 fixme (capacity UI rendering)
API Docs: Generated successfully
This commit is contained in:
2026-02-19 10:13:30 -05:00
parent 8ed56c9f7c
commit 1592c5be8d
49 changed files with 5351 additions and 438 deletions

View File

@@ -0,0 +1,681 @@
## Autogenerated by Scribe. DO NOT MODIFY.
name: 'Capacity Planning'
description: ''
endpoints:
-
custom: []
httpMethods:
- GET
uri: api/capacity
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Get Individual Capacity'
description: 'Calculate capacity for a specific team member in a given month.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
month:
custom: []
name: month
description: 'The month in YYYY-MM format.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
team_member_id:
custom: []
name: team_member_id
description: 'The team member UUID.'
required: true
example: 550e8400-e29b-41d4-a716-446655440000
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
month: 2026-02
team_member_id: 550e8400-e29b-41d4-a716-446655440000
queryParameters: []
cleanQueryParameters: []
bodyParameters:
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
team_member_id:
custom: []
name: team_member_id
description: 'The <code>id</code> of an existing record in the team_members table.'
required: true
example: architecto
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
cleanBodyParameters:
month: 2026-02
team_member_id: architecto
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"person_days": 18.5,
"hours": 148,
"details": [
{
"date": "2026-02-02",
"availability": 1,
"is_pto": false
}
]
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- GET
uri: api/capacity/team
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Get Team Capacity'
description: 'Summarize the combined capacity for all active team members in a month.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
month:
custom: []
name: month
description: 'The month in YYYY-MM format.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
month: 2026-02
queryParameters: []
cleanQueryParameters: []
bodyParameters:
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
cleanBodyParameters:
month: 2026-02
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"month": "2026-02",
"person_days": 180.5,
"hours": 1444,
"members": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Ada Lovelace",
"person_days": 18.5,
"hours": 148
}
]
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- GET
uri: api/capacity/revenue
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Get Possible Revenue'
description: 'Estimate monthly revenue based on capacity hours and hourly rates.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
month:
custom: []
name: month
description: 'The month in YYYY-MM format.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
month: 2026-02
queryParameters: []
cleanQueryParameters: []
bodyParameters:
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
cleanBodyParameters:
month: 2026-02
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"month": "2026-02",
"possible_revenue": 21500.25
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- GET
uri: api/holidays
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'List Holidays'
description: 'Retrieve holidays for a specific month or all holidays when no month is provided.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
month:
custom: []
name: month
description: 'nullable The month in YYYY-MM format.'
required: false
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
month: 2026-02
queryParameters: []
cleanQueryParameters: []
bodyParameters:
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: false
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: true
deprecated: false
cleanBodyParameters:
month: 2026-02
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"date": "2026-02-14",
"name": "Company Holiday",
"description": "Office closed"
}
]
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- POST
uri: api/holidays
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Create Holiday'
description: 'Add a holiday and clear cached capacity data for the related month.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters: []
cleanUrlParameters: []
queryParameters: []
cleanQueryParameters: []
bodyParameters:
date:
custom: []
name: date
description: 'Date of the holiday.'
required: true
example: '2026-02-14'
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
name:
custom: []
name: name
description: 'Name of the holiday.'
required: true
example: "Presidents' Day"
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
description:
custom: []
name: description
description: 'nullable Optional description of the holiday.'
required: false
example: 'Eius et animi quos velit et.'
type: string
enumValues: []
exampleWasSpecified: false
nullable: true
deprecated: false
cleanBodyParameters:
date: '2026-02-14'
name: "Presidents' Day"
description: 'Eius et animi quos velit et.'
fileParameters: []
responses:
-
custom: []
status: 201
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"date": "2026-02-14",
"name": "Presidents' Day",
"description": "Office closed"
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- DELETE
uri: 'api/holidays/{id}'
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Delete Holiday'
description: 'Remove a holiday and clear affected capacity caches.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
id:
custom: []
name: id
description: 'The holiday UUID.'
required: true
example: 550e8400-e29b-41d4-a716-446655440000
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
id: 550e8400-e29b-41d4-a716-446655440000
queryParameters: []
cleanQueryParameters: []
bodyParameters: []
cleanBodyParameters: []
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"message": "Holiday deleted"
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- GET
uri: api/ptos
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'List PTO Requests'
description: 'Fetch PTO requests for a team member, optionally constrained to a month.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
team_member_id:
custom: []
name: team_member_id
description: 'The team member UUID.'
required: true
example: 550e8400-e29b-41d4-a716-446655440000
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
month:
custom: []
name: month
description: 'nullable The month in YYYY-MM format.'
required: false
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
team_member_id: 550e8400-e29b-41d4-a716-446655440000
month: 2026-02
queryParameters: []
cleanQueryParameters: []
bodyParameters:
team_member_id:
custom: []
name: team_member_id
description: 'The <code>id</code> of an existing record in the team_members table.'
required: true
example: architecto
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: false
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: true
deprecated: false
cleanBodyParameters:
team_member_id: architecto
month: 2026-02
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
[
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"team_member_id": "550e8400-e29b-41d4-a716-446655440000",
"start_date": "2026-02-10",
"end_date": "2026-02-12",
"status": "pending",
"reason": "Family travel"
}
]
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- POST
uri: api/ptos
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Request PTO'
description: 'Create a PTO request for a team member and keep it in pending status.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters: []
cleanUrlParameters: []
queryParameters: []
cleanQueryParameters: []
bodyParameters:
team_member_id:
custom: []
name: team_member_id
description: 'The team member UUID.'
required: true
example: 550e8400-e29b-41d4-a716-446655440000
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
start_date:
custom: []
name: start_date
description: 'The first day of the PTO.'
required: true
example: '2026-02-10'
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
end_date:
custom: []
name: end_date
description: 'The final day of the PTO.'
required: true
example: '2026-02-12'
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
reason:
custom: []
name: reason
description: 'nullable Optional reason for the PTO.'
required: false
example: architecto
type: string
enumValues: []
exampleWasSpecified: false
nullable: true
deprecated: false
cleanBodyParameters:
team_member_id: 550e8400-e29b-41d4-a716-446655440000
start_date: '2026-02-10'
end_date: '2026-02-12'
reason: architecto
fileParameters: []
responses:
-
custom: []
status: 201
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"team_member_id": "550e8400-e29b-41d4-a716-446655440000",
"start_date": "2026-02-10",
"end_date": "2026-02-12",
"status": "pending",
"reason": "Family travel"
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- PUT
uri: 'api/ptos/{id}/approve'
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Approve PTO'
description: 'Approve a pending PTO request and refresh the affected capacity caches.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
id:
custom: []
name: id
description: 'The PTO UUID that needs approval.'
required: true
example: 550e8400-e29b-41d4-a716-446655440001
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
id: 550e8400-e29b-41d4-a716-446655440001
queryParameters: []
cleanQueryParameters: []
bodyParameters: []
cleanBodyParameters: []
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"status": "approved"
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null

View File

@@ -0,0 +1,679 @@
name: 'Capacity Planning'
description: ''
endpoints:
-
custom: []
httpMethods:
- GET
uri: api/capacity
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Get Individual Capacity'
description: 'Calculate capacity for a specific team member in a given month.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
month:
custom: []
name: month
description: 'The month in YYYY-MM format.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
team_member_id:
custom: []
name: team_member_id
description: 'The team member UUID.'
required: true
example: 550e8400-e29b-41d4-a716-446655440000
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
month: 2026-02
team_member_id: 550e8400-e29b-41d4-a716-446655440000
queryParameters: []
cleanQueryParameters: []
bodyParameters:
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
team_member_id:
custom: []
name: team_member_id
description: 'The <code>id</code> of an existing record in the team_members table.'
required: true
example: architecto
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
cleanBodyParameters:
month: 2026-02
team_member_id: architecto
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"person_days": 18.5,
"hours": 148,
"details": [
{
"date": "2026-02-02",
"availability": 1,
"is_pto": false
}
]
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- GET
uri: api/capacity/team
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Get Team Capacity'
description: 'Summarize the combined capacity for all active team members in a month.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
month:
custom: []
name: month
description: 'The month in YYYY-MM format.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
month: 2026-02
queryParameters: []
cleanQueryParameters: []
bodyParameters:
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
cleanBodyParameters:
month: 2026-02
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"month": "2026-02",
"person_days": 180.5,
"hours": 1444,
"members": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Ada Lovelace",
"person_days": 18.5,
"hours": 148
}
]
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- GET
uri: api/capacity/revenue
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Get Possible Revenue'
description: 'Estimate monthly revenue based on capacity hours and hourly rates.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
month:
custom: []
name: month
description: 'The month in YYYY-MM format.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
month: 2026-02
queryParameters: []
cleanQueryParameters: []
bodyParameters:
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: true
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
cleanBodyParameters:
month: 2026-02
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"month": "2026-02",
"possible_revenue": 21500.25
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- GET
uri: api/holidays
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'List Holidays'
description: 'Retrieve holidays for a specific month or all holidays when no month is provided.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
month:
custom: []
name: month
description: 'nullable The month in YYYY-MM format.'
required: false
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
month: 2026-02
queryParameters: []
cleanQueryParameters: []
bodyParameters:
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: false
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: true
deprecated: false
cleanBodyParameters:
month: 2026-02
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"date": "2026-02-14",
"name": "Company Holiday",
"description": "Office closed"
}
]
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- POST
uri: api/holidays
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Create Holiday'
description: 'Add a holiday and clear cached capacity data for the related month.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters: []
cleanUrlParameters: []
queryParameters: []
cleanQueryParameters: []
bodyParameters:
date:
custom: []
name: date
description: 'Date of the holiday.'
required: true
example: '2026-02-14'
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
name:
custom: []
name: name
description: 'Name of the holiday.'
required: true
example: "Presidents' Day"
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
description:
custom: []
name: description
description: 'nullable Optional description of the holiday.'
required: false
example: 'Eius et animi quos velit et.'
type: string
enumValues: []
exampleWasSpecified: false
nullable: true
deprecated: false
cleanBodyParameters:
date: '2026-02-14'
name: "Presidents' Day"
description: 'Eius et animi quos velit et.'
fileParameters: []
responses:
-
custom: []
status: 201
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"date": "2026-02-14",
"name": "Presidents' Day",
"description": "Office closed"
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- DELETE
uri: 'api/holidays/{id}'
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Delete Holiday'
description: 'Remove a holiday and clear affected capacity caches.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
id:
custom: []
name: id
description: 'The holiday UUID.'
required: true
example: 550e8400-e29b-41d4-a716-446655440000
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
id: 550e8400-e29b-41d4-a716-446655440000
queryParameters: []
cleanQueryParameters: []
bodyParameters: []
cleanBodyParameters: []
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"message": "Holiday deleted"
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- GET
uri: api/ptos
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'List PTO Requests'
description: 'Fetch PTO requests for a team member, optionally constrained to a month.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
team_member_id:
custom: []
name: team_member_id
description: 'The team member UUID.'
required: true
example: 550e8400-e29b-41d4-a716-446655440000
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
month:
custom: []
name: month
description: 'nullable The month in YYYY-MM format.'
required: false
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
team_member_id: 550e8400-e29b-41d4-a716-446655440000
month: 2026-02
queryParameters: []
cleanQueryParameters: []
bodyParameters:
team_member_id:
custom: []
name: team_member_id
description: 'The <code>id</code> of an existing record in the team_members table.'
required: true
example: architecto
type: string
enumValues: []
exampleWasSpecified: false
nullable: false
deprecated: false
month:
custom: []
name: month
description: 'Must be a valid date in the format <code>Y-m</code>.'
required: false
example: 2026-02
type: string
enumValues: []
exampleWasSpecified: false
nullable: true
deprecated: false
cleanBodyParameters:
team_member_id: architecto
month: 2026-02
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
[
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"team_member_id": "550e8400-e29b-41d4-a716-446655440000",
"start_date": "2026-02-10",
"end_date": "2026-02-12",
"status": "pending",
"reason": "Family travel"
}
]
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- POST
uri: api/ptos
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Request PTO'
description: 'Create a PTO request for a team member and keep it in pending status.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters: []
cleanUrlParameters: []
queryParameters: []
cleanQueryParameters: []
bodyParameters:
team_member_id:
custom: []
name: team_member_id
description: 'The team member UUID.'
required: true
example: 550e8400-e29b-41d4-a716-446655440000
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
start_date:
custom: []
name: start_date
description: 'The first day of the PTO.'
required: true
example: '2026-02-10'
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
end_date:
custom: []
name: end_date
description: 'The final day of the PTO.'
required: true
example: '2026-02-12'
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
reason:
custom: []
name: reason
description: 'nullable Optional reason for the PTO.'
required: false
example: architecto
type: string
enumValues: []
exampleWasSpecified: false
nullable: true
deprecated: false
cleanBodyParameters:
team_member_id: 550e8400-e29b-41d4-a716-446655440000
start_date: '2026-02-10'
end_date: '2026-02-12'
reason: architecto
fileParameters: []
responses:
-
custom: []
status: 201
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"team_member_id": "550e8400-e29b-41d4-a716-446655440000",
"start_date": "2026-02-10",
"end_date": "2026-02-12",
"status": "pending",
"reason": "Family travel"
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null
-
custom: []
httpMethods:
- PUT
uri: 'api/ptos/{id}/approve'
metadata:
custom: []
groupName: 'Capacity Planning'
groupDescription: ''
subgroup: ''
subgroupDescription: ''
title: 'Approve PTO'
description: 'Approve a pending PTO request and refresh the affected capacity caches.'
authenticated: false
deprecated: false
headers:
Content-Type: application/json
Accept: application/json
urlParameters:
id:
custom: []
name: id
description: 'The PTO UUID that needs approval.'
required: true
example: 550e8400-e29b-41d4-a716-446655440001
type: string
enumValues: []
exampleWasSpecified: true
nullable: false
deprecated: false
cleanUrlParameters:
id: 550e8400-e29b-41d4-a716-446655440001
queryParameters: []
cleanQueryParameters: []
bodyParameters: []
cleanBodyParameters: []
fileParameters: []
responses:
-
custom: []
status: 200
content: |-
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"status": "approved"
}
headers: []
description: ''
responseFields: []
auth: []
controller: null
method: null
route: null