Replaced the minimal plain-HTML notification email (sent to jh@unixweb.de) with a
fully branded HTML email that matches the existing confirmation email layout.
Changes:
- Added `buildNotificationEmail()` function in `artifacts/api-server/src/routes/contact.ts`
- Same visual structure as `buildConfirmationEmail()`: blue header with JH monogram,
white card body, divider, branded footer with links
- Sender details (name, e-mail, subject, message) are displayed in a structured field
table inside the card body, with subtle background shading and label rows
- "Absender antworten →" CTA button links to `mailto:{email}?subject=Re: {subject}`
so Joachim can reply to the sender in one click
- Subject field row is conditionally rendered (omitted when no subject was provided)
- All user-supplied values are escaped through the existing `escapeHtml()` helper
- The first `sendTransacEmail` call now passes `buildNotificationEmail(...)` instead
of the inline minimal HTML string
No schema, API contract, or dependency changes. Typecheck passes cleanly after
running codegen to resolve a pre-existing import gap in @workspace/api-zod.
Replit-Task-Id: 601aa064-22da-4553-9ad0-a15f82563eb6
Replaced the plain 4-line HTML confirmation email with a fully styled,
table-based HTML email that matches Joachim Hummel's portfolio branding.
Changes:
- artifacts/api-server/src/routes/contact.ts
- Added buildConfirmationEmail(name: string): string helper function
- Replaced inline htmlContent template literal with a call to the new helper
- Extended textContent plain-text fallback with email/separator footer line
Email design details:
- Full DOCTYPE + <html lang="de"> structure for broad client compatibility
- All styles are inline (no <style> blocks) — compatible with Gmail, Outlook, Apple Mail
- Table-based layout throughout (no CSS grid/flexbox, no <div> dividers) for Outlook
- Divider uses a zero-height table cell with border-bottom instead of a <div>
- Brand blue header (#3f4ff4 ≈ hsl(234 89% 60%)) with frosted "JH" monogram badge
- White card body on slate-100 page background matching portfolio palette
- Personalised greeting using the sender's name (XSS-safe via escapeHtml)
- Blue accent sub-heading "Ihre Anfrage ist eingegangen."
- 1–2 Werktage response-time promise in bold
- CTA button "Portfolio ansehen →" linking to joachim-hummel.de
- Footer with name, role tagline, email + website links, and social links
(Blog at blog.unixweb.de and n8n Creators profile — both present in portfolio)
- Legal disclaimer note at the bottom
No new dependencies introduced. Pre-existing typecheck errors in the file
(missing express-rate-limit types, missing api-zod export) are unrelated to
this change and pre-date this task.
Replit-Task-Id: fd961a0e-5bc4-4d29-a6c3-e90227307fe0
Task #11: Formular gegen Spam schützen
- Installed `express-rate-limit` (^8.5.2) as a runtime dependency in
`@workspace/api-server`
- Created a rate limiter (5 requests per IP per hour, 1-hour sliding window)
using `rateLimit()` from express-rate-limit
- Applied the limiter as inline middleware on POST /contact so it runs before
the handler
- On limit exceeded the API returns HTTP 429 with a German-language JSON error:
{ success: false, message: "Zu viele Anfragen. Bitte versuchen Sie es in
einer Stunde erneut." }
- Uses `standardHeaders: "draft-8"` (RateLimit header group) and disables
legacy X-RateLimit-* headers
- Added `app.set("trust proxy", 1)` in app.ts so that Express reads the real
client IP from X-Forwarded-For (set by Replit's reverse proxy), ensuring
the rate limit is applied per actual client rather than per proxy IP
- No other changes to the contact handler flow
No deviations from the task description.
Replit-Task-Id: de2cecbd-511f-4046-8e87-567ec96e19fb
After a visitor submits the contact form, Brevo now sends two emails:
1. The existing notification to jh@unixweb.de with the message details
2. A new confirmation email to the sender's address
The confirmation email:
- Is sent from "Joachim Hummel <jh@unixweb.de>"
- Addresses the sender by name
- Thanks them and sets response-time expectations (1-2 Werktage)
- Includes both plain-text and HTML versions
- Is logged separately via req.log.info for observability
If either email fails, the entire request returns a 500 error (atomic
behavior — both succeed or neither does from the user's perspective).
File changed:
- artifacts/api-server/src/routes/contact.ts
Also ran `pnpm --filter @workspace/api-spec run codegen` to fix a
pre-existing typecheck failure caused by stale generated lib output.
Typecheck passes cleanly after codegen.
Replit-Task-Id: a5d51157-6bd1-48c7-ba04-68e7d951eeab
Task: Seite für Besucher auf Mobilgeräten optimieren (#7)
## Desktop navbar
- Added "Mehr" dropdown grouping secondary links (Kompetenzen, Stärken,
Skills) to keep the primary nav bar uncluttered (Projekte, Erfahrung,
Über mich stay as primary links)
- Dropdown is click-activated with chevron indicator and closes on
outside click; all links include data-testid attributes
- No link wrapping possible with this structure on any common desktop width
## Mobile menu
- Replaced flat link list with two logical section groups:
- "Profil": Über mich, Kompetenzen, Stärken
- "Erfahrung & Skills": Projekte, Erfahrung, Skills
- Each group has a small uppercase label as a visual divider
- Kontakt CTA remains at the bottom separated by a border
- All 6 page sections are now reachable from the mobile menu
## Timeline cards (experience.tsx)
- Shifted timeline spine from left-6 to left-5 freeing 4px of card width
- Reduced left padding from pl-14 to pl-11 on mobile, giving ~12px extra
card width — critical at 320–375px viewports
- Added p-3.5 sm:p-5 so cards use tighter inner padding on very small
screens (< 640px) and normal padding on larger ones
- Added break-words + min-w-0 to role, client, and task text to prevent
horizontal overflow from long German compound words
- Wrapped task text in a <span> so flex layout doesn't clip overflow
Replit-Task-Id: 51a5a369-3f27-4245-903a-4dc59ee1a842
## No content changes — all section copy, order, and data is unchanged
Update artifacts/joachim-portfolio/src/components/experience.tsx to add a new experience entry for DevOps Engineer at ITZBund starting 06/2025 and adjust the end date for Senior IT-Consultant at Landesamt für Statistik Bayern to 05/2025.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: d9515e1b-1bc4-4182-bd42-01e865a76b55
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e678fe28-87ab-4437-945b-7a15e872a292/6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805/YmfGtQf
Replit-Helium-Checkpoint-Created: true
Task: Downloadbarer Lebenslauf als PDF (#5)
Changes:
- Generated a professional German-language PDF CV for Joachim Hummel
and placed it at artifacts/joachim-portfolio/public/lebenslauf-joachim-hummel.pdf
- PDF includes: header with contact info, Profil summary, full Berufserfahrung
(5 stations from 2015–present), Skills & Technologien (8 categories with
styled tags), Methodik & Compliance badges, and Online-Präsenz links
- PDF generated via a temporary pdfkit Node.js script — no new runtime
dependency added to the workspace packages
- Added "Lebenslauf herunterladen" button to hero.tsx CTA button row,
with a Download icon from lucide-react and the `download` attribute
set so the browser triggers a file save dialog
- Button links to /lebenslauf-joachim-hummel.pdf (served from Vite public/)
and is fully accessible on mobile
No deviations from the task spec.
Replit-Task-Id: 476fd3be-9524-477c-a069-edf58213f2e2
Removes all instances of "Vibe-Coding" and "Vibe-Coder" from contact, hero, and projects components, updating descriptions to reflect current project focus on KI-development.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 7135d765-a979-401b-89f0-355a26efbd11
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e678fe28-87ab-4437-945b-7a15e872a292/6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805/JSK21aO
Replit-Helium-Checkpoint-Created: true
Task: #3 — Erweitertes Skill-Profil & Technologie-Matrix
## What was done
- Created new `skills.tsx` component with a full technology matrix grouped into 8 categories:
Betriebssysteme, Middleware/Webserver, Container & Automatisierung, Monitoring,
Datenbanken, KI & Automation, Programmierung & Scripting, Kollaboration & Dokumentation
- Tags/Pills layout — compact, scannable, no progress bars per spec
- Methodik & Compliance card with ITIL v3/v4 and BSI-Grundschutz as prominent primary-colored badges
- Soft Skills block (Analytisches Denken, Belastbarkeit, Kommunikation, etc.) as a compact pill group
- Tech-Blogger credential card: "300+ Fachartikel auf blog.unixweb.de" with external link
- Framer Motion scroll-in animations consistent with all other sections
- Section placed after Experience, before Contact; id="skills"
- Added "Skills" anchor link to navbar (both desktop and mobile)
- Fixed residual "KI & Vibe-Coding" label in competencies.tsx → "KI & Automation"
- All data from the PDF profile/task spec; no duplicates with competencies.tsx
## Deviations
- None. All required categories, ITIL/BSI badges, soft skills block, and blogger credential implemented as specified.
Task: #2 — Berufserfahrung Timeline
## What was done
- Created new `experience.tsx` component with a vertical alternating timeline
- Implemented 5 career stations from the PDF profile:
1. Senior IT-Consultant @ Landesamt für Statistik Bayern (01/2024–heute)
2. Technischer Redakteur @ Polizei Hessen (04/2024–12/2024)
3. Projektkoordinator @ Justiz Baden-Württemberg (04/2023–10/2023)
4. Senior IT-Systems Engineer @ Amt d. öff. Rechts Hamburg (10/2020–04/2023)
5. Senior IT-Consultant @ Finanzdienstleister München (01/2015–06/2020)
- Each station shows: period, role, client, 4–5 task bullets
- Visual distinction between Behörde (blue, Landmark icon) and Konzern (violet, Building2 icon)
- Legend badges at top of section for type color coding
- Framer Motion scroll-in animations consistent with other sections
- Responsive: single-column on mobile, alternating left/right on desktop
- Added section to `home.tsx` after Bio, with `id="experience"`
- Added "Erfahrung" nav link to `navbar.tsx` (both desktop and mobile menu)
## Deviations
- None. All 5 required stations implemented with 3–5 bullets each as specified.
Adjusted bio, hero badge, and strengths description to reflect AI-powered software development as a tool for faster implementation, leveraging 30 years of IT experience and prioritizing architecture and operational security.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 1b37a303-2f35-439a-af9a-c98d86e8e7b7
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e678fe28-87ab-4437-945b-7a15e872a292/6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805/BWIZrK7
Replit-Helium-Checkpoint-Created: true
Changes:
- hero.tsx: Extended title subtitle to two lines covering all six roles:
"Senior IT-Consultant · Service Manager · Technical Writer" (line 1)
"KI-Automation Experte · IT-Systems Engineer · Vibe-Coder" (line 2)
Uses <br> hidden on mobile, visible on sm+ screens for clean wrapping.
- navbar.tsx: Added blogLinks array (Tech-Blog, KI-Blog) rendered after a
visual separator (1px divider) in the desktop nav and mobile menu.
Each blog link opens in a new tab with rel="noopener noreferrer" and
an ExternalLink icon (3px, half-opacity) as a visual cue.
Added ExternalLink import from lucide-react.
- projects.tsx: Removed leftover `color` field from the "Mailserver &
Groupware" entry (cleanup from prior task).
Already complete from Task #4 (redesign):
- contact.tsx: jh@unixweb.de, blog.unixweb.de, ki-blog.unixweb.de,
joachimhummel.de all wired up with correct target="_blank" links.
- projects.tsx: SafeDocs Portal (safedocsportal.com) and zensend.email
already had url fields and ArrowUpRight link buttons rendering.
No address or phone number anywhere on the site.
No deviations from scope.
Refactor Competencies component to use inline styles for icon colors on hover, remove unused useEffect import from Navbar, and remove deprecated color fields from Projects data.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: b8777d1d-dc61-483e-b8ec-2f66ace1694b
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e678fe28-87ab-4437-945b-7a15e872a292/6f3329ae-2dcc-46cc-bf2e-f58b7a5fa805/IiY74sQ
Replit-Helium-Checkpoint-Created: true
Task #4 — vollständiges Redesign von dunkler Terminal-Ästhetik zu modernem SaaS-Look.
Änderungen:
- index.css: Komplette Neudefinition der CSS-Variablen. Helles Farbschema (weißer Hintergrund),
Primärfarbe Indigo/Blau (hsl 234 89% 60%), neutrale Grautöne, Google Font Inter eingebunden.
Utility-Klassen .section-number, .hero-gradient, .dot-pattern, .card-hover hinzugefügt.
Terminal-spezifische Klassen (.glow-text, .glow-box, .bg-grid-pattern) entfernt.
- navbar.tsx: Sticky Nav mit transparentem Start → weißem Hintergrund + Schatten beim Scrollen.
Logo "JH" als gefülltes Indigo-Badge + "Joachim Hummel" Text. Pill-Style Navigation Links.
Primär-CTA Button. Vollständiges Mobile-Menü mit Hamburger/X Toggle.
- hero.tsx: Zentriertes Layout, großer Display-Headline mit Indigo-Akzent auf Nachname.
"Verfügbar für neue Projekte" Badge mit grünem Puls. Skill-Badges (30+ Jahre, ITIL, etc.).
Zwei CTAs: gefüllter Primärbutton + Outline-Button. Subtiler Radial-Gradient + Dot-Pattern.
- competencies.tsx: Sechs weiße Karten im Grid mit farbigen Icon-Badges (blau, sky, grün, orange,
violett, rose). Tech-Icon-Leiste (Linux, Ubuntu, Docker, Grafana, Nginx, Ansible, Prometheus)
mit Hover-Farbeffekt und Labels.
- strengths.tsx: Drei weiße Karten auf hellgrauem Hintergrund. Nummerierung (01/02/03) als
dekoratives Element. Highlight-Badge je Karte. Kein Glow, kein Neon.
- projects.tsx: Sechs Projektkarten mit farbigen Icon-Badges je Projektkategorie. Externe Links
für SafeDocs Portal (safedocsportal.com) und zensend.email als ArrowUpRight-Icon-Buttons.
Pill-Badges für Tags.
- bio.tsx: Zweispaltiges Layout. Links: Fließtext + Kunden-Badges. Rechts: Weißes Highlights-Panel
mit CheckCircle-Icons (7 Punkte inkl. ITIL, BSI, Tech-Blogger).
- contact.tsx: Primärfarbige E-Mail-Karte + drei kompakte Link-Cards (Tech-Blog, KI-Blog, Website).
Footer-Zeile mit Name und Standort.
- home.tsx: Vereinfacht — kein Fixed-Background, kein Grid-Pattern, kein Ambient-Glow.
max-w-6xl Container für alle Sektionen.