From 9c26f4d6b608c9bbeb182531fd30735a8c225203 Mon Sep 17 00:00:00 2001 From: Eric Andrechek Date: Tue, 26 May 2026 11:19:15 -0400 Subject: [PATCH 1/8] moving docs to own makefile to make them easier to work on --- .github/actions/setup-env/action.yml | 2 +- Makefile | 105 ++++++++++++----------- docs/Makefile | 121 +++++++++++++++++++++++++++ docs/scripts/screenshot.mjs | 2 +- docs/src/content/docs/development.md | 4 +- docs/wrangler.jsonc | 23 ++++- 6 files changed, 204 insertions(+), 53 deletions(-) create mode 100644 docs/Makefile diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index 189a595a..8a292a37 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -101,7 +101,7 @@ runs: # Playwright Chromium binary (~130 MB) lives outside the pnpm store at # ~/.cache/ms-playwright. Without this cache, every CI run cold-pulls - # Chromium during install-docs-playwright — adds 30-60s per run. Keyed + # Chromium during docs-install-playwright — adds 30-60s per run. Keyed # on docs/pnpm-lock.yaml since that's where the Playwright version is # locked. Closes the Playwright half of #132. - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 diff --git a/Makefile b/Makefile index bdfaf619..6381ca14 100644 --- a/Makefile +++ b/Makefile @@ -171,6 +171,24 @@ help: ## Show this help menu tname = $$0; sub(/:.*/, "", tname); \ printf " $(CYAN)%-18s$(RESET) %s\n", tname, $$2 \ }' $(MAKEFILE_LIST) + @# Per-subproject sections are auto-generated from $(SUBPROJECTS). Adding + @# a subproject (or a `## `-annotated target inside one) shows up here + @# automatically — no edit to this target needed. Each sub-Makefile's own + @# `help` entry is filtered out (would be redundant with this menu). + @for sp in $(SUBPROJECTS); do \ + name=$$(basename "$$sp"); \ + awk -v name="$$name" -v y='$(YELLOW)' -v c='$(CYAN)' -v r='$(RESET)' \ + 'BEGIN { \ + FS = "## "; \ + title = toupper(substr(name,1,1)) substr(name,2); \ + printf "\n%s%s%s (%s%s-%%%s)\n", y, title, r, c, name, r \ + } \ + /^[a-zA-Z0-9_-]+:.*## / { \ + tname = $$0; sub(/:.*/, "", tname); \ + if (tname == "help") next; \ + printf " %s%-18s%s %s\n", c, name "-" tname, r, $$2 \ + }' "$$sp/Makefile"; \ + done @printf "\nTunable variables are documented at the top of the Makefile.\n" ##@ Dev @@ -199,24 +217,6 @@ dev: deps-up $(AIR) $(CONFIG_FILES) ## Hot-reload dev server: ClickHouse + WaveH @echo " ClickHouse: $(GREEN)http://localhost:8123$(RESET) (HTTP), $(GREEN)localhost:9000$(RESET) (native)" WH_CONFIG=.config.local.yaml $(AIR) -c .air.toml -# Docs site dev/preview servers — long-running, blocking. Astro dev defaults -# to :4321; `wrangler dev` (preview) defaults to :8787, so both coexist with -# `make dev` on :8080. -.PHONY: dev-docs -dev-docs: install-docs-playwright ## Hot-reload docs site dev server (Astro on :4321) - @cd $(DOCS_DIR) && $(PNPM) dev - -.PHONY: preview-docs -preview-docs: install-docs-playwright ## Preview the production docs build locally (auto-builds if dist/ is missing) - @# Skip the build if `dist/` already exists — running `make build-docs` - @# and then `make preview-docs` should serve the existing artifact, not - @# rebuild from scratch. Re-run `make build-docs` explicitly to refresh. - @if [ ! -d $(DOCS_DIR)/dist ]; then \ - echo "$(CYAN)==> No dist/ — building docs first...$(RESET)"; \ - cd $(DOCS_DIR) && $(PNPM) build; \ - fi - @cd $(DOCS_DIR) && $(PNPM) preview - # `up -d --wait` blocks until the compose healthcheck transitions to # healthy, so callers can chain on success without a polling loop. The # ClickHouse healthcheck (in $(DEV_COMPOSE_FILE)) probes /ping on :8123. @@ -368,7 +368,7 @@ build-cover: $(COVER_BINARIES) ## Compile all binaries with coverage instrumenta .PHONY: build-all build-all: ## Build all artifacts in parallel — Go binaries + SDK + docs site @echo "$(CYAN)==> Building all artifacts...$(RESET)" - @$(MAKE) -j 4 build build-sdk build-docs + @$(MAKE) -j 4 build build-sdk subprojects-build @echo "$(GREEN)$(BOLD)✔ All artifacts built$(RESET)" # --- TypeScript SDK build / install ------------------------------------------ @@ -381,28 +381,46 @@ SDK_DIR := clients/ts E2E_SDK_DIR := tests/e2e/sdk DOCS_DIR := docs -# install-sdk + install-e2e-sdk + install-docs are intermediate prereqs — they -# have no doc comment so they don't show in `make help`. User-facing targets -# below (build-sdk, test-sdk, test-e2e, build-docs, dev-docs, preview-docs) -# depend on them. +# install-sdk + install-e2e-sdk are intermediate prereqs — they have no doc +# comment so they don't show in `make help`. User-facing targets below +# (build-sdk, test-sdk, test-e2e) depend on them. The docs project is wired +# through the subproject orchestration block below (`SUBPROJECTS`, fan-out, +# per-subproject pattern rule) rather than per-target prereqs here. When the +# SDK is later extracted into a sibling Makefile, the same pattern absorbs it. .PHONY: install-sdk install-sdk: @cd $(SDK_DIR) && $(PNPM) install --frozen-lockfile -.PHONY: install-docs -install-docs: - @cd $(DOCS_DIR) && $(PNPM) install --frozen-lockfile - -# Playwright Chromium (~130 MB) is required by `rehype-mermaid` (build-time -# diagram SSR) and `starlight-links-validator`. Kept out of `install-docs` so -# the top-level `make tools` bootstrap doesn't force every Go-only contributor -# to download Chromium. Wired into `build-docs` / `dev-docs` instead. The -# `--with-deps` apt step is $CI-gated since it needs sudo on Linux laptops; -# CI runners on minimal base images need it. Both steps are idempotent. See -# docs/src/content/docs/development.md for the full Linux-dev-machine story. -.PHONY: install-docs-playwright -install-docs-playwright: install-docs - @cd $(DOCS_DIR) && $(PNPM) exec playwright install chromium $${CI:+--with-deps} >/dev/null +# --- Subproject orchestration ------------------------------------------------ +# Sub-projects (docs today; per-language SDKs eventually) live in their own +# directories with their own Makefiles. The root iterates over $(SUBPROJECTS) +# and fans out the common verbs in parallel — adding a subproject is one line +# below plus a Makefile in the new directory that implements the verb set +# (no-op allowed for verbs that don't apply yet). +# +# Direct invocation from root: `make -` (e.g. `make docs-dev`) via +# the per-subproject pattern rules at the end of this section. +SUBPROJECTS := $(DOCS_DIR) +COMMON_VERBS := install build test lint verify clean + +# `/.` — hidden phony ticket that recurses into the subproject. +# Hidden-file shape avoids ever colliding with a real file or directory. +SUBPROJECT_TICKETS := $(foreach d,$(SUBPROJECTS),$(addprefix $(d)/.,$(COMMON_VERBS))) +.PHONY: $(SUBPROJECT_TICKETS) +$(SUBPROJECT_TICKETS): + @$(MAKE) -C $(@D) $(patsubst .%,%,$(@F)) + +# `subprojects-` — fan-out aggregator. `make -jN subprojects-build` runs +# each subproject's build concurrently; --output-sync keeps logs readable. +SUBPROJECT_FANOUTS := $(addprefix subprojects-,$(COMMON_VERBS)) +.PHONY: $(SUBPROJECT_FANOUTS) +$(SUBPROJECT_FANOUTS): subprojects-%: $(addsuffix /.%,$(SUBPROJECTS)) + +# Per-subproject pattern rules for direct invocation: +# make docs- → cd docs && make +# Add one line below per subproject as they're added to SUBPROJECTS. +docs-%: + @$(MAKE) -C $(DOCS_DIR) $* .PHONY: install-e2e-sdk install-e2e-sdk: @@ -413,18 +431,11 @@ build-sdk: install-sdk ## Build TypeScript SDK → clients/ts/dist/ (required by @echo "$(CYAN)==> Building SDK...$(RESET)" @cd $(SDK_DIR) && $(PNPM) build -# Docs site (Astro + Starlight) lives in docs/. Markdown sources are the -# Starlight content collection itself — no separate convert step. -.PHONY: build-docs -build-docs: install-docs-playwright ## Build docs site for production → docs/dist/ - @echo "$(CYAN)==> Building docs site...$(RESET)" - @cd $(DOCS_DIR) && $(PNPM) build - # Single-source-of-truth logo pipeline. Edit scripts/branding/mark.svg (the # path) and run `make branding` to regenerate favicon.{svg,ico}, # apple-touch-icon.png, og.png, and the Starlight nav light/dark SVGs. # Requires librsvg (rsvg-convert) + ImageMagick 7 (magick) — `brew install -# librsvg imagemagick`. Not part of `build-docs`: derived assets are +# librsvg imagemagick`. Not part of `docs-build`: derived assets are # committed so contributors don't need the raster toolchain to build docs. .PHONY: branding branding: ## Regenerate all logo/favicon/OG assets from scripts/branding/mark.svg @@ -514,7 +525,7 @@ cov: ## Merge all available covdata + gate against total threshold # ci-parallel: hidden — the parallel-safe leaves. No `## ` doc comment so # it stays out of `make help`; users invoke `make ci`, not this directly. .PHONY: ci-parallel -ci-parallel: verify build build-cover build-sdk build-docs test test-sdk +ci-parallel: verify subprojects-verify build build-cover build-sdk subprojects-build test test-sdk subprojects-test .PHONY: ci ci: ## Full pipeline — parallel checks, then sequential heavy suites + coverage @@ -632,7 +643,7 @@ clean-all: clean clean-test clean-tools ## Full reset — clean + clean-test + c # Go's build cache makes subsequent invocations near-instant. If you need # them pre-compiled (offline CI image baking), run them once with --help. .PHONY: tools -tools: $(GOLANGCI_LINT) $(AIR) go-mod-download install-sdk install-e2e-sdk install-docs ## Install pinned tools, Go modules, pnpm deps, and git hooks +tools: $(GOLANGCI_LINT) $(AIR) go-mod-download install-sdk install-e2e-sdk subprojects-install ## Install pinned tools, Go modules, pnpm deps, and git hooks @# Install team-wide git hooks via core.hooksPath. Idempotent — running @# `make tools` repeatedly just re-asserts the config. The .githooks/ @# directory is committed; this line plumbs git to it. Users can opt out diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..43a0a699 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,121 @@ +# ============================================================================== +# WaveHouse Docs Site (Astro + Starlight) +# ============================================================================== +# Self-contained Makefile for the docs site. Run `make` from inside docs/ to +# drive Astro directly (install, dev server, build, preview). +# +# The root Makefile exposes every target here as `make docs-` via a +# single pattern rule (`docs-%: ; @$(MAKE) -C docs $*`). Adding a target +# here makes it instantly available from root — no per-target wiring. + +SHELL := /usr/bin/env bash +MAKEFLAGS += --warn-undefined-variables +MAKEFLAGS += --no-print-directory +.DELETE_ON_ERROR: +.DEFAULT_GOAL := help + +# --- Environment Detection ---------------------------------------------------- +CI ?= +NO_COLOR ?= + +# --- Colors ------------------------------------------------------------------- +ifeq ($(strip $(NO_COLOR)),) + ESC := $(shell printf '\033') + CYAN := $(ESC)[36m + GREEN := $(ESC)[32m + YELLOW := $(ESC)[33m + RED := $(ESC)[31m + BOLD := $(ESC)[1m + RESET := $(ESC)[0m +else + CYAN := + GREEN := + YELLOW := + RED := + BOLD := + RESET := +endif + +PNPM ?= pnpm + +# ============================================================================== +# Targets +# ============================================================================== + +##@ General + +.PHONY: help +help: ## Show this help menu + @printf "Usage: $(BOLD)make$(RESET) $(CYAN)$(RESET)\n" + @printf " (run from docs/ — root Makefile exposes the same targets as \`make docs-\`)\n" + @awk 'BEGIN { FS = "## " } \ + /^##@/ { printf "\n$(YELLOW)%s$(RESET)\n", substr($$0, 5); next } \ + /^[a-zA-Z0-9_-]+:.*## / { \ + tname = $$0; sub(/:.*/, "", tname); \ + printf " $(CYAN)%-18s$(RESET) %s\n", tname, $$2 \ + }' $(MAKEFILE_LIST) + +##@ Setup + +.PHONY: install +install: ## Install pnpm dependencies (frozen lockfile) + @$(PNPM) install --frozen-lockfile + +# Playwright Chromium (~130 MB) is required by `rehype-mermaid` (build-time +# diagram SSR) and `starlight-links-validator`. The `--with-deps` apt step +# needs sudo and is only useful on CI's minimal base images; gate on $CI so +# local laptops skip it. Both steps are idempotent. +# +# Hidden from help (no `##` annotation) — it's a transitive prereq of `dev` / +# `preview` / `build`, almost never invoked directly. Run explicitly with +# `make install-playwright` (or `make docs-install-playwright` from root) +# if you ever need to refresh the Chromium cache standalone. +.PHONY: install-playwright +install-playwright: install + @$(PNPM) exec playwright install chromium $${CI:+--with-deps} >/dev/null + +##@ Dev + +.PHONY: dev +dev: install-playwright ## Hot-reload Astro dev server on :4321 + @$(PNPM) dev + +.PHONY: preview +preview: install-playwright ## Preview the production build locally via wrangler (auto-builds if dist/ is missing) + @# Skip the build if `dist/` already exists — running `make build` then + @# `make preview` should serve the existing artifact, not rebuild. Re-run + @# `make build` explicitly to refresh. + @if [ ! -d dist ]; then \ + echo "$(CYAN)==> No dist/ — building first...$(RESET)"; \ + $(PNPM) build; \ + fi + @$(PNPM) preview + +##@ Build + +.PHONY: build +build: install-playwright ## Build the docs site for production → dist/ + @echo "$(CYAN)==> Building docs site...$(RESET)" + @$(PNPM) build + +# --- Common-verb contract ---------------------------------------------------- +# The root Makefile's `subprojects-` fan-out expects every subproject to +# define `test`, `lint`, and `verify`. The docs site doesn't have automated +# tests / lints / type checks yet — these are no-ops for now. Replace with +# real recipes as the project grows (`astro check`, link validator standalone, +# accessibility checks, etc.). Hidden from help on purpose. +.PHONY: test lint verify +test lint verify: + @: + +##@ Cleanup + +.PHONY: clean +clean: ## Remove build output (dist/) + @echo "$(YELLOW)==> Cleaning docs dist/...$(RESET)" + @rm -rf dist/ + +.PHONY: clean-tools +clean-tools: ## Remove node_modules/ + @echo "$(YELLOW)==> Cleaning docs node_modules/...$(RESET)" + @rm -rf node_modules/ diff --git a/docs/scripts/screenshot.mjs b/docs/scripts/screenshot.mjs index 133e3e19..af8be3fd 100644 --- a/docs/scripts/screenshot.mjs +++ b/docs/scripts/screenshot.mjs @@ -1,7 +1,7 @@ /* Visual regression / preview screenshots for the WaveHouse docs site. * Run with: pnpm exec node scripts/screenshot.mjs * Requires the dev server to be running on http://127.0.0.1:4321 - * (the Astro default, which is also what `make dev-docs` starts). */ + * (the Astro default, which is also what `make docs-dev` starts). */ import { chromium } from "playwright"; import { mkdir } from "node:fs/promises"; diff --git a/docs/src/content/docs/development.md b/docs/src/content/docs/development.md index f8a61abf..eee66aae 100644 --- a/docs/src/content/docs/development.md +++ b/docs/src/content/docs/development.md @@ -18,7 +18,7 @@ You need these on your `PATH` before any `make` recipe will work end-to-end: | **bash** | 4+ recommended | Recipes are pinned to `bash`; the helper scripts under `scripts/` use `set -euo pipefail` and bash arrays | macOS default is bash 3.2 (works for current recipes, but `brew install bash` is safer); Linux distros ship 4+ | | **Docker** *(or Podman)* | Engine 20.10+ with the Compose **v2** plugin (`docker compose`, no hyphen) | Compose stacks under `deployments/compose/` and `tests/e2e/compose.yaml`; integration tests boot a ClickHouse testcontainer | [Docker Desktop](https://docs.docker.com/get-docker/), [colima](https://github.com/abiosoft/colima), or [Podman](https://podman.io) with `podman-compose` / the `podman compose` plugin. The testcontainers Go library also honors `DOCKER_HOST` for rootless Podman setups | | **Node.js** | 22 LTS — pinned via `.nvmrc` at the repo root | Runtime for pnpm and the Vitest suites. Pinned to match CI (`setup-node` uses 22) and to avoid Node-major surprises; older Vitest versions in this repo were known to crash on Node 26 with a V8 heap-allocation abort | [nodejs.org](https://nodejs.org/) or `nvm use` / `fnm use` / `volta` (all read `.nvmrc`) | -| **pnpm** | 11.1+ (pinned via `packageManager` in `clients/ts/package.json`, `tests/e2e/sdk/package.json`, and `docs/package.json`) | Package manager for the TypeScript SDK, E2E test harness, and docs site; `make build-sdk`, `make test-sdk`, `make test-e2e`, `make build-docs`, `make dev-docs`, `make preview-docs` all shell out to `pnpm` | `corepack enable && corepack prepare pnpm@11.1.3 --activate` (recommended), or `npm i -g pnpm` | +| **pnpm** | 11.1+ (pinned via `packageManager` in `clients/ts/package.json`, `tests/e2e/sdk/package.json`, and `docs/package.json`) | Package manager for the TypeScript SDK, E2E test harness, and docs site; `make build-sdk`, `make test-sdk`, `make test-e2e`, `make docs-build`, `make docs-dev`, `make docs-preview` all shell out to `pnpm` | `corepack enable && corepack prepare pnpm@11.1.3 --activate` (recommended), or `npm i -g pnpm` | | **git** + **curl** | any recent | `git` for source + version metadata in builds; `curl` is used by the Makefile to fetch the pinned `golangci-lint` binary into `.bin/` | usually preinstalled | ### Auto-installed by `make tools` @@ -28,7 +28,7 @@ Run `make tools` once after cloning to populate everything that doesn't have to - **`golangci-lint` v2.11.4** → installed to `.bin/_/` (version-pinned in the Makefile; bumping the version triggers a reinstall). Not in `go.mod` because its dependency tree conflicts with the main module. - **`air` v1.65.1** → installed to `.bin/_/` via `go install`; used by `make dev` for hot-reload. Same exclusion principle as `golangci-lint` — air's transitive deps (Hugo, Sass libs) would bloat `go.sum`. - **Go `tool` deps** (`gotestsum`, `gofumpt`, `goimports`, `govulncheck`, `go-test-coverage`, `deadcode`, `gsa`, `goda`) — pinned in `go.mod` via native `tool` directives (Go 1.24+), invoked with `go tool `. `make tools` runs `go mod download` so they're cached; they compile lazily on first invocation. -- **pnpm deps** for `clients/ts/`, `tests/e2e/sdk/`, and `docs/` (via `pnpm install --frozen-lockfile`). `make tools` runs only the pnpm install; the Playwright Chromium binary (~130 MB) is fetched on-demand by `make build-docs` / `make dev-docs` via the `install-docs-playwright` target, so Go-only contributors don't pay the download cost. When you do hit `build-docs` / `dev-docs`, Chromium is required by `rehype-mermaid` (SVG diagram rendering at build time) and `starlight-links-validator`. The `--with-deps` flag (which apt-installs Chromium's system libraries: `libnspr4`, `libnss3`, etc.) is only added when `$CI` is set, so contributor laptops don't get an unexpected `sudo` prompt. On Linux dev machines without those libs already present, run `pnpm exec playwright install-deps chromium` once manually. +- **pnpm deps** for `clients/ts/`, `tests/e2e/sdk/`, and `docs/` (via `pnpm install --frozen-lockfile`). `make tools` runs only the pnpm install; the Playwright Chromium binary (~130 MB) is fetched on-demand by `make docs-build` / `make docs-dev` via the `docs-install-playwright` target, so Go-only contributors don't pay the download cost. When you do hit `docs-build` / `docs-dev`, Chromium is required by `rehype-mermaid` (SVG diagram rendering at build time) and `starlight-links-validator`. The `--with-deps` flag (which apt-installs Chromium's system libraries: `libnspr4`, `libnss3`, etc.) is only added when `$CI` is set, so contributor laptops don't get an unexpected `sudo` prompt. On Linux dev machines without those libs already present, run `pnpm exec playwright install-deps chromium` once manually. Root-side targets (`docs-*`) auto-forward to `docs/Makefile` via a pattern rule — from inside `docs/`, run `make help` to see the un-prefixed names (`install`, `dev`, `build`, `preview`). ### Verify your setup diff --git a/docs/wrangler.jsonc b/docs/wrangler.jsonc index 4e305a98..afe5b805 100644 --- a/docs/wrangler.jsonc +++ b/docs/wrangler.jsonc @@ -2,14 +2,33 @@ // Cloudflare Workers + Static Assets. Astro builds the site to ./dist // and the worker in worker/index.ts (using cloudflare-md-router) handles // Accept-header / user-agent routing before falling through to ASSETS. + // + // Deploy is driven by Cloudflare's Workers Builds (the native Git + // integration) — no GitHub Action, no API token secret to manage. On + // pushes to `main`, CF runs `npx wrangler deploy` from `docs/`; on PR + // branches it runs `npx wrangler versions upload`, which produces a + // per-version preview URL of the form + // `-wavehouse-docs.wave-rf.workers.dev`. + "$schema": "node_modules/wrangler/config-schema.json", "name": "wavehouse-docs", "main": "worker/index.ts", - "compatibility_date": "2025-01-01", + "compatibility_date": "2025-11-01", "assets": { "directory": "./dist", "binding": "ASSETS", "not_found_handling": "404-page", "html_handling": "drop-trailing-slash", "run_worker_first": true - } + }, + "routes": [ + { "pattern": "wavehouse.dev", "custom_domain": true } + ], + // need to keep `*.wave-rf.workers.dev` URL alive for PRs + "workers_dev": true, + "preview_urls": true, + "observability": { + "enabled": true, + "head_sampling_rate": 1 + }, + "upload_source_maps": true } From ffdf73e5c0a7fbfab628bf88be1c4d09203cb073 Mon Sep 17 00:00:00 2001 From: Eric Andrechek Date: Tue, 26 May 2026 11:45:00 -0400 Subject: [PATCH 2/8] cleanup repo root with branding move --- Makefile | 10 ---------- docs/Makefile | 10 ++++++++++ {scripts => docs/scripts}/branding/generate.sh | 15 +++++++++------ {scripts => docs/scripts}/branding/lockup.svg | 0 {scripts => docs/scripts}/branding/mark.svg | 0 .../scripts}/branding/og.template.svg | 0 6 files changed, 19 insertions(+), 16 deletions(-) rename {scripts => docs/scripts}/branding/generate.sh (93%) rename {scripts => docs/scripts}/branding/lockup.svg (100%) rename {scripts => docs/scripts}/branding/mark.svg (100%) rename {scripts => docs/scripts}/branding/og.template.svg (100%) diff --git a/Makefile b/Makefile index 6381ca14..84433251 100644 --- a/Makefile +++ b/Makefile @@ -431,16 +431,6 @@ build-sdk: install-sdk ## Build TypeScript SDK → clients/ts/dist/ (required by @echo "$(CYAN)==> Building SDK...$(RESET)" @cd $(SDK_DIR) && $(PNPM) build -# Single-source-of-truth logo pipeline. Edit scripts/branding/mark.svg (the -# path) and run `make branding` to regenerate favicon.{svg,ico}, -# apple-touch-icon.png, og.png, and the Starlight nav light/dark SVGs. -# Requires librsvg (rsvg-convert) + ImageMagick 7 (magick) — `brew install -# librsvg imagemagick`. Not part of `docs-build`: derived assets are -# committed so contributors don't need the raster toolchain to build docs. -.PHONY: branding -branding: ## Regenerate all logo/favicon/OG assets from scripts/branding/mark.svg - @scripts/branding/generate.sh - ##@ Test # Each Go test target writes covdata to tmp/coverage//data/ and diff --git a/docs/Makefile b/docs/Makefile index 43a0a699..8902f4bf 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -98,6 +98,16 @@ build: install-playwright ## Build the docs site for production → dist/ @echo "$(CYAN)==> Building docs site...$(RESET)" @$(PNPM) build +# Single-source-of-truth logo pipeline. Edit scripts/branding/mark.svg and run +# `make branding` (or `make docs-branding` from root) to regenerate favicon +# .{svg,ico}, apple-touch-icon.png, og.png, and the Starlight nav light/dark +# SVGs. Requires librsvg (rsvg-convert) + ImageMagick 7 (magick) — `brew install +# librsvg imagemagick`. Not a `build` prereq: derived assets are committed so +# contributors don't need the raster toolchain to build docs. +.PHONY: branding +branding: ## Regenerate logo/favicon/OG assets from scripts/branding/mark.svg + @scripts/branding/generate.sh + # --- Common-verb contract ---------------------------------------------------- # The root Makefile's `subprojects-` fan-out expects every subproject to # define `test`, `lint`, and `verify`. The docs site doesn't have automated diff --git a/scripts/branding/generate.sh b/docs/scripts/branding/generate.sh similarity index 93% rename from scripts/branding/generate.sh rename to docs/scripts/branding/generate.sh index b501e98c..9064c900 100755 --- a/scripts/branding/generate.sh +++ b/docs/scripts/branding/generate.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Regenerate every WaveHouse logo / favicon / social-card asset from a single -# source: scripts/branding/mark.svg. +# source: docs/scripts/branding/mark.svg. # # Outputs: # docs/public/favicon.svg browser favicon, CSS-swaps light/dark @@ -10,9 +10,10 @@ # docs/src/assets/branding/wavehouse-mark-light.svg Starlight nav logo (light theme) # docs/src/assets/branding/wavehouse-mark-dark.svg Starlight nav logo (dark theme) # -# Edit scripts/branding/mark.svg (one or more SVG elements, single line, using -# `stroke="currentColor"` for any element that should pick up the brand color) -# or the COLOR_* variables below, then run `make branding`. +# Edit docs/scripts/branding/mark.svg (one or more SVG elements, single line, +# using `stroke="currentColor"` for any element that should pick up the brand +# color) or the COLOR_* variables below, then run `make docs-branding` from +# the repo root (or `make branding` from inside docs/). # # Requires rsvg-convert (librsvg) and magick (ImageMagick 7+) on PATH: # brew install librsvg imagemagick @@ -21,8 +22,10 @@ set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT="$(cd "$HERE/../.." && pwd)" -# shellcheck source=scripts/_colors.sh +# Repo root via git rather than a hard-coded relative climb — survives if the +# script ever gets moved again (e.g. into a different subproject). +ROOT="$(git -C "$HERE" rev-parse --show-toplevel)" +# shellcheck source=../../../scripts/_colors.sh source "$ROOT/scripts/_colors.sh" # --- Branding configuration --------------------------------------------------- diff --git a/scripts/branding/lockup.svg b/docs/scripts/branding/lockup.svg similarity index 100% rename from scripts/branding/lockup.svg rename to docs/scripts/branding/lockup.svg diff --git a/scripts/branding/mark.svg b/docs/scripts/branding/mark.svg similarity index 100% rename from scripts/branding/mark.svg rename to docs/scripts/branding/mark.svg diff --git a/scripts/branding/og.template.svg b/docs/scripts/branding/og.template.svg similarity index 100% rename from scripts/branding/og.template.svg rename to docs/scripts/branding/og.template.svg From 772f1b004b33b87f9caf04f22d7f9bcc13652d71 Mon Sep 17 00:00:00 2001 From: Eric Andrechek Date: Tue, 26 May 2026 11:53:23 -0400 Subject: [PATCH 3/8] updating docs for new make patterns --- AGENTS.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c1611837..8ee62ca5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -88,7 +88,7 @@ make test-all # All four suites sequentially + merged coverage gate make cov # Merge whichever covdata exists + gate against total threshold # CI -make ci # Phase 1 (parallel): verify + builds + test-unit + test-sdk +make ci # Phase 1 (parallel): verify + builds + test-unit + test-sdk + subprojects-{verify,build,test} # Phase 2 (sequential): test-integration + test-e2e + cov # Analysis (informational, not in CI) @@ -114,6 +114,12 @@ make clean # Build outputs only (bin/, dist/, clients/ts/dist/) make clean-test # Test outputs only (tmp/ — coverage, logs, NATS state) make clean-tools # Installed tools and pnpm deps (.bin/, node_modules/) make clean-all # Full reset: above + data/ + docker volumes + +# Docs site (Astro + Starlight in docs/, with its own Makefile) +make docs-dev # Hot-reload Astro dev server on :4321 +make docs-build # Production build → docs/dist/ +make docs-preview # Wrangler preview of the production build (auto-builds if dist/ missing) +make docs-branding # Regenerate logo/favicon/OG assets from docs/scripts/branding/mark.svg ``` Verbose test output: `V=1 make test`. Extra flags: `make test ARGS="-run TestFoo"`. @@ -123,7 +129,8 @@ Tooling notes: - Most dev tools (`gotestsum`, `gofumpt`, `goimports`, `govulncheck`, `go-test-coverage`, `deadcode`, `gsa`, `goda`) are pinned in `go.mod` via native `tool` directives and invoked with `go tool ` — no manual install needed. - `golangci-lint` is pinned in the Makefile (currently v2.11.4) and auto-installed to `.bin/_/` on first `make lint` (or via `make tools`). Not in `go.mod` — its dependency tree conflicts with the main module. -- `pnpm` (>= 11.1) and `Node.js` (22 LTS — pinned via `.nvmrc` at the repo root, matches CI) must be on your PATH; the SDK and E2E test harnesses both shell out to `pnpm`. `make tools` runs `pnpm install --frozen-lockfile` in `clients/ts/` and `tests/e2e/sdk/`. +- `pnpm` (>= 11.1) and `Node.js` (22 LTS — pinned via `.nvmrc` at the repo root, matches CI) must be on your PATH; the SDK, E2E test harness, and docs site all shell out to `pnpm`. `make tools` runs `pnpm install --frozen-lockfile` in `clients/ts/`, `tests/e2e/sdk/`, and `docs/`. +- **Subproject Makefiles**: `docs/` has its own `Makefile` so the docs site is self-contained (`cd docs && make build` works directly). The root forwards every `docs-` target via a pattern rule and aggregates the common verbs (`install`, `build`, `test`, `lint`, `verify`, `clean`) through `subprojects-` fan-outs — so `make ci`, `make tools`, etc. pick up new subprojects automatically. When extracting more subprojects (per-language SDKs, etc.), append the directory to `SUBPROJECTS` at the top of the root `Makefile` — no aggregator edits required. - `GNU Make 4+` is required (uses `--output-sync=target`); macOS ships BSD Make 3.81 which will not parse the Makefile. See `docs/src/content/docs/development.md` § Prerequisites for the full setup checklist. ## Testing Conventions From 17bb139eb2bb95da3c7a838b21449c3a0a521deb Mon Sep 17 00:00:00 2001 From: Eric Andrechek Date: Tue, 26 May 2026 12:06:19 -0400 Subject: [PATCH 4/8] agents and changelog updates --- AGENTS.md | 1 + CHANGELOG.md | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 8ee62ca5..3655a9ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -409,6 +409,7 @@ docs/ → Project documentation - **Gemini Code Assist App** configured via `.gemini/styleguide.md`. - **Claude PR review** (`claude-review.yml`) runs only on manual trigger: `@claude` or `/review` from a trusted commenter on a PR, or `workflow_dispatch`. Gated on the HEAD commit's author or committer having ≥read permission so a comment on a fork PR can't run untrusted code with write tokens. Findings post as inline review comments (blocked by `required_review_thread_resolution`) plus a sticky verdict summary. Review-only — Claude can comment but not push. Requires the `CLAUDE_CODE_OAUTH_TOKEN` secret (`claude setup-token`). - **Dependabot auto-merge** (`dependabot-automerge.yml`): patch/minor bumps auto-approve + auto-merge; major bumps hold for human review. CI still gates the actual merge. Patch/minor bypass `Admin approval` (the workflow + CI passing is the trust model); major bumps fall through to admin review like any human PR — this closed a hole where a bot's APPROVED review (e.g. CodeRabbit) could merge a major bump without admin involvement (see #130). +- **Docs site deploy** (`wavehouse.dev`): driven by Cloudflare's Workers Builds (the native Git integration on the CF side), not a GitHub Actions workflow — so no `CLOUDFLARE_API_TOKEN` lives in the repo. Push to `main` runs `npx wrangler deploy` from `docs/` and updates `wavehouse.dev` within ~2 minutes; pushes to PR branches run `npx wrangler versions upload`, which publishes a per-version preview at `-wavehouse-docs.wave-rf.workers.dev`. Wrangler config (custom domain, observability, source maps, preview URLs) lives in `docs/wrangler.jsonc`; the build command (`pnpm install --frozen-lockfile && pnpm build`) and `docs/` root directory are configured on the CF dashboard side. The worker (`docs/worker/index.ts`, delegating to `cloudflare-md-router`) deploys alongside the static assets so `Accept: text/markdown` content negotiation works in production. ## Governance Files diff --git a/CHANGELOG.md b/CHANGELOG.md index 43a03737..2644e046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- **Docs site is now its own Makefile subproject + auto-deploys to `wavehouse.dev` via Cloudflare Workers Builds** (`Makefile`, `docs/Makefile` (new), `docs/wrangler.jsonc`, `docs/scripts/branding/` (moved from `scripts/branding/`), `AGENTS.md`, `docs/src/content/docs/development.md`, `docs/scripts/screenshot.mjs`, `.github/actions/setup-env/action.yml`). Closes #148. Three threads, one PR: + - **Subproject Makefile split.** `docs/` gets its own `Makefile` (`make build`, `make dev`, `make preview`, `make branding`, `make install`, `make install-playwright`, `make clean`) so the docs site is self-contained — `cd docs && make build` works directly without any root-Makefile awareness. The root `Makefile` keeps a single `docs-%: ; @$(MAKE) -C docs $*` pattern rule that forwards every target as `make docs-` from root, and a `SUBPROJECTS := docs` list drives a generic `subprojects-` fan-out for the common verbs (`install`, `build`, `test`, `lint`, `verify`, `clean`) that `make ci` / `make tools` / `make build-all` now call. Adding the next subproject (per-language SDKs eventually) is one line appended to `SUBPROJECTS` plus a sibling Makefile that defines the verb set. **Renames** (root-side targets reshape from `-docs` to `docs-`): `make dev-docs` → `make docs-dev`; `make build-docs` → `make docs-build`; `make preview-docs` → `make docs-preview`; `make branding` → `make docs-branding`; `make install-docs-playwright` → `make docs-install-playwright`. The setup-env composite action's Playwright-cache-restore step gets its comment updated to the new name. `make help` auto-renders a per-subproject section from each sub-Makefile so the menu stays in sync without manual wiring. + - **Branding pipeline relocated.** `scripts/branding/{mark.svg,lockup.svg,og.template.svg,generate.sh}` → `docs/scripts/branding/` since it's a docs-only concern; `generate.sh` now resolves the repo root via `git rev-parse --show-toplevel` instead of a hard-coded relative climb, so future moves don't re-break it. `make docs-branding` is the canonical entry point from root. + - **Auto-deploy via Cloudflare Workers Builds.** Rather than ship `.github/workflows/deploy-docs.yml` with `cloudflare/wrangler-action` and a repo-level `CLOUDFLARE_API_TOKEN`, the deploy is driven by Cloudflare's native Git integration (Workers Builds), configured on the CF dashboard side against this repo's `docs/` directory. Push to `main` runs `npx wrangler deploy` and updates `wavehouse.dev` within ~2 minutes; pushes to PR branches run `npx wrangler versions upload`, which publishes a per-version preview URL of the form `-wavehouse-docs.wave-rf.workers.dev`. `docs/wrangler.jsonc` gains the `routes` block for the `wavehouse.dev` custom domain, `workers_dev: true` + `preview_urls: true` so the per-version preview URLs keep working, `observability: { enabled: true, head_sampling_rate: 1 }`, `upload_source_maps: true`, and a `$schema` pointer for editor validation; `compatibility_date` bumped from `2025-01-01` to `2025-11-01`. The worker (`docs/worker/index.ts`, delegating to `cloudflare-md-router`) deploys alongside the static assets so `Accept: text/markdown` content negotiation works in production, not just under `wrangler dev`. AGENTS.md §"Repository Automation" documents the deploy mechanism so future maintainers know where to look (no GH Actions workflow exists for this on purpose). - **Polish on the `/v1/admin/query` HTTP proxy from PR review** (`internal/api/query.go`, `internal/api/query_test.go`, `docs/src/content/docs/api.md`, `docs/src/content/docs/architecture.md`, `docs/src/content/docs/sdk.md`, `docs/src/content/docs/configuration.md`, `docs/src/content/docs/deployment.md`): tightening fixes from a clean-context review on PR #164. - **Status mapping split.** ClickHouse 4xx responses now map to HTTP 400 (caller-fault, the SQL was bad) and 5xx responses map to HTTP 502 (gateway-fault, the upstream had a problem), instead of every non-200 collapsing to 500. Admin tooling that retries on 5xx-but-not-4xx and dashboards that classify SLO violations get back the signal they need. - **`Content-Type` pass-through on inline `FORMAT`.** The fallback "ClickHouse returned a non-JSON body" branch (triggered by `FORMAT CSV` / `FORMAT Pretty` / etc., which override the URL-level `default_format=JSON`) now passes through the upstream `Content-Type` instead of stamping `application/json`. Confirmed empirically that the inline FORMAT wins at the protocol level; SDK consumers doing `await response.json()` would previously have crashed on the mislabeled CSV. @@ -64,7 +68,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - **Team-wide Claude Code configuration + agent PR discipline gates** (`.claude/agents/pre-push-reviewer.md`, `.claude/hooks/agent-bash-gate.sh`, `.claude/hooks/review-marker.sh`, `.claude/hooks/gofumpt-on-save.sh`, `.claude/settings.json`, `.claude/skills/pr-review-locally/SKILL.md`, `.claude/skills/pr-sync-with-main/SKILL.md`, `.claude/commands/cover.md`, `.githooks/pre-commit`, `.githooks/pre-push`, `.config/wt.toml`, `AGENTS.md` §"Agent PR Discipline" + §"Local-First Validation", `docs/src/content/docs/claude-code.md`). Two distinct enforcement layers: universal git hooks (`.githooks/`, installed by `make tools` via `git config core.hooksPath .githooks`) run `make verify` on commit and require `tmp/ci-passed-` before push for everyone (humans + agents); agent-only gates layer on top in `.claude/hooks/agent-bash-gate.sh` (PreToolUse Bash) and block: `--no-verify` on git push/commit; `gh pr create` without `--draft`; `gh pr ready`, `--approve`, `--request-changes` (humans-only state transitions); `gh pr edit --add-reviewer/--add-assignee` and `gh api .../requested_reviewers` POST/PUT/PATCH (humans-only reviewer assignment — bot reviewers re-triggered via PR comments instead); and `git push` to an open-PR branch without both ci-passed and review-passed markers. The `pre-push-reviewer` subagent runs the canonical `.github/prompts/pr-review.md` in fresh context against the branch's full merge-base diff (`git diff main...HEAD`) plus latest commit, open PR comments + reviews, CI status, and linked-issue acceptance criteria, then emits a parseable `VERDICT: ship_it|iterate|block` consumed by `review-marker.sh` (SubagentStop) which writes `tmp/review-passed-` only on `ship_it`. **`ship_it` is gated to zero findings at any severity** — any `[MUST]`/`[SHOULD]`/`[MAY]` forces `iterate` and the orchestrator loops review → fix → review until clean before pushing. Marker writes are NOT regex-blocked beyond the cheap settings.json deny patterns (`Bash(touch tmp/ci-passed:*)`, `Write(tmp/ci-passed-*)`, `Edit(tmp/ci-passed-*)`, and review-passed equivalents); the rest is an explicit honest-agent rule in AGENTS.md ("you do not write a marker file by any other means — period") because Bash can write a file by a dozen paths and regex enforcement is a porous game of whack-a-mole. Humans retain `--no-verify` for explicit intentional bypass; `.config/wt.toml` ships worktrunk hooks so parallel-agent worktrees install `.githooks/` correctly. `docs/src/content/docs/claude-code.md` is the contributor-facing page that explains the layering, quick-setup, and discipline rules. -- **Astro / Starlight documentation site at `wavehouse.dev`** (`docs/`, `Makefile`, `.github/dependabot.yml`, `.github/workflows/ci.yml`, `.gitignore`, `.vscode/launch.json`): full content + tooling for the public docs (Getting Started, Why WaveHouse, Architecture, API Reference, TypeScript SDK, Configuration, Deployment, Development). Build-time mermaid via `rehype-mermaid` (inline-svg strategy, no client-side JS), LaTeX via `remark-math` + `rehype-katex`, image zoom via `starlight-image-zoom`, expressiveCode with github dark/light + `env`/`dns` Shiki language aliases. PostHog frontend telemetry (key is public by design — embedded in every visitor's browser). `editLink` pointed at `main`; `lastUpdated` on. Sidebar lives in `docs/src/config/sidebar.ts` as the single source of truth, consumed by both Starlight rendering and the LLM-friendly outputs below. Cloudflare Workers + Static Assets deployment via `docs/wrangler.jsonc` (no auto-deploy yet — wired up when the GH Actions workflow lands separately). Make targets stay minimal: `dev-docs` (Astro dev server on :4321), `build-docs`, `preview-docs` — the last serves the production build through `wrangler dev`, so the Cloudflare Worker's content negotiation (`Accept: text/markdown` / LLM-bot User-Agent → `.md` twin) is exercised end-to-end the same way it will be in production. +- **Astro / Starlight documentation site at `wavehouse.dev`** (`docs/`, `Makefile`, `.github/dependabot.yml`, `.github/workflows/ci.yml`, `.gitignore`, `.vscode/launch.json`): full content + tooling for the public docs (Getting Started, Why WaveHouse, Architecture, API Reference, TypeScript SDK, Configuration, Deployment, Development). Build-time mermaid via `rehype-mermaid` (inline-svg strategy, no client-side JS), LaTeX via `remark-math` + `rehype-katex`, image zoom via `starlight-image-zoom`, expressiveCode with github dark/light + `env`/`dns` Shiki language aliases. PostHog frontend telemetry (key is public by design — embedded in every visitor's browser). `editLink` pointed at `main`; `lastUpdated` on. Sidebar lives in `docs/src/config/sidebar.ts` as the single source of truth, consumed by both Starlight rendering and the LLM-friendly outputs below. Cloudflare Workers + Static Assets deployment via `docs/wrangler.jsonc`. Make targets stay minimal: `dev-docs` (Astro dev server on :4321), `build-docs`, `preview-docs` — the last serves the production build through `wrangler dev`, so the Cloudflare Worker's content negotiation (`Accept: text/markdown` / LLM-bot User-Agent → `.md` twin) is exercised end-to-end the same way it will be in production. (Auto-deploy wire-up, target renames, and the docs-subproject Makefile split land in a later [Unreleased] entry below.) - **Per-page `.md` twin + `llms.txt` family via `starlight-llm-tools`** (`docs/astro.config.mjs`, `docs/worker/index.ts`, `docs/wrangler.jsonc`): every doc is also served as raw markdown at `.md` with a navigation header (Section / Subpages / Related / HTML version pointers), plus three concatenated views — `/llms.txt` manifest, `/llms-full.txt` (every page, sidebar-ordered), `/llms-small.txt` (overview pages only). Page-title slot gains a **Copy Markdown** button and **Open with AI** dropdown (Claude / ChatGPT / Cursor). Content negotiation is handled by a Cloudflare Worker that re-exports the `cloudflare-md-router` package's default handler in one line — `Accept: text/markdown` or known LLM-bot User-Agent (GPTBot, ClaudeBot, PerplexityBot, Applebot-Extended, etc.) gets the `.md` twin transparently, with a fall-through to the HTML response when the twin doesn't exist. - **Two extracted plugin packages, MIT-licensed**: [`github.com/Wave-RF/cloudflare-md-router`](https://github.com/Wave-RF/cloudflare-md-router) (Workers handler + `createMdRouter()` factory + extensible bot-UA regex; consumed in `docs/worker/index.ts` as a one-line re-export) and [`github.com/Wave-RF/starlight-llm-tools`](https://github.com/Wave-RF/starlight-llm-tools) (Starlight plugin that auto-injects the four routes, the two components, and the `PageTitle` override; optionally calls into `starlight-glossary/transform` when present). Both pinned via `github:Wave-RF/...` in `docs/package.json`; lockfile pins the resolved commit SHAs. Pre-npm-publish state — switch to normal version specifiers when the packages land on npm. - **Custom WaveHouse mark + favicon / OG card / Starlight nav logo / README header, fed by a single-source `make branding` pipeline** (`scripts/branding/{mark.svg,lockup.svg,og.template.svg,generate.sh}`, `Makefile`, `docs/astro.config.mjs`, `docs/public/{favicon.svg,favicon.ico,apple-touch-icon.png,og.png}`, `docs/src/assets/branding/wavehouse-mark-{light,dark}.svg`, `README.md`): replaces the default Astro sparkle favicon and the 🏖️ emoji in the README header with the **clickwave** mark — four vertical sine-curve columns + a filled cursor square on the right, on a 100-unit viewBox. The columns echo ClickHouse's column-store grammar; the cursor square reads as both the "click" in ClickHouse and a "live cell" indicator for the streaming/real-time story. Brand colors live as design tokens: `#086D77` deep teal on light backgrounds, `#06B0BF` electric blue (Wave RF parent brand) on dark — both also exposed in `docs/src/styles/global.css` as `--wh-accent` / `--wh-accent-hi`. `scripts/branding/mark.svg` is the single source of truth (one multi-element SVG using `stroke="currentColor"` for the wave columns and `fill="currentColor"` for the cursor square); `make branding` extracts its inner content + viewBox and emits six derived artifacts via `rsvg-convert` + ImageMagick: a CSS-swap browser favicon (`:root{color}` block flips via `prefers-color-scheme:dark` and the inner `currentColor` attributes inherit, covering both stroke and fill in one declaration), a multi-resolution legacy `favicon.ico` (16/32/48), a 180×180 iOS home-screen tile (`apple-touch-icon.png`; electric-blue mark on near-black `#0A0B0E` background, scale rebased to `1.24` for the new 100-unit viewBox, solid because transparent apple-touch icons render a white halo on iOS), a 1200×630 OG card rendered from `og.template.svg` (gradient background + faint accent grid + corner radial glow + canonical lockup (mark + "WaveHouse" wordmark as a designed 480×100 unit from `lockup.svg`, with the mark in accent cyan and the wordmark in off-white via a two-color substitution so the visual hierarchy reads as "logo + headline" instead of one monochrome bar) + two-line tagline with `ClickHouse` highlighted in the accent color + footer row pairing `A Wave RF open-source project` (left) with `wavehouse.dev` (right), lockup spliced into a `__LOCKUP_GROUP__` placeholder via `sed`), and the two hardcoded-color Starlight nav SVGs that Starlight's `logo: { light, dark }` config picks between (CSS media queries inside an SVG don't fire when loaded via ``, so a single CSS-swap SVG won't work in the nav). Wave-column centers + cursor square shifted left by 4 units inside the viewBox so left and right padding match — without the shift the cursor square sits flush against the right edge while the leftmost wave has ~7 units of breathing room. `make branding` is **not** wired into `build-docs` or any CI workflow — derived artifacts are committed so contributors don't need `librsvg` / `imagemagick` on their PATH to build docs, only someone iterating on the mark itself does. `astro.config.mjs` gains the Starlight `logo:` block and the `` head tag; the legacy `favicon.ico` still ships in `public/` so older clients (IE/Edge, some RSS readers) that can't load SVG favicons auto-probe `/favicon.ico` from the site root by convention — no explicit `` tag needed. README H1 uses a `` element with `` so GitHub renders the right variant per visitor theme. Future edits: tweak `mark.svg` (or `COLOR_*` in `generate.sh`, or the OG composition in `og.template.svg`), run `make branding`, commit the diff. From 30d194dc7f0e26d9a12c6c6ba3ab0a696e71fc1d Mon Sep 17 00:00:00 2001 From: Eric Andrechek Date: Tue, 26 May 2026 12:58:22 -0400 Subject: [PATCH 5/8] security and support docs, how to get help --- .github/ISSUE_TEMPLATE/bug_report.md | 4 +++ .github/ISSUE_TEMPLATE/config.yml | 6 ++++ .github/ISSUE_TEMPLATE/feature_request.md | 4 +++ AGENTS.md | 1 + CHANGELOG.md | 4 +++ CONTRIBUTING.md | 2 ++ README.md | 8 +++++ SUPPORT.md | 36 +++++++++++++++++++++++ docs/src/components/Footer.astro | 3 ++ docs/src/config/sidebar.ts | 10 +++++++ docs/src/content/docs/index.mdx | 21 +++++++++++++ 11 files changed, 99 insertions(+) create mode 100644 SUPPORT.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1b4f2e0c..60229af9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -40,3 +40,7 @@ Paste relevant log output here ## Additional Context Any other context, screenshots, or configuration details. + +--- + +Before submitting: this template is for **reproducible bugs**. Usage questions ("how do I…") belong in [Discussions → Q&A](https://github.com/Wave-RF/WaveHouse/discussions/categories/q-a); security issues go to `security@wave-rf.com` per [SECURITY.md](https://github.com/Wave-RF/WaveHouse/blob/main/SECURITY.md). For the alpha-stage response cadence, see [SUPPORT.md](https://github.com/Wave-RF/WaveHouse/blob/main/SUPPORT.md). diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 1c77a96a..98d4e8a1 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,11 @@ blank_issues_enabled: false contact_links: + - name: Question or "how do I…?" — GitHub Discussions + url: https://github.com/Wave-RF/WaveHouse/discussions/categories/q-a + about: Usage questions belong in Discussions → Q&A, not Issues. Filing a bug report for a usage question will get redirected here. + - name: Idea or open-ended proposal — GitHub Discussions + url: https://github.com/Wave-RF/WaveHouse/discussions/categories/ideas + about: Want to gauge interest or shape a proposal before filing a concrete feature request? Start here. - name: Security vulnerability url: https://github.com/Wave-RF/WaveHouse/security/policy about: Do NOT open a public issue for security vulnerabilities. See SECURITY.md for the private reporting process. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 433d16e1..61ab7923 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -22,3 +22,7 @@ Any alternative approaches you've thought about. ## Additional Context Any mockups, examples, or references that help explain the request. + +--- + +Before submitting: if you're still ideating or want to gauge interest before filing a concrete proposal, consider [Discussions → Ideas](https://github.com/Wave-RF/WaveHouse/discussions/categories/ideas) first. For the alpha-stage response cadence, see [SUPPORT.md](https://github.com/Wave-RF/WaveHouse/blob/main/SUPPORT.md). Security-related concerns go to `security@wave-rf.com` per [SECURITY.md](https://github.com/Wave-RF/WaveHouse/blob/main/SECURITY.md). diff --git a/AGENTS.md b/AGENTS.md index 3655a9ca..bf8e4c7c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -418,3 +418,4 @@ docs/ → Project documentation - `housekeeping.yml` — requests review from a non-author admin on PR open / ready-for-review via the `assign-and-request-review` composite. Task Board placement is handled by native Projects v2 workflows configured in the project UI. - **`CLAUDE.md`** and **`.gemini/styleguide.md`**: thin pointer files to AGENTS.md. Keep those pointers short; never duplicate content. - **`CONTRIBUTING.md`**: the Conventional Commits type list must stay in sync with the regex in `housekeeping.yml`. The title linter validates squash-merge commit messages. +- **`SUPPORT.md`** (alpha-stage public triage policy): the externally-promised cadence is **best-effort, 1–2 business days for an initial response** on bugs / features / usage questions; **security reports are prioritized** with the 48-hour acknowledge / 5-business-day initial-assessment targets in `SECURITY.md`. Usage questions ("how do I…") are routed to [GitHub Discussions → Q&A](https://github.com/Wave-RF/WaveHouse/discussions/categories/q-a) — do not file them as bug-report Issues; bug-reporters who use the wrong template get redirected. There is no Discord/Slack. Don't quietly let threads slip — if one sits longer than a week, that's a miss. **Out-of-scope items publicly stated in `SUPPORT.md` are only "Older releases" and "Non-ClickHouse backends"**. When tweaking the policy, update `SUPPORT.md` first and keep this paragraph in sync. The docs footer (`docs/src/components/Footer.astro`) and sidebar (`docs/src/config/sidebar.ts`) cross-link Discussions, `SUPPORT.md`, and `SECURITY.md` so they're one click from anywhere on `wavehouse.dev`; `README.md`, `CONTRIBUTING.md`, and both issue templates (`.github/ISSUE_TEMPLATE/bug_report.md`, `feature_request.md`) also link out — change those together if the policy moves. diff --git a/CHANGELOG.md b/CHANGELOG.md index 2644e046..a4e3f9d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **BREAKING: `POST /v1/admin/query` is now a thin HTTP proxy to ClickHouse, not a `clickhouse-go` Query/Exec wrapper** (`internal/api/query.go`, `internal/api/query_test.go`, `internal/api/clickhouse_exec.go` (new), `internal/api/clickhouse_exec_test.go` (new), `cmd/wavehouse/main.go`, `clients/ts/src/sql.ts`, `clients/ts/src/client.ts`, `clients/ts/src/namespaces.test.ts`, `tests/integration/query_test.go`, `docs/src/content/docs/api.md`, `docs/src/content/docs/architecture.md`). The handler now POSTs the SQL string verbatim to `://:/?default_format=JSON&date_time_output_format=iso&database=` with `X-ClickHouse-User` / `X-ClickHouse-Key` auth headers (matching the ingest worker's convention), reads ClickHouse's response, and forwards just the `data` array (or `[]` for mutations that return an empty body, or a JSON error envelope of shape `{"error":""}` for non-200 responses — the upstream plain-text body is wrapped inside the standard error envelope, not forwarded raw). Closes the `isMutation` / `mutationVerbs` / `containsMutationVerbAtTopLevel` / `stripLeadingSQLComments` / `transformRow` ~150-LOC machinery that lived in `query.go` to classify verbs and route between `driver.Exec` and `driver.Query`. Those primitives are still needed by the structured-query and pipes handlers (clickhouse-go's native Query() errors on no-result-set statements), so they moved into a new `internal/api/clickhouse_exec.go` and are called via `executeCHQuery(ctx, conn, sql, params)` — pipes and structured-query no longer instantiate a temporary `QueryHandler` just to borrow `executeQuery`. Three wins: (a) any ClickHouse-accepted SQL works, including multi-statement input (`SELECT 1; TRUNCATE t`) and arbitrary DDL/DML/SYSTEM verbs (current and future) without WaveHouse code changes; (b) ClickHouse's own error messages reach the admin verbatim — what they want from an escape hatch; (c) the handler is ~50 LOC of forward-and-shape-response with no SQL-parsing surface. **Breaking implications:** the request body no longer accepts a `params` array (ClickHouse's HTTP interface uses named `{name:Type}` binding, not positional `?`). Inline literals into the SQL string, or use the structured query endpoint for safe binding from user inputs. The TypeScript SDK's `sql()` method drops its `params?: unknown[]` argument; callers of `client.sql(sql, params)` need to inline. `NewQueryHandler` signature changes from `(driver.Conn)` to `(endpoint, username, password, database string)`. The response also gains a `Cache-Control: no-store` header so no downstream layer caches raw-SQL results. New tests in `clickhouse_exec_test.go` keep `isMutation` + Exec/Query routing + the `transformRow` UUID/time conversions covered for the structured-query and pipes paths that still need them; new tests in `query_test.go` pin the proxy contract (SQL forwarded verbatim, data array extracted, empty-body → `[]`, ClickHouse error forwarded, security headers set on every response path, request context cancel propagates). - **`POST /v1/admin/query` no longer caches, singleflights, or bypasses cache for mutations** (`internal/api/query.go`, `internal/api/query_test.go`, `internal/api/cache_key.go` (new), `internal/api/cache_key_test.go` (new), `cmd/wavehouse/main.go`, `docs/src/content/docs/api.md`, `docs/src/content/docs/architecture.md`). **Note (largely superseded — see the HTTP-proxy entry above):** the structural details below (`QueryHandler` struct shape, `NewQueryHandler(conn)` signature, in-handler verb classifier, `X-Cache: MISS` header) describe the state immediately after the cache-strip commit. The subsequent HTTP-proxy refactor changed `NewQueryHandler` to `(endpoint, username, password, database string)`, dropped the `driver.Conn` field, moved the verb classifier to `internal/api/clickhouse_exec.go` for the structured-query/pipes consumers that still need it, and uses `Cache-Control: no-store` in place of `X-Cache`. The cache-strip motivation below still stands; the historical implementation specifics follow. With the endpoint now an admin-only escape hatch (see the Security entry below), the L1/L2 + singleflight + mutation-cache-bypass machinery added in the original raw-SQL handler is dead weight: admin calls are infrequent, often mutations, often one-shot, so the cache hit rate is effectively zero and singleflight has no concurrent-request herd to collapse. `QueryHandler` shrinks to `{ CHConn driver.Conn }`; `Handle` is parse → executeQuery → marshal → write. `NewQueryHandler(conn)` is the new signature (was `NewQueryHandler(conn, *cache.TieredCache, time.Duration)`). The `X-Cache: HIT/MISS` response header is gone from this endpoint — every response is a fresh ClickHouse round-trip, no header needed to disambiguate. The verb-classification machinery (`isMutation`, `mutationVerbs`, the comment-aware CTE parser) STAYS; it's correctness, not performance — clickhouse-go's `driver.Query()` errors on statements that return no result set, so we still route mutations through `driver.Exec`. The shared `queryCacheKey` helper moved to a new `internal/api/cache_key.go` since it's now consumed only by the structured query (`/v1/tables/{table}/query`) and pipes (`/v1/pipes/{name}`) handlers, which keep their caching + singleflight intact — those are the high-QPS read paths where the machinery earns its keep. Two now-obsolete tests removed: `TestQueryCacheKey_Deterministic` (moved to a fresh `cache_key_test.go` since the helper still has callers) and `TestQueryHandler_MutationBypassesCache` (no cache to bypass). The mutation-routing tests (`TestExecuteQuery_MutationRoutesToExec`, `TestExecuteQuery_SelectRoutesToQuery`) stay — they pin the still-required Exec-vs-Query classification. +### Added + +- **`SUPPORT.md` + `SECURITY.md` are now one click from every public surface; GitHub Discussions is the new home for usage questions** (`SUPPORT.md` (new), `README.md`, `CONTRIBUTING.md`, `.github/ISSUE_TEMPLATE/bug_report.md`, `.github/ISSUE_TEMPLATE/feature_request.md`, `docs/src/content/docs/index.mdx`, `docs/src/components/Footer.astro`, `docs/src/config/sidebar.ts`, `AGENTS.md`). Closes #154, #155. New `SUPPORT.md` at the repo root sets honest alpha-stage expectations: best-effort response, 1–2 business days for an initial response on bugs/features/usage questions; security reports prioritized per `SECURITY.md` (48-hour acknowledge / 5-business-day initial assessment); no auto-close on stale threads. Usage questions ("how do I…") route to **[GitHub Discussions → Q&A](https://github.com/Wave-RF/WaveHouse/discussions/categories/q-a)** (Discussions was just enabled on the repo); bug-report Issues filed for usage questions get redirected. No Discord/Slack today. README gains a Security section + a Support section near the bottom; CONTRIBUTING gains a top-of-file pointer; both issue templates gain a footer pointing at SUPPORT.md, Discussions, and the private SECURITY channel; the docs landing page gains a "Project policies" CardGrid with cross-links to SECURITY/SUPPORT; the Starlight footer's Project column adds Discussions + Support + Security so they're reachable from every page on `wavehouse.dev`; the sidebar's Contributing group adds Discussions + Support next to the existing Security Policy link. AGENTS.md §"Governance Files" documents the SLA so internal expectations match the public statement. + ### Removed - **BREAKING: the ingest pipeline is now insert-only; the `action` field on `ingest.` envelopes is gone from the wire format** (`internal/ingest/bento.go`, `internal/ingest/bento_test.go`, `tests/integration/ingest_test.go`, `tests/integration/dlq_test.go`, `docs/src/content/docs/architecture.md`, `docs/src/content/docs/api.md`, `AGENTS.md`): the worker accepts `{table_name, received_timestamp, data}` envelopes (the existing `EventMessage` shape) and bulk-INSERTs them. All non-insert mutations (`DELETE`/`UPDATE`/`TRUNCATE`/`DROP`/`ALTER`/`REPLACE`/…) must go through `POST /v1/admin/query` under the `admin` / `service` role (the raw-SQL endpoint moved under `/v1/admin/*` in a follow-up commit on this same Unreleased section — see the Security entry below; the `RawSQL: true` policy field is gone too). The rationale: our policy engine authorizes mutations by evaluating row/column rules against the *payload* of an operation, which works for inserts but not for predicate-driven mutations (we can't prove a `WHERE` clause is satisfiable only for rows the caller is allowed to touch, and `WHERE 1=1` would otherwise nuke a table). Rather than ship a partial enforcement story, the pipelined surface narrows to the shape policy can authorize today; `/v1/admin/query` becomes the single sanctioned admin-equivalent surface for everything else. The embedded NATS server runs with `DontListen: true` (`internal/mq/embedded.go`), so the only Publishers reachable on `ingest.>` are in-process Go code (today, only the HTTP `/v1/ingest/{table}` handler), and `EventMessage` carries no `action` field so the legitimate producer never sets one. The `delete-envelope` DLQ shape and the `Wave-DLQ-Type` NATS header it required are gone with this — `dlq.
` now carries only insert-failure payloads (the inner data object), so DLQ consumers no longer need to discriminate. The `jsInput.chConn` and `jsInput.js` fields are dropped along with the `chConn driver.Conn` parameter on `StartIngestWorker`. Re-introducing pipelined / structured mutations is deferred until the policy engine can authorize predicates — track separately if/when scheduled. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9995e096..058b5e5b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,8 @@ Thank you for your interest in contributing to WaveHouse! This guide will help you get started. +> Looking for help instead of contributing code? See [SUPPORT.md](SUPPORT.md) for where to ask questions, report bugs, and what the alpha-stage response cadence is. Found a security issue? Use the private channel in [SECURITY.md](SECURITY.md), not a public issue. + ## Getting Started 1. [Fork the repository](https://github.com/Wave-RF/WaveHouse/fork) and clone your fork. diff --git a/README.md b/README.md index afa8baa0..d4234298 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,14 @@ The full documentation site lives at **[wavehouse.dev](https://wavehouse.dev)**. * [Development](docs/src/content/docs/development.md) — Building, testing, linting, and project structure * [SDK Reference](docs/src/content/docs/sdk.md) — TypeScript client SDK usage and codegen +## 🛡️ Security + +Found a vulnerability? **Please don't open a public issue.** Email `security@wave-rf.com` per [SECURITY.md](SECURITY.md) — we acknowledge within 48 hours and aim for an initial assessment in 5 business days. + +## 🙋 Support + +WaveHouse is in **alpha**. See [SUPPORT.md](SUPPORT.md) for where to ask what, the alpha-stage response cadence (best-effort, 1–2 business days), and what's in vs. out of scope right now. + ## 📜 License WaveHouse is open source under the [MIT License](LICENSE). diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 00000000..fca7b619 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,36 @@ +# Support + +WaveHouse is in **alpha**. We're a small team building publicly while shipping the gateway toward GA. This page sets honest expectations for what we can (and can't) commit to during this phase. + +## Where to ask + +| Topic | Where | +| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Security vulnerabilities** | See [SECURITY.md](SECURITY.md) — email `security@wave-rf.com`. **Do not** open a public issue. | +| **Bug reports** | Open a [bug report](https://github.com/Wave-RF/WaveHouse/issues/new?template=bug_report.md). | +| **Feature requests** | Open a [feature request](https://github.com/Wave-RF/WaveHouse/issues/new?template=feature_request.md). | +| **Usage questions** ("how do I…") | Open a thread in [GitHub Discussions → Q&A](https://github.com/Wave-RF/WaveHouse/discussions/categories/q-a). Ideas / show-and-tell / general chat live in the [other Discussion categories](https://github.com/Wave-RF/WaveHouse/discussions). Please don't open a bug-report issue for a usage question — we'll redirect. | +| **Real-time chat** | No Discord or Slack today. | +| **Commercial / enterprise interest** | Email `hello@wave-rf.com`. WaveHouse is and will remain MIT-licensed open source; Wave RF (the parent company) is the operator behind it. | + +## Response cadence (alpha) + +- **Best-effort, no SLA.** Expect **1–2 business days** for an initial response on most issues during the alpha. Quieter weeks (holidays, freezes, releases) may stretch to a week. +- **Security reports get priority** — see [SECURITY.md](SECURITY.md) for the 48-hour acknowledgement and 5-business-day initial-assessment targets. +- **No auto-close.** If a thread sits without a response longer than a week, that's a miss on our end. Feel free to bump it. + +## In scope during alpha + +- Bug reports against the latest tagged release or `main` HEAD. +- Reproducible regressions vs. the previous tag. +- Documentation gaps or wrong examples (especially `getting-started.md`, `api.md`, `configuration.md`). +- Configuration questions where the docs disagree with reality. + +## Out of scope during alpha + +- **Older releases.** We patch the latest release; older releases are best-effort. +- **Non-ClickHouse backends.** WaveHouse is ClickHouse-specific by design — see [Why WaveHouse?](docs/src/content/docs/why-wavehouse.md). + +## Code of conduct + +Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). Be kind; assume good faith; do the work. diff --git a/docs/src/components/Footer.astro b/docs/src/components/Footer.astro index 85368eb1..f5232dc1 100644 --- a/docs/src/components/Footer.astro +++ b/docs/src/components/Footer.astro @@ -42,8 +42,11 @@ const year = new Date().getFullYear(); diff --git a/docs/src/config/sidebar.ts b/docs/src/config/sidebar.ts index 36d1eafb..a63d19cc 100644 --- a/docs/src/config/sidebar.ts +++ b/docs/src/config/sidebar.ts @@ -34,6 +34,16 @@ export const sidebar: StarlightUserConfig["sidebar"] = [ link: "https://github.com/Wave-RF/WaveHouse/blob/main/CONTRIBUTING.md", attrs: { target: "_blank", rel: "noopener" }, }, + { + label: "Discussions", + link: "https://github.com/Wave-RF/WaveHouse/discussions", + attrs: { target: "_blank", rel: "noopener" }, + }, + { + label: "Support", + link: "https://github.com/Wave-RF/WaveHouse/blob/main/SUPPORT.md", + attrs: { target: "_blank", rel: "noopener" }, + }, { label: "Security Policy", link: "https://github.com/Wave-RF/WaveHouse/blob/main/SECURITY.md", diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index 67bae2de..fe276575 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -134,3 +134,24 @@ Five minutes from `git clone` to a live event stream. See the [Getting Started]( href="/deployment" /> + +## Project policies + +WaveHouse is in **alpha** — what we ship is built openly with honest expectations. + + + + + From 6590326b4f6cd64da9c060a58c02de176967f14f Mon Sep 17 00:00:00 2001 From: Eric Andrechek Date: Tue, 26 May 2026 13:20:25 -0400 Subject: [PATCH 6/8] makefile + doc fixes per review comments --- CHANGELOG.md | 8 ++++---- docs/Makefile | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4e3f9d0..a79d116f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- **Docs site is now its own Makefile subproject + auto-deploys to `wavehouse.dev` via Cloudflare Workers Builds** (`Makefile`, `docs/Makefile` (new), `docs/wrangler.jsonc`, `docs/scripts/branding/` (moved from `scripts/branding/`), `AGENTS.md`, `docs/src/content/docs/development.md`, `docs/scripts/screenshot.mjs`, `.github/actions/setup-env/action.yml`). Closes #148. Three threads, one PR: +- **Docs site is now its own Makefile subproject + auto-deploys to `wavehouse.dev` via Cloudflare Workers Builds** (`Makefile`, `docs/Makefile` (new), `docs/wrangler.jsonc`, `docs/scripts/branding/` (moved from `scripts/branding/`), `AGENTS.md`, `docs/src/content/docs/development.md`, `docs/scripts/screenshot.mjs`, `.github/actions/setup-env/action.yml`). Three threads, one PR: - **Subproject Makefile split.** `docs/` gets its own `Makefile` (`make build`, `make dev`, `make preview`, `make branding`, `make install`, `make install-playwright`, `make clean`) so the docs site is self-contained — `cd docs && make build` works directly without any root-Makefile awareness. The root `Makefile` keeps a single `docs-%: ; @$(MAKE) -C docs $*` pattern rule that forwards every target as `make docs-` from root, and a `SUBPROJECTS := docs` list drives a generic `subprojects-` fan-out for the common verbs (`install`, `build`, `test`, `lint`, `verify`, `clean`) that `make ci` / `make tools` / `make build-all` now call. Adding the next subproject (per-language SDKs eventually) is one line appended to `SUBPROJECTS` plus a sibling Makefile that defines the verb set. **Renames** (root-side targets reshape from `-docs` to `docs-`): `make dev-docs` → `make docs-dev`; `make build-docs` → `make docs-build`; `make preview-docs` → `make docs-preview`; `make branding` → `make docs-branding`; `make install-docs-playwright` → `make docs-install-playwright`. The setup-env composite action's Playwright-cache-restore step gets its comment updated to the new name. `make help` auto-renders a per-subproject section from each sub-Makefile so the menu stays in sync without manual wiring. - **Branding pipeline relocated.** `scripts/branding/{mark.svg,lockup.svg,og.template.svg,generate.sh}` → `docs/scripts/branding/` since it's a docs-only concern; `generate.sh` now resolves the repo root via `git rev-parse --show-toplevel` instead of a hard-coded relative climb, so future moves don't re-break it. `make docs-branding` is the canonical entry point from root. - **Auto-deploy via Cloudflare Workers Builds.** Rather than ship `.github/workflows/deploy-docs.yml` with `cloudflare/wrangler-action` and a repo-level `CLOUDFLARE_API_TOKEN`, the deploy is driven by Cloudflare's native Git integration (Workers Builds), configured on the CF dashboard side against this repo's `docs/` directory. Push to `main` runs `npx wrangler deploy` and updates `wavehouse.dev` within ~2 minutes; pushes to PR branches run `npx wrangler versions upload`, which publishes a per-version preview URL of the form `-wavehouse-docs.wave-rf.workers.dev`. `docs/wrangler.jsonc` gains the `routes` block for the `wavehouse.dev` custom domain, `workers_dev: true` + `preview_urls: true` so the per-version preview URLs keep working, `observability: { enabled: true, head_sampling_rate: 1 }`, `upload_source_maps: true`, and a `$schema` pointer for editor validation; `compatibility_date` bumped from `2025-01-01` to `2025-11-01`. The worker (`docs/worker/index.ts`, delegating to `cloudflare-md-router`) deploys alongside the static assets so `Accept: text/markdown` content negotiation works in production, not just under `wrangler dev`. AGENTS.md §"Repository Automation" documents the deploy mechanism so future maintainers know where to look (no GH Actions workflow exists for this on purpose). @@ -72,11 +72,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - **Team-wide Claude Code configuration + agent PR discipline gates** (`.claude/agents/pre-push-reviewer.md`, `.claude/hooks/agent-bash-gate.sh`, `.claude/hooks/review-marker.sh`, `.claude/hooks/gofumpt-on-save.sh`, `.claude/settings.json`, `.claude/skills/pr-review-locally/SKILL.md`, `.claude/skills/pr-sync-with-main/SKILL.md`, `.claude/commands/cover.md`, `.githooks/pre-commit`, `.githooks/pre-push`, `.config/wt.toml`, `AGENTS.md` §"Agent PR Discipline" + §"Local-First Validation", `docs/src/content/docs/claude-code.md`). Two distinct enforcement layers: universal git hooks (`.githooks/`, installed by `make tools` via `git config core.hooksPath .githooks`) run `make verify` on commit and require `tmp/ci-passed-` before push for everyone (humans + agents); agent-only gates layer on top in `.claude/hooks/agent-bash-gate.sh` (PreToolUse Bash) and block: `--no-verify` on git push/commit; `gh pr create` without `--draft`; `gh pr ready`, `--approve`, `--request-changes` (humans-only state transitions); `gh pr edit --add-reviewer/--add-assignee` and `gh api .../requested_reviewers` POST/PUT/PATCH (humans-only reviewer assignment — bot reviewers re-triggered via PR comments instead); and `git push` to an open-PR branch without both ci-passed and review-passed markers. The `pre-push-reviewer` subagent runs the canonical `.github/prompts/pr-review.md` in fresh context against the branch's full merge-base diff (`git diff main...HEAD`) plus latest commit, open PR comments + reviews, CI status, and linked-issue acceptance criteria, then emits a parseable `VERDICT: ship_it|iterate|block` consumed by `review-marker.sh` (SubagentStop) which writes `tmp/review-passed-` only on `ship_it`. **`ship_it` is gated to zero findings at any severity** — any `[MUST]`/`[SHOULD]`/`[MAY]` forces `iterate` and the orchestrator loops review → fix → review until clean before pushing. Marker writes are NOT regex-blocked beyond the cheap settings.json deny patterns (`Bash(touch tmp/ci-passed:*)`, `Write(tmp/ci-passed-*)`, `Edit(tmp/ci-passed-*)`, and review-passed equivalents); the rest is an explicit honest-agent rule in AGENTS.md ("you do not write a marker file by any other means — period") because Bash can write a file by a dozen paths and regex enforcement is a porous game of whack-a-mole. Humans retain `--no-verify` for explicit intentional bypass; `.config/wt.toml` ships worktrunk hooks so parallel-agent worktrees install `.githooks/` correctly. `docs/src/content/docs/claude-code.md` is the contributor-facing page that explains the layering, quick-setup, and discipline rules. -- **Astro / Starlight documentation site at `wavehouse.dev`** (`docs/`, `Makefile`, `.github/dependabot.yml`, `.github/workflows/ci.yml`, `.gitignore`, `.vscode/launch.json`): full content + tooling for the public docs (Getting Started, Why WaveHouse, Architecture, API Reference, TypeScript SDK, Configuration, Deployment, Development). Build-time mermaid via `rehype-mermaid` (inline-svg strategy, no client-side JS), LaTeX via `remark-math` + `rehype-katex`, image zoom via `starlight-image-zoom`, expressiveCode with github dark/light + `env`/`dns` Shiki language aliases. PostHog frontend telemetry (key is public by design — embedded in every visitor's browser). `editLink` pointed at `main`; `lastUpdated` on. Sidebar lives in `docs/src/config/sidebar.ts` as the single source of truth, consumed by both Starlight rendering and the LLM-friendly outputs below. Cloudflare Workers + Static Assets deployment via `docs/wrangler.jsonc`. Make targets stay minimal: `dev-docs` (Astro dev server on :4321), `build-docs`, `preview-docs` — the last serves the production build through `wrangler dev`, so the Cloudflare Worker's content negotiation (`Accept: text/markdown` / LLM-bot User-Agent → `.md` twin) is exercised end-to-end the same way it will be in production. (Auto-deploy wire-up, target renames, and the docs-subproject Makefile split land in a later [Unreleased] entry below.) +- **Astro / Starlight documentation site at `wavehouse.dev`** (`docs/`, `Makefile`, `.github/dependabot.yml`, `.github/workflows/ci.yml`, `.gitignore`, `.vscode/launch.json`): full content + tooling for the public docs (Getting Started, Why WaveHouse, Architecture, API Reference, TypeScript SDK, Configuration, Deployment, Development). Build-time mermaid via `rehype-mermaid` (inline-svg strategy, no client-side JS), LaTeX via `remark-math` + `rehype-katex`, image zoom via `starlight-image-zoom`, expressiveCode with github dark/light + `env`/`dns` Shiki language aliases. PostHog frontend telemetry (key is public by design — embedded in every visitor's browser). `editLink` pointed at `main`; `lastUpdated` on. Sidebar lives in `docs/src/config/sidebar.ts` as the single source of truth, consumed by both Starlight rendering and the LLM-friendly outputs below. Cloudflare Workers + Static Assets deployment via `docs/wrangler.jsonc`. Make targets stay minimal: `docs-dev` (Astro dev server on :4321), `docs-build`, `docs-preview` — the last serves the production build through `wrangler dev`, so the Cloudflare Worker's content negotiation (`Accept: text/markdown` / LLM-bot User-Agent → `.md` twin) is exercised end-to-end the same way it will be in production. (Auto-deploy wire-up and the docs-subproject Makefile split land in a later [Unreleased] entry below.) - **Per-page `.md` twin + `llms.txt` family via `starlight-llm-tools`** (`docs/astro.config.mjs`, `docs/worker/index.ts`, `docs/wrangler.jsonc`): every doc is also served as raw markdown at `.md` with a navigation header (Section / Subpages / Related / HTML version pointers), plus three concatenated views — `/llms.txt` manifest, `/llms-full.txt` (every page, sidebar-ordered), `/llms-small.txt` (overview pages only). Page-title slot gains a **Copy Markdown** button and **Open with AI** dropdown (Claude / ChatGPT / Cursor). Content negotiation is handled by a Cloudflare Worker that re-exports the `cloudflare-md-router` package's default handler in one line — `Accept: text/markdown` or known LLM-bot User-Agent (GPTBot, ClaudeBot, PerplexityBot, Applebot-Extended, etc.) gets the `.md` twin transparently, with a fall-through to the HTML response when the twin doesn't exist. - **Two extracted plugin packages, MIT-licensed**: [`github.com/Wave-RF/cloudflare-md-router`](https://github.com/Wave-RF/cloudflare-md-router) (Workers handler + `createMdRouter()` factory + extensible bot-UA regex; consumed in `docs/worker/index.ts` as a one-line re-export) and [`github.com/Wave-RF/starlight-llm-tools`](https://github.com/Wave-RF/starlight-llm-tools) (Starlight plugin that auto-injects the four routes, the two components, and the `PageTitle` override; optionally calls into `starlight-glossary/transform` when present). Both pinned via `github:Wave-RF/...` in `docs/package.json`; lockfile pins the resolved commit SHAs. Pre-npm-publish state — switch to normal version specifiers when the packages land on npm. -- **Custom WaveHouse mark + favicon / OG card / Starlight nav logo / README header, fed by a single-source `make branding` pipeline** (`scripts/branding/{mark.svg,lockup.svg,og.template.svg,generate.sh}`, `Makefile`, `docs/astro.config.mjs`, `docs/public/{favicon.svg,favicon.ico,apple-touch-icon.png,og.png}`, `docs/src/assets/branding/wavehouse-mark-{light,dark}.svg`, `README.md`): replaces the default Astro sparkle favicon and the 🏖️ emoji in the README header with the **clickwave** mark — four vertical sine-curve columns + a filled cursor square on the right, on a 100-unit viewBox. The columns echo ClickHouse's column-store grammar; the cursor square reads as both the "click" in ClickHouse and a "live cell" indicator for the streaming/real-time story. Brand colors live as design tokens: `#086D77` deep teal on light backgrounds, `#06B0BF` electric blue (Wave RF parent brand) on dark — both also exposed in `docs/src/styles/global.css` as `--wh-accent` / `--wh-accent-hi`. `scripts/branding/mark.svg` is the single source of truth (one multi-element SVG using `stroke="currentColor"` for the wave columns and `fill="currentColor"` for the cursor square); `make branding` extracts its inner content + viewBox and emits six derived artifacts via `rsvg-convert` + ImageMagick: a CSS-swap browser favicon (`:root{color}` block flips via `prefers-color-scheme:dark` and the inner `currentColor` attributes inherit, covering both stroke and fill in one declaration), a multi-resolution legacy `favicon.ico` (16/32/48), a 180×180 iOS home-screen tile (`apple-touch-icon.png`; electric-blue mark on near-black `#0A0B0E` background, scale rebased to `1.24` for the new 100-unit viewBox, solid because transparent apple-touch icons render a white halo on iOS), a 1200×630 OG card rendered from `og.template.svg` (gradient background + faint accent grid + corner radial glow + canonical lockup (mark + "WaveHouse" wordmark as a designed 480×100 unit from `lockup.svg`, with the mark in accent cyan and the wordmark in off-white via a two-color substitution so the visual hierarchy reads as "logo + headline" instead of one monochrome bar) + two-line tagline with `ClickHouse` highlighted in the accent color + footer row pairing `A Wave RF open-source project` (left) with `wavehouse.dev` (right), lockup spliced into a `__LOCKUP_GROUP__` placeholder via `sed`), and the two hardcoded-color Starlight nav SVGs that Starlight's `logo: { light, dark }` config picks between (CSS media queries inside an SVG don't fire when loaded via ``, so a single CSS-swap SVG won't work in the nav). Wave-column centers + cursor square shifted left by 4 units inside the viewBox so left and right padding match — without the shift the cursor square sits flush against the right edge while the leftmost wave has ~7 units of breathing room. `make branding` is **not** wired into `build-docs` or any CI workflow — derived artifacts are committed so contributors don't need `librsvg` / `imagemagick` on their PATH to build docs, only someone iterating on the mark itself does. `astro.config.mjs` gains the Starlight `logo:` block and the `` head tag; the legacy `favicon.ico` still ships in `public/` so older clients (IE/Edge, some RSS readers) that can't load SVG favicons auto-probe `/favicon.ico` from the site root by convention — no explicit `` tag needed. README H1 uses a `` element with `` so GitHub renders the right variant per visitor theme. Future edits: tweak `mark.svg` (or `COLOR_*` in `generate.sh`, or the OG composition in `og.template.svg`), run `make branding`, commit the diff. -- **Documentation site design-system rebuild with custom Hero / Header / SiteTitle / Footer components** (`docs/src/styles/global.css`, `docs/src/components/{Hero,Footer,SiteTitle,Head}.astro`, `docs/src/content/docs/index.mdx`, `docs/astro.config.mjs`, `docs/package.json`, `Makefile`, `docs/scripts/screenshot.mjs`): replaces the previous `custom.css` baseline with a full Tailwind v4 token system in `global.css` — accent / ink / surface / border tokens for both light and dark themes, plus Starlight `--sl-color-*` overrides so the existing Starlight chrome picks up the WaveHouse palette without per-page overrides. New `Hero.astro` powers the splash landing page (`index.mdx`) with an animated terminal preview, stats grid, and CTA actions; `Footer.astro` adds a brand-aware site-wide footer with Docs / Operations / Project link columns and a copyright row; `SiteTitle.astro` replaces Starlight's default header title with the clickwave mark + wordmark and a small hover transform; `Head.astro` adds theme-color meta tags for both color schemes. New runtime deps: `@astrojs/starlight-tailwind`, `@tailwindcss/vite`, `tailwindcss@4`, `@fontsource-variable/inter`, `@fontsource-variable/jetbrains-mono`. `docs/scripts/screenshot.mjs` is a new Playwright-based visual-regression script (`pnpm exec node scripts/screenshot.mjs` from `docs/`, with `make dev-docs` running in another shell on :4321) that captures landing / getting-started / API / architecture pages in both themes at desktop and mobile widths, used for design iteration and golden-image diffing. Chromium is fetched on-demand by `make build-docs` / `make dev-docs` (via a dedicated `install-docs-playwright` Make target) so `rehype-mermaid`'s SSR diagram pipeline (used by `architecture.md` / `why-wavehouse.md`) and `starlight-links-validator` can run in CI without an out-of-band Chromium install step; Go-only contributors running `make tools` skip the ~130 MB download. +- **Custom WaveHouse mark + favicon / OG card / Starlight nav logo / README header, fed by a single-source `make docs-branding` pipeline** (`docs/scripts/branding/{mark.svg,lockup.svg,og.template.svg,generate.sh}`, `Makefile`, `docs/astro.config.mjs`, `docs/public/{favicon.svg,favicon.ico,apple-touch-icon.png,og.png}`, `docs/src/assets/branding/wavehouse-mark-{light,dark}.svg`, `README.md`): replaces the default Astro sparkle favicon and the 🏖️ emoji in the README header with the **clickwave** mark — four vertical sine-curve columns + a filled cursor square on the right, on a 100-unit viewBox. The columns echo ClickHouse's column-store grammar; the cursor square reads as both the "click" in ClickHouse and a "live cell" indicator for the streaming/real-time story. Brand colors live as design tokens: `#086D77` deep teal on light backgrounds, `#06B0BF` electric blue (Wave RF parent brand) on dark — both also exposed in `docs/src/styles/global.css` as `--wh-accent` / `--wh-accent-hi`. `docs/scripts/branding/mark.svg` is the single source of truth (one multi-element SVG using `stroke="currentColor"` for the wave columns and `fill="currentColor"` for the cursor square); `make docs-branding` extracts its inner content + viewBox and emits six derived artifacts via `rsvg-convert` + ImageMagick: a CSS-swap browser favicon (`:root{color}` block flips via `prefers-color-scheme:dark` and the inner `currentColor` attributes inherit, covering both stroke and fill in one declaration), a multi-resolution legacy `favicon.ico` (16/32/48), a 180×180 iOS home-screen tile (`apple-touch-icon.png`; electric-blue mark on near-black `#0A0B0E` background, scale rebased to `1.24` for the new 100-unit viewBox, solid because transparent apple-touch icons render a white halo on iOS), a 1200×630 OG card rendered from `og.template.svg` (gradient background + faint accent grid + corner radial glow + canonical lockup (mark + "WaveHouse" wordmark as a designed 480×100 unit from `lockup.svg`, with the mark in accent cyan and the wordmark in off-white via a two-color substitution so the visual hierarchy reads as "logo + headline" instead of one monochrome bar) + two-line tagline with `ClickHouse` highlighted in the accent color + footer row pairing `A Wave RF open-source project` (left) with `wavehouse.dev` (right), lockup spliced into a `__LOCKUP_GROUP__` placeholder via `sed`), and the two hardcoded-color Starlight nav SVGs that Starlight's `logo: { light, dark }` config picks between (CSS media queries inside an SVG don't fire when loaded via ``, so a single CSS-swap SVG won't work in the nav). Wave-column centers + cursor square shifted left by 4 units inside the viewBox so left and right padding match — without the shift the cursor square sits flush against the right edge while the leftmost wave has ~7 units of breathing room. `make docs-branding` is **not** wired into `docs-build` or any CI workflow — derived artifacts are committed so contributors don't need `librsvg` / `imagemagick` on their PATH to build docs, only someone iterating on the mark itself does. `astro.config.mjs` gains the Starlight `logo:` block and the `` head tag; the legacy `favicon.ico` still ships in `public/` so older clients (IE/Edge, some RSS readers) that can't load SVG favicons auto-probe `/favicon.ico` from the site root by convention — no explicit `` tag needed. README H1 uses a `` element with `` so GitHub renders the right variant per visitor theme. Future edits: tweak `mark.svg` (or `COLOR_*` in `generate.sh`, or the OG composition in `og.template.svg`), run `make docs-branding`, commit the diff. +- **Documentation site design-system rebuild with custom Hero / Header / SiteTitle / Footer components** (`docs/src/styles/global.css`, `docs/src/components/{Hero,Footer,SiteTitle,Head}.astro`, `docs/src/content/docs/index.mdx`, `docs/astro.config.mjs`, `docs/package.json`, `Makefile`, `docs/scripts/screenshot.mjs`): replaces the previous `custom.css` baseline with a full Tailwind v4 token system in `global.css` — accent / ink / surface / border tokens for both light and dark themes, plus Starlight `--sl-color-*` overrides so the existing Starlight chrome picks up the WaveHouse palette without per-page overrides. New `Hero.astro` powers the splash landing page (`index.mdx`) with an animated terminal preview, stats grid, and CTA actions; `Footer.astro` adds a brand-aware site-wide footer with Docs / Operations / Project link columns and a copyright row; `SiteTitle.astro` replaces Starlight's default header title with the clickwave mark + wordmark and a small hover transform; `Head.astro` adds theme-color meta tags for both color schemes. New runtime deps: `@astrojs/starlight-tailwind`, `@tailwindcss/vite`, `tailwindcss@4`, `@fontsource-variable/inter`, `@fontsource-variable/jetbrains-mono`. `docs/scripts/screenshot.mjs` is a new Playwright-based visual-regression script (`pnpm exec node scripts/screenshot.mjs` from `docs/`, with `make docs-dev` running in another shell on :4321) that captures landing / getting-started / API / architecture pages in both themes at desktop and mobile widths, used for design iteration and golden-image diffing. Chromium is fetched on-demand by `make docs-build` / `make docs-dev` (via a dedicated `docs-install-playwright` Make target) so `rehype-mermaid`'s SSR diagram pipeline (used by `architecture.md` / `why-wavehouse.md`) and `starlight-links-validator` can run in CI without an out-of-band Chromium install step; Go-only contributors running `make tools` skip the ~130 MB download. - **In-process OTLP gRPC test receiver + integration tests for the OTel pipeline** (`internal/testutil/otlp.go`, `tests/integration/otel_test.go`): `testutil.NewFakeOTLP(t)` binds a gRPC server on `127.0.0.1:0`, registers the trace/metric/log Export services, and captures every received payload — exposing `SpanCount()`, `MetricCount()`, `LogCount()`, and `LogCountAtLevel()` for assertions. Test cases verify trace sampling (1.0 → all, 0.5 → ~half within binomial tolerance, 0.0 → none), the WARN+ERROR floor (logs at `sample_rate=0.0` still export 100% of WARN/ERROR), per-signal gating (traces-only, logs-only), and the unreachable-endpoint invariant (InitProvider succeeds on lazy gRPC dial, emits don't block on failed export). Avoids spinning a full SigNoz stack in CI — the receiver is ~150 LOC and the whole suite runs in <5s. - **OpenTelemetry pipeline is now opt-in via `[otel]` config block with per-signal gates and configurable sampling** (`internal/config/config.go`, `cmd/wavehouse/main.go`, `internal/observability/provider.go`, `internal/observability/logger.go`, `config.yaml`, `docs/configuration.md`, `docs/deployment.md`): `otel.enabled` (`WH_OTEL_ENABLED`, default `false`) is the master switch, and `otel.addr` (`WH_OTEL_ADDR`, default `127.0.0.1:4317`) points at the OTLP gRPC collector. Each signal is then individually gated: `otel.traces.{enabled,sample_rate}` (head-based, default `1.0` — matches the OpenTelemetry SDK default), `otel.metrics.enabled` (no sampling — pre-aggregated), `otel.logs.{enabled,sample_rate}` (DEBUG/INFO at default `1.0` — `WARN`/`ERROR` always export at 100% as a non-configurable safety floor). All sampling knobs apply only to the OTLP push path; stdout always emits 100% of records (scraping-style pipelines like Promtail/Alloy → Loki own their own ingest policy). All sample rates are validated to `[0.0, 1.0]` at config load. Stdout logging is always active (the logger fans out to both stdout and OTLP), so logs never disappear regardless of collector state. gRPC exporters are lazy, so an unreachable collector does not block startup — startup was previously fatal on OTel init failure, now it is not. `WH_LOG_LEVEL` (`DEBUG`/`INFO`/`WARN`/`ERROR`, case-insensitive) now drives the slog `LevelVar` for both stdout and the OTLP log exporter. `provider.go` adds the `otlploggrpc` log exporter alongside the existing trace/metric exporters and registers the global OTel logger provider. `InitProvider` now takes a `ProviderConfig` struct AND returns a `(shutdown, promHandler http.Handler, err)` triple (breaking signature change within the internal package); `NewLogger` gains a `otlpSampleRate float64` parameter. - **Prometheus exposition is its own top-level `[prometheus]` config block, independent of OTel** (`internal/config/config.go`, `internal/observability/provider.go`, `cmd/wavehouse/main.go`, `config.yaml`, `docs/configuration.md`, `docs/deployment.md`): `prometheus.{enabled,path,port}` (env vars `WH_PROMETHEUS_{ENABLED,PATH,PORT}`, defaults `false` / `/metrics` / `0`) drives a Prometheus-format `/metrics` endpoint. Lives at the top level — not nested under `[otel.metrics]` — so operators using a scrape pipeline (Grafana Alloy / Mimir / vanilla Prometheus) do not need to enable or even understand `[otel]` to expose metrics. Three modes are first-class: OTLP push only (`otel.enabled=true`, `prometheus.enabled=false`), Prometheus only (`otel.enabled=false`, `prometheus.enabled=true`), or both. When both are on the underlying OTel MeterProvider feeds both readers — same `Meter()` API records to both; OTel→Prometheus name translation is automatic (dots/dashes → underscores, counters get `_total`). `InitProvider`'s `MetricsEnabled` and `PrometheusEnabled` fields are independent; `main.go` runs init whenever either is wanted. `port=0` mounts on the API router; non-zero spins a sidecar listener for firewall-isolated production posture. Disabled by default — explicit opt-in since enabling adds an unauthenticated endpoint. Validated at config load: port range `[0, 65535]`, must not collide with `server.port`, path must start with `/`. This unblocks Grafana Cloud / Mimir / Loki / Tempo via Alloy (stdout scrape + Prometheus scrape + OTLP traces) — see `docs/deployment.md` for the wiring patterns. `deployments/signoz/` is a new self-contained compose setup for running SigNoz locally (ClickHouse + query service + collector); credentials are env-substituted with a `.env.example` template so the literal `default:password` no longer ships in source-controlled YAML. diff --git a/docs/Makefile b/docs/Makefile index 8902f4bf..1f02721e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -87,7 +87,7 @@ preview: install-playwright ## Preview the production build locally via wrangler @# `make build` explicitly to refresh. @if [ ! -d dist ]; then \ echo "$(CYAN)==> No dist/ — building first...$(RESET)"; \ - $(PNPM) build; \ + $(MAKE) build; \ fi @$(PNPM) preview From 1222a029eec19d77f56dac8e28e64a805cc949be Mon Sep 17 00:00:00 2001 From: Eric Andrechek Date: Wed, 27 May 2026 09:55:02 -0400 Subject: [PATCH 7/8] add phony make targets manually for tab completion --- Makefile | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 84433251..9919c54a 100644 --- a/Makefile +++ b/Makefile @@ -416,9 +416,26 @@ SUBPROJECT_FANOUTS := $(addprefix subprojects-,$(COMMON_VERBS)) .PHONY: $(SUBPROJECT_FANOUTS) $(SUBPROJECT_FANOUTS): subprojects-%: $(addsuffix /.%,$(SUBPROJECTS)) -# Per-subproject pattern rules for direct invocation: +# Per-subproject targets for direct invocation: # make docs- → cd docs && make -# Add one line below per subproject as they're added to SUBPROJECTS. +# +# The static pattern rule below enumerates docs- aliases as literal, +# explicit, phony targets. That gives us two things: +# 1. zsh `_make` completion parses the Makefile to enumerate targets — it +# can't expand `%`, so without literal names `make docs-` falls back +# to filename completion and surfaces the `docs/` directory contents. +# 2. `.PHONY` coverage means a stray file or directory named e.g. +# `docs-build` can't shadow the target (and the implicit-rule search is +# skipped, so phony targets need an explicit recipe — that's what the +# static pattern rule provides). +# The catch-all pattern rule at the bottom keeps the "add a target in +# docs/Makefile, free fanout from root" property — newly-added recipes work +# immediately, just without tab-completion or phony coverage until promoted +# into the literal list. +.PHONY: docs-install docs-install-playwright docs-dev docs-preview docs-build docs-branding docs-test docs-lint docs-verify docs-clean docs-clean-tools +docs-install docs-install-playwright docs-dev docs-preview docs-build docs-branding docs-test docs-lint docs-verify docs-clean docs-clean-tools: docs-%: + @$(MAKE) -C $(DOCS_DIR) $* + docs-%: @$(MAKE) -C $(DOCS_DIR) $* From a69b32d811e8489fdbfd388d11b2f29f850eee33 Mon Sep 17 00:00:00 2001 From: Eric Andrechek Date: Wed, 27 May 2026 10:49:55 -0400 Subject: [PATCH 8/8] og tags updated --- docs/astro.config.mjs | 10 +++++++++- docs/src/content/docs/index.mdx | 12 +++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 31913bee..23c34ed4 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -40,11 +40,19 @@ posthog.init('phc_xFG2NGQa7bFg4QjBp3MAn8kr8bAPJxM7GvKzfoNEwZwj',{api_host:'https { tag: "link", attrs: { rel: "icon", type: "image/svg+xml", href: "/favicon.svg", sizes: "any" } }, { tag: "link", attrs: { rel: "icon", type: "image/x-icon", sizes: "16x16 32x32 48x48", href: "/favicon.ico" } }, { tag: "link", attrs: { rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.png" } }, - // Open Graph + // Open Graph — Starlight already emits og:title, og:type, og:url, + // og:locale, og:description, og:site_name, twitter:card. These are + // the bits it doesn't, applied site-wide so every shareable page + // carries them. og:image:alt doubles as accessibility text for + // screen readers and the fallback string platforms render when the + // image fails to load. { tag: "meta", attrs: { property: "og:image", content: "https://wavehouse.dev/og.png" } }, + { tag: "meta", attrs: { property: "og:image:type", content: "image/png" } }, { tag: "meta", attrs: { property: "og:image:width", content: "1200" } }, { tag: "meta", attrs: { property: "og:image:height", content: "630" } }, + { tag: "meta", attrs: { property: "og:image:alt", content: "WaveHouse — open-source real-time API gateway for ClickHouse" } }, { tag: "meta", attrs: { name: "twitter:image", content: "https://wavehouse.dev/og.png" } }, + { tag: "meta", attrs: { name: "twitter:image:alt", content: "WaveHouse — open-source real-time API gateway for ClickHouse" } }, ], logo: { light: "./src/assets/branding/wavehouse-mark-light.svg", diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index fe276575..4d0a643f 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -1,8 +1,18 @@ --- -title: WaveHouse +title: Real-time API gateway for ClickHouse description: The open-source real-time API gateway for ClickHouse — schema-aware ingest, async batching, real-time streaming, and tiered query caching in a single binary. template: splash +# Homepage-only structured data: lets Google/GitHub attach the canonical +# SoftwareSourceCode + Organization entities to the project's root URL. +# Inner doc pages don't need this — it'd just dilute the signal. +head: + - tag: script + attrs: + type: application/ld+json + content: | + {"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://wave-rf.com/#org","name":"Wave RF","url":"https://wave-rf.com","email":"hello@wave-rf.com","sameAs":["https://github.com/Wave-RF"]},{"@type":"SoftwareSourceCode","@id":"https://wavehouse.dev/#project","name":"WaveHouse","description":"The open-source real-time API gateway for ClickHouse — schema-aware ingest, async batching, real-time streaming, and tiered query caching in a single binary.","codeRepository":"https://github.com/Wave-RF/WaveHouse","programmingLanguage":["Go","TypeScript"],"license":"https://opensource.org/license/mit/","image":"https://wavehouse.dev/og.png","url":"https://wavehouse.dev","author":{"@id":"https://wave-rf.com/#org"}}]} hero: + title: WaveHouse tagline: The open-source real-time API gateway for ClickHouse. Schema-aware ingest, async batching, real-time streaming, and tiered query caching — in a single binary. actions: - text: Get started