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:
681
backend/.scribe/endpoints.cache/03.yaml
Normal file
681
backend/.scribe/endpoints.cache/03.yaml
Normal 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
|
||||
679
backend/.scribe/endpoints/03.yaml
Normal file
679
backend/.scribe/endpoints/03.yaml
Normal 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
|
||||
Reference in New Issue
Block a user