zeekayandHanzo Dev 110f98a1d0 Pin off two module versions that cannot be fetched
luxfi/consensus v1.36.2 has a signed hash in go.sum and in sum.golang.org
that no longer matches the tag. proxy.golang.org 404s .info, .mod and .zip
for it while v1.36.1 and v1.36.3 serve 200, and a direct fetch of the tag
returns a go.mod hashing to m4aMFbKY..., which is byte-identical to what
v1.36.3 publishes. The tag was moved forward after release; go.sum is the
side that is right, so the pin moves to v1.36.3 rather than the check
being suppressed.

hanzoai/base v1.4.6 and v1.4.7 require github.com/hanzoai/cloud v0.1.1.
That version is tagged on hanzo-inc/cloud but not on hanzoai/cloud, which
is the path the module declares and the only place a fetch looks; every
tag there is forge/v1.801.*. v1.4.5 is the last release whose own graph
resolves. go.mod had already moved to v1.4.7 while go.sum still carried
v1.4.2, so nothing in this module built at all.

go vet ./... and go test ./... are clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 14:52:59 -07:00
2026-09-03 17:43:25 -07:00
2026-07-26 01:22:30 -07:00

dashboards — FOLDED INTO hanzoai/observability

This service no longer ships as its own binary. Its whole surface — the five tRPC routers below — now lives in hanzoai/observability, served on the same ZAP router (msgType 203, port 9992) as the traces / observations / scores backbone, with the method ordinals preserved at +200 (allDashboards was @0, is now @200). Implementation is the dash_*.go file set there; the schema is merged into proto/observability.zap.

Why: a dashboard is a saved QUERY over exactly the traces, observations and scores that service already owns, and both halves were blocked on the same ClickHouse analytics shim. Kept apart, that shim had to be written twice against two copies of one OLTP model, and chart/scoreHistogram could not reach the scores they aggregate without a network hop. One service, one shim, one capability gate.

Do not build or deploy this repo. Open PRs against hanzoai/observability. The history here is kept because the ordinals, the wire layout and the per-category permission bits it established are still the live contract.


Original README (historical)

A Hanzo Base-native Go service binary in the console tRPC→ZAP migration. It replaces five in-process console tRPC routers — dashboardRouter, dashboardWidgetRouter, tableRouter, TableViewPresetsRouter, monitorsRouter — with one typed ZAP capability-RPC interface at msgType 206.

Pattern: Go binary built on Hanzo Base (embedded encrypted SQLite

  • plugins) exposing a typed ZAP capability-RPC interface. No Prisma, no Postgres-as-source-of-truth, no Mongo, no Cap'n Proto, no tRPC in the backend.
.zap schema (source of truth)  ──zapgen──▶  gen/ (Go views)
        │                                        │
        └──zapgen --target=ts──▶ console TS      ▼
                                   server/  ─ ZAP RPC handler (cap-gated)
                                   main.go  ─ base.New() + ZAP router :9995
                                              Base HTTP (health/metrics) :8090
                                              vault → per-org encrypted SQLite

Run

make build
./dashboards serve --http=127.0.0.1:8090 --zap=127.0.0.1:9995

Optional per-org encrypted SQLite (vault plugin): add --vaultDir=/data/vaults. The five backing collections (dashboards, dashboard_widgets, table_batch_jobs, table_view_presets, monitors) are provisioned on first boot (idempotent, see server/collections.go).

Smoke test

In-process suite (per-method CRUD + per-category permission gate + pipelining proof + analytics/queue 501 contracts):

make test

Out-of-process probe against a live binary (dashboard CRUD + pipelined dashboard→widget create):

./dashboards serve --zap=127.0.0.1:9995 &
go run ./cmd/probe --addr 127.0.0.1:9995 --peer dashboards

The interface

30 methods on a CapKindIAMSession capability, each gated on exactly one DashPermissions bit (server/wire.go). The bits are the orthogonal product of the five resource categories × {Read, Write} plus an analytics-read bit, mapping 1:1 to the console RBAC scopes:

Category Methods DashPermissions bit ⇄ RBAC scope
Dashboard CRUD allDashboards, getDashboard, createDashboard, updateDashboardMetadata, updateDashboardDefinition, updateDashboardFilters, cloneDashboard, deleteDashboard dashboards:read / dashboards:CUD
Widget CRUD allWidgets, getWidget, createWidget, updateWidget, copyWidgetToProject, deleteWidget (shares Dashboard bits)
Dashboard analytics chart, scoreHistogram, executeQuery PermAnalyticsRead — 501, ClickHouse shim pending
Table batch-action isBatchActionInProgress PermDashboardRead — 501, BullMQ shim pending
TableViewPreset CRUD getPresetsByTableName, getPresetById, createPreset, updatePreset, updatePresetName, deletePreset, generatePermalink TableViewPresets:read / TableViewPresets:CUD
Monitor CRUD allMonitors, getMonitor, createMonitor, updateMonitor, deleteMonitor monitors:read / monitors:CUD

Capability auth is the single chokepoint Server.authorize: it Wraps the opaque capability buffer, enforces Kind == CapKindIAMSession and the method's DashPermissions bit (via permissionFor), and (when an issuer registry is wired) verifies the signature. The signature step is stubbed in bootstrap (TODO in server.go) — Kind + Permissions are always enforced. Every data query is scoped to the projectId in the request — the multi-tenant boundary.

Pipelining

createDashboard/createWidget support Cap'n Proto-style promise pipelining: the widget call Targets the dashboard call's PromiseID, so the server resolves the dashboard's project scope and dispatches the promised widget create against it — eliding a client round trip. See Client.PipelineCreateDashboardThenWidget and TestPipelineDashboardThenWidget.

Not-yet-wired (TODO, return 501)

The analytics reads (chart/scoreHistogram/executeQuery) hit ClickHouse (OLAP), and the table batch-action read hits a BullMQ/Valkey queue — neither is Base. Both return 501 until their shims land; they never fabricate data:

  • server/analytics.go — ClickHouse reader porting getScoreAggregate, getNumericScoreHistogram, getObservation*ByTime, and the features/query executeQuery builder from @hanzo/shared.
  • server/batchqueue.go — Valkey/BullMQ reader porting generateBatchActionId
    • getJobState from console/web/src/features/table/server.

Wiring the console to this service (handoff)

The console keeps its existing TS client (same .zap contract, compiled to TS by zapgen --target=ts instead of Go). Its ZAP bridge substitutes the in-process routers for a ZAP client to this service. The wire envelope is (method:u32, promiseID:u32, target:u32, cap:bytes, payload:bytes) at ZAP msgType 206; responses are (status:u32, promiseID:u32, body:bytes). Method ordinals match the schema (allDashboards=0 … deleteMonitor=29).

This repo does not edit console.

Layout

Path What
proto/dashboards.zap Canonical schema (zap-spec dialect → Go + TS).
gen/ zapgen output (make zap-gen). Generated; do not edit.
server/wire.go Transport envelope codec + msgType/method/status/permission consts.
server/server.go ZAP RPC handler: cap auth, project scoping, dispatch, promise pipelining.
server/handlers.go The 30 per-router method bodies (Base CRUD + analytics/queue TODOs).
server/encode.go Base record → generated wire-struct projection (one encoder per model).
server/collections.go The five Base collection schemas.
server/client.go Typed client (one method per RPC) + pipelining + SyntheticCap.
main.go Binary: base.New() + vault + ZAP router :9995.
cmd/probe/ Out-of-process smoke probe.

Container registry: ghcr.io/hanzoai/dashboards (CI-built, multi-arch).

S
Description
[ARCHIVED] Superseded by hanzoai/o11y pkg/modules/dashboard — was folded into hanzoai/observability, which is itself superseded.
Readme BSD-3-Clause
1.1 GiB
Languages
Go 85.4%
ZAP 10.9%
Dockerfile 2.4%
Makefile 1.3%