openapi: 3.1.0
info:
title: Dev-Portal NLQ SQL Params API
version: 0.1.0
description: |
nlq-dev から SQL/Cypher を送らず、sql_params のみで Dev-Portal 側が
(1) 必要なら ChromaDB でモデル/フィールド候補を特定し
(2) SQL を生成し
(3) 安全に実行して
tabular_result を返すためのインターフェース。
servers:
- url: https://{DEVPORTAL_HOST}
variables:
DEVPORTAL_HOST:
default: api.dev-portal.local
security:
- DevPortalApiKeyAuth: []
- BearerAuth: []
- {}: []
paths:
/health:
get:
tags: [Health]
summary: Health check (no auth recommended)
operationId: healthCheck
security:
- {}: []
responses:
"200":
description: OK
content:
application/json:
schema:
type: object
properties:
status: { type: string, enum: [ok] }
service: { type: string, example: dev-portal }
version: { type: string, example: "0.1.0" }
required: [status]
/sql/execute_params:
post:
tags: [NLQ]
summary: Execute sql_params (Dev-Portal generates SQL and runs safely)
operationId: executeSqlParams
description: |
nlq-dev は SQL を送らない。自然文を params 化した sql_params を送信する。
Dev-Portal 側が sql_params と (任意で) Chroma 検索を用いて対象モデル/フィールドを確定し、
SQL を生成して安全に実行し、表形式結果を返す。
実行は原則 READ-ONLY。
Dev-Portal 側は max_rows に基づき LIMIT を強制し、危険なクエリを拒否すること。
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SqlParamsExecuteRequest"
examples:
aggregate_example:
summary: Simple aggregate
value:
sql_params:
intent: kpi_aggregate
model: sale.order
measures:
- name: amount_total
agg: sum
group_by:
- field: date_order
granularity: month
filters:
- field: date_order
op: between
value: ["2025-01-01", "2025-12-31"]
max_rows: 200
dry_run: false
responses:
"200":
description: Tabular result
content:
application/json:
schema:
$ref: "#/components/schemas/TabularResult"
"400":
description: Invalid params / validation error
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
"401":
description: Unauthorized
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
"403":
description: Forbidden (policy/permission)
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
"422":
description: Unprocessable (params are syntactically valid but not executable)
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
"500":
description: Internal error
content:
application/json:
schema:
$ref: "#/components/schemas/Problem"
components:
securitySchemes:
DevPortalApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: Optional API key auth (if enabled in prod).
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: Optional JWT/JWKS auth (if enabled in prod).
schemas:
SqlParamsExecuteRequest:
type: object
additionalProperties: false
properties:
sql_params:
$ref: "#/components/schemas/SqlParams"
max_rows:
type: integer
minimum: 1
maximum: 5000
default: 200
description: |
Dev-Portal 側で LIMIT を強制するための最大行数。
実装側は必ずこの値を上限として適用すること。
dry_run:
type: boolean
default: false
description: |
true の場合、SQL を生成し、可能なら EXPLAIN/validate まで行うが、実データ取得は行わない。
explain:
type: boolean
default: false
description: |
true の場合、可能なら EXPLAIN を返す(dry_run と併用推奨)。
timeout_ms:
type: integer
minimum: 1000
maximum: 120000
default: 30000
description: |
実行タイムアウト(ms)。実装側はドライバ/DB側タイムアウトも含めて尊重すること。
trace_id:
type: string
description: |
呼び出し側(nlq-dev)が指定する任意の相関ID。指定がなければ Dev-Portal が生成して返す。
required: [sql_params]
SqlParams:
type: object
description: |
nlq-dev が自然文から生成する params。
Dev-Portal はこの params を元に(必要なら Chroma 検索を併用して)SQL を生成する。
NOTE: 初期は柔軟性のため additionalProperties=true とし、nlq-dev 側の進化に追従しやすくする。
additionalProperties: true
properties:
intent:
type: string
description: |
実行意図(例:kpi_aggregate, list_records, trend, compare_periods など)
model:
type: string
description: Odoo model technical name (e.g., sale.order)
measures:
type: array
items:
$ref: "#/components/schemas/Measure"
group_by:
type: array
items:
$ref: "#/components/schemas/GroupBy"
filters:
type: array
items:
$ref: "#/components/schemas/Filter"
order_by:
type: array
items:
$ref: "#/components/schemas/OrderBy"
Measure:
type: object
additionalProperties: false
properties:
name: { type: string, description: Measure field or logical metric name }
agg:
type: string
enum: [sum, avg, min, max, count, count_distinct]
required: [name, agg]
GroupBy:
type: object
additionalProperties: false
properties:
field: { type: string }
granularity:
type: string
enum: [day, week, month, quarter, year]
required: [field]
Filter:
type: object
additionalProperties: false
properties:
field: { type: string }
op:
type: string
enum: [eq, ne, lt, lte, gt, gte, in, not_in, like, ilike, between, is_null, is_not_null]
value:
description: |
op に応じて型が変わる(例:betweenは [from,to] 配列)。
oneOf:
- type: string
- type: number
- type: boolean
- type: array
items: {}
- type: "null"
required: [field, op]
OrderBy:
type: object
additionalProperties: false
properties:
field: { type: string }
dir:
type: string
enum: [asc, desc]
default: asc
required: [field]
TabularResult:
type: object
additionalProperties: false
properties:
columns:
type: array
items:
$ref: "#/components/schemas/Column"
rows:
type: array
items:
type: array
items: {}
row_count:
type: integer
description: Returned row count
truncated:
type: boolean
description: True if max_rows caused truncation
warnings:
type: array
items:
type: string
generated_sql:
type: string
description: |
オプション。デバッグ用。prodでは返さない運用でもよい(設定で制御)。
explain_text:
type: string
description: Optional EXPLAIN output (if explain=true or dry_run=true)
trace_id:
type: string
description: Correlation id
required: [columns, rows, row_count, truncated, trace_id]
Column:
type: object
additionalProperties: false
properties:
name: { type: string }
type: { type: string, description: logical type hint (e.g., number, string, date) }
required: [name]
Problem:
type: object
additionalProperties: false
properties:
type: { type: string, example: "about:blank" }
title: { type: string, example: "Bad Request" }
status: { type: integer, example: 400 }
detail: { type: string }
instance: { type: string }
trace_id: { type: string }
errors:
type: array
items:
type: object
additionalProperties: true
required: [title, status]
コメントを残す