424 lines
13 KiB
YAML
424 lines
13 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: BikepackPilot API
|
|
version: 0.1.0
|
|
description: MVP API contract for bikepacking route planning, staging, POI corridor, offline packs, exports, and local reports.
|
|
servers:
|
|
- url: http://localhost:8000
|
|
paths:
|
|
/v1/trips:
|
|
post:
|
|
summary: Create trip
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TripRequest'
|
|
responses:
|
|
'201':
|
|
description: Trip created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Trip'
|
|
/v1/routes/plan:
|
|
post:
|
|
summary: Plan a bikepacking route
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoutePlanRequest'
|
|
responses:
|
|
'200':
|
|
description: Route plan
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RoutePlan'
|
|
/v1/stages/plan:
|
|
post:
|
|
summary: Split a route into daily stages
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/StagePlanRequest'
|
|
responses:
|
|
'200':
|
|
description: Stage plans
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
stages:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/StagePlan'
|
|
/v1/routes/{routeId}/pois:
|
|
get:
|
|
summary: Get route-corridor POIs
|
|
parameters:
|
|
- in: path
|
|
name: routeId
|
|
required: true
|
|
schema: { type: string }
|
|
- in: query
|
|
name: category
|
|
schema: { $ref: '#/components/schemas/PoiCategory' }
|
|
- in: query
|
|
name: buffer_km
|
|
schema: { type: number, default: 5 }
|
|
responses:
|
|
'200':
|
|
description: POIs
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
pois:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Poi'
|
|
attribution:
|
|
type: array
|
|
items: { type: string }
|
|
/v1/routes/{routeId}/gaps:
|
|
get:
|
|
summary: Get critical service gaps
|
|
parameters:
|
|
- in: path
|
|
name: routeId
|
|
required: true
|
|
schema: { type: string }
|
|
responses:
|
|
'200':
|
|
description: Service gaps
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
gaps:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ServiceGap'
|
|
/v1/rules:
|
|
get:
|
|
summary: Get local rule cards
|
|
parameters:
|
|
- in: query
|
|
name: bbox
|
|
schema:
|
|
type: string
|
|
description: minLon,minLat,maxLon,maxLat
|
|
- in: query
|
|
name: route_id
|
|
schema: { type: string }
|
|
responses:
|
|
'200':
|
|
description: Rule cards
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
rules:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/RuleCard'
|
|
disclaimer:
|
|
type: string
|
|
/v1/offline-packs:
|
|
post:
|
|
summary: Create offline pack manifest
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [tripId, routeId]
|
|
properties:
|
|
tripId: { type: string }
|
|
routeId: { type: string }
|
|
routeBufferKm: { type: number, default: 5 }
|
|
responses:
|
|
'200':
|
|
description: Offline pack manifest
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/OfflinePackManifest'
|
|
/v1/routes/{routeId}/export:
|
|
get:
|
|
summary: Export route
|
|
parameters:
|
|
- in: path
|
|
name: routeId
|
|
required: true
|
|
schema: { type: string }
|
|
- in: query
|
|
name: format
|
|
required: true
|
|
schema:
|
|
type: string
|
|
enum: [gpx, tcx, fit]
|
|
responses:
|
|
'200':
|
|
description: Route export file
|
|
content:
|
|
application/gpx+xml:
|
|
schema: { type: string }
|
|
application/json:
|
|
schema: { type: object }
|
|
/v1/reports:
|
|
post:
|
|
summary: Submit local report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LocalReportCreate'
|
|
responses:
|
|
'201':
|
|
description: Report submitted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LocalReport'
|
|
components:
|
|
schemas:
|
|
Coordinate:
|
|
type: object
|
|
required: [lat, lon]
|
|
properties:
|
|
lat: { type: number }
|
|
lon: { type: number }
|
|
elevationM:
|
|
type: number
|
|
description: Optional elevation in meters above sea level when supplied by the active provider.
|
|
TripRequest:
|
|
type: object
|
|
required: [start, end, profile, sleepPreference, dailyDistanceKm]
|
|
properties:
|
|
start: { $ref: '#/components/schemas/Coordinate' }
|
|
end: { $ref: '#/components/schemas/Coordinate' }
|
|
viaPoints:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Coordinate' }
|
|
maxItems: 24
|
|
startDate: { type: string, format: date }
|
|
endDate: { type: string, format: date }
|
|
profile: { type: string }
|
|
sleepPreference: { type: string }
|
|
dailyDistanceKm:
|
|
type: object
|
|
required: [min, target, max]
|
|
properties:
|
|
min: { type: number }
|
|
target: { type: number }
|
|
max: { type: number }
|
|
waterGapMaxKm: { type: number }
|
|
foodGapMaxKm: { type: number }
|
|
Trip:
|
|
type: object
|
|
properties:
|
|
id: { type: string }
|
|
title: { type: string }
|
|
request: { $ref: '#/components/schemas/TripRequest' }
|
|
RoutePlanRequest:
|
|
type: object
|
|
required: [tripRequest]
|
|
properties:
|
|
tripRequest: { $ref: '#/components/schemas/TripRequest' }
|
|
provider: { type: string, default: mock }
|
|
RoutePlan:
|
|
type: object
|
|
properties:
|
|
id: { type: string }
|
|
tripId: { type: string }
|
|
geometry:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Coordinate' }
|
|
distanceM: { type: integer }
|
|
ascentM: { type: integer }
|
|
descentM: { type: integer }
|
|
provider: { type: string }
|
|
segments:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/RouteSegment' }
|
|
surfaceBreakdown:
|
|
type: object
|
|
additionalProperties: { type: number }
|
|
suitabilityScore: { type: number }
|
|
warnings:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/RouteWarning' }
|
|
attribution:
|
|
type: array
|
|
items: { type: string }
|
|
RouteSegment:
|
|
type: object
|
|
properties:
|
|
id: { type: string }
|
|
geometry:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Coordinate' }
|
|
distanceM: { type: integer }
|
|
startMeters: { type: integer }
|
|
endMeters: { type: integer }
|
|
ascentM: { type: integer }
|
|
descentM: { type: integer }
|
|
avgGradePercent: { type: number }
|
|
maxGradePercent: { type: number }
|
|
surface: { type: string }
|
|
smoothness: { type: string }
|
|
highway: { type: string }
|
|
bicycleAccess: { type: string }
|
|
legalAccessConfidence: { type: string }
|
|
trafficStress: { type: number }
|
|
officialCycleRoute: { type: boolean }
|
|
protectedAreaOverlap: { type: boolean }
|
|
sourceConfidence: { type: string }
|
|
StagePlanRequest:
|
|
type: object
|
|
required: [routeId, tripRequest]
|
|
properties:
|
|
routeId: { type: string }
|
|
tripRequest: { $ref: '#/components/schemas/TripRequest' }
|
|
StagePlan:
|
|
type: object
|
|
properties:
|
|
id: { type: string }
|
|
dayIndex: { type: integer }
|
|
startMeters: { type: integer }
|
|
endMeters: { type: integer }
|
|
distanceM: { type: integer }
|
|
ascentM: { type: integer }
|
|
descentM: { type: integer }
|
|
expectedRideTimeMinutes:
|
|
type: object
|
|
properties:
|
|
low: { type: integer }
|
|
high: { type: integer }
|
|
sleepCandidates:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Poi' }
|
|
waterPois:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Poi' }
|
|
foodPois:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Poi' }
|
|
repairPois:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Poi' }
|
|
bailoutPois:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/Poi' }
|
|
warnings:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/RouteWarning' }
|
|
planB:
|
|
type: object
|
|
properties:
|
|
earlierEndMeters: { type: integer }
|
|
laterEndMeters: { type: integer }
|
|
reason: { type: string }
|
|
PoiCategory:
|
|
type: string
|
|
enum: [water, food, sleep, repair, bailout, charging, emergency]
|
|
Poi:
|
|
type: object
|
|
properties:
|
|
id: { type: string }
|
|
category: { $ref: '#/components/schemas/PoiCategory' }
|
|
name: { type: string }
|
|
location: { $ref: '#/components/schemas/Coordinate' }
|
|
source: { type: string }
|
|
confidence: { type: string }
|
|
metersFromStart: { type: integer }
|
|
distanceFromRouteM: { type: integer }
|
|
detourDistanceM: { type: integer }
|
|
RouteWarning:
|
|
type: object
|
|
properties:
|
|
code: { type: string }
|
|
severity: { type: string, enum: [info, notice, warning, critical] }
|
|
title: { type: string }
|
|
message: { type: string }
|
|
metersFromStart: { type: integer }
|
|
segmentId: { type: string }
|
|
ServiceGap:
|
|
type: object
|
|
properties:
|
|
category: { $ref: '#/components/schemas/PoiCategory' }
|
|
startM: { type: integer }
|
|
endM: { type: integer }
|
|
distanceM: { type: integer }
|
|
severity: { type: string }
|
|
explanation: { type: string }
|
|
RuleCard:
|
|
type: object
|
|
properties:
|
|
id: { type: string }
|
|
ruleType: { type: string }
|
|
jurisdiction: { type: string }
|
|
status: { type: string }
|
|
confidence: { type: string }
|
|
summary: { type: string }
|
|
sourceUrl: { type: string }
|
|
lastReviewedAt: { type: string, format: date }
|
|
OfflinePackManifest:
|
|
type: object
|
|
properties:
|
|
packId: { type: string }
|
|
tripId: { type: string }
|
|
routeId: { type: string }
|
|
createdAt: { type: string, format: date-time }
|
|
expiresAt: { type: string, format: date-time }
|
|
bbox:
|
|
type: array
|
|
minItems: 4
|
|
maxItems: 4
|
|
items: { type: number }
|
|
routeBufferKm: { type: number }
|
|
includedLayers:
|
|
type: array
|
|
items: { type: string }
|
|
dataVersions: { type: object }
|
|
files:
|
|
type: array
|
|
items: { type: object }
|
|
warnings:
|
|
type: array
|
|
items: { $ref: '#/components/schemas/RouteWarning' }
|
|
LocalReportCreate:
|
|
type: object
|
|
required: [reportType, location, observedAt]
|
|
properties:
|
|
reportType: { type: string }
|
|
location: { $ref: '#/components/schemas/Coordinate' }
|
|
routeId: { type: string }
|
|
metersFromStart: { type: integer }
|
|
observedAt: { type: string, format: date-time }
|
|
details: { type: string }
|
|
payload: { type: object }
|
|
offlineClientId: { type: string }
|
|
LocalReport:
|
|
allOf:
|
|
- $ref: '#/components/schemas/LocalReportCreate'
|
|
- type: object
|
|
properties:
|
|
id: { type: string }
|
|
moderationStatus: { type: string }
|
|
trustScore: { type: number }
|
|
queuedOffline: { type: boolean }
|