This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# Start development server
pnpm dev
# Build for production
pnpm build
# Run production server
pnpm start
# Database operations (Drizzle)
# Note: No db:push script in package.json - use drizzle-kit directly
npx drizzle-kit push
npx drizzle-kit generate
npx drizzle-kit studio
# Electron desktop builds
pnpm dist:win # Windows
pnpm dist:linux # Linux- Next.js 15 (App Router) - React 19.2.3
- Supabase - Auth (SSR) + Storage
- Drizzle ORM - PostgreSQL with
postgres.jsdriver - Puck Editor - Self-hosted visual page builder
- Google Gemini AI - Content generation (
@google/generative-ai) - Tailwind CSS 4 - Styling
- TipTap - Rich text editor
The app runs without configuration using mock data when DATABASE_URL or NEXT_PUBLIC_SUPABASE_URL is missing:
src/db/index.tsexports a recursive proxy DB that returns empty arrays/nullssrc/lib/auth.tsreturnsMOCK_ADMINuser (demo@starter-kit.local)- All API routes gracefully handle missing DB/Supabase
- Never blocks development - useful for UI work and testing
| Table | Purpose | Key Fields |
|---|---|---|
users |
Admin/editors | role: ADMIN|EDITOR |
posts |
CMS content | type: ARTICLE|PROJECT|PAGE|NEWS, published, slug |
pages |
Puck editor data | slug (PK), data: jsonb, status: draft|published |
media_files |
Uploaded assets | Stored in Supabase Storage, tracked in DB |
site_settings |
Key/value config | Generic settings store |
contact_messages |
Contact form submissions | |
hero_slides |
Homepage slider | order, active |
activity_logs |
Audit trail | action, entity, entity_id |
- Server components: Use
requireAuth()from@/lib/auth.ts- redirects to/loginif unauthenticated - API routes: Use
requireApiAuth(request)from@/lib/api-auth.ts- returns 401 JSON response - Supabase SSR: Client created per-request using cookies from
@/lib/supabase/server.ts
Config: src/lib/puck/config.tsx
- Component registry with categories (layout, hero, content, forms, etc.)
- Custom fields:
richTextField,imageField,documentField,colorField,iconField - All components wrapped with
CanvasComponentWrapperfor inline editing
Data flow:
- Pages stored in
pagestable as JSONB (datacolumn) - Public routes rendered by
src/app/(public)/[slug]/page.tsx - Admin editor at
/admin/editor/[...puckPath]
AI Integration: src/app/api/puck/generate/route.ts uses Gemini to generate Puck JSON from prompts
/[slug] → Puck pages from DB (excluded: home, despre-noi, etc.)
/articole/[slug] → Blog posts (type=ARTICLE)
/proiecte/[slug] → Projects (type=PROJECT)
Important: EXCLUDED slugs in [slug]/page.tsx have dedicated routes and won't render from Puck data.
| Route | Purpose |
|---|---|
/api/auth/* |
Supabase auth callbacks |
/api/puck/generate |
AI page generation (Gemini) |
/api/ai/process-text |
Text formatting/correction/expansion |
/api/pages/[slug] |
CRUD for Puck pages |
/api/posts |
CMS posts CRUD |
/api/media |
Media upload/management |
/api/hero-slides |
Hero slider CRUD |
/api/contact |
Contact form submissions |
Critical: .env.example was updated to fix GEMINI_API_KEY → GOOGLE_AI_API_KEY
Required for full functionality:
DATABASE_URL- PostgreSQL connectionNEXT_PUBLIC_SUPABASE_URL+NEXT_PUBLIC_SUPABASE_ANON_KEY+SUPABASE_SERVICE_ROLE_KEYGOOGLE_AI_API_KEY- For AI features
Optional:
SMTP_*- Email sendingNEXT_PUBLIC_GA_ID- AnalyticsNEXT_PUBLIC_SITE_*- Metadata defaults (has fallbacks)
Puck Components (src/lib/puck/components/):
- All receive
puck,id,positionTypeprops from editor - Use
CanvasComponentWrapperfor inline editing transforms - Strip internal props with
strip({ puck, id, ...rest })helper
Rich Text: Uses TipTap with custom extensions:
- Character count, color, highlight, image, link, placeholder, text align, underline
- Configured in
ExtendedRichTextField
Media Picker: Integrates with Supabase Storage for image/document uploads