Skip to content

Commit 3f630a8

Browse files
[Dashboard] Add coding standards and best practices documentation (#6901)
1 parent 818189e commit 3f630a8

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

.cursor/rules/dashboard.mdc

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
description: Rules for writing features in apps/dashboard
3+
globs: dashboard
4+
alwaysApply: false
5+
---
6+
7+
# Reusable Core UI Components
8+
9+
- Always import from the central UI library under `@/components/ui/*` – e.g. `import { Button } from "@/components/ui/button"`.
10+
- Prefer composable primitives over custom markup: `Button`, `Input`, `Select`, `Tabs`, `Card`, `Sidebar`, `Separator`, `Badge`.
11+
- Use `NavLink` (`@/components/ui/NavLink`) for internal navigation so active states are handled automatically.
12+
- Layouts should reuse `SidebarLayout` / `FullWidthSidebarLayout` (`@/components/blocks/SidebarLayout`).
13+
- For notices & skeletons rely on `AnnouncementBanner`, `GenericLoadingPage`, `EmptyStateCard`.
14+
- Icons come from `lucide-react` or the project-specific `…/icons` exports – never embed raw SVG.
15+
- Group related components in their own folder and expose a single barrel `index.ts` where necessary.
16+
- Keep components pure; fetch data outside (server component or hook) and pass it down via props.
17+
18+
# Styling
19+
20+
- Tailwind CSS is **the** styling system – avoid inline styles or CSS modules.
21+
- Merge class names with `cn` from `@/lib/utils` to keep conditional logic readable.
22+
- Stick to design-tokens: background (`bg-card`), borders (`border-border`), muted text (`text-muted-foreground`) etc.
23+
- Use the `container` class with a `max-w-7xl` cap for page width consistency.
24+
- Spacing utilities (`px-*`, `py-*`, `gap-*`) are preferred over custom margins.
25+
- Responsive helpers follow mobile-first (`max-sm`, `md`, `lg`, `xl`).
26+
- Never hard-code colors – always go through Tailwind variables.
27+
- Add `className` to the root element of every component for external overrides.
28+
29+
# Creating a new Component
30+
31+
- Place the file close to its feature: `feature/components/MyComponent.tsx`.
32+
- Name files after the component in **PascalCase**; append `.client.tsx` when interactive.
33+
- Client components must start with `'use client';` before imports.
34+
- Accept a typed `props` object and export a **named** function (`export function MyComponent()`).
35+
- Reuse core UI primitives; avoid re-implementing buttons, cards, modals.
36+
- Combine class names via `cn`, expose `className` prop if useful.
37+
- Local state or effects live inside; data fetching happens in hooks.
38+
- Provide a Storybook story (`MyComponent.stories.tsx`) or unit test alongside the component.
39+
40+
# When to use Server Side Rendering (Server Components)
41+
42+
- Reading cookies/headers with `next/headers` (`getAuthToken()`, `cookies()`).
43+
- Accessing server-only environment variables or secrets.
44+
- Heavy data fetching that should not ship to the client (e.g. analytics, billing).
45+
- Redirect logic using `redirect()` from `next/navigation`.
46+
- Building layout shells (`layout.tsx`) and top-level pages that mainly assemble data.
47+
- Export default async functions without `'use client';` – they run on the Node edge.
48+
- Co-locate data helpers under `@/api/**` and mark them with `"server-only"`.
49+
50+
# When to use Client Side Rendering (Client Components)
51+
52+
- Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
53+
- Components that listen to user events, animations or live updates.
54+
- When you need access to browser APIs (localStorage, window, IntersectionObserver etc.).
55+
- Pages requiring fast transitions where data is prefetched on the client.
56+
- Anything that consumes hooks from `@tanstack/react-query` or thirdweb SDKs.
57+
58+
# Fetching Authenticated Data – Server
59+
60+
```ts
61+
import "server-only";
62+
import { API_SERVER_URL } from "@/constants/env";
63+
import { getAuthToken } from "@/app/(app)/api/lib/getAuthToken";
64+
65+
export async function getProjects(teamSlug: string) {
66+
const token = await getAuthToken();
67+
if (!token) return [];
68+
const res = await fetch(`${API_SERVER_URL}/v1/teams/${teamSlug}/projects`, {
69+
headers: { Authorization: `Bearer ${token}` },
70+
});
71+
return res.ok ? (await res.json()).result : [];
72+
}
73+
```
74+
75+
Guidelines:
76+
77+
- Always call `getAuthToken()` to get the JWT from cookies.
78+
- Prefix files with `import "server-only";` so they never end up in the client bundle.
79+
- Pass the token in the `Authorization: Bearer` header – never embed it in the URL.
80+
- Return typed results (`Project[]`, `User[]`, …) – avoid `any`.
81+
82+
# Fetching Authenticated Data – Client
83+
84+
```ts
85+
import { useQuery } from "@tanstack/react-query";
86+
import { fetchJson } from "@/lib/fetch-json";
87+
88+
export function useProjects(teamSlug: string) {
89+
return useQuery({
90+
queryKey: ["projects", teamSlug],
91+
queryFn: () => fetchJson(`/api/projects?team=${teamSlug}`), // internal API route handles token
92+
staleTime: 60_000,
93+
});
94+
}
95+
```
96+
97+
Guidelines:
98+
99+
- Use **React Query** (`@tanstack/react-query`) for all client data fetching.
100+
- Create light wrappers (e.g. `fetchJson`) that automatically attach the JWT from cookies/session when calling internal API routes.
101+
- Keep `queryKey` stable and descriptive for cache hits.
102+
- Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.
103+
- Configure `staleTime` / `cacheTime` according to freshness requirements.

0 commit comments

Comments
 (0)