Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Failing after 10m3s
Added rate limiting to APIs, cleaned up docs, implemented fallback logic for reviews without text, and added comprehensive n8n guide.
157 lines
5.8 KiB
Markdown
157 lines
5.8 KiB
Markdown
# 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**: Sentry
|
|
- **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://...
|
|
SENTRY_DSN=...
|
|
```
|
|
|
|
## 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/<name>/route.ts`
|
|
3. Create a component in `app/components/<Name>.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
|