Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
26794bb
feat(docs): rebuild site with clickwave logo and design tokens
EricAndrechek May 19, 2026
1e13730
fix(docs): address PR #142 review feedback + center clickwave mark
EricAndrechek May 19, 2026
20f90ac
Merge remote-tracking branch 'origin/main' into pretty-docs
EricAndrechek May 19, 2026
7195d85
fix(docs): second round of PR #142 review feedback
EricAndrechek May 19, 2026
0c68741
fix(docs): third round — SSE table param + favicon MIME
EricAndrechek May 19, 2026
c46b9bb
fix(docs): fourth round — screenshot.mjs port + CHANGELOG invocation
EricAndrechek May 19, 2026
6fd6735
fix(docs): fifth round — document Playwright in development.md + guar…
EricAndrechek May 19, 2026
13075dd
fix(docs): restore dramatic OG card design from the 26794bb intent
EricAndrechek May 19, 2026
ef835d1
fix(docs): refine OG card — more visible grid, height-matched lockup,
EricAndrechek May 19, 2026
edc9d05
fix(docs): wire canonical lockup.svg into OG + extra tagline padding +
EricAndrechek May 19, 2026
c37d06e
fix(docs): OG footer back below tagline size for correct hierarchy
EricAndrechek May 19, 2026
e559e69
Merge remote-tracking branch 'origin/main' into pretty-docs
EricAndrechek May 19, 2026
9a8f313
fix(docs): sixth round — address remaining Claude review threads
EricAndrechek May 19, 2026
7877000
fix(docs): seventh round — clarify install-docs comment + drop hero v…
EricAndrechek May 19, 2026
51ef0a1
fix(docs): eighth round — extract install-docs-playwright + selector-…
EricAndrechek May 19, 2026
49cc8ee
fix(docs): ninth round — sync CHANGELOG to install-docs-playwright + …
EricAndrechek May 19, 2026
c984a93
ci(docs): cache Playwright Chromium + Astro content-collection state;…
EricAndrechek May 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/actions/setup-env/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@
# runners it falls back to a workspace-relative path. Hard-coding
# the default silently fails the save with a Path Validation
# Error.
#
# 4. Playwright browser cache (~/.cache/ms-playwright) keyed on the
# docs lockfile. ~130 MB Chromium download otherwise re-fetched
# every run. See #132.
#
# 5. Astro content-collection cache (docs/.astro/) keyed on docs
# lockfile + astro.config.mjs. Speeds up warm `astro build` —
# unchanged content skips the parse + transform pipeline. See
# #132.
name: Setup CI environment
description: Restores caches and sets up Go + pnpm + Node for WaveHouse CI

Expand All @@ -34,6 +43,12 @@ outputs:
pnpm-store-path:
description: "Absolute path to the pnpm content-addressable store on this runner — pass to actions/cache/save in the consuming workflow."
value: ${{ steps.pnpm-store.outputs.path }}
playwright-cache-hit:
description: "true if the exact-key Playwright browser cache was restored"
value: ${{ steps.playwright-cache.outputs.cache-hit }}
astro-cache-hit:
description: "true if the exact-key Astro content cache was restored"
value: ${{ steps.astro-cache.outputs.cache-hit }}

runs:
using: composite
Expand Down Expand Up @@ -84,6 +99,34 @@ runs:
restore-keys: |
pnpm-${{ runner.os }}-

# 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
# 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
id: playwright-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('docs/pnpm-lock.yaml') }}
restore-keys: |
playwright-${{ runner.os }}-

# Astro's content-collection cache (docs/.astro/data-store.json plus
# generated content types). Restored across runs so unchanged Markdown
# / MDX content skips the parse + transform pipeline. Keyed on
# lockfile + astro.config.mjs since plugin-chain changes invalidate
# the cache shape; intra-key content changes are caught by Astro's
# own file-hash check inside data-store.json. Closes the build-cache
# half of #132.
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
id: astro-cache
with:
path: docs/.astro
key: astro-${{ runner.os }}-${{ hashFiles('docs/pnpm-lock.yaml', 'docs/astro.config.mjs') }}
restore-keys: |
astro-${{ runner.os }}-

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "22"
18 changes: 16 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ jobs:

# Saves run on every branch, gated on `*-cache-hit != 'true'` so a
# same-key re-push is a no-op. PRs inherit main's cache scope, so a
# main-push save warms every PR. Three saves mirror three restores
# in setup-env — keep paths and keys in sync.
# main-push save warms every PR. Saves mirror restores in setup-env
# — keep paths and keys in sync.
- name: Save Go module + build cache
if: steps.setup.outputs.gobuild-cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
Expand Down Expand Up @@ -78,6 +78,20 @@ jobs:
path: ${{ steps.setup.outputs.pnpm-store-path }}
key: pnpm-${{ runner.os }}-${{ hashFiles('clients/ts/pnpm-lock.yaml', 'tests/e2e/sdk/pnpm-lock.yaml', 'docs/pnpm-lock.yaml') }}

- name: Save Playwright browser cache
if: steps.setup.outputs.playwright-cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('docs/pnpm-lock.yaml') }}

- name: Save Astro content cache
if: steps.setup.outputs.astro-cache-hit != 'true'
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: docs/.astro
key: astro-${{ runner.os }}-${{ hashFiles('docs/pnpm-lock.yaml', 'docs/astro.config.mjs') }}

# Coverage in the job-summary panel. See #133 for post-launch
# reporting decisions.
- name: Coverage summary
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **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.
- **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 `<path>.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,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 a teal outlined-house silhouette containing two horizontal wave bands — a literal "WaveHouse" pun that also nods to the ClickHouse "house" naming and reads as multi-layer storage. `scripts/branding/mark.svg` is the single source of truth (one multi-element SVG using `stroke="currentColor"`); `make branding` extracts its inner content + viewBox and emits six derived artifacts via `rsvg-convert` + ImageMagick: a CSS-swap browser favicon (`<style>` block targets `g{stroke}` so it overrides the presentation attribute; `prefers-color-scheme:dark` flips the brand color), a multi-resolution legacy `favicon.ico` (16/32/48), a white-on-teal 180×180 iOS home-screen tile (`apple-touch-icon.png`; solid background since transparent apple-touch icons render a white halo on iOS), a 1200×630 OG card rendered from `og.template.svg` (gradient + wordmark + tagline + subtle wave texture baked in, mark spliced into a `__MARK_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 `<img>`, so a single CSS-swap SVG won't work in the nav). `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 `<link rel="apple-touch-icon">` 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 `<link>` tag needed. README H1 uses a `<picture>` element with `<source media="(prefers-color-scheme: dark)">` 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.
- **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 `<img>`, 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 `<link rel="apple-touch-icon">` 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 `<link>` tag needed. README H1 uses a `<picture>` element with `<source media="(prefers-color-scheme: dark)">` 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.
- **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.
Comment thread
EricAndrechek marked this conversation as resolved.
Resolved
- **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.
Expand Down
Loading
Loading