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.