# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Memorial website for Maria Malejka (1945–2026), built in German. Production-deployed at `maria-malejka.de`. ## Commands ```bash # Development npm run dev # Start dev server (with Turbopack) npm run build # Production build npm run start # Start production server # Docker (local development) docker compose up # Start with Docker Compose docker compose build # Rebuild Docker image ``` No linting or test scripts are configured. ## Environment Variables ``` ADMIN_PASSWORD= # Admin dashboard password (SHA256 hashed) DATA_DIR=/data # SQLite database + uploads location NEXT_PUBLIC_URL= # Public site URL (used for OG tags, QR codes) OLLAMA_URL= # AI moderation endpoint (default: http://localhost:11434) ``` ## Architecture ### Tech Stack - **Next.js** (App Router) + **React 18** + **TypeScript** - **SQLite** via Node.js built-in `node:sqlite` (no ORM) - **Tailwind CSS** with custom warm-toned palette (`cream`, `warm-brown`, `warm-gold`) - **Framer Motion** for animations - **Ollama** (llama3.2) for AI content moderation ### Data Layer Database singleton in `src/lib/db.ts` (`getDb()`). All API routes use `export const runtime = 'nodejs'` to access SQLite and the filesystem. Key tables: `memories`, `media`, `candles`, `timeline`, `contributions`, `recipes`. The `contributions` table is the user submission queue — content flows through `pending → approved/rejected/flagged`. Status `flagged` means the auto-moderator caught something but admin review is needed. ### Content Moderation Pipeline (`/api/contributions` POST) 1. Hardcoded German bad-word list → auto-flag 2. Ollama AI review (fire-and-forget, 15s timeout, very lenient prompt) → flag if rejected 3. Clean content → immediately `approved` ### File Uploads `/api/upload` handles photos, videos, and audio. SHA256 deduplication prevents duplicate files. Files are stored in `$DATA_DIR/uploads/{photos,videos,music}/` with UUID filenames. The `/api/files/[...path]` route serves them with 1-year immutable cache headers. ### Home Page Data Fetching (`src/app/page.tsx`) Server component with `dynamic = 'force-dynamic'` and `revalidate = 10`. Fetches all data server-side and merges: - Admin memories + approved memory contributions - Official timeline + approved timeline contributions - Photos from media table + timeline entries + photo contributions (deduplicated by filename) ### Admin Auth Cookie `admin_auth` with SHA256(password). Routes at `/api/auth` (GET/POST/DELETE). 30-day expiry. ### Styling Conventions - Fonts: `font-cormorant` (headings, serif/italic) and `font-lora` (body) - All UI text is in German - Custom Tailwind colors: `cream`, `warm-brown`, `warm-brown-light`, `warm-gold`, `warm-gold-light`, `warm-border` - Animations: `animate-fade-in`, `animate-float` (defined in tailwind.config.ts) ### Deployment Docker multi-stage build → standalone Next.js output. The container runs as non-root user `nextjs` (uid 1001). Data persisted via volume at `/app/data`. Deployed behind a reverse proxy (no external port exposure). CI/CD via Gitea Actions (`.gitea/workflows/`).