feat: wire up Template Builder session telemetry endpoint (#27124)

`TemplateBuilderSession` telemetry types and telemetry-server ingestion
were added in earlier PRs (#25082, coder/coder-telemetry-server#41), but
no code ever produced session events. This adds the missing producer.

**Backend**: `POST /api/v2/templatebuilder/sessions` reports wizard
entry and compose completion events directly via
`api.Telemetry.Report()`, using the same inline pattern as
`NetworkEvents` and `UserTailnetConnections`. No database migration or
`createSnapshot()` changes needed. RBAC requires `policy.ActionCreate`
on `ResourceTemplate.AnyOrganization()`, matching the compose endpoint.

**Frontend**: The template builder wizard fires `wizard_entry` on page
mount and `compose_completion` on create success or failure. A
client-generated session ID (UUID) correlates the two events for the
same wizard visit, enabling precise funnel analysis and abandonment
detection in BigQuery. Duration is tracked via `Date.now()` in the
wizard state.

Closes https://linear.app/codercom/issue/DEVEX-599

<details>
<summary>Implementation plan</summary>

## Root Cause Analysis

The DEVEX-599 ticket diagnosis suggested missing DB tables, queries, and
`eg.Go` blocks. That diagnosis assumes the DB-backed periodic snapshot
path is required. It is not. Investigation shows two telemetry reporting
patterns in the codebase:

1. **DB-backed periodic snapshots** (`createSnapshot()` with `eg.Go`
blocks): Used for durable entities like workspaces, templates, users.
2. **Direct inline reporting**
(`api.Telemetry.Report(&telemetry.Snapshot{...})`): Used for ephemeral
events like `NetworkEvents`, `UserTailnetConnections`, `CLIInvocations`.

Template builder sessions are ephemeral events, so the direct inline
reporting pattern is the correct fit.

## Backend Changes

- `codersdk/templatebuilder.go`: `TemplateBuilderSessionRequest` type
with `SessionID`, `EventType` enum, `TemplateBuilderSession()` client
method
- `coderd/coderd.go`: Route registration in `/templatebuilder` group
- `coderd/templatebuilder_handler.go`: Handler with RBAC check, request
validation, session ID fallback, and inline telemetry report
- `coderd/templatebuilder_handler_test.go`: Tests for wizard entry,
compose completion, invalid event type, disabled feature, and member
RBAC rejection

## Frontend Changes

- `site/src/api/api.ts`: `recordTemplateBuilderSession` API method
- `site/src/api/queries/templateBuilder.ts`: React Query mutation
- `site/src/pages/TemplateBuilder/wizardState.ts`: `sessionId` and
`enteredAt` fields, `createWizardState()` factory for per-mount
initialization
- `site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx`:
`sessionId` prop, `useReducer` initializer form
- `site/src/pages/TemplateBuilder/TemplateBuilderPage.tsx`: Telemetry
calls for wizard entry (on mount) and compose completion (on create
success/failure)

</details>

> 🤖 Generated by Coder Agents

---------

Co-authored-by: Coder Agent <agent@coder.com>
This commit is contained in:
Jeremy Ruppel
2026-07-27 16:10:40 -04:00
committed by GitHub
co-authored by Coder Agent
parent daf655dff8
commit 51ac968d5a
15 changed files with 570 additions and 21 deletions
+46
View File
@@ -12614,6 +12614,52 @@ Restarts will only happen on weekdays in this list on weeks which line up with W
|-----------|---------------------------------------------------------------------------|----------|--------------|-------------|
| `modules` | array of [codersdk.TemplateBuilderModule](#codersdktemplatebuildermodule) | false | | |
## codersdk.TemplateBuilderSessionEventType
```json
"wizard_entry"
```
### Properties
#### Enumerated Values
| Value(s) |
|--------------------------------------|
| `compose_completion`, `wizard_entry` |
## codersdk.TemplateBuilderSessionRequest
```json
{
"base_template_id": "string",
"duration_seconds": 0,
"event_type": "wizard_entry",
"module_ids": [
"string"
],
"session_id": "1ffd059c-17ea-40a8-8aef-70fd0307db82",
"success": true
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
|--------------------|--------------------------------------------------------------------------------------|----------|--------------|-------------|
| `base_template_id` | string | false | | |
| `duration_seconds` | number | false | | |
| `event_type` | [codersdk.TemplateBuilderSessionEventType](#codersdktemplatebuildersessioneventtype) | true | | |
| `module_ids` | array of string | false | | |
| `session_id` | string | true | | |
| `success` | boolean | false | | |
#### Enumerated Values
| Property | Value(s) |
|--------------|--------------------------------------|
| `event_type` | `compose_completion`, `wizard_entry` |
## codersdk.TemplateBuilderVariableType
```json
+42
View File
@@ -290,3 +290,45 @@ curl -X GET http://coder-server:8080/api/v2/templatebuilder/modules \
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.TemplateBuilderModulesResponse](schemas.md#codersdktemplatebuildermodulesresponse) |
To perform this operation, you must be authenticated. [Learn more](authentication.md).
## Report a template builder session event
### Code samples
```sh
# Example request using curl
curl -X POST http://coder-server:8080/api/v2/templatebuilder/sessions \
-H 'Content-Type: application/json' \
-H 'Coder-Session-Token: API_KEY'
```
`POST /api/v2/templatebuilder/sessions`
> Body parameter
```json
{
"base_template_id": "string",
"duration_seconds": 0,
"event_type": "wizard_entry",
"module_ids": [
"string"
],
"session_id": "1ffd059c-17ea-40a8-8aef-70fd0307db82",
"success": true
}
```
### Parameters
| Name | In | Type | Required | Description |
|--------|------|--------------------------------------------------------------------------------------------|----------|---------------|
| `body` | body | [codersdk.TemplateBuilderSessionRequest](schemas.md#codersdktemplatebuildersessionrequest) | true | Session event |
### Responses
| Status | Meaning | Description | Schema |
|--------|-----------------------------------------------------------------|-------------|--------|
| 204 | [No Content](https://tools.ietf.org/html/rfc7231#section-6.3.5) | No Content | |
To perform this operation, you must be authenticated. [Learn more](authentication.md).