# CLAUDE.md - Portfolio Project Guide ## Project Overview Personal portfolio website for Dennis Konkol (dk0.dev). Built with Next.js 15 (App Router), TypeScript, Tailwind CSS, and Framer Motion. Uses a "liquid" design system with soft gradient colors and glassmorphism effects. ## Tech Stack - **Framework**: Next.js 15 (App Router), TypeScript 5.9 - **Styling**: Tailwind CSS 3.4 with custom `liquid-*` color tokens - **Theming**: `next-themes` for Dark Mode support (system/light/dark) - **Animations**: Framer Motion 12 - **3D**: Three.js + React Three Fiber (shader gradient background) - **Database**: PostgreSQL via Prisma ORM - **Cache**: Redis (optional) - **CMS**: Directus (self-hosted, REST/GraphQL, optional) - **Automation**: n8n webhooks (status, chat, hardcover, image generation) - **i18n**: next-intl (EN + DE), message files in `messages/` - **Monitoring**: Console error logging (development mode only) - **Deployment**: Docker + Nginx, CI via Gitea Actions ## Commands ```bash npm run dev # Full dev environment (Docker + Next.js) npm run dev:simple # Next.js only (no Docker) npm run dev:next # Plain Next.js dev server npm run build # Production build npm run lint # ESLint npm run test # Jest unit tests npm run test:e2e # Playwright E2E tests ``` ## Project Structure ``` app/ [locale]/ # i18n routes (en, de) page.tsx # Homepage (hero, about, projects, contact) projects/ # Project listing + detail pages api/ # API routes book-reviews/ # Book reviews from Directus CMS content/ # CMS content pages hobbies/ # Hobbies from Directus n8n/ # n8n webhook proxies hardcover/ # Currently reading (Hardcover API via n8n) status/ # Activity status (coding, music, gaming) chat/ # AI chatbot generate-image/ # AI image generation projects/ # Projects API (PostgreSQL + Directus fallback) tech-stack/ # Tech stack from Directus components/ # React components About.tsx # About section (tech stack, hobbies, books) CurrentlyReading.tsx # Currently reading widget (n8n/Hardcover) ReadBooks.tsx # Read books with ratings (Directus CMS) Projects.tsx # Featured projects section Hero.tsx # Hero section Contact.tsx # Contact form lib/ directus.ts # Directus GraphQL client (no SDK) auth.ts # Auth utilities + rate limiting prisma/ schema.prisma # Database schema messages/ en.json # English translations de.json # German translations docs/ # Documentation ``` ## Architecture Patterns ### Data Source Hierarchy (Fallback Chain) 1. Directus CMS (if configured via `DIRECTUS_STATIC_TOKEN`) 2. PostgreSQL (for projects, analytics) 3. JSON files (`messages/*.json`) 4. Hardcoded defaults 5. Display key itself as last resort All external data sources fail gracefully - the site never crashes if Directus, PostgreSQL, n8n, or Redis are unavailable. ### CMS Integration (Directus) - REST/GraphQL calls via `lib/directus.ts` (no Directus SDK) - Collections: `tech_stack_categories`, `tech_stack_items`, `hobbies`, `content_pages`, `projects`, `book_reviews` - Translations use Directus native translation system (M2O to `languages`) - Locale mapping: `en` -> `en-US`, `de` -> `de-DE` ### n8n Integration - Webhook base URL: `N8N_WEBHOOK_URL` env var - Auth via `N8N_SECRET_TOKEN` and/or `N8N_API_KEY` headers - All n8n endpoints have rate limiting and timeout protection (10s) - Hardcover data cached for 5 minutes ### Component Patterns - Client components with `"use client"` for interactive/data-fetching parts - `useEffect` for data loading on mount - `useTranslations` from next-intl for i18n - Framer Motion `variants` pattern with `staggerContainer` + `fadeInUp` - Gradient cards with `liquid-*` color tokens and `backdrop-blur-sm` ## Design System Custom Tailwind colors prefixed with `liquid-`: - `liquid-sky`, `liquid-mint`, `liquid-lavender`, `liquid-pink` - `liquid-rose`, `liquid-peach`, `liquid-coral`, `liquid-teal`, `liquid-lime` Cards use gradient backgrounds (`bg-gradient-to-br from-liquid-*/15 via-liquid-*/10 to-liquid-*/15`) with `border-2` and `rounded-xl`. ## Key Environment Variables ```bash # Required for CMS DIRECTUS_URL=https://cms.dk0.dev DIRECTUS_STATIC_TOKEN=... # Required for n8n features N8N_WEBHOOK_URL=https://n8n.dk0.dev N8N_SECRET_TOKEN=... N8N_API_KEY=... # Database DATABASE_URL=postgresql://... # Optional REDIS_URL=redis://... ``` ## Conventions - Language: Code in English, user-facing text via i18n (EN + DE) - Commit messages: Conventional Commits (`feat:`, `fix:`, `chore:`) - Components: PascalCase files in `app/components/` - API routes: kebab-case directories in `app/api/` - CMS data always has a static fallback - never rely solely on Directus - Error logging: Only in `development` mode (`process.env.NODE_ENV === "development"`) - No emojis in code unless explicitly requested ## Common Tasks ### Adding a new CMS-managed section 1. Define the GraphQL query + types in `lib/directus.ts` 2. Create an API route in `app/api//route.ts` 3. Create a component in `app/components/.tsx` 4. Add i18n keys to `messages/en.json` and `messages/de.json` 5. Integrate into the parent component (usually `About.tsx`) ### Adding i18n strings 1. Add keys to `messages/en.json` and `messages/de.json` 2. Access via `useTranslations("key.path")` in client components 3. Or `getTranslations("key.path")` in server components ### Working with Directus collections - All queries go through `directusRequest()` in `lib/directus.ts` - Uses GraphQL endpoint (`/graphql`) - 2-second timeout, graceful null fallback - Translations filtered by `languages_code.code` matching Directus locale