- Hero.tsx: pass locale prop directly to getTranslations instead of
relying on setRequestLocale async storage, which can be lost during
Next.js RSC streaming
- book-reviews route: replace revalidate=300 with force-dynamic to
prevent cached English responses being served to German locale requests
- content/page route: add runtime=nodejs and force-dynamic (was missing
both, violating CLAUDE.md API route conventions)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Notification email (to Dennis):
- Complete dark-theme redesign: #0c0c0c bg, #141414 card, gradient top bar
- Sender avatar with liquid-mint/sky gradient + initial letter
- Subject displayed as pill badge
- Message in styled blockquote with mint left border
- Gradient "Direkt antworten" CTA button
- replyTo header already set so email Reply goes directly to sender
Telegram notification:
- sendTelegramNotification() fires after successful email send (fire-and-forget)
- Uses TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID env vars (silently skips if absent)
- HTML-formatted message with emojis, name/email/subject/message preview
- Inline keyboard button "Per E-Mail antworten" with pre-filled mailto link
- Never blocks the contact form response if Telegram fails
Reply email templates (respond/route.tsx):
- Same dark design system as notification email
- baseEmail() generates consistent header + footer
- messageCard() helper for styled message blocks with colored left border
- ctaButton() helper for gradient CTA buttons
- Templates: welcome, project, quick, reply — all updated to dark theme
Required new env vars:
TELEGRAM_BOT_TOKEN=<from @BotFather>
TELEGRAM_CHAT_ID=<your chat/user ID>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TipTap (ProseMirror) was causing:
- chunks 1007 (85 KiB) and 3207 (58 KiB) in the initial bundle
- Array.prototype.at/flat/flatMap, Object.fromEntries/hasOwn polyfills
(ProseMirror bundles core-js for these — the 12 KiB legacy JS flag)
- 2+ seconds of main thread blocking on mobile
Fix: move HTML conversion to the server (API route) and pass the
resulting HTML string to the client, eliminating the need to import
richTextToSafeHtml (and transitively TipTap) in any client component.
Changes:
- app/api/content/page/route.ts: call richTextToSafeHtml server-side,
add html: string to response alongside existing content
- app/components/RichTextClient.tsx: accept html string, remove all
TipTap imports — TipTap/ProseMirror now has zero client bundle cost
- app/components/About.tsx, Contact.tsx: use cmsHtml from API
- app/legal-notice/page.tsx, privacy-policy/page.tsx: same
- app/components/ClientWrappers.tsx: change static imports of About,
Projects, Contact, Footer to next/dynamic so their JS is in
separate lazy-loaded chunks, not in the initial bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add POST /api/n8n/hardcover/sync-books — n8n calls this after detecting
finished books in Hardcover. Authenticates via N8N_SECRET_TOKEN/N8N_API_KEY,
deduplicates by hardcover_id, creates new book_reviews entries in Directus.
- Add getBookReviewByHardcoverId() + createBookReview() to lib/directus.ts.
Check uses GraphQL filter; create uses Directus REST POST /items/book_reviews.
- ReadBooks: replace silent return null with a visible empty state so the
section stays visible with a hint until the n8n sync populates it.
- Projects: add "No projects yet." placeholder instead of blank grid when
both Directus and PostgreSQL return no data.
- Add home.about.readBooks.empty i18n key (EN + DE).
n8n workflow setup:
Schedule → HTTP Hardcover GraphQL (books_read) → Code (transform) →
POST /api/n8n/hardcover/sync-books with array of { hardcover_id, title,
author, image, rating, finished_at }
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove @sentry/nextjs and all related files since it was never actively used.
- Delete sentry.server.config.ts, sentry.edge.config.ts
- Delete sentry-example-page and sentry-example-api routes
- Clean up instrumentation.ts, global-error.tsx, middleware.ts
- Remove Sentry env vars from env.example and docs
- Update CLAUDE.md, copilot-instructions.md, PRODUCTION_READINESS.md
Middleware bundle reduced from 86KB to 34.8KB (-51KB).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add `prefix` param to checkRateLimit/getRateLimitHeaders so each endpoint
has its own bucket (previously all shared `admin_${ip}`, causing 429s when
analytics/track incremented past n8n endpoints' lower limits)
- n8n/hardcover/currently-reading → prefix 'n8n-reading'
- n8n/status → prefix 'n8n-status'
- analytics/track → prefix 'analytics-track'
- Remove custom analytics system (AnalyticsProvider, lib/analytics,
lib/useWebVitals, all /api/analytics/* routes) — was causing 500s in
production due to missing PostgreSQL PageView table
- Remove analytics consent toggle from ConsentBanner/ConsentProvider
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove unused imports, replace `any` types with proper interfaces in directus.ts
and i18n-loader.ts, exclude scripts/ and coverage/ from ESLint, and fix
unused variable warnings across the codebase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Centralized UI labels in Directus, integrated AI Chat and Status into Bento grid, created standalone Books page, and redesigned project sub-pages for consistent high-end aesthetic.
Adds a new "Read Books" section below "Currently Reading" in the About
page. Book reviews with star ratings and comments are fetched from a
Directus CMS collection (book_reviews) and displayed with the existing
liquid design system. Includes i18n support (EN/DE), show more/less
toggle, and graceful fallback when the CMS collection does not exist yet.
https://claude.ai/code/session_017E8W9CcHFM5WQVHw74JP34
* Fix ActivityFeed: Remove dynamic import that was causing it to disappear in production
* Fix ActivityFeed hydration error: Move localStorage read to useEffect to prevent server/client mismatch
* Update Node.js version to 25 in Gitea workflows
- Fix EBADENGINE error for camera-controls@3.1.2 which requires Node.js >=22
- Update production-deploy.yml, dev-deploy.yml, and ci-cd-with-gitea-vars.yml.disabled
- Node.js v25 matches local development environment
* Update Dockerfile to use Node.js 25
- Update base image from node:20 to node:25
- Matches Gitea workflow configuration and camera-controls@3.1.2 requirements
* Fix production deployment: Start database dependencies
- Remove --no-deps flag which prevented postgres and redis from starting
- Remove --build flag as image is already built in previous step
- This fixes 'Can't reach database server at postgres:5432' error
* Fix postgres health check in production
- Remove init-db.sql volume mount (not available in CI/CD environment)
- Init script not needed as Prisma handles schema migrations
- Postgres will initialize empty database automatically
* Fix cache permission error in Docker container
- Create cache directories AFTER copying standalone files
- Create both fetch-cache and images subdirectories
- Set proper ownership for nextjs user
- Fixes EACCES permission denied errors for prerender cache
* Fix German jogging fallback text
* Use Directus content in production
* fix: Security vulnerability - block malicious file requests
* fix: Switch projects to Directus, add security fixes and example projects
- Created setup-directus-collections.js to automate the creation of tech stack collections, fields, and relations in Directus.
- Created setup-directus-hobbies.js for setting up hobbies collection with translations.
- Created setup-directus-projects.js for establishing projects collection with comprehensive fields and translations.
- Added setup-tech-stack-directus.js to populate tech_stack_items with predefined data.
- Updated deployment script to check for existing containers and free ports before starting a new container.
- Added a new script to check the status of the Gitea runner, including service checks, running processes, Docker containers, common directories, and network connections.
- Add CurrentlyReading component with beautiful design
- Integrate into About section
- Add German and English translations
- Add n8n API route for Hardcover integration
- Add comprehensive documentation for n8n setup
Initialize consent state from cookie synchronously so the banner only shows when no choice was made.
fix(api): fail-soft when DB schema missing
Return null/empty content for CMS endpoints when migrations are not applied instead of crashing with Prisma P2021/P2022.
fix(n8n): parse status response defensively
Handle empty/invalid JSON bodies from n8n to prevent activity feed from getting stuck.
Co-authored-by: dennis <dennis@konkol.net>
Avoid shared dev rate-limit bucket for n8n status and fall back to a stable offline state when the status call fails, preventing the widget from getting stuck in the small translucent loading UI.
feat(api): require session authentication for admin routes and improve error handling
fix(api): streamline project image generation by fetching data directly from the database
fix(api): optimize project import/export functionality with session validation and improved error handling
fix(api): enhance analytics dashboard and email manager with session token for admin requests
fix(components): improve loading states and dynamic imports for better user experience
chore(security): update Content Security Policy to avoid unsafe-eval in production
chore(deps): update package.json scripts for consistent environment handling in linting and testing
- Update Content Security Policy (CSP) in next.config.ts to avoid `unsafe-eval` in production, improving security against XSS attacks.
- Refactor API routes to enforce admin authentication and session validation, ensuring secure access to sensitive endpoints.
- Optimize analytics data retrieval by using database aggregation instead of loading all records into memory, improving performance and reducing memory usage.
- Implement session token creation and verification for better session management and security across the application.
- Enhance error handling and input validation in various API routes to ensure robustness and prevent potential issues.
- Improve localStorage access in ActivityFeed, ChatWidget, and AdminPage with try-catch blocks to handle potential errors gracefully.
- Update performance tracking in AnalyticsProvider and analytics.ts to ensure robust error handling and prevent failures from affecting user experience.
- Refactor Web Vitals tracking to include error handling for observer initialization and data collection.
- Ensure consistent handling of hydration mismatches in components like BackgroundBlobs and ChatWidget to improve rendering reliability.
- Migrate contact API from route.tsx to route.ts for improved organization.
- Implement filtering, pagination, and rate limiting for GET and POST requests.
- Enhance error handling for database operations, including graceful handling of missing tables.
- Validate input fields and email format in POST requests to ensure data integrity.
- Integrate real page view data from the database for accurate analytics.
- Implement cache-busting for fresh data retrieval in analytics dashboard.
- Calculate and display bounce rate, average session duration, and unique users.
- Refactor performance metrics to ensure only real data is considered.
- Improve user experience with toast notifications for success and error messages.
- Update project editor with undo/redo functionality and enhanced content management.
- Update background colors and text styles for better contrast and legibility.
- Enhance button styles and hover effects for a more modern look.
- Remove unnecessary scaling effects and adjust border styles for consistency.
- Introduce a cohesive design language across components to improve user experience.
- Add N8N_WEBHOOK_URL, N8N_SECRET_TOKEN, N8N_API_KEY to docker-compose.production.yml
- Export environment variables in workflow before docker-compose up
- Improve error logging in chat API for better debugging
- Add better error handling in ChatWidget component
- Create setup guide for n8n chat configuration
- Add comprehensive parsing for various n8n response formats
- Check multiple field names (reply, message, response, text, content, answer, output, result)
- Handle array responses and nested structures (data, json, items)
- Add recursive search for string values in complex objects
- Improve logging to show full n8n response structure
- Only use fallback if truly no response found
- Add HTML entity decoding for chat responses (fixes ' display issue)
- Add timeout handling for n8n webhook requests (30s chat, 10s status)
- Improve error logging with detailed error information
- Add N8N_SECRET_TOKEN support for authentication
- Better fallback handling when n8n is unavailable
- Fix server-side HTML entity decoding for chat and status endpoints
refactor: modify layout to use ClientOnly and BackgroundBlobsClient components
fix: correct import statement for ActivityFeed in the main page
fix: enhance sitemap fetching logic with error handling and mock support
refactor: convert BackgroundBlobs to default export for consistency
refactor: simplify ErrorBoundary component and improve error handling UI
chore: update framer-motion to version 12.24.10 in package.json and package-lock.json
test: add minimal Prisma Client mock for testing purposes
feat: create BackgroundBlobsClient for dynamic import of BackgroundBlobs
feat: implement ClientOnly component to handle client-side rendering
feat: add custom error handling components for better user experience