query
A clicky + clicky-ui app for managing connections and query profiles and
running them. query serve starts an embedded postgres, exposes a REST API, and
serves the web UI.
go run ./cmd/query serve --port 8080 --profiles-dir ./profiles
# UI: http://localhost:8080/
# OpenAPI: http://localhost:8080/api/openapi.json
Lifecycle
- Add connections — DB-backed (
models.Connection); the create form is driven
by a polymorphic (if/then) JSON Schema keyed on the connection type. The
url/username/password/certificate fields carry an
x-clicky-component: secret-key-selector hint, so the form renders a
clicky-ui SecretKeySelector (Secret / ConfigMap / Value) backed by
GET /api/v1/secrets[/preview]; the chosen reference is stored as an
EnvVar string (secret://<name>/<key>) and resolved at runtime.
- Create profiles — stored as YAML under
--profiles-dir; the form is driven
by the profile-setup schema. A profile declares a provider, a query,
server-side filter params, and output columns.
- Run profiles —
GET /api/v1/profile/{name}?<param>=<value> validates the
params, templates them into the query ({{.params.<name>}}), executes via the
query engine, and returns the rows.
API
Resources are addressed by one REST endpoint; content negotiation selects the
representation:
| Request |
Result |
GET /api/v1/connection |
list connections (secrets redacted) |
GET /api/v1/connection + Accept: application/schema+json |
if/then connection schema |
POST/PUT/DELETE /api/v1/connection[/{id}] |
create / update / delete |
GET /api/v1/profile |
list profile definitions |
GET /api/v1/profile + Accept: application/schema+json |
profile-setup schema |
POST/PUT/DELETE /api/v1/profile[/{name}] |
create / update / delete |
GET /api/v1/profile/{name}?<params> |
execute the profile → rows |
GET /api/v1/profile/{name} + Accept: application/schema+json |
per-profile schema: properties = FilterBar inputs, x-clicky-columns = DataTable columns |
(?__schema is accepted as an alias for the schema Accept header.)
Architecture
cmd/query request pipeline (outer → inner):
execHandler → schemaHandler → clicky executor + UI mux
(execution) (schema c-neg) (CRUD, OpenAPI, /entities, SPA)
- All connection/profile CRUD (list/get/create/update/delete), OpenAPI and the
cobra CLI come from registered clicky entities. Create/Update use the
context-aware handlers and read the raw nested JSON body via
rpc.RequestFromContext, so connection properties and profile
provider/params/columns survive intact (the executor still flattens flags
for parameter-style operations).
- Entities are registered in a shadow init (before cobra parses flags) so
connection, profile, and each profile-<slug> are real CLI subcommands;
serve only injects the DB and execution context. The base profile flow needs
no database — only postgres/sqlite processors do.
- Schemas are generated by
query/schema, committed under schemas/
(task query:schema / query schema --out schemas), and served live via content
negotiation. The clicky-ui add/edit forms render from them with JsonSchemaForm.
Frontend (www/)
A Vite + React app using @flanksource/clicky-ui's EntityExplorerApp, embedded
via go:embed (www/embed.go). A placeholder dist/index.html is committed so the
Go binary builds before a frontend build.
task www:build # pnpm install && vite build → www/dist
task query:build # build the binary with the embedded UI
# dev: run the API, then `pnpm --dir cmd/query/www dev` (proxies /api → :8080)
go run ./cmd/query serve --dev # serves the Vite dev server through the binary
Note: the per-resource schema endpoints (Accept: application/schema+json) are
the contract that drives the connection if/then form, the profile-setup form,
and the per-profile FilterBar + DataTable. EntityExplorerApp's add/edit modals
fetch these (clicky-ui SchemaActionForm) and render JsonSchemaForm; submit
sends the nested value to the entity's create/update route.