Files
denshooter bf070ec47f Fix UI issues, add tests, and patch missing auth on API routes
- Rewrote CandleSection with properly aligned animated flames (fix
  Framer Motion transform-overwrite bug by using left:0 / pixel offsets
  instead of translateX(-50%)); added size prop for inline flames
- Fixed Timeline: CSS dots/line replacing broken SVG estimates, mobile
  padding (pl-10), larger dots, cards grow with content
- Fixed MusicPlayer: actual play/pause (not mute), visibilitychange +
  pagehide handlers so music stops on iOS lock screen / app switch
- Fixed nav: horizontal scroll on mobile (overflow-x-auto whitespace-nowrap)
- Fixed footer: Impressum centered, admin link moved to absolute/hidden
- Removed meine-oma link from TributeSection (page still accessible)
- Added admin auth (isAdmin cookie check) to /api/upload POST,
  /api/contributions/[id] PUT/DELETE, and /api/candles/[id] PUT/DELETE
- Extracted sp(), relativeTime(), formatDate() to src/lib/utils.ts
- Added Vitest with 15 unit tests for utility functions (npm test)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 23:20:48 +01:00

3.2 KiB
Raw Permalink Blame History

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 (19452026), built in German. Production-deployed at maria-malejka.de.

Commands

# 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/).