# Implementation Plan: personal-homepage (andreknie.de) ## Overview Build a personal homepage for Dr. Andre Knie at andreknie.de using Vite 8 + React 19 (JSX), react-router-dom v7, Express 5 backend, CSS custom properties theming, file-based CMS (content/ directory with markdown + YAML), and Docker + Caddy deployment. The Projekt-KIQ-HP reference (cloned at reference/Projekt-KIQ-HP/) serves as a code reference for visual patterns (glass morphism, animated background, bottom dock, bento grid). ## Tasks - [x] 1. Project scaffolding and core infrastructure - [x] 1.1 Initialize project with Vite 8 + React 19 and configure tooling - Create new repository `andreknie.de/` with `npm create vite@latest` (React template) - Install dependencies: react-router-dom v7, vite (v8), vitest, fast-check, @testing-library/react - Configure `vite.config.js` with plugin slot for content loader - Create `.env.example` with SMTP and server config placeholders - Set up `vitest.config.js` with jsdom environment - _Requirements: 18.1, 18.2_ - [x] 1.2 Create CSS theming system with custom properties - Create `src/index.css` with full `:root` variable block (colors, spacing, typography, transitions, radii) - Use placeholder neutral blue (`#4a9eff`) as accent color - Define glass morphism utility classes (`.glass-panel`, `.text-gradient`, `.bento-glow`) - Import Inter font from Google Fonts - Implement dark theme base (`--bg-color: #0a0a0a`) - _Requirements: 17.1, 17.2_ - [x] 1.3 Create directory structure for content, server, and plugins - Create `content/` with subdirectories: posts/, kniepunkt/, podcast/, talks/, consulting/, resources/, events/, meta/ - Create `public/` with subdirectories: images/, logos/, resources/, patterns/ - Create `server/` with subdirectories: routes/, middleware/, services/, data/ - Create `plugins/` directory - Create `src/` with subdirectories: components/, pages/, hooks/, utils/, data/ - _Requirements: 14.1, 14.3_ - [x] 1.4 Create sample content files for all content types - Create `content/meta/profile.yaml` with stakeholder profile data (name, roles, summary, positioning, dHive info) - Create `content/meta/stats.yaml` with key facts (50+ Projekte, 13+ Jahre KI, 60+ Publikationen, 100% DSGVO & AI-Act) - Create `content/meta/audiences.yaml` with target audience descriptions - Create at least 1 sample file per content type (post, kniepunkt issue, podcast episode, talk, consulting example, resource, event) - Follow exact YAML/frontmatter schemas from design document - _Requirements: 1.1, 1.2, 1.4, 2.1, 14.1, 15.1_ - [x] 2. Vite content plugin and content utilities - [x] 2.1 Implement `plugins/vite-plugin-content.js` for build-time content transformation - Read all files from `content/` subdirectories at build time - Parse markdown files with frontmatter (gray-matter) into JSON (title, date, tags, summary, body as HTML via marked/remark) - Parse YAML files into JSON objects - Validate required fields per content type (warn on missing, don't fail build) - Export transformed content as virtual modules importable by React components - _Requirements: 14.1, 14.2, 14.3_ - [x] 2.2 Implement `src/utils/contentLoader.js` for runtime content access - Implemented as `src/hooks/useContent.js` (loading by type, sorting by date desc, tag filtering) - Create utility functions to load content by type (getPosts, getTalks, getConsultingExamples, etc.) - Implement sorting by publication date descending (newest first) - Implement tag extraction for dynamic filter options (max 20 distinct tags) - Implement content-area validation (reject invalid content-area values with error message) - _Requirements: 13.4, 13.5, 14.4, 14.5_ - [ ]* 2.3 Write property tests for content transformation and validation (Property 10) - **Property 10: Content file validation** - Generate arbitrary content objects with random missing/invalid fields - Assert: missing required attributes → rejection with error indicating missing fields - Assert: invalid content-area → rejection with error listing valid areas - **Validates: Requirements 9.4, 14.1, 14.4** - [ ]* 2.4 Write property tests for content list sorting (Property 2) - **Property 2: Content list sorting** - Generate arbitrary lists of content objects with random dates - Assert: output is always sorted by publication date descending - **Validates: Requirements 3.3, 7.3, 8.2, 14.5** - [ ]* 2.5 Write property tests for dynamic filter derivation (Property 8) - **Property 8: Dynamic filter options derived from content** - Generate arbitrary sets of content objects with random tags - Assert: available filter options = complete set of distinct tags (up to 20) - **Validates: Requirements 13.4, 13.5** - [ ] 3. Checkpoint — Content pipeline verified - Ensure all tests pass, ask the user if questions arise. - [x] 4. Shared UI components - [x] 4.1 Implement BackgroundPattern, GlassCard, and BentoGrid components - BackgroundPattern implemented (canvas particle field); glass/grid realized via `.glass-panel` utility + per-page grids - `BackgroundPattern.jsx` + `.css`: animated drifting SVG background (mirrored-quadrant technique from reference) - `GlassCard.jsx` + `.css`: reusable glass-morphism card with backdrop-filter blur - `BentoGrid.jsx` + `.css`: responsive grid layout for content cards with hover glow effect - Reference: Projekt-KIQ-HP patterns for visual implementation - _Requirements: 17.1, 17.2_ - [x] 4.2 Implement Navigation and BottomDock components - Navigation uses written-out top-bar links (no hamburger overlay, per stakeholder preference) - `Navigation.jsx` + `.css`: top bar with logo + hamburger overlay menu (same overlay pattern from reference) - `BottomDock.jsx` + `.css`: fixed bottom navigation pill with rotating conic-gradient light border - Navigation items: Home, Kniepunkt, Podcast, Speaking, Consulting, Resources, Kontakt - _Requirements: 1.1_ - [x] 4.3 Implement Footer with dHive cross-reference and newsletter form slot - `Footer.jsx` + `.css`: CTA section + newsletter form slot + legal links (Impressum, Datenschutz) - Include visible link to d-hive.de with stakeholder role (Founder & Managing Director) - dHive branding ≤ 20% of section area, positioned after personal name/title - Link opens in new tab (`target="_blank"`) - _Requirements: 16.1, 16.2, 16.3_ - [ ] 4.4 Implement ContentFilter and Pagination components - OPEN: dedicated ContentFilter, Pagination, SEOHead components not yet implemented (ScrollToTop exists) - `ContentFilter.jsx` + `.css`: tag-based filtering UI, derives options dynamically from content metadata - `Pagination.jsx` + `.css`: page navigation for lists (10 items per page) - `ScrollToTop.jsx`: scroll restoration on route change - `SEOHead.jsx`: meta tags per page - _Requirements: 13.1, 13.2, 13.3, 8.3_ - [ ]* 4.5 Write property tests for content filtering (Property 7) - **Property 7: Content filtering returns only matching items** - Generate arbitrary content sets with random tags and arbitrary filter selections - Assert: filtered result contains exactly those items whose tags include the selected criterion - **Validates: Requirements 13.1, 13.2** - [ ]* 4.6 Write property tests for pagination (Property 12) - **Property 12: Pagination constraint** - Generate arbitrary lists of items (length 0–100) - Assert: each page contains at most 10 items; pagination controls present when items > 10 - **Validates: Requirements 8.3** - [x] 5. App shell and routing - [x] 5.1 Implement App.jsx with react-router-dom v7 routing - Set up `App.jsx` with BackgroundPattern, Navigation, Routes, Footer, BottomDock - Configure routes: `/`, `/kniepunkt`, `/kniepunkt/:slug`, `/podcast`, `/speaking`, `/consulting`, `/resources`, `/kontakt`, `/impressum`, `/datenschutz` - Add 404 fallback route with friendly error page - Implement `main.jsx` entry point with BrowserRouter - _Requirements: 3.4, 18.4_ - [x] 5.2 Implement custom hooks (useContent, useFormSubmit) - useContent, useFormSubmit, validation.js, formatDate.js all present - `src/hooks/useContent.js`: content loading, filtering by tag, sorting, pagination - `src/hooks/useFormSubmit.js`: form submission with validation, error handling, loading state - `src/utils/validation.js`: email format validation, field presence checks, length constraints - `src/utils/formatDate.js`: German locale date formatting - _Requirements: 13.1, 13.2, 4.4, 11.5, 12.5_ - [x] 6. Page implementations — Home and content pages - [x] 6.1 Implement HomePage with Hero, Stats, ContentHighlights, AudienceSection, CTASection - Home includes Hero, StatsCube, photo-band, Mein-Ansatz (positioning), Audiences, LogoMarquee, Testimonials, UpcomingEvents - `Hero.jsx`: stakeholder name, professional photo, summary (≤150 words), all roles listed - `Stats.jsx`: key facts from stats.yaml in animated counters - `AudienceSection.jsx`: explicitly name target audiences (mid-sized companies, HR, OD, IT leaders, managing directors) - `ContentHighlights.jsx`: latest content from each area - `CTASection.jsx`: call-to-action for contact/speaking - Profile visible without scrolling on 1280×720 viewport - _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 2.1, 2.3, 2.4, 17.3, 17.4, 17.5_ - [x] 6.2 Implement KniepunktPage and KniepunktIssuePage - `Kniepunkt.jsx`: distinct labeled section, list of all newsletter issues (title + date), sorted newest first, with ContentFilter - `KniepunktIssue.jsx`: full rendered markdown content of selected issue - Visually separated from other homepage content - _Requirements: 7.1, 7.2, 7.3, 7.4_ - [x] 6.3 Implement PodcastPage - 12 episodes with Spotify/Apple/YouTube/Castro links - `Podcast.jsx`: visually distinct section with podcast name, description, episode listing - Episodes: title, date, summary, sorted reverse-chronological - Max 10 episodes per page with Pagination component - Each episode links to audio on hosting platform or embedded player - Empty state message when no episodes available - _Requirements: 8.1, 8.2, 8.3, 8.4, 8.5_ - [x] 6.4 Implement SpeakingPage with talk list and talk request form - `Speaking.jsx`: list of talks with topic title, description, format (keynote/workshop/panel), past events - Show at least 3 speaking examples with topic title, event name, and format - Include TalkRequestForm component (implemented in task 7) - Hide section if no talks available - _Requirements: 2.2, 5.1, 5.2, 5.3, 5.4_ - [x] 6.5 Implement ConsultingPage - ServiceAccordion + 3 consulting examples (OPEN: more examples per MATERIAL-LISTE) - `Consulting.jsx`: BentoGrid of ExampleCards (3–10 examples) - Each card: title, industry tag, org-size category (50–5000 employees), problem domain, approach, outcomes - No client names, revenue figures, or internal identifiers exposed - Informational message if no examples available - _Requirements: 6.1, 6.2, 6.3, 6.4_ - [x] 6.6 Implement ResourcesPage with lead capture - OPEN: no resource content files yet (content/resources/ empty) - `Resources.jsx`: list of resources with title, short description (≤200 chars), download indicator - `LeadCaptureForm.jsx`: modal form requiring name (max 100), email (validated), company (max 150) - Display required fields and purpose before submission - Inline validation errors with data retention on failure - _Requirements: 4.1, 4.2, 4.3, 4.4, 4.6_ - [x] 6.7 Implement ContactPage, Impressum, and Datenschutz - OPEN: Impressum/Datenschutz contain placeholder legal data (needs real address, USt-IdNr) - `Contact.jsx`: contact form with name, email, message (max 2000 chars), validation errors per field - `Impressum.jsx`: static legal content - `Datenschutz.jsx`: static privacy policy content - _Requirements: 11.1, 11.5_ - [ ] 6.8 Implement Events display (within relevant pages or as section) - UpcomingEvents component exists, but content/events/ is empty — OPEN: add event content - Display events grouped by year, upcoming before past, each group sorted by date descending - Each event: title, date (ISO 8601), location, event type, description (≤300 chars) - _Requirements: 9.1, 9.2, 9.3_ - [ ]* 6.9 Write property tests for content rendering completeness (Property 1) - **Property 1: Content rendering completeness** - Generate arbitrary content objects per type with all required fields - Assert: rendered output contains all required fields for that type - **Validates: Requirements 3.1, 3.2, 3.5, 4.1, 5.2, 6.1, 6.3, 7.2, 8.2, 8.4** - [ ]* 6.10 Write property tests for event chronological grouping (Property 9) - **Property 9: Event chronological grouping** - Generate arbitrary event sets with dates spanning past and future - Assert: upcoming events appear before past events; each group sorted by date descending; grouped by year - **Validates: Requirements 9.2** - [ ] 7. Checkpoint — Frontend pages complete - Ensure all tests pass, ask the user if questions arise. - [x] 8. Express 5 backend — form handling and confirmation flow - [x] 8.1 Set up Express 5 server with middleware - `server/index.js`: Express 5 entry point with JSON body parsing, CORS, error middleware - `server/middleware/rateLimiter.js`: rate limiting per endpoint (contact: 3/h, talk: 3/h, newsletter: 5/h, resource: 10/h) - `server/middleware/validator.js`: input validation middleware (field presence, email format, length constraints) - Health check endpoint: `GET /api/health` - _Requirements: 11.1, 12.1_ - [x] 8.2 Implement confirmation token service - `server/services/confirmationToken.js`: generate unique tokens (crypto.randomUUID), store with expiration, verify, cleanup expired - Token storage in JSON files under `server/data/` - Contact tokens expire after 24h, talk request and newsletter tokens after 48h - Scheduled cleanup interval (every hour) for expired tokens - _Requirements: 10.3, 10.4, 11.2, 11.4, 12.2, 12.4_ - [x] 8.3 Implement mailer service with nodemailer - `server/services/mailer.js`: nodemailer configuration from environment variables - Email templates: confirmation email (with unique link), stakeholder notification email - Send exactly one confirmation email per valid submission - _Requirements: 10.3, 11.2, 12.2_ - [x] 8.4 Implement contact form route with double opt-in - `server/routes/contact.js`: POST `/api/contact` — validate, store pending, send confirmation email - POST `/api/contact/confirm/:token` — verify token, forward message to stakeholder, mark confirmed - Reject expired/invalid tokens with appropriate status codes (404/410) - _Requirements: 11.1, 11.2, 11.3, 11.4, 11.5_ - [x] 8.5 Implement talk request route with double opt-in - `server/routes/talk-request.js`: POST `/api/talk-request` — validate (name, email, event_name, topic, message), store pending, send confirmation - POST `/api/talk-request/confirm/:token` — verify token (48h), forward to stakeholder - _Requirements: 12.1, 12.2, 12.3, 12.4, 12.5_ - [x] 8.6 Implement newsletter signup route with double opt-in - `server/routes/newsletter.js`: POST `/api/newsletter` — validate email, check for existing subscription, store pending, send confirmation - GET `/api/newsletter/confirm/:token` — verify token (48h), activate subscription, create Sales_Funnel entry - Detect and reject duplicate subscriptions with informational message - Discard unconfirmed subscriptions after 48h - _Requirements: 10.1, 10.2, 10.3, 10.4, 10.5, 10.6_ - [x] 8.7 Implement resource download route with lead capture - `server/routes/resource-download.js`: POST `/api/resource-download` — validate (name, email, company, resource_id), store lead record with timestamp, return download URL - Lead record must be retrievable for Sales_Funnel development - _Requirements: 4.2, 4.3, 4.5_ - [ ]* 8.8 Write property tests for form validation (Property 3) - **Property 3: Form validation rejects invalid input** - Generate arbitrary form payloads with random missing/invalid fields - Assert: invalid submissions are rejected with field-level errors; valid data retained - **Validates: Requirements 4.4, 10.5, 11.5, 12.5** - [ ]* 8.9 Write property tests for token expiration (Property 4) - **Property 4: Confirmation token expiration** - Generate tokens with arbitrary creation times and verify against expiration windows - Assert: expired tokens are rejected; associated records discarded - **Validates: Requirements 10.4, 11.4, 12.4** - [ ]* 8.10 Write property tests for valid submission triggering confirmation (Property 5) - **Property 5: Valid submission triggers confirmation email** - Generate arbitrary valid form submissions (all fields present, valid email) - Assert: unique token generated, pending request stored, exactly one confirmation email sent - **Validates: Requirements 10.3, 11.2, 12.2** - [ ]* 8.11 Write property tests for valid token confirmation (Property 6) - **Property 6: Valid token confirmation forwards to stakeholder** - Generate valid unexpired tokens with associated pending records - Assert: confirmation results in forwarding to stakeholder and record marked confirmed - **Validates: Requirements 11.3, 12.3** - [ ]* 8.12 Write property tests for lead data storage (Property 11) - **Property 11: Lead data storage integrity** - Generate arbitrary valid lead capture submissions - Assert: stored record contains all submitted fields + resource_id + timestamp; record is retrievable - **Validates: Requirements 4.5** - [ ]* 8.13 Write property tests for duplicate subscription detection (Property 13) - **Property 13: Duplicate subscription detection** - Generate arbitrary email addresses, some already in active subscriptions - Assert: duplicate emails are rejected with informational message; no duplicate entry created - **Validates: Requirements 10.6** - [ ] 9. Checkpoint — Backend API complete - Ensure all tests pass, ask the user if questions arise. - [ ] 10. Integration and wiring - [x] 10.1 Wire frontend forms to backend API endpoints - useFormSubmit posts to /api endpoints with success/error handling - Connect ContactForm to POST `/api/contact` - Connect TalkRequestForm to POST `/api/talk-request` - Connect NewsletterForm to POST `/api/newsletter` - Connect LeadCaptureForm to POST `/api/resource-download` - Handle success/error responses with appropriate UI feedback (toast notifications, success messages) - _Requirements: 10.1, 11.1, 12.1, 4.2_ - [ ] 10.2 Create confirmation landing pages - OPEN: inline success messages exist, but dedicated email-confirmation landing pages / token-confirm routes in the SPA are not yet built - Success page shown after email confirmation (contact, talk request) - Newsletter confirmation success page - Expired/invalid token error page - _Requirements: 11.2, 11.3, 12.2, 12.3_ - [ ]* 10.3 Write integration tests for form submission flows - Test contact form: submit → pending stored → confirmation email triggered - Test talk request: submit → pending stored → confirmation email triggered - Test newsletter: submit → pending stored → double opt-in email triggered - Test resource download: submit lead data → lead stored → download URL returned - _Requirements: 10.2, 10.3, 11.2, 11.3, 12.2, 12.3, 4.5_ - [ ] 11. Deployment configuration - [x] 11.1 Create Dockerfile and docker-compose.yml for backend - Dockerfile: Node.js image, install dependencies, run Express server on port 3003 - docker-compose.yml: single `backend` service, volume mount for `server/data/`, env file reference - _Requirements: 18.1_ - [x] 11.2 Create Caddyfile for production serving - Auto HTTPS via Let's Encrypt for andreknie.de - Reverse proxy `/api/*` to Express backend on port 3003 - Serve static SPA files with `try_files {path} /index.html` - Security headers (HSTS, X-Content-Type-Options, CSP) - Gzip/zstd compression - Immutable cache for `/assets/*` - _Requirements: 18.4_ - [x] 11.3 Configure Vite build with content plugin integration - vite-plugin-content registered; `npm run build` produces complete dist/ (verified) - Register `vite-plugin-content` in `vite.config.js` - Verify `npm run build` produces complete `dist/` with all content embedded - Ensure build output is deployable as static files to `/opt/andreknie/site/` - _Requirements: 14.2_ - [ ] 12. Final checkpoint — Full integration verified - Ensure all tests pass, ask the user if questions arise. ## Notes - Tasks marked with `*` are optional and can be skipped for faster MVP - Each task references specific requirements for traceability - Checkpoints ensure incremental validation - Property tests validate universal correctness properties from the design document (13 properties total) - Unit tests validate specific examples and edge cases - The project is created as a NEW repository — not inside the current CV workspace - Use `reference/Projekt-KIQ-HP/` as visual pattern reference (glass morphism, animated background, bottom dock, bento grid) - Colors are placeholder (neutral blue #4a9eff) — easily changeable via CSS custom properties in `:root` - Content files in `content/` ARE the CMS — no database needed for content - Backend only handles forms (contact, talk request, newsletter, resource download) - All forms use double opt-in (confirmation email with token) - fast-check is the property-based testing library; Vitest is the test runner ## Task Dependency Graph ```json { "waves": [ { "id": 0, "tasks": ["1.1", "1.3"] }, { "id": 1, "tasks": ["1.2", "1.4"] }, { "id": 2, "tasks": ["2.1"] }, { "id": 3, "tasks": ["2.2", "2.3", "2.4", "2.5"] }, { "id": 4, "tasks": ["4.1", "4.2", "4.3", "4.4", "5.1"] }, { "id": 5, "tasks": ["4.5", "4.6", "5.2"] }, { "id": 6, "tasks": ["6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8"] }, { "id": 7, "tasks": ["6.9", "6.10", "8.1"] }, { "id": 8, "tasks": ["8.2", "8.3"] }, { "id": 9, "tasks": ["8.4", "8.5", "8.6", "8.7"] }, { "id": 10, "tasks": ["8.8", "8.9", "8.10", "8.11", "8.12", "8.13"] }, { "id": 11, "tasks": ["10.1", "10.2"] }, { "id": 12, "tasks": ["10.3", "11.1", "11.2", "11.3"] } ] } ``` ## Offene Themen (Stand-Abgleich) Die Kernimplementierung (Frontend-Seiten, Backend-Formulare mit Double-Opt-In, Content-Pipeline, Deployment-Konfiguration) steht und baut fehlerfrei. Offen sind im Wesentlichen Inhalte, Verifikation und optionale Tests. ### Inhalte / Redaktion (blockiert Go-Live) - [x] Impressum mit echten Daten füllen — Telefon entfernt, E-Mail kontakt@d-hive.de (Task 6.7) - [ ] Datenschutzerklärung final juristisch prüfen — Inhalt vorhanden, Telefon entfernt, datenschutz@d-hive.de für Betroffenenrechte (Task 6.7) - [ ] Weitere Consulting-Beispiele (Ziel 5+, aktuell 3) inkl. Leistungsübersicht & Ergebnis-Zahlen (Task 6.5, MATERIAL-LISTE) — *in Arbeit beim Stakeholder* - [ ] Testimonials final freigeben (3 Entwürfe vorhanden, Freigabe der Personen ausstehend) — *in Arbeit beim Stakeholder* ### Nice to have (Inhalte, kein Go-Live-Blocker) - [ ] Event-Inhalte ergänzen — `content/events/` ist leer (Task 6.8) - [ ] Resource-Inhalte ergänzen — `content/resources/` ist leer (Task 6.6) ### Funktionale Lücken - [ ] Dedizierte ContentFilter-, Pagination- und SEOHead-Komponenten (Task 4.4) - [ ] Confirmation-Landingpages im SPA (Token-Confirm-Routen, Erfolg/Abgelaufen) — bisher nur Inline-Erfolgsmeldungen (Task 10.2) ### Verifikation & Deployment - [ ] Backend lokal end-to-end testen (Formular → Bestätigungsmail → Weiterleitung); SMTP-Konfiguration in `.env` erforderlich - [ ] Produktiv-Deployment durchführen (dist/ auf Server, Docker-Backend starten, Caddy) ### Optionale Property-/Integrationstests (mit `*` markiert, MVP-übersprungen) - [ ] 2.3, 2.4, 2.5 — Content-Validierung, Sortierung, Filter-Ableitung - [ ] 4.5, 4.6 — Filterung, Pagination - [ ] 6.9, 6.10 — Rendering-Vollständigkeit, Event-Gruppierung - [ ] 8.8–8.13 — Formularvalidierung, Token-Ablauf, Bestätigungsmail, Lead-Speicherung, Duplikat-Erkennung - [ ] 10.3 — Integrationstests der Formular-Flows ### Material (siehe `andreknie.de/MATERIAL-LISTE.md`) - [ ] Professionelles Hero-/Profilbild (freigestellt) — aktuell Platzhalter `andre-knie.jpg` - [ ] Open-Graph-Image, Favicon - [ ] Optional: Hero-Video, Testimonial-Videos, Podcast-Cover