Skip to content

Commit 8e3d9b9

Browse files
committed
posthog migration: part 4
1 parent beca7ef commit 8e3d9b9

File tree

5 files changed

+153
-41
lines changed

5 files changed

+153
-41
lines changed

.cursor/rules/dashboard.mdc

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ description: Rules for writing features in apps/dashboard
33
globs: dashboard
44
alwaysApply: false
55
---
6-
76
# Reusable Core UI Components
87

98
- Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
@@ -101,3 +100,29 @@ Guidelines:
101100
- Keep `queryKey` stable and descriptive for cache hits.
102101
- Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.
103102
- Configure `staleTime` / `cacheTime` according to freshness requirements.
103+
104+
# Analytics Event Reporting
105+
106+
- **Add events intentionally** – only when they answer a concrete product/business question.
107+
- **Event name**: human-readable `<subject> <verb>` phrase (e.g. `"contract deployed"`).
108+
- **Reporting helper**: `report<Subject><Verb>` (PascalCase); all live in `src/@/analytics/report.ts`.
109+
- **Mandatory JSDoc**: explain *Why* the event exists and *Who* owns it (`@username`).
110+
- **Typed properties**: accept a single `properties` object and pass it unchanged to `posthog.capture`.
111+
- **Client-side only**: never import `posthog-js` in server components.
112+
- **Housekeeping**: ping **#core-services** before renaming or removing an event.
113+
114+
```ts
115+
/**
116+
* ### Why do we need to report this event?
117+
* - Tracks number of contracts deployed
118+
*
119+
* ### Who is responsible for this event?
120+
* @jnsdls
121+
*/
122+
export function reportContractDeployed(properties: {
123+
address: string;
124+
chainId: number;
125+
}) {
126+
posthog.capture("contract deployed", properties);
127+
}
128+
```

AGENTS.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,41 @@ Welcome, AI copilots! This guide captures the coding standards, architectural de
104104
-- Configure staleTime / cacheTime based on freshness requirements (default ≥ 60 s).
105105
-- Keep tokens secret by calling internal API routes or server actions.
106106

107+
6.5 Analytics Event Reporting
108+
109+
- **When to create a new event**
110+
-- Only add events that answer a clear product or business question.
111+
-- Check `src/@/analytics/report.ts` first; avoid duplicates.
112+
113+
- **Naming conventions**
114+
-- **Event name**: human-readable phrase in the form `<subject> <verb>` (e.g. "contract deployed").
115+
-- **Reporting function**: `report<Subject><Verb>` (PascalCase).
116+
-- All reporting helpers currently live in the shared `report.ts` file.
117+
118+
- **Boilerplate template**
119+
-- Add a JSDoc header explaining **Why** the event exists and **Who** owns it (`@username`).
120+
-- Accept a single typed `properties` object and forward it unchanged to `posthog.capture`.
121+
-- Example:
122+
123+
```ts
124+
/**
125+
* ### Why do we need to report this event?
126+
* - Tracks number of contracts deployed
127+
*
128+
* ### Who is responsible for this event?
129+
* @jnsdls
130+
*/
131+
export function reportContractDeployed(properties: {
132+
address: string;
133+
chainId: number;
134+
}) {
135+
posthog.capture("contract deployed", properties);
136+
}
137+
```
138+
139+
- **Client-side only**: never import `posthog-js` in server components.
140+
- **Housekeeping**: Inform **#core-services** before renaming or removing an existing event.
141+
107142
108143

109144
7. Performance & Bundle Size
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Analytics Guidelines
2+
3+
This folder centralises the **PostHog** tracking logic for the dashboard app.
4+
Most developers will only need to add or extend _event-reporting_ functions in `report.ts`.
5+
6+
---
7+
8+
## 1. When to add an event
9+
1. Ask yourself if the data will be **actionable**. Every event should have a clear product or business question it helps answer.
10+
2. Check if a similar event already exists in `report.ts`. Avoid duplicates.
11+
12+
---
13+
14+
## 2. Naming conventions
15+
| Concept | Convention | Example |
16+
|---------|------------|---------|
17+
| **Event name** (string sent to PostHog) | Human-readable phrase formatted as `<subject> <verb>` | `"contract deployed"` |
18+
| **Reporting function** | `report<Subject><Verb>` (PascalCase) | `reportContractDeployed` |
19+
| **File** | All event functions live in the shared `report.ts` file (for now) ||
20+
21+
> Keeping names predictable makes it easy to search both code and analytics.
22+
23+
---
24+
25+
## 3. Boilerplate / template
26+
Add a new function to `report.ts` following this pattern:
27+
28+
```ts
29+
/**
30+
* ### Why do we need to report this event?
31+
* - _Add bullet points explaining the product metrics/questions this event answers._
32+
*
33+
* ### Who is responsible for this event?
34+
* @your-github-handle
35+
*/
36+
export function reportExampleEvent(properties: {
37+
/* Add typed properties here */
38+
}) {
39+
posthog.capture("example event", {
40+
/* Pass the same properties here */
41+
});
42+
}
43+
```
44+
45+
Guidelines:
46+
1. **Explain the "why".** The JSDoc block is mandatory so future contributors know the purpose.
47+
2. **Type everything.** The `properties` object should be fully typed—this doubles as documentation.
48+
3. **Client-side only.** `posthog-js` must never run on the server. Call these reporting helpers from client components, event handlers, etc.
49+
50+
---
51+
52+
## 4. Editing or removing events
53+
1. Update both the function and the PostHog event definition (if required).
54+
2. Inform the core services team before removing or renaming an event.
55+
56+
---
57+
58+
## 5. Identification & housekeeping (FYI)
59+
Most devs can ignore this section, but for completeness:
60+
61+
- `hooks/identify-account.ts` and `hooks/identify-team.ts` wrap `posthog.identify`/`group` calls.
62+
- `resetAnalytics` clears identity state (used on logout).
63+
64+
---
65+
66+
## 6. Need help?
67+
Ping #core-services in slack.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import posthog from "posthog-js";
2+
3+
/**
4+
* ### Why do we need to report this event?
5+
* - To track the number of contracts deployed
6+
* - To track the number of contracts deployed on each chain
7+
*
8+
* ### Who is responsible for this event?
9+
* @jnsdls
10+
*
11+
*/
12+
export function reportContractDeployed(properties: {
13+
address: string;
14+
chainId: number;
15+
}) {
16+
posthog.capture("contract deployed", {
17+
address: properties.address,
18+
chainId: properties.chainId,
19+
});
20+
}

apps/dashboard/src/components/contract-components/contract-deploy-form/custom-contract.tsx

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"use client";
2+
import { reportContractDeployed } from "@/analytics/report";
23
import {
34
Accordion,
45
AccordionContent,
@@ -21,7 +22,6 @@ import {
2122
} from "constants/addresses";
2223
import { ZERO_FEE_CHAINS } from "constants/fee-config";
2324
import { SolidityInput } from "contract-ui/components/solidity-inputs";
24-
import { useTrack } from "hooks/analytics/useTrack";
2525
import { useTxNotifications } from "hooks/useTxNotifications";
2626
import { replaceTemplateValues } from "lib/deployment/template-values";
2727
import {
@@ -144,13 +144,6 @@ function checkTwPublisher(publisher: string | undefined) {
144144
}
145145
}
146146

147-
function rewriteTwPublisher(publisher: string | undefined) {
148-
if (checkTwPublisher(publisher)) {
149-
return "deployer.thirdweb.eth";
150-
}
151-
return publisher;
152-
}
153-
154147
export const CustomContractForm: React.FC<CustomContractFormProps> = ({
155148
metadata,
156149
metadataNoFee,
@@ -204,7 +197,6 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
204197
"Successfully deployed contract",
205198
"Failed to deploy contract",
206199
);
207-
const trackEvent = useTrack();
208200

209201
const constructorParams =
210202
metadata.abi.find((a) => a.type === "constructor")?.inputs || [];
@@ -638,21 +630,6 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
638630
},
639631
];
640632

641-
const publisherAnalyticsData = metadata.publisher
642-
? {
643-
publisherAndContractName: `${rewriteTwPublisher(metadata.publisher)}/${metadata.name}`,
644-
}
645-
: {};
646-
647-
trackEvent({
648-
category: "custom-contract",
649-
action: "deploy",
650-
label: "attempt",
651-
...publisherAnalyticsData,
652-
chainId: walletChain.id,
653-
metadataUri: metadata.metadataUri,
654-
});
655-
656633
deployStatusModal.setViewContractLink("");
657634
deployStatusModal.open(steps);
658635
try {
@@ -668,15 +645,11 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
668645
}),
669646
);
670647

671-
trackEvent({
672-
category: "custom-contract",
673-
action: "deploy",
674-
label: "success",
675-
...publisherAnalyticsData,
676-
contractAddress: contractAddr,
648+
reportContractDeployed({
649+
address: contractAddr,
677650
chainId: walletChain.id,
678-
metadataUri: metadata.metadataUri,
679651
});
652+
680653
deployStatusModal.nextStep();
681654
if (importSelection.team && importSelection.project) {
682655
deployStatusModal.setViewContractLink(
@@ -707,15 +680,7 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
707680
} catch (e) {
708681
onError(e);
709682
console.error("failed to deploy contract", e);
710-
trackEvent({
711-
category: "custom-contract",
712-
action: "deploy",
713-
label: "error",
714-
...publisherAnalyticsData,
715-
chainId: walletChain.id,
716-
metadataUri: metadata.metadataUri,
717-
error: e,
718-
});
683+
719684
deployStatusModal.close();
720685
}
721686
})}

0 commit comments

Comments
 (0)