Files
jnsdls 2aa9ce5f78 posthog migration: part 4 (#7366)
# Analytics Event Reporting System

This PR introduces a structured analytics event reporting system for the dashboard app using PostHog. It provides clear guidelines and standardized patterns for tracking user actions.

## Key Features

- Added a centralized analytics reporting system in `src/@/analytics/report.ts`
- Implemented standardized naming conventions for events (`<subject> <verb>`) and reporting functions (`report<Subject><Verb>`)
- Created comprehensive documentation in `apps/dashboard/src/@/analytics/README.md`
- Added mandatory JSDoc requirements to document the purpose and ownership of each event
- Integrated the first event: `reportContractDeployed` to track contract deployments
- Updated the contract deployment form to use the new analytics system

## Guidelines

- Events should only be added when they answer concrete product/business questions
- All events must include typed properties and proper documentation
- Analytics code is client-side only (never import `posthog-js` in server components)
- Developers should notify #core-services before renaming or removing events

This standardized approach will make our analytics more maintainable, discoverable, and purposeful.

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Documentation**
  - Added comprehensive guidelines and a README for analytics event reporting, including naming conventions, usage examples, and requirements for event tracking in the dashboard app.

- **New Features**
  - Introduced new analytics events covering contract deployments and multiple stages of team onboarding, such as plan selection, member invitations, and onboarding completion.

- **Refactor**
  - Centralized analytics reporting by replacing generic event tracking with dedicated reporting functions across contract deployment and team onboarding flows.
  - Removed redundant and granular event tracking calls, simplifying analytics integration and improving consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing analytics event reporting for onboarding and contract deployment processes across the application, ensuring better tracking of user interactions and feedback.

### Detailed summary
- Added `.eslintignore` entries for markdown files.
- Updated `InviteTeamMembers` and `InviteSection` to report success counts on invites.
- Introduced new reporting functions in `report.ts` for onboarding and contract events.
- Removed unused `trackEvent` calls, replacing them with specific reporting functions.
- Enhanced documentation for analytics guidelines and event reporting in `README.md` files.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2025-06-19 00:53:58 +00:00

129 lines
5.9 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: Rules for writing features in apps/dashboard
globs: dashboard
alwaysApply: false
---
# Reusable Core UI Components
- Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
- Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.
- Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.
- Layouts should reuse `SidebarLayout` / `FullWidthSidebarLayout` (`@/components/blocks/SidebarLayout`).
- For notices & skeletons rely on `AnnouncementBanner`, `GenericLoadingPage`, `EmptyStateCard`.
- Icons come from `lucide-react` or the project-specific `…/icons` exports – never embed raw SVG.
- Group related components in their own folder and expose a single barrel `index.ts` where necessary.
- Keep components pure; fetch data outside (server component or hook) and pass it down via props.
# Styling
- Tailwind CSS is **the** styling system – avoid inline styles or CSS modules.
- Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.
- Stick to design-tokens: background (`bg-card`), borders (`border-border`), muted text (`text-muted-foreground`) etc.
- Use the `container` class with a `max-w-7xl` cap for page width consistency.
- Spacing utilities (`px-*`, `py-*`, `gap-*`) are preferred over custom margins.
- Responsive helpers follow mobile-first (`max-sm`, `md`, `lg`, `xl`).
- Never hard-code colors – always go through Tailwind variables.
- Add `className` to the root element of every component for external overrides.
# Creating a new Component
- Place the file close to its feature: `feature/components/MyComponent.tsx`.
- Name files after the component in **PascalCase**; append `.client.tsx` when interactive.
- Client components must start with `'use client';` before imports.
- Accept a typed `props` object and export a **named** function (`export function MyComponent()`).
- Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
- Combine class names via `cn`, expose `className` prop if useful.
- Local state or effects live inside; data fetching happens in hooks.
- Provide a Storybook story (`MyComponent.stories.tsx`) or unit test alongside the component.
# When to use Server Side Rendering (Server Components)
- Reading cookies/headers with `next/headers` (`getAuthToken()`, `cookies()`).
- Accessing server-only environment variables or secrets.
- Heavy data fetching that should not ship to the client (e.g. analytics, billing).
- Redirect logic using `redirect()` from `next/navigation`.
- Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.
- Export default async functions without `'use client';` – they run on the Node edge.
- Co-locate data helpers under `@/api/**` and mark them with `"server-only"`.
# When to use Client Side Rendering (Client Components)
- Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
- Components that listen to user events, animations or live updates.
- When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).
- Pages requiring fast transitions where data is prefetched on the client.
- Anything that consumes hooks from `@tanstack/react-query` or thirdweb SDKs.
# Fetching Authenticated Data – Server
```ts
import "server-only";
import { API_SERVER_URL } from "@/constants/env";
import { getAuthToken } from "@/app/(app)/api/lib/getAuthToken";
export async function getProjects(teamSlug: string) {
const token = await getAuthToken();
if (!token) return [];
const res = await fetch(`${API_SERVER_URL}/v1/teams/${teamSlug}/projects`, {
headers: { Authorization: `Bearer ${token}` },
});
return res.ok ? (await res.json()).result : [];
}
```
Guidelines:
- Always call `getAuthToken()` to get the JWT from cookies.
- Prefix files with `import "server-only";` so they never end up in the client bundle.
- Pass the token in the `Authorization: Bearer` header – never embed it in the URL.
- Return typed results (`Project[]`, `User[]`, …) – avoid `any`.
# Fetching Authenticated Data – Client
```ts
import { useQuery } from "@tanstack/react-query";
import { fetchJson } from "@/lib/fetch-json";
export function useProjects(teamSlug: string) {
return useQuery({
queryKey: ["projects", teamSlug],
queryFn: () => fetchJson(`/api/projects?team=${teamSlug}`), // internal API route handles token
staleTime: 60_000,
});
}
```
Guidelines:
- Use **React Query** (`@tanstack/react-query`) for all client data fetching.
- Create light wrappers (e.g. `fetchJson`) that automatically attach the JWT from cookies/session when calling internal API routes.
- Keep `queryKey` stable and descriptive for cache hits.
- Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.
- Configure `staleTime` / `cacheTime` according to freshness requirements.
# Analytics Event Reporting
- **Add events intentionally** – only when they answer a concrete product/business question.
- **Event name**: human-readable `<subject> <verb>` phrase (e.g. `"contract deployed"`).
- **Reporting helper**: `report<Subject><Verb>` (PascalCase); all live in `src/@/analytics/report.ts`.
- **Mandatory JSDoc**: explain *Why* the event exists and *Who* owns it (`@username`).
- **Typed properties**: accept a single `properties` object and pass it unchanged to `posthog.capture`.
- **Client-side only**: never import `posthog-js` in server components.
- **Housekeeping**: ping **#core-services** before renaming or removing an event.
```ts
/**
* ### Why do we need to report this event?
* - Tracks number of contracts deployed
*
* ### Who is responsible for this event?
* @jnsdls
*/
export function reportContractDeployed(properties: {
address: string;
chainId: number;
}) {
posthog.capture("contract deployed", properties);
}
```