Skip to content

Commit f67c54f

Browse files
ArtieReusandypf
andauthored
feat(metrics): add semantic route tracking with dynamic provider support (#994)
* chore(metrics): introduced own static data Signed-off-by: Arturo Reuschenbach Puncernau <reuschenbach@gmail.com> * chore(metrics): docs cleanup Signed-off-by: Arturo Reuschenbach Puncernau <reuschenbach@gmail.com> * chore(metrics): docs tracking moved Signed-off-by: Arturo Reuschenbach Puncernau <reuschenbach@gmail.com> * chore(metrics): added changeset Signed-off-by: Arturo Reuschenbach Puncernau <reuschenbach@gmail.com> * chore(metrics): prettier Signed-off-by: Arturo Reuschenbach Puncernau <reuschenbach@gmail.com> --------- Signed-off-by: Arturo Reuschenbach Puncernau <reuschenbach@gmail.com> Co-authored-by: Andreas Pfau <andreas.pfau@sap.com>
1 parent 16a5a52 commit f67c54f

22 files changed

Lines changed: 386 additions & 285 deletions

File tree

.changeset/swift-seas-scream.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@cobaltcore-dev/aurora": patch
3+
---
4+
5+
Routes now track with meaningful names like `storage.swift.list` or `compute.flavors.detail` instead of raw URL paths like `/_auth/projects/$projectId/storage/$provider/$storageType/`
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Analytics Tracking in Routes
2+
3+
This guide explains how to add semantic analytics tracking to your routes using TanStack Router's `staticData`.
4+
5+
## Overview
6+
7+
Aurora's analytics system uses the `onResolved` event from TanStack Router to track page views. Instead of tracking raw URLs like `/projects/abc-123/storage/swift/containers`, we track semantic names like `storage.swift.list` that have meaning independent of dynamic parameters.
8+
9+
## Basic Pattern
10+
11+
Add an `analytics` field to your route's `staticData`:
12+
13+
```tsx
14+
import { createFileRoute } from "@tanstack/react-router"
15+
import type { RouteInfo } from "@/client/routes/routeInfo"
16+
17+
export const Route = createFileRoute("/_auth/projects/$projectId/storage/$provider/$storageType/")({
18+
staticData: {
19+
section: "storage",
20+
service: "swift",
21+
analytics: {
22+
name: "storage.swift.list",
23+
},
24+
} satisfies RouteInfo,
25+
component: StorageComponent,
26+
})
27+
```
28+
29+
## Naming Convention
30+
31+
Use dot-separated semantic names that describe **what** the user is viewing, not the URL structure:
32+
33+
### ✅ Good Examples
34+
35+
- `storage.swift.list` - List of Swift containers
36+
- `storage.swift.detail` - Single Swift container detail view
37+
- `compute.flavors.list` - List of compute flavors
38+
- `compute.instances.create` - Instance creation form
39+
- `network.floatingips.edit` - Edit floating IP
40+
41+
### ❌ Avoid
42+
43+
- `/_auth/projects/$projectId/storage/swift/` - Raw route paths
44+
- `/projects/abc-123/storage/swift/containers` - URLs with IDs
45+
- `page_view_storage_swift` - Generic prefixes
46+
47+
## Pattern by Route Type
48+
49+
### List Views
50+
51+
```tsx
52+
analytics: {
53+
name: "storage.swift.list"
54+
}
55+
```
56+
57+
### Detail Views
58+
59+
```tsx
60+
analytics: {
61+
name: "storage.swift.detail"
62+
}
63+
```
64+
65+
### Action Views (Create/Edit)
66+
67+
```tsx
68+
analytics: {
69+
name: "compute.instances.create"
70+
}
71+
```
72+
73+
### Section Landing Pages
74+
75+
```tsx
76+
analytics: {
77+
name: "compute.overview"
78+
}
79+
```
80+
81+
## What Gets Tracked
82+
83+
The analytics event includes:
84+
85+
```typescript
86+
{
87+
source: "router",
88+
action: "storage.swift.list", // From analytics.name, or routeId if not set
89+
metadata: {
90+
pathname: "/projects/abc-123/storage/swift/containers", // For debugging
91+
search: "?sortBy=name", // Query params (if present)
92+
}
93+
}
94+
```
95+
96+
The semantic `action` name contains all the context you need - section, service, and operation are all encoded in the analytics name itself (e.g., `storage.swift.list`).
97+
98+
## Fallback Behavior
99+
100+
If you don't set `analytics.name`, the system falls back to the `routeId`:
101+
102+
```typescript
103+
// Without analytics.name:
104+
action: "/_auth/projects/$projectId/storage/$provider/$storageType/"
105+
106+
// With analytics.name:
107+
action: "storage.swift.list"
108+
```
109+
110+
## Migration Guide
111+
112+
To add analytics tracking to an existing route:
113+
114+
1. **Identify the semantic name** - What is the user actually viewing?
115+
- Swift containers list → `storage.swift.list`
116+
- Flavor detail page → `compute.flavors.detail`
117+
118+
2. **Add the analytics field** to staticData:
119+
120+
```tsx
121+
staticData: {
122+
section: "storage",
123+
service: "swift",
124+
analytics: { name: "storage.swift.list" } // ADD THIS
125+
} satisfies RouteInfo
126+
```
127+
128+
3. **Test** - Navigate to the route and check the console for the track event
129+
130+
## Complete Example
131+
132+
```tsx
133+
import { createFileRoute } from "@tanstack/react-router"
134+
import type { RouteInfo } from "@/client/routes/routeInfo"
135+
import { z } from "zod"
136+
137+
const searchSchema = z.object({
138+
sortBy: z.enum(["name", "size"]).optional(),
139+
search: z.string().optional(),
140+
})
141+
142+
export const Route = createFileRoute("/_auth/projects/$projectId/compute/flavors")({
143+
staticData: {
144+
section: "compute",
145+
service: "flavors",
146+
sectionCrumb: { labelKey: "Compute" },
147+
crumb: { labelKey: "Flavors" },
148+
analytics: {
149+
name: "compute.flavors.list",
150+
},
151+
} satisfies RouteInfo,
152+
validateSearch: searchSchema,
153+
component: FlavorsComponent,
154+
})
155+
```
156+
157+
## Best Practices
158+
159+
1. **Be consistent** - Use the same naming pattern across your app
160+
2. **Be specific** - `storage.swift.list` is better than `storage.list`
161+
3. **Keep it flat** - 2-3 levels deep is ideal (section.service.action)
162+
4. **Add analytics early** - Add it when creating the route, not as an afterthought
163+
5. **Document unusual names** - If the semantic name isn't obvious, add a comment
164+
165+
## Testing
166+
167+
To verify your analytics tracking works:
168+
169+
1. Start the dev server
170+
2. Navigate to your route
171+
3. Check the console for `>>>>Track event metadata:`
172+
4. Verify the `action` field contains your semantic name

0 commit comments

Comments
 (0)