From 272c8fa0bc14fe9138ff638bbb0fffa4a1870c1a Mon Sep 17 00:00:00 2001 From: Maruthi Prithivi Date: Tue, 28 Jul 2026 14:25:42 +0800 Subject: [PATCH 1/5] docs(workshop): archive module 06b --- workshops/build_workshop/README.md | 6 +- .../docs/diagrams/gen_diagrams.py | 4 +- .../docs/diagrams/workshop-architecture.svg | 3 - .../docs/diagrams/workshop-module-flow.svg | 37 +++++------- .../playbook/content/docs/index.mdx | 13 ++-- .../content/docs/instructor/05-clickstack.mdx | 2 + .../docs/instructor/06b-ai-sre-librechat.mdx | 18 ++++-- .../docs/instructor/07-break-and-fix.mdx | 2 - .../content/docs/instructor/09-wrap-up.mdx | 4 +- .../content/docs/instructor/index.mdx | 6 +- .../content/docs/instructor/meta.json | 1 - .../content/docs/learner/00-setup.mdx | 2 +- .../content/docs/learner/05-clickstack.mdx | 60 +++++++++---------- .../content/docs/learner/06-ai-sre.mdx | 8 +-- .../docs/learner/06b-ai-sre-librechat.mdx | 18 ++++-- .../content/docs/learner/07-break-and-fix.mdx | 6 +- .../playbook/content/docs/learner/index.mdx | 6 +- .../playbook/content/docs/learner/meta.json | 1 - .../playbook/public/workshop-architecture.svg | 3 - .../playbook/public/workshop-module-flow.svg | 37 +++++------- .../build_workshop/scripts/check-docs.sh | 26 ++++++++ 21 files changed, 132 insertions(+), 131 deletions(-) diff --git a/workshops/build_workshop/README.md b/workshops/build_workshop/README.md index ff88d9f..b6c9f94 100644 --- a/workshops/build_workshop/README.md +++ b/workshops/build_workshop/README.md @@ -15,8 +15,8 @@ feature branch, open a PR to protected `dev-build-workshop-v1`, verify ## Architecture The app edge runs on the participant's laptop. ClickHouse, Postgres, ClickPipes, and -ClickStack/HyperDX live in ClickHouse Cloud; OpenAI, Langfuse, and optional LibreChat are -separate hosted services. No database or product UI is deployed locally. +ClickStack/HyperDX live in ClickHouse Cloud; OpenAI and Langfuse are separate hosted +services. No database or product UI is deployed locally. ```mermaid flowchart LR @@ -40,7 +40,6 @@ flowchart LR subgraph THIRD["Third-party"] OAI["OpenAI API
chat completions"] LF["Langfuse Cloud
chat traces"] - LC["Hosted LibreChat
optional SRE chat"] TLC["NYC TLC public dataset
download source only"] end @@ -58,7 +57,6 @@ flowchart LR TLC -.->|url seed, module 01| CH HDX -->|reads otel db| CH AG -->|RBAC-governed SQL| CH - LC -.->|remote MCP| MCP ``` The published diagrams (the ClickHouse Cloud platform stack, the workshop architecture, the diff --git a/workshops/build_workshop/docs/diagrams/gen_diagrams.py b/workshops/build_workshop/docs/diagrams/gen_diagrams.py index 4947446..bef57de 100644 --- a/workshops/build_workshop/docs/diagrams/gen_diagrams.py +++ b/workshops/build_workshop/docs/diagrams/gen_diagrams.py @@ -106,7 +106,6 @@ def module_flow(): ("04 ClickHouse Agents", "10 min", "conversational BI", "over your taxi data"), ("05 ClickStack", "15 min", "OTel overlay: traces", "+ logs in HyperDX"), ("06 AI SRE", "15 min", "agent + ClickStack MCP", "builds dashboard + alert"), - ("06b Hosted LibreChat", "optional · 15 min", "remote ClickStack + GitHub MCP", "chat-native SRE workflow"), ("07 Test, fail, and fix", "20 min", "inject a fault, diagnose", "with the AI SRE, fix it"), ("08 Chat + Langfuse", "15 min", "in-app AI chat,", "every turn traced"), ("09 Wrap-up", "10 min", "running prototype,", "take it home"), @@ -122,7 +121,7 @@ def module_flow(): s += (f'' f'ClickHouse BUILD Workshop · Module flow\n') s += (f'' - f'~2h30 core + optional 06b · only module 07 switches to a fault branch\n') + f'~2h30 hands-on · only module 07 switches to a fault branch\n') top = gy + 52 pos = {} @@ -203,7 +202,6 @@ def architecture(): s += box(1315, 195, 330, 74, "Langfuse Cloud", ["chat traces, sessions, cost"]) s += box(1315, 300, 330, 74, "OpenAI API", ["chat completions (gpt-5.4-mini)"]) s += box(1315, 410, 330, 88, "NYC TLC dataset", ["public parquet; read once by the", "module 01 seed. Data source only."]) - s += box(1315, 530, 330, 74, "Hosted LibreChat", ["optional SRE chat · remote MCP"]) # --- edges (laptop internal) --- s += edge(287, 252, 287, 300, "/api proxy", label_dx=42) diff --git a/workshops/build_workshop/docs/diagrams/workshop-architecture.svg b/workshops/build_workshop/docs/diagrams/workshop-architecture.svg index cd365ec..0e36cfa 100644 --- a/workshops/build_workshop/docs/diagrams/workshop-architecture.svg +++ b/workshops/build_workshop/docs/diagrams/workshop-architecture.svg @@ -62,9 +62,6 @@ NYC TLC dataset public parquet; read once by the module 01 seed. Data source only. - -Hosted LibreChat -optional SRE chat · remote MCP /api proxy diff --git a/workshops/build_workshop/docs/diagrams/workshop-module-flow.svg b/workshops/build_workshop/docs/diagrams/workshop-module-flow.svg index 322eaf7..7318a01 100644 --- a/workshops/build_workshop/docs/diagrams/workshop-module-flow.svg +++ b/workshops/build_workshop/docs/diagrams/workshop-module-flow.svg @@ -1,8 +1,8 @@ - - + + ClickHouse BUILD Workshop · Module flow -~2h30 core + optional 06b · only module 07 switches to a fault branch +~2h30 hands-on · only module 07 switches to a fault branch 00 Setup @@ -47,28 +47,22 @@ builds dashboard + alert -06b Hosted LibreChat -optional · 15 min -remote ClickStack + GitHub MCP -chat-native SRE workflow +07 Test, fail, and fix +20 min +inject a fault, diagnose +with the AI SRE, fix it -07 Test, fail, and fix -20 min -inject a fault, diagnose -with the AI SRE, fix it +08 Chat + Langfuse +15 min +in-app AI chat, +every turn traced -08 Chat + Langfuse -15 min -in-app AI chat, -every turn traced - - -09 Wrap-up -10 min -running prototype, -take it home +09 Wrap-up +10 min +running prototype, +take it home @@ -78,6 +72,5 @@ - After module 03: historical + live data both flowing into your Cloud service. diff --git a/workshops/build_workshop/playbook/content/docs/index.mdx b/workshops/build_workshop/playbook/content/docs/index.mdx index 083dd68..7a2a11b 100644 --- a/workshops/build_workshop/playbook/content/docs/index.mdx +++ b/workshops/build_workshop/playbook/content/docs/index.mdx @@ -89,15 +89,15 @@ stateful data or product service is cloud-hosted from the start. ClickHouse Cloud is a single platform that spans the whole stack — from ingesting data at the bottom, to storing and analyzing it in ClickHouse, to observing it and layering AI on top. This workshop is a guided tour through exactly these pieces: you ingest with -ClickPipes, analyze in ClickHouse, and observe with Managed ClickStack/HyperDX. Langfuse, -OpenAI, and optional LibreChat are separate hosted services. +ClickPipes, analyze in ClickHouse, and observe with Managed ClickStack/HyperDX. Langfuse +and OpenAI are separate hosted services. ![The ClickHouse Cloud platform: layered stack from sources and ClickPipes ingestion, through ClickHouse and Postgres, up to HyperDX, Langfuse and agentic AI](/clickhouse-platform.svg) ### Architecture (target end state) Here is how those pieces come together: the app edge on your laptop; ClickHouse-managed -state in your trial; and separate hosted OpenAI, Langfuse, and optional LibreChat services. +state in your trial; and separate hosted OpenAI and Langfuse services. ![Workshop architecture: participant laptop, your ClickHouse Cloud trial (service, ClickPipes, managed Postgres), and third-party services](/workshop-architecture.svg) @@ -111,11 +111,11 @@ via CDC, then read by the dashboards, chat, and agents, and observed through Cli The diagrams above are generated from `workshops/build_workshop/docs/diagrams/gen_diagrams.py` (edit the script and re-run it to regenerate the SVGs) — see the module flow below. -![Module flow: ten core modules plus optional hosted LibreChat 06b](/workshop-module-flow.svg) +![Module flow: ten core workshop modules](/workshop-module-flow.svg) ## Modules -Ten core modules plus optional 06b, in order. The app is complete on `build-workshop-v1`, so every module except +Ten core modules, in order. The app is complete on `build-workshop-v1`, so every module except 07 needs no per-module checkout — you configure and connect services rather than change app code. The only branch switches are the fault branches in module 07. @@ -128,8 +128,7 @@ app code. The only branch switches are the fault branches in module 07. | 04 | 10 min | [ClickHouse Agents](/docs/learner/04-clickhouse-agents) | [notes](/docs/instructor/04-clickhouse-agents) | `build-workshop-v1` | Conversational BI: create an agent over your taxi data and explore it in natural language | | 05 | 15 min | [ClickStack](/docs/learner/05-clickstack) | [notes](/docs/instructor/05-clickstack) | `build-workshop-v1` | Enable ClickStack and send app traces and logs to HyperDX | | 06 | 15 min | [AI SRE](/docs/learner/06-ai-sre) | [notes](/docs/instructor/06-ai-sre) | `build-workshop-v1` | Use the ClickStack MCP connection to build an SRE dashboard and alert | -| 06b | Optional, 15 min | [Hosted LibreChat AI SRE](/docs/learner/06b-ai-sre-librechat) | [notes](/docs/instructor/06b-ai-sre-librechat) | `build-workshop-v1` | Use a hosted chat agent with remote ClickStack and GitHub MCP connections | -| 07 | 20 min | [Test, fail, and fix](/docs/learner/07-break-and-fix) | [notes](/docs/instructor/07-break-and-fix) | `fault/*` | Continue from AI SRE or optional 06b, inject a fault, diagnose it, fix it, and prove recovery | +| 07 | 20 min | [Test, fail, and fix](/docs/learner/07-break-and-fix) | [notes](/docs/instructor/07-break-and-fix) | `fault/*` | Continue from AI SRE, inject a fault, diagnose it, fix it, and prove recovery | | 08 | 15 min | [Chat and Langfuse](/docs/learner/08-chat-langfuse) | [notes](/docs/instructor/08-chat-langfuse) | `build-workshop-v1` | Use the in-app AI chat and follow its traces, generations, and costs in Langfuse | | 09 | 10 min | [Wrap-up](/docs/learner/09-wrap-up) | [notes](/docs/instructor/09-wrap-up) | `build-workshop-v1` | Review what you built, take it home, and extend it to your own data | diff --git a/workshops/build_workshop/playbook/content/docs/instructor/05-clickstack.mdx b/workshops/build_workshop/playbook/content/docs/instructor/05-clickstack.mdx index 862cdff..b6b869d 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/05-clickstack.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/05-clickstack.mdx @@ -15,6 +15,8 @@ collector as early as this module allows and keep it running. - Managed ClickStack stores telemetry in ClickHouse Cloud; HyperDX is the hosted UI. The local collector only forwards data. Show both an end-to-end request trace and a fresh `DEBUG ... ClickHouse query ok` record in the Log source. +- Have learners start the collector in Step 1 before they launch Managed ClickStack in + Step 2. This gives telemetry time to arrive and makes the first hosted-UI view useful. - Show one end-to-end request trace on the projector. ## Common failures diff --git a/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx b/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx index a88fc20..f9d788d 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx @@ -1,17 +1,23 @@ --- -title: 06b AI SRE with hosted LibreChat -description: Instructor prework and facilitation notes for the optional cloud-hosted LibreChat module. +title: "Archived: 06b AI SRE with hosted LibreChat" +description: Archived instructor reference for the former optional hosted LibreChat module. --- + + Module 06b is no longer part of the run of show. Do not provision LibreChat, learner + accounts, or its MCP connections for the current workshop. Continue directly from + Module 06 to Module 07. The notes below remain only as a historical reference. + + Facilitator companion to [06b AI SRE with hosted LibreChat](/docs/learner/06b-ai-sre-librechat). -## Timing +## Historical timing -Optional, about 15 minutes. Run it immediately before Module 07. Skip it if the room is -tight; Module 06a already covers the remote ClickStack MCP workflow. +This module previously took about 15 minutes immediately before Module 07. Module 06 +already covers the remote ClickStack MCP workflow. -## Required cloud prework +## Historical cloud prework Learners must not deploy LibreChat or MongoDB locally. diff --git a/workshops/build_workshop/playbook/content/docs/instructor/07-break-and-fix.mdx b/workshops/build_workshop/playbook/content/docs/instructor/07-break-and-fix.mdx index 8bddf83..070e51a 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/07-break-and-fix.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/07-break-and-fix.mdx @@ -17,8 +17,6 @@ so the wrap-up is not squeezed. ## Talk track - This is the payoff: use everything built so far to run a real incident. -- If the room completed 06b, fault 01 is already diagnosed — this module becomes - confirm-fix-verify, so keep the momentum and move quickly to the fix. - Describe the symptom, not the cause, and let the agents converge from telemetry. - Consider showing several attendees' diagnoses side by side on the projector. - The lab runs fault 01. If time permits an extra round, add fault 02 (and fault 03 only diff --git a/workshops/build_workshop/playbook/content/docs/instructor/09-wrap-up.mdx b/workshops/build_workshop/playbook/content/docs/instructor/09-wrap-up.mdx index d8c8d58..129c257 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/09-wrap-up.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/09-wrap-up.mdx @@ -24,6 +24,6 @@ About 10 minutes. Reserve time for two or three volunteer demos on the projector ## Reset steps -- Reset any shared state used for demos (managed Postgres fallback pool, hosted LibreChat, - projector channel). +- Reset any shared state used for demos (managed Postgres fallback pool and projector + channel). - TODO: confirm the shared-state teardown checklist. diff --git a/workshops/build_workshop/playbook/content/docs/instructor/index.mdx b/workshops/build_workshop/playbook/content/docs/instructor/index.mdx index 31f195a..cd5cc30 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/index.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/index.mdx @@ -31,8 +31,7 @@ the dry run and record the final numbers here. | 04 | ClickHouse Agents | 10 min | Beta tool; have a fallback question ready | | 05 | ClickStack | 15 min | Telemetry needs time to accumulate before module 07 | | 06 | AI SRE | 15 min | MCP OAuth is the fragile moment; pre-stage config | -| 06b | Hosted LibreChat AI SRE | Optional, 15 min | Pre-provision HTTPS instance, model, accounts, and remote MCPs | -| 07 | Break and fix | 20 min | Direct payoff from 06/06b; hard-stop management matters | +| 07 | Break and fix | 20 min | Direct payoff from 06; hard-stop management matters | | 08 | Chat and Langfuse | 15 min | Keys already set in module 00; restart plus trace tour | | 09 | Wrap-up | 10 min | Volunteers demo; reset any shared state | @@ -52,8 +51,6 @@ before doors open: - **Managed Postgres fallback pool** — cloud-hosted instances only for attendees whose org cannot create one. The primary path is one ClickHouse-managed Postgres per learner. -- **Hosted LibreChat** — an HTTPS cloud deployment and learner accounts for optional - Module 06b. Do not run LibreChat or MongoDB on learner machines. - **Loaner ClickHouse Cloud services** — a small pool for attendees whose trial fails. TODO: pool size and distribution method. - **Runtime LLM key pool** — spend-capped fallback keys for the in-app chat (module 08). @@ -77,7 +74,6 @@ should arrive then. TODO: confirm the clinic start time and staffing. - diff --git a/workshops/build_workshop/playbook/content/docs/instructor/meta.json b/workshops/build_workshop/playbook/content/docs/instructor/meta.json index f26058f..8c9386c 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/meta.json +++ b/workshops/build_workshop/playbook/content/docs/instructor/meta.json @@ -12,7 +12,6 @@ "04-clickhouse-agents", "05-clickstack", "06-ai-sre", - "06b-ai-sre-librechat", "07-break-and-fix", "08-chat-langfuse", "09-wrap-up" diff --git a/workshops/build_workshop/playbook/content/docs/learner/00-setup.mdx b/workshops/build_workshop/playbook/content/docs/learner/00-setup.mdx index 8cc0326..bc80909 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/00-setup.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/00-setup.mdx @@ -17,7 +17,7 @@ In about **25 minutes** you will have: - Langfuse and OpenAI keys; and - the app healthy at [localhost:8080](http://localhost:8080). -ClickHouse, Postgres, ClickPipes, ClickStack/HyperDX, Langfuse, LibreChat, and MCP +ClickHouse, Postgres, ClickPipes, ClickStack/HyperDX, Langfuse, and MCP endpoints are cloud-hosted. Only the workshop app, CLI/client tools, coding agent, load generator, and stateless telemetry collector run on your machine. diff --git a/workshops/build_workshop/playbook/content/docs/learner/05-clickstack.mdx b/workshops/build_workshop/playbook/content/docs/learner/05-clickstack.mdx index 9c28303..525b591 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/05-clickstack.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/05-clickstack.mdx @@ -1,6 +1,6 @@ --- title: 05 ClickStack -description: Enable Managed ClickStack, forward telemetry with a local stateless collector, and inspect it in cloud-hosted HyperDX. +description: Forward telemetry with a local stateless collector, enable Managed ClickStack, and inspect it in cloud-hosted HyperDX. --- ## Starting point @@ -23,35 +23,7 @@ produces telemetry you can query. App traces and backend query logs flowing into ClickStack, with at least one end-to-end request trace and a visible stream of successful query records. -## Step 1 — Enable Managed ClickStack on your service - -The workshop uses **Managed ClickStack (HyperDX)** inside your own ClickHouse Cloud -service: the collector writes `otel_*` tables to your service and the HyperDX UI renders -them there. Enable it in the console: - -Console - your service -> **ClickStack** -> **Start Ingestion** -> skip the collector -step (the app ships its own collector in Step 2) -> **Launch ClickStack** - -That single-signs you on into HyperDX. (The UI is empty at this point — telemetry starts -flowing once the collector overlay is running in Step 2.) - - - - The back end uses vanilla OpenTelemetry, not the convenience - `hyperdx-opentelemetry` package the ClickStack docs suggest. That package hard-pins - `opentelemetry-api==1.30.0`, which conflicts with the Langfuse v4 SDK the chat - feature uses (needs `opentelemetry-api>=1.33.1`) — the two cannot share one - environment. The ClickStack collector ingests standard OTLP, so the vanilla distro - behaves identically; the workshop just sets the exporter env vars itself. - - ClickStack's telemetry lives in a separate database on your service - (`CLICKSTACK_DATABASE=otel`), distinct from the app's data database - (`CLICKHOUSE_DATABASE=nyc_tlc_data`). - - Traces and backend Python logs flow over OTLP from the auto-instrumented back end. - The optional `--profile container-logs` collector is only for non-instrumented - services such as the trip writer; its Linux Docker log path may not be available on - Docker Desktop. - - -## Step 2 — Run the OpenTelemetry collector overlay +## Step 1 — Run the OpenTelemetry collector overlay HyperDX, storage, and query compute stay managed in ClickHouse Cloud. The only local component here is a stateless OpenTelemetry collector beside the local app; it forwards @@ -95,6 +67,34 @@ The collector reuses `CLICKHOUSE_HOST` / `CLICKHOUSE_PORT` / `CLICKHOUSE_USER` / `http://otel-collector:4318` (HTTP/protobuf). To also scrape raw container stdout on a Linux host, add `--profile container-logs`. +## Step 2 — Enable Managed ClickStack on your service + +The workshop uses **Managed ClickStack (HyperDX)** inside your own ClickHouse Cloud +service: the collector writes `otel_*` tables to your service and the HyperDX UI renders +them there. Enable it in the console: + +Console - your service -> **ClickStack** -> **Start Ingestion** -> skip the collector +step (the app collector is already running from Step 1) -> **Launch ClickStack** + +That single-signs you on into HyperDX. Telemetry has already started flowing, so the +hosted UI can populate as soon as it opens. + + + - The back end uses vanilla OpenTelemetry, not the convenience + `hyperdx-opentelemetry` package the ClickStack docs suggest. That package hard-pins + `opentelemetry-api==1.30.0`, which conflicts with the Langfuse v4 SDK the chat + feature uses (needs `opentelemetry-api>=1.33.1`) — the two cannot share one + environment. The ClickStack collector ingests standard OTLP, so the vanilla distro + behaves identically; the workshop just sets the exporter env vars itself. + - ClickStack's telemetry lives in a separate database on your service + (`CLICKSTACK_DATABASE=otel`), distinct from the app's data database + (`CLICKHOUSE_DATABASE=nyc_tlc_data`). + - Traces and backend Python logs flow over OTLP from the auto-instrumented back end. + The optional `--profile container-logs` collector is only for non-instrumented + services such as the trip writer; its Linux Docker log path may not be available on + Docker Desktop. + + ## Step 3 — Generate and find traffic in ClickStack Open the Ops dashboard and leave its default `1m` interval and `5s` auto-refresh running diff --git a/workshops/build_workshop/playbook/content/docs/learner/06-ai-sre.mdx b/workshops/build_workshop/playbook/content/docs/learner/06-ai-sre.mdx index 3ff5017..fec3155 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/06-ai-sre.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/06-ai-sre.mdx @@ -125,8 +125,6 @@ artifacts from it. That is exactly what you will lean on when something breaks. ## End state -An AI-built SRE dashboard and alert are in place. Continue to optional -[06b AI SRE with LibreChat](/docs/learner/06b-ai-sre-librechat) if you want a chat-native -agent that reads both telemetry and source, then use that agent in -[07 Test, fail, and fix](/docs/learner/07-break-and-fix). If you are skipping 06b, go straight -to module 07 with the editor agent you configured here. +An AI-built SRE dashboard and alert are in place. Continue to +[07 Test, fail, and fix](/docs/learner/07-break-and-fix) with the editor agent you +configured here. diff --git a/workshops/build_workshop/playbook/content/docs/learner/06b-ai-sre-librechat.mdx b/workshops/build_workshop/playbook/content/docs/learner/06b-ai-sre-librechat.mdx index f7a1a39..c52abca 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/06b-ai-sre-librechat.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/06b-ai-sre-librechat.mdx @@ -1,11 +1,19 @@ --- -title: 06b AI SRE with hosted LibreChat -description: Optional — use a cloud-hosted LibreChat SRE agent with remote ClickStack and GitHub MCP connections. +title: "Archived: 06b AI SRE with hosted LibreChat" +description: Archived reference for the former optional hosted LibreChat module. --- -## Starting point + + Module 06b is no longer part of the workshop. Do not provision LibreChat for the + current learner path. Continue directly from [06 AI SRE](/docs/learner/06-ai-sre) to + [07 Test, fail, and fix](/docs/learner/07-break-and-fix). The material below remains + available only as a historical reference. + + +## Historical starting point -Optional module. You are on `build-workshop-v1`; budget about **15 minutes**. +When this module was active, learners stayed on `build-workshop-v1` and budgeted about +**15 minutes**. Prerequisites: Module 05 is complete, your instructor has provided an HTTPS LibreChat URL and account, and you have a fine-grained GitHub token with read-only access to @@ -93,4 +101,4 @@ The agent should connect the `nyc-taxi-frontend` error to - The agent has connected remote `clickstack` and `github` MCP tools. - Its diagnosis cites both telemetry and a source file on the selected fault branch. -Continue to [07 Test, fail, and fix](/docs/learner/07-break-and-fix). +The active workshop continues at [07 Test, fail, and fix](/docs/learner/07-break-and-fix). diff --git a/workshops/build_workshop/playbook/content/docs/learner/07-break-and-fix.mdx b/workshops/build_workshop/playbook/content/docs/learner/07-break-and-fix.mdx index b562f7e..1fa59dc 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/07-break-and-fix.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/07-break-and-fix.mdx @@ -6,8 +6,7 @@ description: Inject a known fault, diagnose it through ClickStack, apply a fix, ## Outcome In about **20 minutes**, you will run one incident from failure to verified recovery. This -continues directly from Module 06a or optional 06b and uses the ClickStack MCP configured -in Module 00. +continues directly from Module 06 and uses the ClickStack MCP configured in Module 00. ## Step 1 — Choose one fault @@ -40,9 +39,6 @@ docker compose --env-file .env.workshop \ Open a fresh browser session at [localhost:8080](http://localhost:8080). **The empty map is expected now**; a failure elsewhere is not part of this scenario. -If Module 06b already injected Fault 01, skip the branch switch and rebuild only the -frontend. - ## Step 3 — Diagnose from evidence Give the agent the symptom, not the answer: diff --git a/workshops/build_workshop/playbook/content/docs/learner/index.mdx b/workshops/build_workshop/playbook/content/docs/learner/index.mdx index 87ae992..1379450 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/index.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/index.mdx @@ -21,8 +21,7 @@ on WSL 2, so all shared command blocks are identical after setup. 4. [ClickHouse Agents](/docs/learner/04-clickhouse-agents) - ask your data questions in plain language. 5. [ClickStack](/docs/learner/05-clickstack) - see the app's own traces and logs in HyperDX. 6. [AI SRE](/docs/learner/06-ai-sre) - have your agent build an SRE dashboard and alert over that telemetry. -6b. [Hosted LibreChat AI SRE](/docs/learner/06b-ai-sre-librechat) - optional hosted chat workflow over ClickStack and GitHub MCP. -7. [Break and fix](/docs/learner/07-break-and-fix) - continue from AI SRE or optional 06b, inject a fault, diagnose it, and fix it. +7. [Break and fix](/docs/learner/07-break-and-fix) - continue from AI SRE, inject a fault, diagnose it, and fix it. 8. [Chat and Langfuse](/docs/learner/08-chat-langfuse) - wire an in-app AI chat and trace every turn. 9. [Wrap-up](/docs/learner/09-wrap-up) - recap, take it home, extend it to your own data. @@ -44,8 +43,7 @@ About **2h30 hands-on** - and your dashboard is live on real data within the fir ## Cost ClickHouse Cloud trial credits cover the ClickHouse-managed services. Budget about -**$5 of OpenAI credit** for Module 08. Optional self-paced Module 06b may also incur a -small Railway hosting charge; instructor-led sessions use the provided hosted instance. +**$5 of OpenAI credit** for Module 08. ## Everything is copy-paste diff --git a/workshops/build_workshop/playbook/content/docs/learner/meta.json b/workshops/build_workshop/playbook/content/docs/learner/meta.json index 367c48a..858d7a9 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/meta.json +++ b/workshops/build_workshop/playbook/content/docs/learner/meta.json @@ -13,7 +13,6 @@ "04-clickhouse-agents", "05-clickstack", "06-ai-sre", - "06b-ai-sre-librechat", "07-break-and-fix", "08-chat-langfuse", "09-wrap-up", diff --git a/workshops/build_workshop/playbook/public/workshop-architecture.svg b/workshops/build_workshop/playbook/public/workshop-architecture.svg index cd365ec..0e36cfa 100644 --- a/workshops/build_workshop/playbook/public/workshop-architecture.svg +++ b/workshops/build_workshop/playbook/public/workshop-architecture.svg @@ -62,9 +62,6 @@ NYC TLC dataset public parquet; read once by the module 01 seed. Data source only. - -Hosted LibreChat -optional SRE chat · remote MCP /api proxy diff --git a/workshops/build_workshop/playbook/public/workshop-module-flow.svg b/workshops/build_workshop/playbook/public/workshop-module-flow.svg index 322eaf7..7318a01 100644 --- a/workshops/build_workshop/playbook/public/workshop-module-flow.svg +++ b/workshops/build_workshop/playbook/public/workshop-module-flow.svg @@ -1,8 +1,8 @@ - - + + ClickHouse BUILD Workshop · Module flow -~2h30 core + optional 06b · only module 07 switches to a fault branch +~2h30 hands-on · only module 07 switches to a fault branch 00 Setup @@ -47,28 +47,22 @@ builds dashboard + alert -06b Hosted LibreChat -optional · 15 min -remote ClickStack + GitHub MCP -chat-native SRE workflow +07 Test, fail, and fix +20 min +inject a fault, diagnose +with the AI SRE, fix it -07 Test, fail, and fix -20 min -inject a fault, diagnose -with the AI SRE, fix it +08 Chat + Langfuse +15 min +in-app AI chat, +every turn traced -08 Chat + Langfuse -15 min -in-app AI chat, -every turn traced - - -09 Wrap-up -10 min -running prototype, -take it home +09 Wrap-up +10 min +running prototype, +take it home @@ -78,6 +72,5 @@ - After module 03: historical + live data both flowing into your Cloud service. diff --git a/workshops/build_workshop/scripts/check-docs.sh b/workshops/build_workshop/scripts/check-docs.sh index e3f41f6..5d3c19e 100755 --- a/workshops/build_workshop/scripts/check-docs.sh +++ b/workshops/build_workshop/scripts/check-docs.sh @@ -29,6 +29,22 @@ fail_if_found \ '(comment|uncomment).*(sql|variant)|(run|execute|open).*(db/cloud|\.sql file)' \ "${CONTENT}/learner" +if grep -RInE --exclude='06b-ai-sre-librechat.mdx' \ + '06b|LibreChat' "${CONTENT}"; then + echo "ERROR: archived Module 06b must not appear in the active workshop journey" >&2 + exit 1 +fi + +fail_if_found \ + "active workshop summaries and diagrams must not include archived Module 06b" \ + '06b|LibreChat' \ + "${ROOT}/README.md" \ + "${ROOT}/docs/diagrams/gen_diagrams.py" \ + "${ROOT}/docs/diagrams/workshop-module-flow.svg" \ + "${ROOT}/docs/diagrams/workshop-architecture.svg" \ + "${ROOT}/playbook/public/workshop-module-flow.svg" \ + "${ROOT}/playbook/public/workshop-architecture.svg" + fail_if_found \ "workshop material must not direct users to local managed-service substitutes" \ 'PGHOST=postgres|localhost:3090|docker-compose\.librechat|local `mcp-clickhouse`|start (a |the )?local (Postgres|ClickHouse|LibreChat|HyperDX)|using (a |the )?local (Postgres|ClickHouse)' \ @@ -69,6 +85,16 @@ require_fixed \ 'git switch build-workshop-v1' \ "${CONTENT}/learner/00-setup.mdx" +require_fixed \ + "the former learner Module 06b page must remain clearly archived" \ + 'Module 06b is no longer part of the workshop.' \ + "${CONTENT}/learner/06b-ai-sre-librechat.mdx" + +require_fixed \ + "the former instructor Module 06b page must remain clearly archived" \ + 'Module 06b is no longer part of the run of show.' \ + "${CONTENT}/instructor/06b-ai-sre-librechat.mdx" + require_count() { local description=$1 local expected=$2 From dbca6eb7f54c8060a93d459c28668dd5545b768c Mon Sep 17 00:00:00 2001 From: Maruthi Prithivi Date: Tue, 28 Jul 2026 14:26:58 +0800 Subject: [PATCH 2/5] docs(workshop): close archive review gaps --- workshops/build_workshop/app/README.md | 2 +- .../build_workshop/app/WORKSHOP_CHANGES.md | 9 +++---- .../app/docker-compose.otel.yml | 2 +- .../content/docs/instructor/06-ai-sre.mdx | 2 +- .../docs/instructor/06b-ai-sre-librechat.mdx | 3 ++- .../content/docs/learner/05-clickstack.mdx | 26 ++++++++++++------- .../content/docs/learner/06-ai-sre.mdx | 2 +- .../build_workshop/scripts/check-docs.sh | 11 ++++++-- 8 files changed, 36 insertions(+), 21 deletions(-) diff --git a/workshops/build_workshop/app/README.md b/workshops/build_workshop/app/README.md index 958d53a..d224276 100644 --- a/workshops/build_workshop/app/README.md +++ b/workshops/build_workshop/app/README.md @@ -48,7 +48,7 @@ docker compose --env-file .env.workshop -f docker-compose.workshop.yml up -d # with the ClickStack observability overlay (module 05 onward): docker compose --env-file .env.workshop \ - -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d + -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d --build ``` Frontend: http://localhost:8080 - Backend API docs (FastAPI Swagger): diff --git a/workshops/build_workshop/app/WORKSHOP_CHANGES.md b/workshops/build_workshop/app/WORKSHOP_CHANGES.md index 6b4e9a9..3029c24 100644 --- a/workshops/build_workshop/app/WORKSHOP_CHANGES.md +++ b/workshops/build_workshop/app/WORKSHOP_CHANGES.md @@ -19,10 +19,9 @@ The workshop intentionally separates application code from managed services. - remote ClickHouse and ClickStack MCP endpoints - ClickHouse Agents - Langfuse Cloud and OpenAI -- the optional instructor-provided HTTPS LibreChat instance -No PostgreSQL, ClickHouse, MongoDB, LibreChat, HyperDX, Langfuse, or MCP server is -started on a learner machine. +No PostgreSQL, ClickHouse, MongoDB, HyperDX, Langfuse, or MCP server is started on a +learner machine. ## Runtime sequence @@ -30,8 +29,8 @@ started on a learner machine. 2. Module 01 creates and seeds the Cloud schema. 3. Module 03 creates managed Postgres, validates it with `./preflight.sh --require-postgres`, then explicitly enables the `cdc` trip writer. -4. Module 05 enables Managed ClickStack and starts the stateless collector overlay. -5. Module 06b uses hosted LibreChat; Module 08 sends chat traces to Langfuse Cloud. +4. Module 05 starts the stateless collector overlay, then enables Managed ClickStack. +5. Module 08 sends chat traces to Langfuse Cloud. `.env.workshop.example` leaves managed Postgres credentials blank until Module 03 and requires TLS. `preflight.sh` rejects loopback/local database hosts. CI policy checks in diff --git a/workshops/build_workshop/app/docker-compose.otel.yml b/workshops/build_workshop/app/docker-compose.otel.yml index 6b524f0..922ed7f 100644 --- a/workshops/build_workshop/app/docker-compose.otel.yml +++ b/workshops/build_workshop/app/docker-compose.otel.yml @@ -14,7 +14,7 @@ # "ClickStack observability" section of .env.workshop.example): # # docker compose --env-file .env.workshop \ -# -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d +# -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d --build # # Add raw container-log scraping (optional, see VERIFY-LIVE notes in OBSERVABILITY.md): # ... -f docker-compose.otel.yml --profile container-logs up -d diff --git a/workshops/build_workshop/playbook/content/docs/instructor/06-ai-sre.mdx b/workshops/build_workshop/playbook/content/docs/instructor/06-ai-sre.mdx index ac47ac6..4accbdc 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/06-ai-sre.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/06-ai-sre.mdx @@ -1,5 +1,5 @@ --- -title: 06a AI SRE +title: 06 AI SRE description: Instructor notes for module 06 — timing, talk track, common failures, and reset steps. --- diff --git a/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx b/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx index f9d788d..34369ab 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx @@ -6,7 +6,8 @@ description: Archived instructor reference for the former optional hosted LibreC Module 06b is no longer part of the run of show. Do not provision LibreChat, learner accounts, or its MCP connections for the current workshop. Continue directly from - Module 06 to Module 07. The notes below remain only as a historical reference. + Module 06 to [Module 07](/docs/instructor/07-break-and-fix). The notes below remain + only as a historical reference. Facilitator companion to diff --git a/workshops/build_workshop/playbook/content/docs/learner/05-clickstack.mdx b/workshops/build_workshop/playbook/content/docs/learner/05-clickstack.mdx index 525b591..2d8a8b2 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/05-clickstack.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/05-clickstack.mdx @@ -43,15 +43,6 @@ telemetry and is not a local ClickStack or HyperDX deployment. ### `.env.workshop` and `docker-compose.otel.yml` -Append the observability variables to your single `.env.workshop`, then bring the stack -up with the overlay. The overlay sets `OTEL_ENABLED=true` on the back end for you and -adds the `otel-collector` service (`clickhouse/clickstack-otel-collector`): - -```bash -docker compose --env-file .env.workshop \ - -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d -``` - These live in the ClickStack observability section of `.env.workshop.example`; fill them in your `.env.workshop`: @@ -62,6 +53,23 @@ OTEL_SERVICE_NAME=nyc-taxi-backend # the service name shown in HyperDX LOG_LEVEL=DEBUG # show successful queries in Log source ``` +Source the updated file so later commands can use the same values: + +```bash +set -a +source .env.workshop +set +a +``` + +Now bring the stack up with the overlay. The overlay sets `OTEL_ENABLED=true` on the +back end, adds the `otel-collector` service (`clickhouse/clickstack-otel-collector`), +and rebuilds the front end with the browser telemetry settings: + +```bash +docker compose --env-file .env.workshop \ + -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d --build +``` + The collector reuses `CLICKHOUSE_HOST` / `CLICKHOUSE_PORT` / `CLICKHOUSE_USER` / `CLICKHOUSE_PASSWORD` from `.env.workshop`; the back end exports OTLP to `http://otel-collector:4318` (HTTP/protobuf). To also scrape raw container stdout on a diff --git a/workshops/build_workshop/playbook/content/docs/learner/06-ai-sre.mdx b/workshops/build_workshop/playbook/content/docs/learner/06-ai-sre.mdx index fec3155..f3aacd1 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/06-ai-sre.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/06-ai-sre.mdx @@ -1,5 +1,5 @@ --- -title: 06a AI SRE +title: 06 AI SRE description: Connect your coding agent to the ClickStack MCP and have it build an SRE dashboard and an alert over your telemetry. --- diff --git a/workshops/build_workshop/scripts/check-docs.sh b/workshops/build_workshop/scripts/check-docs.sh index 5d3c19e..f7691d6 100755 --- a/workshops/build_workshop/scripts/check-docs.sh +++ b/workshops/build_workshop/scripts/check-docs.sh @@ -30,8 +30,8 @@ fail_if_found \ "${CONTENT}/learner" if grep -RInE --exclude='06b-ai-sre-librechat.mdx' \ - '06b|LibreChat' "${CONTENT}"; then - echo "ERROR: archived Module 06b must not appear in the active workshop journey" >&2 + '06a|06b|LibreChat' "${CONTENT}"; then + echo "ERROR: active workshop must use Module 06 and exclude archived Module 06b" >&2 exit 1 fi @@ -39,6 +39,8 @@ fail_if_found \ "active workshop summaries and diagrams must not include archived Module 06b" \ '06b|LibreChat' \ "${ROOT}/README.md" \ + "${ROOT}/app/README.md" \ + "${ROOT}/app/WORKSHOP_CHANGES.md" \ "${ROOT}/docs/diagrams/gen_diagrams.py" \ "${ROOT}/docs/diagrams/workshop-module-flow.svg" \ "${ROOT}/docs/diagrams/workshop-architecture.svg" \ @@ -95,6 +97,11 @@ require_fixed \ 'Module 06b is no longer part of the run of show.' \ "${CONTENT}/instructor/06b-ai-sre-librechat.mdx" +require_fixed \ + "the archived instructor page must link to active Module 07" \ + '[Module 07](/docs/instructor/07-break-and-fix)' \ + "${CONTENT}/instructor/06b-ai-sre-librechat.mdx" + require_count() { local description=$1 local expected=$2 From 116be7a4a784f7e0aea344247f848808ba3f8bed Mon Sep 17 00:00:00 2001 From: Maruthi Prithivi Date: Tue, 28 Jul 2026 15:13:07 +0800 Subject: [PATCH 3/5] style(design): FINDING-001 simplify workshop diagrams --- workshops/build_workshop/README.md | 2 +- .../docs/diagrams/gen_diagrams.py | 230 +++++++----------- .../docs/diagrams/workshop-architecture.svg | 160 +++++------- .../docs/diagrams/workshop-data-flow.svg | 161 +++++------- .../playbook/content/docs/index.mdx | 12 +- .../playbook/public/workshop-architecture.svg | 160 +++++------- .../playbook/public/workshop-data-flow.svg | 161 +++++------- 7 files changed, 321 insertions(+), 565 deletions(-) diff --git a/workshops/build_workshop/README.md b/workshops/build_workshop/README.md index b6c9f94..7235a29 100644 --- a/workshops/build_workshop/README.md +++ b/workshops/build_workshop/README.md @@ -98,7 +98,7 @@ sequenceDiagram G->>P: INSERT trips (throttled, TLS) Note over G,P: first run also creates the table
and publication pub_taxi P->>CP: WAL changes via publication + slot - CP->>CH: rows land in realtime_trips (_peerdb_* cols), about 60s + CP->>CH: rows land in default.realtime_trips, about 60s CH->>CH: materialized view fans rows into nyc_tlc_data.taxi_trips UI->>CH: parameterized SQL / guarded NL-to-SQL / RBAC-governed BI CH-->>UI: live Ops dashboard + 3M-row Historical seed diff --git a/workshops/build_workshop/docs/diagrams/gen_diagrams.py b/workshops/build_workshop/docs/diagrams/gen_diagrams.py index bef57de..fa39dcb 100644 --- a/workshops/build_workshop/docs/diagrams/gen_diagrams.py +++ b/workshops/build_workshop/docs/diagrams/gen_diagrams.py @@ -46,11 +46,11 @@ def box(x, y, w, h, title, lines=None, accent=False, rounded=12, fill=BOX_FILL, cx = x + w / 2 # title ty = y + (22 if lines else h/2 + 5) - s += (f'{escape(title)}\n') if lines: for i, ln in enumerate(lines): - s += (f'{escape(ln)}\n') return s @@ -60,7 +60,7 @@ def zone(x, y, w, h, key): s = (f'\n') s += (f'{escape(z["label"])}\n') + f'font-size="15" font-weight="700" letter-spacing="0.5">{escape(z["label"])}\n') return s @@ -72,9 +72,9 @@ def edge(x1, y1, x2, y2, label=None, mid=None, dashed=False, label_dx=0, label_d lx = (x1 + x2) / 2 + label_dx if mid is None else mid[0] ly = (y1 + y2) / 2 + label_dy if mid is None else mid[1] w = 7.2 * len(label) + 10 - s += (f'\n') - s += (f'\n') + s += (f'{escape(label)}\n') return s @@ -87,9 +87,9 @@ def elbow(pts, label=None, mid=None, dashed=False): f'marker-end="url(#arrow)"/>\n') if label and mid: w = 7.2 * len(label) + 10 - s += (f'\n') - s += (f'\n') + s += (f'{escape(label)}\n') return s @@ -166,65 +166,42 @@ def module_flow(): # =========================================================================== -# ARCHITECTURE (3 zones, aligned rows, top bus for third-party API calls) +# ARCHITECTURE (three simple groups; the data-flow diagram owns sequencing) # =========================================================================== def architecture(): - W, H = 1700, 1000 + W, H = 1500, 650 s = _svg_header(W, H) s += (f'' - f'ClickHouse BUILD Workshop · Architecture (target end state)\n') + f'ClickHouse BUILD Workshop · Where each component runs\n') s += (f'' - f'App-side components run locally; stateful data services run in ClickHouse Cloud. ' - f'Dashed lines are control/OAuth; solid lines are data.\n') + f'Group components by location first. Follow the next diagram for the trip data path.\n') # zones - s += zone(30, 135, 515, 700, "laptop") - s += zone(590, 135, 650, 760, "cloud") - s += zone(1290, 135, 380, 560, "third") - - # --- laptop boxes --- - s += box(60, 190, 455, 62, "frontend", ["React SPA · nginx :8080", "Ops + Historical dashboards, chat"]) - s += box(60, 300, 455, 62, "backend", ["FastAPI :8000", "analytics API + /api/chat (NL-to-SQL)"]) - s += box(60, 410, 455, 56, "otel-collector", ["ClickStack overlay (module 05)"]) - s += box(60, 520, 455, 62, "pg-trip-writer", ["synthetic trips; creates the CDC", "table + publication on first run"]) - s += box(60, 660, 455, 62, "coding agent + clickhousectl", ["Claude Code / Cursor / Codex", "+ ClickHouse skills + docs llms.txt"]) - - # --- cloud boxes --- - s += box(620, 185, 590, 96, "ClickHouse service :8443 TLS", ["nyc_tlc_data (taxi_trips, taxi_zones,", "views, CDC MV) + otel db (logs, traces)"], accent=True) - s += box(620, 330, 280, 88, "ClickPipes", ["Postgres CDC pipe", "snapshot + stream (~60s)"]) - s += box(930, 330, 280, 88, "Managed ClickStack / HyperDX", ["traces + logs UI", "module 05"]) - s += box(620, 500, 590, 82, "Postgres managed by ClickHouse :5432 TLS", ["you create it with clickhousectl (module 03) · public.realtime_trips + pub_taxi"]) - s += box(620, 628, 280, 74, "Remote MCP", ["/mcp + /clickstack (OAuth)"]) - s += box(930, 628, 280, 74, "ClickHouse Agents", ["ai.clickhouse.cloud (module 04)"]) - s += box(620, 748, 590, 60, "Instructor cloud fallback only", ["managed Postgres pool when a trial org cannot create one"], dashed=True, fill="#1C1B14") - - # --- third-party boxes --- - s += box(1315, 195, 330, 74, "Langfuse Cloud", ["chat traces, sessions, cost"]) - s += box(1315, 300, 330, 74, "OpenAI API", ["chat completions (gpt-5.4-mini)"]) - s += box(1315, 410, 330, 88, "NYC TLC dataset", ["public parquet; read once by the", "module 01 seed. Data source only."]) - - # --- edges (laptop internal) --- - s += edge(287, 252, 287, 300, "/api proxy", label_dx=42) - s += edge(180, 362, 180, 410, "OTLP", label_dx=-34) - - # laptop -> cloud (near-horizontal, labels in the gap) - s += elbow([(515, 331), (560, 331), (560, 250), (620, 250)], "SQL · TLS :8443", mid=(567, 300)) - s += elbow([(515, 438), (585, 438), (585, 262), (620, 262)], "traces → otel db", mid=(585, 400), dashed=False) - s += edge(515, 545, 620, 541, "INSERT trips · TLS", label_dy=-8) - s += edge(515, 690, 620, 665, "MCP · OAuth", label_dy=-8) - - # cloud internal (CDC chain + reads) - s += edge(760, 500, 760, 418, "logical replication", label_dx=0, label_dy=-4) - s += edge(760, 330, 760, 281, "CDC rows ~60s", label_dy=-4) - s += edge(1070, 330, 1070, 281, "reads otel db", label_dy=-4) - # agents -> service (RBAC), up the cloud's right margin - s += elbow([(1070, 628), (1215, 628), (1215, 235), (1210, 235)], "RBAC SQL", mid=(1215, 470)) - - # third-party: backend -> OpenAI / Langfuse along the top bus (above zones) - s += elbow([(360, 300), (360, 118), (1480, 118), (1480, 300)], "chat completions", mid=(950, 112)) - s += elbow([(330, 300), (330, 96), (1430, 96), (1430, 195)], "chat traces (Langfuse SDK)", mid=(760, 90)) - # TLC seed -> service (in the cloud/third gap) - s += elbow([(1315, 452), (1262, 452), (1262, 215), (1210, 215)], "url() seed", mid=(1262, 305)) + s += zone(30, 110, 430, 480, "laptop") + s += zone(510, 110, 620, 480, "cloud") + s += zone(1180, 110, 290, 480, "third") + + # Participant laptop: application edge and stateless tools only. + s += box(60, 165, 370, 78, "Frontend + FastAPI", ["dashboards, chat, and API", "runs with Docker Compose"]) + s += box(60, 270, 370, 68, "Load generator", ["creates synthetic trip rows"]) + s += box(60, 365, 370, 68, "OpenTelemetry forwarder", ["sends app telemetry to ClickStack"]) + s += box(60, 460, 370, 78, "Coding agent + clickhousectl", ["workshop commands, MCP,", "and ClickHouse skills"]) + + # ClickHouse Cloud: state, ingestion, observability, and AI surfaces. + s += box(540, 165, 560, 88, "ClickHouse service", ["default.realtime_trips lands here", "nyc_tlc_data.taxi_trips powers the app"], accent=True) + s += box(540, 285, 265, 78, "Managed Postgres", ["public.realtime_trips"]) + s += box(835, 285, 265, 78, "ClickPipes", ["streams Postgres changes"]) + s += box(540, 395, 265, 88, "Managed ClickStack", ["HyperDX traces, logs,", "dashboards, and alerts"]) + s += box(835, 395, 265, 88, "Agents + remote MCP", ["ask questions and let", "the coding agent use tools"]) + + # External services used by the app, kept separate from workshop data storage. + s += box(1210, 175, 230, 82, "OpenAI API", ["chat completions"]) + s += box(1210, 290, 230, 82, "Langfuse Cloud", ["chat traces and cost"]) + s += box(1210, 405, 230, 92, "NYC TLC dataset", ["one-time historical", "seed source"]) + + # Only zone-level relationships. Detailed sequencing belongs in data_flow(). + s += edge(460, 565, 510, 565, "uses", mid=(485, 548)) + s += edge(1130, 565, 1180, 565, "calls", mid=(1155, 548)) s += "\n" return s @@ -318,99 +295,56 @@ def up_arrow(cx, y_from, y_to): # =========================================================================== -# DATA FLOW (four swimlanes: seed, live CDC, read, observe) +# DATA FLOW (one learner-facing left-to-right story) # =========================================================================== def data_flow(): - W, H = 1560, 900 + W, H = 1200, 620 s = _svg_header(W, H) s += (f'' - f'ClickHouse BUILD Workshop · Data flow\n') + f'ClickHouse BUILD Workshop · A trip\'s path\n') s += (f'' - f'How a row moves: seeded once, streamed continuously, then read and observed — ' - f'all through your ClickHouse service.\n') - - LX, LW = 30, W - 60 - TITLE_W = 176 # left title gutter per lane - - def lane(y, h, title, subtitle): - t = (f'\n') - t += (f'\n') - t += (f'{escape(title)}\n') - # wrap subtitle into the gutter - words, line, ln = subtitle.split(), "", 0 - for wd in words: - if len(line) + len(wd) > 20: - t += (f'{escape(line)}\n'); line = wd; ln += 1 - else: - line = (line + " " + wd).strip() - if line: - t += (f'{escape(line)}\n') - return t + f'Read left to right: generate a trip, stream it into ClickHouse, then show it in the app.\n') + + xcols, yrows, bw, bh = [40, 450, 860], [135, 345], 300, 110 + steps = [ + ("Load generator", ["creates synthetic trips", "on your laptop"], False), + ("Managed Postgres", ["source table:", "public.realtime_trips"], False), + ("ClickPipes", ["streams each change", "with Postgres CDC"], False), + ("ClickHouse", ["first landing table:", "default.realtime_trips"], True), + ("Materialized view", ["moves new rows into", "nyc_tlc_data.taxi_trips"], False), + ("Frontend + FastAPI", ["reads taxi_trips for", "the live dashboards"], False), + ] - def fbox(x, y, w, label, sub, accent=False): - return box(x, y, w, 62, label, [sub] if sub else None, accent=accent, rounded=10) - - def harrow(x1, x2, y, label): - return edge(x1, y, x2, y, label, label_dy=-9) - - x0 = LX + TITLE_W + 10 # where the flow chain starts - bw = 216 # box width - gap = 140 # arrow gap (wide enough for the longest label chip) - - def col(i): - return x0 + i*(bw+gap) - - # Lane 1 — SEED (module 01) - y = 96; s += lane(y, 96, "Seed", "one-time, module 01") - by = y + 17 - s += fbox(col(0), by, bw, "NYC TLC parquet", "~3.2M rows, public") - s += fbox(col(2), by, bw, "ClickHouse service", "nyc_tlc_data.taxi_trips", accent=True) - s += harrow(col(0)+bw, col(2)-6, by+31, "url() seed — one statement, module 01") - - # Lane 2 — LIVE CDC (module 03) - y = 212; s += lane(y, 110, "Live CDC", "continuous, module 03") - by = y + 24 - s += fbox(col(0), by, bw, "pg-trip-writer", "synthetic trips") - s += fbox(col(1), by, bw, "Managed Postgres", "public.realtime_trips") - s += fbox(col(2), by, bw, "ClickPipes", "Postgres CDC pipe") - s += fbox(col(3), by, bw, "ClickHouse service", "MV → taxi_trips", accent=True) - s += harrow(col(0)+bw, col(1)-6, by+31, "INSERT · TLS") - s += harrow(col(1)+bw, col(2)-6, by+31, "replication") - s += harrow(col(2)+bw, col(3)-6, by+31, "CDC rows ~60s") - - # Lane 3 — READ (modules 02, 04, 08) - y = 342; s += lane(y, 176, "Read", "modules 02, 04, 08") - by = y + 22 - s += fbox(col(0), by, bw, "ClickHouse service", "nyc_tlc_data", accent=True) - s += fbox(col(1), by, bw, "FastAPI", "safe parameterized SQL") - s += fbox(col(2), by, bw, "Ops + Historical", "React dashboards") - s += harrow(col(0)+bw, col(1)-6, by+31, "SELECT") - s += harrow(col(1)+bw, col(2)-6, by+31, "GET /api/*") - # two more consumers off the service (stacked below) - by2 = y + 104 - s += fbox(col(1), by2, bw, "in-app AI chat", "guarded SELECT (module 08)") - s += fbox(col(2), by2, bw, "ClickHouse Agents", "RBAC SQL (module 04)") - s += elbow([(col(0)+bw/2, by+62), (col(0)+bw/2, by2+31), (col(1)-6, by2+31)], "NL → SQL", mid=(col(0)+bw/2+70, by2+22)) - s += harrow(col(1)+bw, col(2)-6, by2+31, "RBAC SQL") - - # Lane 4 — OBSERVE (modules 05, 06, 07) - y = 538; s += lane(y, 176, "Observe", "modules 05, 06, 07") - by = y + 22 - s += fbox(col(0), by, bw, "backend spans", "clickhouse.query + logs") - s += fbox(col(1), by, bw, "stateless OTel forwarder", "local OTLP :4318") - s += fbox(col(2), by, bw, "otel db", "in your service") - s += fbox(col(3), by, bw, "HyperDX UI", "search, traces, dashboards") - s += harrow(col(0)+bw, col(1)-6, by+31, "OTLP") - s += harrow(col(1)+bw, col(2)-6, by+31, "write") - s += harrow(col(2)+bw, col(3)-6, by+31, "read") - by2 = y + 104 - s += fbox(col(1), by2, bw, "coding agent", "via ClickStack MCP") - s += elbow([(col(1)+bw/2, by2), (col(1)+bw/2, by+62)], None) - s += (f'' - f'clickstack_search / save_dashboard / save_alert\n') + # Numbered snake: left-to-right on row one, then right-to-left on row two. + positions = [ + (xcols[0], yrows[0]), + (xcols[1], yrows[0]), + (xcols[2], yrows[0]), + (xcols[2], yrows[1]), + (xcols[1], yrows[1]), + (xcols[0], yrows[1]), + ] + for i, (title, lines, accent) in enumerate(steps): + x, y = positions[i] + s += box(x, y, bw, bh, title, lines, accent=accent, rounded=12) + s += (f'\n' + f'{i+1}\n') + + # Every connector stays in the gutter between boxes. Label chips are painted + # after each line, so a line can never cut through its text. + s += edge(340, 190, 443, 190, "INSERT", mid=(395, 167)) + s += edge(750, 190, 853, 190, "CDC", mid=(805, 167)) + s += elbow([(1010, 245), (1010, 338)], "lands here", mid=(1010, 302)) + s += edge(860, 400, 757, 400, "feeds", mid=(805, 377)) + s += edge(450, 400, 347, 400, "reads", mid=(395, 377)) + + s += (f'\n') + s += (f'' + f'What the other workshop tools do\n') + s += (f'' + f'ClickStack observes the app · ClickHouse Agents answers data questions · Langfuse traces the chat\n') s += "\n" return s diff --git a/workshops/build_workshop/docs/diagrams/workshop-architecture.svg b/workshops/build_workshop/docs/diagrams/workshop-architecture.svg index 0e36cfa..5ba1a4b 100644 --- a/workshops/build_workshop/docs/diagrams/workshop-architecture.svg +++ b/workshops/build_workshop/docs/diagrams/workshop-architecture.svg @@ -1,104 +1,60 @@ - - + + -ClickHouse BUILD Workshop · Architecture (target end state) -App-side components run locally; stateful data services run in ClickHouse Cloud. Dashed lines are control/OAuth; solid lines are data. - -PARTICIPANT LAPTOP · the NYC-taxi app runs here - -CLICKHOUSE CLOUD · your trial org (you create all of this) - -THIRD-PARTY - -frontend -React SPA · nginx :8080 -Ops + Historical dashboards, chat - -backend -FastAPI :8000 -analytics API + /api/chat (NL-to-SQL) - -otel-collector -ClickStack overlay (module 05) - -pg-trip-writer -synthetic trips; creates the CDC -table + publication on first run - -coding agent + clickhousectl -Claude Code / Cursor / Codex -+ ClickHouse skills + docs llms.txt - -ClickHouse service :8443 TLS -nyc_tlc_data (taxi_trips, taxi_zones, -views, CDC MV) + otel db (logs, traces) - -ClickPipes -Postgres CDC pipe -snapshot + stream (~60s) - -Managed ClickStack / HyperDX -traces + logs UI -module 05 - -Postgres managed by ClickHouse :5432 TLS -you create it with clickhousectl (module 03) · public.realtime_trips + pub_taxi - -Remote MCP -/mcp + /clickstack (OAuth) - -ClickHouse Agents -ai.clickhouse.cloud (module 04) - -Instructor cloud fallback only -managed Postgres pool when a trial org cannot create one - -Langfuse Cloud -chat traces, sessions, cost - -OpenAI API -chat completions (gpt-5.4-mini) - -NYC TLC dataset -public parquet; read once by the -module 01 seed. Data source only. - - -/api proxy - - -OTLP - - -SQL · TLS :8443 - - -traces → otel db - - -INSERT trips · TLS - - -MCP · OAuth - - -logical replication - - -CDC rows ~60s - - -reads otel db - - -RBAC SQL - - -chat completions - - -chat traces (Langfuse SDK) - - -url() seed +ClickHouse BUILD Workshop · Where each component runs +Group components by location first. Follow the next diagram for the trip data path. + +PARTICIPANT LAPTOP · the NYC-taxi app runs here + +CLICKHOUSE CLOUD · your trial org (you create all of this) + +THIRD-PARTY + +Frontend + FastAPI +dashboards, chat, and API +runs with Docker Compose + +Load generator +creates synthetic trip rows + +OpenTelemetry forwarder +sends app telemetry to ClickStack + +Coding agent + clickhousectl +workshop commands, MCP, +and ClickHouse skills + +ClickHouse service +default.realtime_trips lands here +nyc_tlc_data.taxi_trips powers the app + +Managed Postgres +public.realtime_trips + +ClickPipes +streams Postgres changes + +Managed ClickStack +HyperDX traces, logs, +dashboards, and alerts + +Agents + remote MCP +ask questions and let +the coding agent use tools + +OpenAI API +chat completions + +Langfuse Cloud +chat traces and cost + +NYC TLC dataset +one-time historical +seed source + + +uses + + +calls diff --git a/workshops/build_workshop/docs/diagrams/workshop-data-flow.svg b/workshops/build_workshop/docs/diagrams/workshop-data-flow.svg index e60ec1a..a36109a 100644 --- a/workshops/build_workshop/docs/diagrams/workshop-data-flow.svg +++ b/workshops/build_workshop/docs/diagrams/workshop-data-flow.svg @@ -1,105 +1,60 @@ - - + + -ClickHouse BUILD Workshop · Data flow -How a row moves: seeded once, streamed continuously, then read and observed — all through your ClickHouse service. - - -Seed -one-time, module 01 - -NYC TLC parquet -~3.2M rows, public - -ClickHouse service -nyc_tlc_data.taxi_trips - - -url() seed — one statement, module 01 - - -Live CDC -continuous, module 03 - -pg-trip-writer -synthetic trips - -Managed Postgres -public.realtime_trips - -ClickPipes -Postgres CDC pipe - -ClickHouse service -MV → taxi_trips - - -INSERT · TLS - - -replication - - -CDC rows ~60s - - -Read -modules 02, 04, 08 - -ClickHouse service -nyc_tlc_data - -FastAPI -safe parameterized SQL - -Ops + Historical -React dashboards - - -SELECT - - -GET /api/* - -in-app AI chat -guarded SELECT (module 08) - -ClickHouse Agents -RBAC SQL (module 04) - - -NL → SQL - - -RBAC SQL - - -Observe -modules 05, 06, 07 - -backend spans -clickhouse.query + logs - -stateless OTel forwarder -local OTLP :4318 - -otel db -in your service - -HyperDX UI -search, traces, dashboards - - -OTLP - - -write - - -read - -coding agent -via ClickStack MCP - -clickstack_search / save_dashboard / save_alert +ClickHouse BUILD Workshop · A trip's path +Read left to right: generate a trip, stream it into ClickHouse, then show it in the app. + +Load generator +creates synthetic trips +on your laptop + +1 + +Managed Postgres +source table: +public.realtime_trips + +2 + +ClickPipes +streams each change +with Postgres CDC + +3 + +ClickHouse +first landing table: +default.realtime_trips + +4 + +Materialized view +moves new rows into +nyc_tlc_data.taxi_trips + +5 + +Frontend + FastAPI +reads taxi_trips for +the live dashboards + +6 + + +INSERT + + +CDC + + +lands here + + +feeds + + +reads + +What the other workshop tools do +ClickStack observes the app · ClickHouse Agents answers data questions · Langfuse traces the chat diff --git a/workshops/build_workshop/playbook/content/docs/index.mdx b/workshops/build_workshop/playbook/content/docs/index.mdx index 7a2a11b..a7cbdbb 100644 --- a/workshops/build_workshop/playbook/content/docs/index.mdx +++ b/workshops/build_workshop/playbook/content/docs/index.mdx @@ -96,17 +96,17 @@ and OpenAI are separate hosted services. ### Architecture (target end state) -Here is how those pieces come together: the app edge on your laptop; ClickHouse-managed -state in your trial; and separate hosted OpenAI and Langfuse services. +First, group the pieces by where they run: the stateless app and tools on your laptop, +stateful services in ClickHouse Cloud, and the separate hosted AI services. -![Workshop architecture: participant laptop, your ClickHouse Cloud trial (service, ClickPipes, managed Postgres), and third-party services](/workshop-architecture.svg) +![Workshop components grouped into participant laptop, ClickHouse Cloud, and external hosted services](/workshop-architecture.svg) ### How data flows -The same picture, followed as data: seeded once from object storage, streamed continuously -via CDC, then read by the dashboards, chat, and agents, and observed through ClickStack. +Now follow one live trip from the local load generator through managed Postgres and +ClickPipes, into `default.realtime_trips`, and finally into the application dashboards. -![Data flow: four lanes — one-time seed, live CDC, read paths, and observability — all through your ClickHouse service](/workshop-data-flow.svg) +![A live trip flows from the load generator to managed Postgres, through ClickPipes into default.realtime_trips, then through a materialized view to the app](/workshop-data-flow.svg) The diagrams above are generated from `workshops/build_workshop/docs/diagrams/gen_diagrams.py` (edit the script and re-run it to regenerate the SVGs) — see the module flow below. diff --git a/workshops/build_workshop/playbook/public/workshop-architecture.svg b/workshops/build_workshop/playbook/public/workshop-architecture.svg index 0e36cfa..5ba1a4b 100644 --- a/workshops/build_workshop/playbook/public/workshop-architecture.svg +++ b/workshops/build_workshop/playbook/public/workshop-architecture.svg @@ -1,104 +1,60 @@ - - + + -ClickHouse BUILD Workshop · Architecture (target end state) -App-side components run locally; stateful data services run in ClickHouse Cloud. Dashed lines are control/OAuth; solid lines are data. - -PARTICIPANT LAPTOP · the NYC-taxi app runs here - -CLICKHOUSE CLOUD · your trial org (you create all of this) - -THIRD-PARTY - -frontend -React SPA · nginx :8080 -Ops + Historical dashboards, chat - -backend -FastAPI :8000 -analytics API + /api/chat (NL-to-SQL) - -otel-collector -ClickStack overlay (module 05) - -pg-trip-writer -synthetic trips; creates the CDC -table + publication on first run - -coding agent + clickhousectl -Claude Code / Cursor / Codex -+ ClickHouse skills + docs llms.txt - -ClickHouse service :8443 TLS -nyc_tlc_data (taxi_trips, taxi_zones, -views, CDC MV) + otel db (logs, traces) - -ClickPipes -Postgres CDC pipe -snapshot + stream (~60s) - -Managed ClickStack / HyperDX -traces + logs UI -module 05 - -Postgres managed by ClickHouse :5432 TLS -you create it with clickhousectl (module 03) · public.realtime_trips + pub_taxi - -Remote MCP -/mcp + /clickstack (OAuth) - -ClickHouse Agents -ai.clickhouse.cloud (module 04) - -Instructor cloud fallback only -managed Postgres pool when a trial org cannot create one - -Langfuse Cloud -chat traces, sessions, cost - -OpenAI API -chat completions (gpt-5.4-mini) - -NYC TLC dataset -public parquet; read once by the -module 01 seed. Data source only. - - -/api proxy - - -OTLP - - -SQL · TLS :8443 - - -traces → otel db - - -INSERT trips · TLS - - -MCP · OAuth - - -logical replication - - -CDC rows ~60s - - -reads otel db - - -RBAC SQL - - -chat completions - - -chat traces (Langfuse SDK) - - -url() seed +ClickHouse BUILD Workshop · Where each component runs +Group components by location first. Follow the next diagram for the trip data path. + +PARTICIPANT LAPTOP · the NYC-taxi app runs here + +CLICKHOUSE CLOUD · your trial org (you create all of this) + +THIRD-PARTY + +Frontend + FastAPI +dashboards, chat, and API +runs with Docker Compose + +Load generator +creates synthetic trip rows + +OpenTelemetry forwarder +sends app telemetry to ClickStack + +Coding agent + clickhousectl +workshop commands, MCP, +and ClickHouse skills + +ClickHouse service +default.realtime_trips lands here +nyc_tlc_data.taxi_trips powers the app + +Managed Postgres +public.realtime_trips + +ClickPipes +streams Postgres changes + +Managed ClickStack +HyperDX traces, logs, +dashboards, and alerts + +Agents + remote MCP +ask questions and let +the coding agent use tools + +OpenAI API +chat completions + +Langfuse Cloud +chat traces and cost + +NYC TLC dataset +one-time historical +seed source + + +uses + + +calls diff --git a/workshops/build_workshop/playbook/public/workshop-data-flow.svg b/workshops/build_workshop/playbook/public/workshop-data-flow.svg index e60ec1a..a36109a 100644 --- a/workshops/build_workshop/playbook/public/workshop-data-flow.svg +++ b/workshops/build_workshop/playbook/public/workshop-data-flow.svg @@ -1,105 +1,60 @@ - - + + -ClickHouse BUILD Workshop · Data flow -How a row moves: seeded once, streamed continuously, then read and observed — all through your ClickHouse service. - - -Seed -one-time, module 01 - -NYC TLC parquet -~3.2M rows, public - -ClickHouse service -nyc_tlc_data.taxi_trips - - -url() seed — one statement, module 01 - - -Live CDC -continuous, module 03 - -pg-trip-writer -synthetic trips - -Managed Postgres -public.realtime_trips - -ClickPipes -Postgres CDC pipe - -ClickHouse service -MV → taxi_trips - - -INSERT · TLS - - -replication - - -CDC rows ~60s - - -Read -modules 02, 04, 08 - -ClickHouse service -nyc_tlc_data - -FastAPI -safe parameterized SQL - -Ops + Historical -React dashboards - - -SELECT - - -GET /api/* - -in-app AI chat -guarded SELECT (module 08) - -ClickHouse Agents -RBAC SQL (module 04) - - -NL → SQL - - -RBAC SQL - - -Observe -modules 05, 06, 07 - -backend spans -clickhouse.query + logs - -stateless OTel forwarder -local OTLP :4318 - -otel db -in your service - -HyperDX UI -search, traces, dashboards - - -OTLP - - -write - - -read - -coding agent -via ClickStack MCP - -clickstack_search / save_dashboard / save_alert +ClickHouse BUILD Workshop · A trip's path +Read left to right: generate a trip, stream it into ClickHouse, then show it in the app. + +Load generator +creates synthetic trips +on your laptop + +1 + +Managed Postgres +source table: +public.realtime_trips + +2 + +ClickPipes +streams each change +with Postgres CDC + +3 + +ClickHouse +first landing table: +default.realtime_trips + +4 + +Materialized view +moves new rows into +nyc_tlc_data.taxi_trips + +5 + +Frontend + FastAPI +reads taxi_trips for +the live dashboards + +6 + + +INSERT + + +CDC + + +lands here + + +feeds + + +reads + +What the other workshop tools do +ClickStack observes the app · ClickHouse Agents answers data questions · Langfuse traces the chat From c17eed688705817f293a6738f798b0eb06c63c4e Mon Sep 17 00:00:00 2001 From: Maruthi Prithivi Date: Tue, 28 Jul 2026 15:36:05 +0800 Subject: [PATCH 4/5] style(design): FINDING-002 improve diagram readability --- .../docs/diagrams/gen_diagrams.py | 55 +++++---- .../docs/diagrams/workshop-architecture.svg | 108 +++++++++--------- .../docs/diagrams/workshop-data-flow.svg | 38 +++--- .../playbook/public/workshop-architecture.svg | 108 +++++++++--------- .../playbook/public/workshop-data-flow.svg | 38 +++--- 5 files changed, 166 insertions(+), 181 deletions(-) diff --git a/workshops/build_workshop/docs/diagrams/gen_diagrams.py b/workshops/build_workshop/docs/diagrams/gen_diagrams.py index fa39dcb..d4317e7 100644 --- a/workshops/build_workshop/docs/diagrams/gen_diagrams.py +++ b/workshops/build_workshop/docs/diagrams/gen_diagrams.py @@ -20,9 +20,9 @@ # zone tints (muted, harmonious) ZONES = { - "laptop": {"fill": "#1B2531", "stroke": "#3E5A78", "label": "PARTICIPANT LAPTOP · the NYC-taxi app runs here"}, - "cloud": {"fill": "#211F14", "stroke": YELLOW, "label": "CLICKHOUSE CLOUD · your trial org (you create all of this)"}, - "third": {"fill": "#1E1E22", "stroke": "#54545C", "label": "THIRD-PARTY"}, + "laptop": {"fill": "#1B2531", "stroke": "#3E5A78", "label": "PARTICIPANT LAPTOP · local app + tools"}, + "cloud": {"fill": "#211F14", "stroke": YELLOW, "label": "CLICKHOUSE CLOUD · your trial org"}, + "third": {"fill": "#1E1E22", "stroke": "#54545C", "label": "EXTERNAL SERVICES"}, } @@ -46,21 +46,22 @@ def box(x, y, w, h, title, lines=None, accent=False, rounded=12, fill=BOX_FILL, cx = x + w / 2 # title ty = y + (22 if lines else h/2 + 5) - s += (f'{escape(title)}\n') if lines: for i, ln in enumerate(lines): - s += (f'{escape(ln)}\n') return s def zone(x, y, w, h, key): z = ZONES[key] + label_color = YELLOW if key == "cloud" else SUBINK s = (f'\n') - s += (f'{escape(z["label"])}\n') + s += (f'{escape(z["label"])}\n') return s @@ -169,39 +170,35 @@ def module_flow(): # ARCHITECTURE (three simple groups; the data-flow diagram owns sequencing) # =========================================================================== def architecture(): - W, H = 1500, 650 + W, H = 1200, 650 s = _svg_header(W, H) s += (f'' f'ClickHouse BUILD Workshop · Where each component runs\n') s += (f'' - f'Group components by location first. Follow the next diagram for the trip data path.\n') + f'Grouped by location; no data direction is implied. Follow the next diagram for the trip path.\n') # zones - s += zone(30, 110, 430, 480, "laptop") - s += zone(510, 110, 620, 480, "cloud") - s += zone(1180, 110, 290, 480, "third") + s += zone(30, 110, 330, 480, "laptop") + s += zone(400, 110, 500, 480, "cloud") + s += zone(940, 110, 230, 480, "third") # Participant laptop: application edge and stateless tools only. - s += box(60, 165, 370, 78, "Frontend + FastAPI", ["dashboards, chat, and API", "runs with Docker Compose"]) - s += box(60, 270, 370, 68, "Load generator", ["creates synthetic trip rows"]) - s += box(60, 365, 370, 68, "OpenTelemetry forwarder", ["sends app telemetry to ClickStack"]) - s += box(60, 460, 370, 78, "Coding agent + clickhousectl", ["workshop commands, MCP,", "and ClickHouse skills"]) + s += box(50, 165, 290, 78, "Frontend + FastAPI", ["dashboards, chat, and API", "runs with Docker Compose"]) + s += box(50, 270, 290, 68, "Load generator", ["creates synthetic trip rows"]) + s += box(50, 365, 290, 68, "OTel forwarder", ["sends telemetry to ClickStack"]) + s += box(50, 460, 290, 78, "Coding agent + CLI", ["workshop commands, MCP,", "and ClickHouse skills"]) # ClickHouse Cloud: state, ingestion, observability, and AI surfaces. - s += box(540, 165, 560, 88, "ClickHouse service", ["default.realtime_trips lands here", "nyc_tlc_data.taxi_trips powers the app"], accent=True) - s += box(540, 285, 265, 78, "Managed Postgres", ["public.realtime_trips"]) - s += box(835, 285, 265, 78, "ClickPipes", ["streams Postgres changes"]) - s += box(540, 395, 265, 88, "Managed ClickStack", ["HyperDX traces, logs,", "dashboards, and alerts"]) - s += box(835, 395, 265, 88, "Agents + remote MCP", ["ask questions and let", "the coding agent use tools"]) + s += box(425, 165, 450, 88, "ClickHouse service", ["default.realtime_trips lands here", "nyc_tlc_data.taxi_trips powers the app"], accent=True) + s += box(425, 285, 215, 78, "Managed Postgres", ["public.realtime_trips"]) + s += box(660, 285, 215, 78, "ClickPipes", ["streams Postgres changes"]) + s += box(425, 395, 215, 88, "Managed ClickStack", ["HyperDX traces, logs,", "dashboards, and alerts"]) + s += box(660, 395, 215, 88, "Agents + MCP", ["data questions and", "coding-agent tools"]) # External services used by the app, kept separate from workshop data storage. - s += box(1210, 175, 230, 82, "OpenAI API", ["chat completions"]) - s += box(1210, 290, 230, 82, "Langfuse Cloud", ["chat traces and cost"]) - s += box(1210, 405, 230, 92, "NYC TLC dataset", ["one-time historical", "seed source"]) - - # Only zone-level relationships. Detailed sequencing belongs in data_flow(). - s += edge(460, 565, 510, 565, "uses", mid=(485, 548)) - s += edge(1130, 565, 1180, 565, "calls", mid=(1155, 548)) + s += box(960, 175, 190, 82, "OpenAI API", ["chat completions"]) + s += box(960, 290, 190, 82, "Langfuse Cloud", ["chat traces and cost"]) + s += box(960, 405, 190, 92, "NYC TLC dataset", ["one-time historical", "seed source"]) s += "\n" return s @@ -303,7 +300,7 @@ def data_flow(): s += (f'' f'ClickHouse BUILD Workshop · A trip\'s path\n') s += (f'' - f'Read left to right: generate a trip, stream it into ClickHouse, then show it in the app.\n') + f'Follow steps 1–6: across the top, then back across the bottom.\n') xcols, yrows, bw, bh = [40, 450, 860], [135, 345], 300, 110 steps = [ diff --git a/workshops/build_workshop/docs/diagrams/workshop-architecture.svg b/workshops/build_workshop/docs/diagrams/workshop-architecture.svg index 5ba1a4b..f261096 100644 --- a/workshops/build_workshop/docs/diagrams/workshop-architecture.svg +++ b/workshops/build_workshop/docs/diagrams/workshop-architecture.svg @@ -1,60 +1,54 @@ - - + + ClickHouse BUILD Workshop · Where each component runs -Group components by location first. Follow the next diagram for the trip data path. - -PARTICIPANT LAPTOP · the NYC-taxi app runs here - -CLICKHOUSE CLOUD · your trial org (you create all of this) - -THIRD-PARTY - -Frontend + FastAPI -dashboards, chat, and API -runs with Docker Compose - -Load generator -creates synthetic trip rows - -OpenTelemetry forwarder -sends app telemetry to ClickStack - -Coding agent + clickhousectl -workshop commands, MCP, -and ClickHouse skills - -ClickHouse service -default.realtime_trips lands here -nyc_tlc_data.taxi_trips powers the app - -Managed Postgres -public.realtime_trips - -ClickPipes -streams Postgres changes - -Managed ClickStack -HyperDX traces, logs, -dashboards, and alerts - -Agents + remote MCP -ask questions and let -the coding agent use tools - -OpenAI API -chat completions - -Langfuse Cloud -chat traces and cost - -NYC TLC dataset -one-time historical -seed source - - -uses - - -calls +Grouped by location; no data direction is implied. Follow the next diagram for the trip path. + +PARTICIPANT LAPTOP · local app + tools + +CLICKHOUSE CLOUD · your trial org + +EXTERNAL SERVICES + +Frontend + FastAPI +dashboards, chat, and API +runs with Docker Compose + +Load generator +creates synthetic trip rows + +OTel forwarder +sends telemetry to ClickStack + +Coding agent + CLI +workshop commands, MCP, +and ClickHouse skills + +ClickHouse service +default.realtime_trips lands here +nyc_tlc_data.taxi_trips powers the app + +Managed Postgres +public.realtime_trips + +ClickPipes +streams Postgres changes + +Managed ClickStack +HyperDX traces, logs, +dashboards, and alerts + +Agents + MCP +data questions and +coding-agent tools + +OpenAI API +chat completions + +Langfuse Cloud +chat traces and cost + +NYC TLC dataset +one-time historical +seed source diff --git a/workshops/build_workshop/docs/diagrams/workshop-data-flow.svg b/workshops/build_workshop/docs/diagrams/workshop-data-flow.svg index a36109a..dd9f36b 100644 --- a/workshops/build_workshop/docs/diagrams/workshop-data-flow.svg +++ b/workshops/build_workshop/docs/diagrams/workshop-data-flow.svg @@ -2,41 +2,41 @@ ClickHouse BUILD Workshop · A trip's path -Read left to right: generate a trip, stream it into ClickHouse, then show it in the app. +Follow steps 1–6: across the top, then back across the bottom. -Load generator -creates synthetic trips -on your laptop +Load generator +creates synthetic trips +on your laptop 1 -Managed Postgres -source table: -public.realtime_trips +Managed Postgres +source table: +public.realtime_trips 2 -ClickPipes -streams each change -with Postgres CDC +ClickPipes +streams each change +with Postgres CDC 3 -ClickHouse -first landing table: -default.realtime_trips +ClickHouse +first landing table: +default.realtime_trips 4 -Materialized view -moves new rows into -nyc_tlc_data.taxi_trips +Materialized view +moves new rows into +nyc_tlc_data.taxi_trips 5 -Frontend + FastAPI -reads taxi_trips for -the live dashboards +Frontend + FastAPI +reads taxi_trips for +the live dashboards 6 diff --git a/workshops/build_workshop/playbook/public/workshop-architecture.svg b/workshops/build_workshop/playbook/public/workshop-architecture.svg index 5ba1a4b..f261096 100644 --- a/workshops/build_workshop/playbook/public/workshop-architecture.svg +++ b/workshops/build_workshop/playbook/public/workshop-architecture.svg @@ -1,60 +1,54 @@ - - + + ClickHouse BUILD Workshop · Where each component runs -Group components by location first. Follow the next diagram for the trip data path. - -PARTICIPANT LAPTOP · the NYC-taxi app runs here - -CLICKHOUSE CLOUD · your trial org (you create all of this) - -THIRD-PARTY - -Frontend + FastAPI -dashboards, chat, and API -runs with Docker Compose - -Load generator -creates synthetic trip rows - -OpenTelemetry forwarder -sends app telemetry to ClickStack - -Coding agent + clickhousectl -workshop commands, MCP, -and ClickHouse skills - -ClickHouse service -default.realtime_trips lands here -nyc_tlc_data.taxi_trips powers the app - -Managed Postgres -public.realtime_trips - -ClickPipes -streams Postgres changes - -Managed ClickStack -HyperDX traces, logs, -dashboards, and alerts - -Agents + remote MCP -ask questions and let -the coding agent use tools - -OpenAI API -chat completions - -Langfuse Cloud -chat traces and cost - -NYC TLC dataset -one-time historical -seed source - - -uses - - -calls +Grouped by location; no data direction is implied. Follow the next diagram for the trip path. + +PARTICIPANT LAPTOP · local app + tools + +CLICKHOUSE CLOUD · your trial org + +EXTERNAL SERVICES + +Frontend + FastAPI +dashboards, chat, and API +runs with Docker Compose + +Load generator +creates synthetic trip rows + +OTel forwarder +sends telemetry to ClickStack + +Coding agent + CLI +workshop commands, MCP, +and ClickHouse skills + +ClickHouse service +default.realtime_trips lands here +nyc_tlc_data.taxi_trips powers the app + +Managed Postgres +public.realtime_trips + +ClickPipes +streams Postgres changes + +Managed ClickStack +HyperDX traces, logs, +dashboards, and alerts + +Agents + MCP +data questions and +coding-agent tools + +OpenAI API +chat completions + +Langfuse Cloud +chat traces and cost + +NYC TLC dataset +one-time historical +seed source diff --git a/workshops/build_workshop/playbook/public/workshop-data-flow.svg b/workshops/build_workshop/playbook/public/workshop-data-flow.svg index a36109a..dd9f36b 100644 --- a/workshops/build_workshop/playbook/public/workshop-data-flow.svg +++ b/workshops/build_workshop/playbook/public/workshop-data-flow.svg @@ -2,41 +2,41 @@ ClickHouse BUILD Workshop · A trip's path -Read left to right: generate a trip, stream it into ClickHouse, then show it in the app. +Follow steps 1–6: across the top, then back across the bottom. -Load generator -creates synthetic trips -on your laptop +Load generator +creates synthetic trips +on your laptop 1 -Managed Postgres -source table: -public.realtime_trips +Managed Postgres +source table: +public.realtime_trips 2 -ClickPipes -streams each change -with Postgres CDC +ClickPipes +streams each change +with Postgres CDC 3 -ClickHouse -first landing table: -default.realtime_trips +ClickHouse +first landing table: +default.realtime_trips 4 -Materialized view -moves new rows into -nyc_tlc_data.taxi_trips +Materialized view +moves new rows into +nyc_tlc_data.taxi_trips 5 -Frontend + FastAPI -reads taxi_trips for -the live dashboards +Frontend + FastAPI +reads taxi_trips for +the live dashboards 6 From dad716da8d98ba0d8f83d2809081bbee5b42448f Mon Sep 17 00:00:00 2001 From: Maruthi Prithivi Date: Tue, 28 Jul 2026 15:42:01 +0800 Subject: [PATCH 5/5] docs(workshop): sync archive and collector references --- workshops/build_workshop/app/OBSERVABILITY.md | 4 ++-- .../content/docs/instructor/05-clickstack.mdx | 2 +- .../docs/instructor/06b-ai-sre-librechat.mdx | 4 ++-- .../docs/learner/06b-ai-sre-librechat.mdx | 2 +- workshops/build_workshop/scripts/check-docs.sh | 16 ++++++++++++++++ 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/workshops/build_workshop/app/OBSERVABILITY.md b/workshops/build_workshop/app/OBSERVABILITY.md index dfcf758..c7d03e0 100644 --- a/workshops/build_workshop/app/OBSERVABILITY.md +++ b/workshops/build_workshop/app/OBSERVABILITY.md @@ -107,12 +107,12 @@ cp .env.workshop.example .env.workshop # 2) Bring up the stack with the overlay: docker compose --env-file .env.workshop \ - -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d + -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d --build # Optional: also scrape raw container stdout (see VERIFY-LIVE): docker compose --env-file .env.workshop \ -f docker-compose.workshop.yml -f docker-compose.otel.yml \ - --profile container-logs up -d + --profile container-logs up -d --build ``` ## Environment variables diff --git a/workshops/build_workshop/playbook/content/docs/instructor/05-clickstack.mdx b/workshops/build_workshop/playbook/content/docs/instructor/05-clickstack.mdx index b6b869d..404d9de 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/05-clickstack.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/05-clickstack.mdx @@ -44,6 +44,6 @@ collector as early as this module allows and keep it running. ## Reset steps - Restart with both compose files: - `docker compose --env-file .env.workshop -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d`. + `docker compose --env-file .env.workshop -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d --build`. - In the Cloud console, open the service, choose **ClickStack**, and relaunch the hosted UI if the SSO session expired. diff --git a/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx b/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx index 34369ab..612e1cc 100644 --- a/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx +++ b/workshops/build_workshop/playbook/content/docs/instructor/06b-ai-sre-librechat.mdx @@ -48,14 +48,14 @@ LibreChat documents remote MCP OAuth, per-user credentials, and agent sharing in ## Talk track -- Module 06a is an agent in the editor; 06b is the same evidence chain in a hosted chat UI. +- Module 06 is an agent in the editor; 06b was the same evidence chain in a hosted chat UI. - LibreChat is a client surface. ClickStack/HyperDX and the telemetry remain managed in ClickHouse Cloud; GitHub remains the source-of-truth service. - Each learner owns their ClickHouse OAuth session and GitHub PAT. ## Common failures -- **Hosted URL is unavailable**: skip 06b and continue with Module 06a. Do not improvise a +- **Hosted URL is unavailable**: skip this archived module and continue with Module 06. Do not improvise a local Docker deployment during the workshop. - **OAuth returns to the wrong host**: correct LibreChat's public `DOMAIN_SERVER` and `DOMAIN_CLIENT` to the HTTPS deployment URL, then reconnect. diff --git a/workshops/build_workshop/playbook/content/docs/learner/06b-ai-sre-librechat.mdx b/workshops/build_workshop/playbook/content/docs/learner/06b-ai-sre-librechat.mdx index c52abca..f314a8f 100644 --- a/workshops/build_workshop/playbook/content/docs/learner/06b-ai-sre-librechat.mdx +++ b/workshops/build_workshop/playbook/content/docs/learner/06b-ai-sre-librechat.mdx @@ -29,7 +29,7 @@ starting this module. ## Why -Module 06a put the agent in your editor. Here a chat-native SRE agent investigates two +Module 06 put the agent in your editor. Here a chat-native SRE agent investigates two remote planes at once: ClickStack telemetry and the public workshop source on GitHub. ## Step 1 — Sign in to hosted LibreChat diff --git a/workshops/build_workshop/scripts/check-docs.sh b/workshops/build_workshop/scripts/check-docs.sh index f7691d6..6aac6a2 100755 --- a/workshops/build_workshop/scripts/check-docs.sh +++ b/workshops/build_workshop/scripts/check-docs.sh @@ -102,6 +102,22 @@ require_fixed \ '[Module 07](/docs/instructor/07-break-and-fix)' \ "${CONTENT}/instructor/06b-ai-sre-librechat.mdx" +for file in \ + "${ROOT}/app/README.md" \ + "${ROOT}/app/OBSERVABILITY.md" \ + "${CONTENT}/learner/05-clickstack.mdx" \ + "${CONTENT}/instructor/05-clickstack.mdx"; do + require_fixed \ + "ClickStack overlay startup must rebuild the frontend telemetry bundle" \ + 'docker-compose.otel.yml up -d --build' \ + "${file}" +done + +require_fixed \ + "the optional container-log overlay must also rebuild the frontend" \ + '--profile container-logs up -d --build' \ + "${ROOT}/app/OBSERVABILITY.md" + require_count() { local description=$1 local expected=$2