Alpha stage commit
This commit is contained in:
423
schemas/openapi.yaml
Normal file
423
schemas/openapi.yaml
Normal file
@@ -0,0 +1,423 @@
|
||||
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 }
|
||||
Reference in New Issue
Block a user