CRITICAL: Never perform a git stash under any circumstance unless explicitly told to.
Use Bun exclusively. Never use npm, npx, or yarn.
Install: bun install
Run: bun run <script>
Execute: bunx <pkg>
Test: bun run test (NOT bun test)
Build: bun run build — use sparingly; never run in parallel with test/lint
Lint: bun run lint — use sparingly; never run in parallel with build/test
Add: bun add <pkg>
- Next.js (App Router, latest stable patch)
- React 19
- TypeScript (strict)
- Convex
- shadcn/ui + Tailwind CSS
- Server Components by default. Add
'use client'only at the leaves that need interactivity/hooks. - Convex is the source of truth for server state; local state is for UI-only concerns.
- Always leverage typescript; avoid usage of
anywhich defeats the point of using Typescript.
- Prefer small, focused components. Split when a component mixes concerns or becomes hard to scan.
- Presentational components: props in → JSX out (no data fetching; minimal/no app logic).
- Feature components: coordinate data + state + composition.
- Prefer composition (children, slots) over giant prop APIs.
- Keep state closest to where it’s used; lift only for shared ownership.
- Don’t mirror Convex query results into local state. Store UI state (selection, filters, draft text), not server data.
- Avoid
useEffectfor app data fetching. Use it for browser-only side effects (subscriptions, observers, localStorage).
- Client reactivity:
useQuery/useMutationin Client Components. - SSR + reactivity: in a Server Component,
preloadQuery(...)and pass the payload to a Client Component usingusePreloadedQuery(...). - Server-only (non-reactive) rendering:
fetchQuery(...)in Server Components. - Server Actions / Route Handlers: call Convex via
fetchMutation/fetchActionwhen you must mutate from the server boundary (e.g., form action, webhook, route handler). - Optimistic UI: prefer Convex optimistic updates (
useMutation(...).withOptimisticUpdate(...)) over duplicating server logic in ad-hoc local state. - Consistency: avoid multiple
preloadQuerycalls on the same page; consolidate queries or design around a single preload.
- Use
loading.tsxanderror.tsxfor route-segment UX. - Use
not-found.tsxfor 404 states. - Prefer colocating components with the route/feature that owns them; extract to shared only when reused.
- Prefer Actions +
useActionStatefor form submission state when using form actions. - Use
useOptimisticfor instant UI feedback when appropriate. - Use
useFormStatusinside design-system components that need form pending state. usecan read a Promise/Context during render (only where Suspense semantics make sense).
- Let inference work; export explicit prop types for shared/public components.
- No
any. Useunknownand narrow. - Avoid
ascasts; prefersatisfies, generics, and runtime validation. @ts-expect-errorallowed only with a comment explaining why + link/TODO to remove.
- Minimize client bundles: keep heavy logic/components server-side when possible.
- Use dynamic imports for non-critical client UI.
- Use
next/imagefor images. - Memoization is opt-in: use
memo/useMemo/useCallbackonly when profiling shows value.
- Use shadcn/ui as the base; extend via composition + variants.
- Tailwind utilities in JSX; extract repetition into components, not
@apply. - Theme via CSS variables; keep design tokens centralized.