Enhance API documentation and extend customer context handling for subuser permissions

- Add `X-Customer-Number` header for subuser-specific customer targeting across endpoints.
- Update vehicle-related endpoints (`listVehicles`, `addVehicle`, `editVehicle`, etc.) to include subuser permission checks and customer context handling.
- Refactor request and response schemas for vehicle operations to reflect new requirements and improve clarity.
- Include detailed permission scoping and descriptions for subuser and broader access handling.
- Extend OpenAPI specification with enriched schema properties and additional responses for edge cases.
This commit is contained in:
Jeppe Bundgaard
2026-02-12 16:01:30 +01:00
parent 16094575a7
commit 4f9f2a2d71
+188 -28
View File
@@ -12,6 +12,12 @@ info:
## Permissions
Many endpoints require specific permissions that are assigned to user groups/roles.
## Subusers and customer targeting
When authenticated as a subuser, most customer-scoped endpoints require an explicit target
customer context. Provide the header `X-Customer-Number: <customer_number>` to target a
specific customer. If omitted, the API attempts to infer the customer from the authenticated
user context when possible. Classic user sessions ignore this header.
version: 1.0.0
contact:
name: Copenhagen Truck Wash
@@ -3788,11 +3794,23 @@ paths:
tags:
- Vehicles
summary: List vehicles
description: Get list of vehicles
description: |
List vehicles or fetch a specific vehicle when `id` is provided.
- When `id` is present, returns a single vehicle object (404 if not found).
- Otherwise returns a paginated list of vehicles.
Permissions:
- Own scope: `list_own_vehicles` (linked to subuser node `VEHICLES_LIST`).
- Broader scope: `list_vehicles_other`.
Subusers may specify header `X-Customer-Number` to target a specific customer. If the broader
permission is missing, the list will automatically be restricted to the effective customer context.
operationId: listVehicles
parameters:
- $ref: '#/components/parameters/PageParam'
- $ref: '#/components/parameters/PerPageParam'
- $ref: '#/components/parameters/XCustomerNumber'
- name: id
in: query
schema: {type: integer}
@@ -3804,37 +3822,72 @@ paths:
schema: {type: integer}
responses:
'200':
description: Vehicles retrieved successfully
description: Vehicle(s) retrieved successfully
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Vehicle'
oneOf:
- $ref: '#/components/schemas/Vehicle'
- type: array
items:
$ref: '#/components/schemas/Vehicle'
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/NotFound' }
post:
tags:
- Vehicles
summary: Add vehicle
operationId: addVehicle
description: |
Create a new vehicle for a customer.
Permissions:
- Own scope: `add_vehicle` (linked to subuser node `VEHICLES_ADD`).
- Broader scope: `add_vehicle_other`.
parameters:
- $ref: '#/components/parameters/XCustomerNumber'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [reg, customer_id]
required: [reg, type, wash_subscription]
properties:
reg: {type: string}
customer_id: {type: integer}
type: {type: integer}
reference: {type: string}
reg:
type: string
minLength: 2
maxLength: 12
description: Vehicle registration number
type:
type: integer
description: Product ID representing the vehicle wash type
wash_subscription:
type: boolean
reference:
type: string
maxLength: 255
nullable: true
customer_id:
type: integer
description: Optional explicit target customer. Defaults to the effective customer context.
responses:
'200': {description: Success}
'200': {description: Vehicle created}
'400': { $ref: '#/components/responses/BadRequest' }
'403': { $ref: '#/components/responses/Forbidden' }
put:
tags:
- Vehicles
summary: Edit vehicle
operationId: editVehicle
description: |
Update fields on an existing vehicle.
Permissions:
- Own scope: `edit_vehicle` (linked to subuser node `VEHICLES_EDIT`).
- Broader scope: `edit_vehicle_other`.
parameters:
- $ref: '#/components/parameters/XCustomerNumber'
requestBody:
required: true
content:
@@ -3844,64 +3897,99 @@ paths:
required: [id]
properties:
id: {type: integer}
reg: {type: string}
customer_id: {type: integer}
reg:
type: string
minLength: 2
maxLength: 12
type: {type: integer}
reference: {type: string}
wash_subscription: {type: boolean}
reference:
type: string
maxLength: 255
nullable: true
responses:
'200': {description: Success}
'200': {description: Vehicle updated}
'400': { $ref: '#/components/responses/BadRequest' }
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/NotFound' }
delete:
tags:
- Vehicles
summary: Delete vehicle
operationId: deleteVehicle
description: |
Delete an existing vehicle.
Permissions:
- Own scope: `delete_vehicle` (linked to subuser node `VEHICLES_DELETE`).
- Broader scope: `delete_vehicle_other`.
parameters:
- $ref: '#/components/parameters/XCustomerNumber'
- name: id
in: query
required: true
schema: {type: integer}
responses:
'200': {description: Success}
'200': {description: Vehicle deleted}
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/NotFound' }
/vehicles/addons/available:
get:
tags:
- Vehicles
summary: Get available vehicle addons
description: Get list of available addons for a vehicle
description: |
Get list of available addons for a vehicle.
Permissions:
- Own scope: `list_vehicle_addon_own` (linked to subuser node `VEHICLES_LIST`).
- Broader scope: `list_vehicles_addon_other`.
operationId: getAvailableVehicleAddons
parameters:
- name: vehicle_id
- $ref: '#/components/parameters/XCustomerNumber'
- name: id
in: query
required: true
schema:
type: integer
responses:
'200':
description: Available addons retrieved successfully
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/NotFound' }
/vehicles/addons/toggle:
post:
tags:
- Vehicles
summary: Toggle vehicle addon
description: Enable or disable a vehicle addon
description: |
Enable or disable a vehicle addon for a vehicle.
Permissions:
- Own scope: `toggle_vehicle_addon_own` (linked to subuser node `VEHICLES_EDIT`).
- Broader scope: `toggle_vehicle_addon_other`.
operationId: toggleVehicleAddon
parameters:
- $ref: '#/components/parameters/XCustomerNumber'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [vehicle_id, addon_id]
properties:
vehicle_id:
type: integer
addon_id:
type: integer
enabled:
type: boolean
responses:
'200':
description: Vehicle addon toggled successfully
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/NotFound' }
/department/vehicles/unknown-customer:
get:
@@ -3932,18 +4020,28 @@ paths:
- Vehicles
summary: Set auto start on LPR
operationId: setVehicleAutoStartOnLpr
description: |
Enable or disable automatic start on LPR for a vehicle in XL Vask.
Permissions:
- Own scope: `set_auto_start_on_lpr` (linked to subuser node `VEHICLES_EDIT`).
- Broader scope: `set_auto_start_on_lpr_other`.
parameters:
- $ref: '#/components/parameters/XCustomerNumber'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [reg, auto_start_on_lpr]
required: [id, active]
properties:
reg: {type: string}
auto_start_on_lpr: {type: boolean}
id: {type: integer}
active: {type: boolean}
responses:
'200': {description: Success}
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/NotFound' }
/vehicles/set-vehicle-type-id:
post:
@@ -3951,18 +4049,32 @@ paths:
- Vehicles
summary: Set vehicle type ID
operationId: setVehicleTypeId
description: |
Set or change the XL Vask `vehicleTypeId` for a vehicle.
Permissions:
- Own scope: `set_vehicle_type_id` (linked to subuser node `VEHICLES_EDIT`).
- Broader scope: `set_vehicle_type_id_other`.
parameters:
- $ref: '#/components/parameters/XCustomerNumber'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [reg, vehicle_type_id]
required: [id, vehicleTypeId]
properties:
reg: {type: string}
vehicle_type_id: {type: integer}
id: {type: integer}
vehicleTypeId:
type: string
minLength: 1
maxLength: 50
responses:
'200': {description: Success}
'400': { $ref: '#/components/responses/BadRequest' }
'403': { $ref: '#/components/responses/Forbidden' }
'404': { $ref: '#/components/responses/NotFound' }
/superuser/users-with-vehicle-subscriptions:
get:
@@ -6038,6 +6150,16 @@ components:
description: Filters for the list (e.g., module:selfserve,status_code:200)
schema:
type: string
XCustomerNumber:
name: X-Customer-Number
in: header
required: false
description: |
Target customer number for subuser requests. Ignored for classic user sessions.
Required on customer-scoped endpoints when authenticated as a subuser unless
the target customer can be inferred from context.
schema:
type: integer
responses:
BadRequest:
@@ -6954,10 +7076,48 @@ components:
properties:
id:
type: integer
plate:
user_id:
type: integer
description: Internal user ID owning the customer account
reg:
type: string
description: Vehicle registration number
customer_id:
type: integer
customer_name:
type: string
type:
type: integer
description: Product ID representing the vehicle wash type
reference:
type: string
nullable: true
description: Optional external reference/label
wash_subscription:
type: boolean
barred:
type: boolean
description: True if the associated customer is barred
addons:
type: object
properties:
enabled: { type: integer }
available: { type: integer }
list:
type: array
items:
type: object
last_order_id:
type: integer
nullable: true
xlvask:
type: object
nullable: true
description: XL Vask vehicle data when available
vehicle_types:
type: array
items:
type: object
created_at:
type: string
format: date-time