Skip to main content

Conventions

Server vs Client components

  • Server Components by default — add 'use client' only when using hooks (useState, useEffect, usePathname, useRouter) or event handlers
  • Server Components fetch data and pass it as props to Client Components
  • Never import data files or call async functions inside Client Components

File locations

  • 'use server' belongs only in app/actions/ — not in lib/
  • lib/ files use import 'server-only' for server-only modules
  • lib/project-types.ts has no server-only — safe to import in Client Components

Design tokens

  • Always use var(--mm-*) tokens — never hardcode hex values
  • No inline styles except for CSS variable references
  • Framer Motion animation variants defined at the top of the file, not inline

Naming

  • Supabase returns snake_case — always map to camelCase in the data layer before returning
  • Never access .service_type, .created_at, etc. on a typed model

Global UI

  • Drawers, modals, toasts → render in app/layout.tsx root, never scoped to sub-routes
  • CartDrawer is already there — follow that pattern

Path segment counting

/work/[category]/[slug] has 3 non-empty segments. Always:

pathname.split('/').filter(Boolean).length

Resend SDK v6

emails.send() does not throw on API errors — it returns { data, error }. Always destructure and check:

const { data, error } = await emails.send(...);
if (error) throw new Error(error.message);

Static vs dynamic routes

  • dynamicParams = false on closed-set detail pages (all valid slugs known at build time)
  • Already applied to marketplace/[slug] — apply to work/[category]/[slug] when project data is stable