Files
james.maesandClaude Opus 5.5 84a7033ae4 feat(api): serve the sql-workbench routes as spec'd UI API extension endpoints
Replace SqlWorkbenchRouteProvider (21 raw /qqq/v1/sql-workbench Javalin
routes) with one MiddlewareSpecExtension "sql-workbench" (prefix
/sql-workbench). JSON operations use AbstractJsonEndpointSpec; the result
export stream extends AbstractEndpointSpec.

Paths, methods and payloads are unchanged, and so are the permission
checks, read-only gates, limits and audit. The generated fragment is
committed at openapi/qqq-v1/sql-workbench.yaml and checked by a contract
test. The server tests run in strict raw-route mode.

The core baseline becomes 4.1.0-RC.6, the first RC with the extension
point (QRun-IO/qqq#1128).

Closes #20 (architecture review QRun-IO/qqq#1150, finding F2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 19:48:18 -05:00

4.9 KiB

SQL Workbench UI API contract

All 21 operations are registered by SqlWorkbenchQBitProducer through SqlWorkbenchEndpoints as one MiddlewareSpecExtension named sql-workbench, version 1.0.0, with the established /sql-workbench prefix. Full URLs remain /qqq/v1/sql-workbench/.... QQQ 4.1.0-RC.6 is the minimum core version. registerRoutes=false disables extension registration; middleware remains optional.

The producer registers no raw routes. Twenty JSON operations extend AbstractJsonEndpointSpec through SqlWorkbenchJsonSpec; ExportResultSpec extends AbstractEndpointSpec directly and streams CSV, JSON or XLSX with the existing attachment filename and Cache-Control: no-store headers.

The checked-in fragment is src/main/resources/openapi/qqq-v1/sql-workbench.yaml. It is also included in a host's /qqq/v1/openapi.yaml and .json, and the extension appears in /qqq/v1/version. All component names begin with SqlWorkbench. Schemas explicitly describe the existing map payloads rather than changing their serialization. SQL results include nullable scalar values, binary previews and nested arrays; execute responses vary by execution status.

Compatibility and security

No existing operation paths, methods, request or response shapes, status codes, or export headers change. Next UI can vendor the fragment without adapting its existing calls. New metadata consists of the extension/version advertisement, OpenAPI schemas and stable operation identifiers.

Core authenticates the caller before each spec runs and clears QContext after the request. Workbench access is checked before parsing bodies, path integers or export formats. JSON object parsing retains BigDecimal precision, JSON-only content-type checks, empty/null-body behavior, and existing error messages. Duplicate execution UUIDs still return 409. SQL failures remain HTTP 200 with a FAILED, TIMED_OUT or CANCELLED execution status.

Specs call the same SqlWorkbenchApi, notebook service and execution engine. Write/EXPLAIN ANALYZE gates, sharing permissions, caller record locks, notebook ownership, cached-result ownership, cancellation ownership, per-user concurrency limits, audit-before-SQL and deferred audit updates remain in place. Client IPs continue into execution audits. No request bodies or result data are logged by the transport.

Operations

Method Path (after /qqq/v1/sql-workbench) operationId
GET /capabilities sqlWorkbenchGetCapabilities
POST /execute sqlWorkbenchExecute
POST /executions/{uuid}/cancel sqlWorkbenchCancelExecution
GET /executions/{uuid}/export sqlWorkbenchExportResult
GET /executions/{uuid}/rows sqlWorkbenchGetRows
POST /explain sqlWorkbenchExplain
GET /history sqlWorkbenchGetHistory
GET /notebooks sqlWorkbenchListNotebooks
POST /notebooks sqlWorkbenchCreateNotebook
DELETE /notebooks/{id} sqlWorkbenchDeleteNotebook
GET /notebooks/{id} sqlWorkbenchGetNotebook
PUT /notebooks/{id} sqlWorkbenchUpdateNotebook
POST /notebooks/{id}/duplicate sqlWorkbenchDuplicateNotebook
POST /notebooks/{id}/publish sqlWorkbenchPublishNotebook
GET /notebooks/{id}/snapshots sqlWorkbenchListSnapshots
POST /notebooks/{id}/snapshots sqlWorkbenchCreateSnapshot
DELETE /notebooks/{id}/snapshots/{snapshotId} sqlWorkbenchDeleteSnapshot
GET /notebooks/{id}/versions sqlWorkbenchListVersions
GET /notebooks/{id}/versions/{n} sqlWorkbenchGetVersion
POST /notebooks/{id}/versions/{n}/restore sqlWorkbenchRestoreVersion
GET /schema/{backendName} sqlWorkbenchGetSchema

Verification and regeneration

SqlWorkbenchApiContractTest regenerates the fragment in memory and checks it against the checked-in file using core's deterministic UiApiContract tooling. It also checks the namespace, secured specs, prefix, media types and 21 unique operation IDs. Intentional contract changes can regenerate the file with:

./mvnw -B test -Dtest=SqlWorkbenchApiContractTest -DsqlWorkbench.openapi.update=true

Before RC.6 is released, local verification uses the separately installed core:

./mvnw -B verify -Dqqq.snapshot.version=4.1.0-ARCHRC6-SNAPSHOT

The POM must continue to name 4.1.0-RC.6; the local override is never a release dependency. On PowerShell, quote each -D... argument and use mvnw.cmd.

SqlWorkbenchEndpointSpecTest runs real HTTP through QApplicationJavalinServer.withStrictUiApiRoutes(true). It preserves the former route-provider tests and adds 401/403 coverage for every operation, mutation denials, execution limits, audited rejection, exact decimals, SQL failures and all three exports. Engine tests continue to verify audit and transaction safety.