Initial commit: add .gitignore and README
Some checks failed
CI / lint-and-test (push) Has been cancelled
Some checks failed
CI / lint-and-test (push) Has been cancelled
This commit is contained in:
175
docs/openapi.yaml
Normal file
175
docs/openapi.yaml
Normal file
@@ -0,0 +1,175 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Sankofa HW Infra API
|
||||
version: 0.1.0
|
||||
servers:
|
||||
- url: /api/v1
|
||||
security:
|
||||
- BearerAuth: []
|
||||
components:
|
||||
schemas:
|
||||
ApiError:
|
||||
type: object
|
||||
properties:
|
||||
error: { type: string, description: Human-readable message }
|
||||
code: { type: string, enum: [BAD_REQUEST, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, CONFLICT, INTERNAL_ERROR] }
|
||||
details: { type: object, description: Optional validation or extra data }
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: JWT with optional vendorId for vendor users
|
||||
IngestionApiKey:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: x-ingestion-api-key
|
||||
description: Required for POST /ingestion/offers (env INGESTION_API_KEY)
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
summary: Health
|
||||
security: []
|
||||
/auth/token:
|
||||
post:
|
||||
summary: Get JWT token
|
||||
description: Exchange email (and optional password) for a JWT with roles and vendorId. No auth required.
|
||||
security: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [email]
|
||||
properties:
|
||||
email: { type: string, format: email }
|
||||
password: { type: string }
|
||||
responses:
|
||||
"200":
|
||||
description: Token and user info
|
||||
"401":
|
||||
description: Invalid credentials
|
||||
/vendors:
|
||||
get:
|
||||
summary: List vendors
|
||||
description: If JWT contains vendorId (vendor user), returns only that vendor.
|
||||
post:
|
||||
summary: Create vendor
|
||||
description: Forbidden for vendor users.
|
||||
/vendors/{id}:
|
||||
get:
|
||||
summary: Get vendor
|
||||
description: Vendor users may only request their own vendor id.
|
||||
/offers:
|
||||
get:
|
||||
summary: List offers
|
||||
description: If JWT contains vendorId, returns only that vendor's offers.
|
||||
post:
|
||||
summary: Create offer
|
||||
description: Vendor users' vendorId is forced to their vendor.
|
||||
/offers/{id}:
|
||||
get:
|
||||
summary: Get offer
|
||||
patch:
|
||||
summary: Update offer
|
||||
delete:
|
||||
summary: Delete offer
|
||||
/purchase-orders:
|
||||
get:
|
||||
summary: List purchase orders
|
||||
description: If JWT contains vendorId, returns only POs for that vendor.
|
||||
/purchase-orders/{id}:
|
||||
get:
|
||||
summary: Get purchase order
|
||||
/ingestion/offers:
|
||||
post:
|
||||
summary: Ingest offer (scrape or email)
|
||||
description: Creates an offer with source (scraped|email), source_ref, source_metadata. Secured by x-ingestion-api-key only; no JWT. Use x-org-id for target org.
|
||||
security:
|
||||
- IngestionApiKey: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [source, quantity, unit_price]
|
||||
properties:
|
||||
source:
|
||||
type: string
|
||||
enum: [scraped, email]
|
||||
source_ref:
|
||||
type: string
|
||||
description: URL or email message id
|
||||
source_metadata:
|
||||
type: object
|
||||
vendor_id:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
sku:
|
||||
type: string
|
||||
mpn:
|
||||
type: string
|
||||
quantity:
|
||||
type: integer
|
||||
unit_price:
|
||||
type: string
|
||||
incoterms:
|
||||
type: string
|
||||
lead_time_days:
|
||||
type: integer
|
||||
country_of_origin:
|
||||
type: string
|
||||
condition:
|
||||
type: string
|
||||
warranty:
|
||||
type: string
|
||||
evidence_refs:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
key: { type: string }
|
||||
hash: { type: string }
|
||||
responses:
|
||||
"201":
|
||||
description: Offer created
|
||||
"401":
|
||||
description: Invalid or missing x-ingestion-api-key
|
||||
/capacity/sites/{siteId}:
|
||||
get:
|
||||
summary: RU utilization for a site
|
||||
description: Returns usedRu, totalRu, utilizationPercent for the site (from racks and assigned positions).
|
||||
parameters:
|
||||
- name: siteId
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
responses:
|
||||
"200":
|
||||
description: Site capacity (usedRu, totalRu, utilizationPercent)
|
||||
"404":
|
||||
description: Site not found
|
||||
/capacity/sites/{siteId}/power:
|
||||
get:
|
||||
summary: Power headroom for a site
|
||||
description: Returns circuitLimitWatts from rack power_feeds; measuredDrawWatts/headroomWatts null until Phase 4.
|
||||
parameters:
|
||||
- name: siteId
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
responses:
|
||||
"200":
|
||||
description: Power info (circuitLimitWatts, measuredDrawWatts, headroomWatts)
|
||||
"404":
|
||||
description: Site not found
|
||||
/capacity/gpu-inventory:
|
||||
get:
|
||||
summary: GPU inventory
|
||||
description: Returns total, bySite, and byType (part number) counts.
|
||||
responses:
|
||||
"200":
|
||||
description: GPU counts (total, bySite, byType)
|
||||
Reference in New Issue
Block a user