Skip to main content

Data Layer

Source of truth

DataLives inImport from
ProjectsSupabase projects tablelib/projects-db.ts (server-only)
Leads / CRMSupabaselib/supabase.ts
Questionnaire templatesSupabase questionnaire_templateslib/questionnaire-db.ts
Questionnaire responsesSupabase questionnaire_responseslib/questionnaire-db.ts
ProposalsSupabaselib/proposal-data.ts
ContractsSupabaselib/contract-data.ts
InvoicesSupabaselib/invoice-data.ts
Work ordersSupabase(actions/work-orders.ts)
ProductsStatic filedata/products.ts
ServicesStatic filedata/services.ts

data/projects.ts is deleted. Any import of it will break the build.

Server / client split

  • lib/projects-db.ts — uses server-only; never import in Client Components
  • lib/project-types.ts — types only, no server-only; safe to import anywhere
  • lib/questionnaire-db.ts — server-only; use for all template CRUD
  • lib/questionnaire-data.ts — legacy; only getResponseByToken is still used

Supabase naming conventions

Supabase returns snake_case columns. All data-layer helpers map rows to camelCase TypeScript models before returning them.

// ✅ correct — use typed model fields
template.serviceType
template.createdAt

// ❌ wrong — raw DB column names
template.service_type
template.created_at

See the mapRow pattern in lib/questionnaire-db.ts as the reference implementation.

Project types

// lib/project-types.ts
export type Project = {
slug: string; title: string; category: string
tags: string[]; featured: boolean; thumb: string
videoUrl?: string; year: number; mediaType: 'image' | 'video'
description: string; client?: string; deliverables: string[]
industry?: string; challenge?: string; solution?: string; outcome?: string
processSteps?: ProcessStep[]; results?: Record<string, string>
testimonial?: string; testimonialAuthor?: string; gallery?: string[]
}

categoryLabels and categoryDotClass are also in lib/project-types.ts — import from there, never redeclare.

generateStaticParams

For Supabase-backed detail pages, pre-render slugs at build time:

export async function generateStaticParams() {
const projects = await getAllProjects({ status: 'published' });
return projects.map((p) => ({ category: p.category, slug: p.slug }));
}

Call notFound() when a slug isn't found at runtime.