Replaces em dashes with en dashes across all hardcoded copy, emails, and
seed content, then reworks the site's visual language so it reads as
deliberately designed rather than assembled from generic components:
- New ArrowLink component replaces ad hoc "Mehr erfahren ->" links and
ghost buttons; one shared FormField (TextField/TextAreaField) replaces
7 near-duplicate field styles across every form
- Navbar loses its glassmorphism blur for a solid warm background, gets a
subtle active-link underline and a softer, warmer mega-menu
- PageHeader supports per-page blob tone/position and a compact mode
instead of an identical band on every interior page
- Homepage: the core offer is featured large instead of four equal cards,
the philosophy section gets a single calmer accent blob, blog teasers
now show their cover image like the real /aktuelles page does
- Booking calendar and widget: 44px touch targets throughout (month nav,
day cells, time slots, cancel action), a visible "today" ring, and
responsive padding so the calendar isn't cramped on small screens
- Quieter, warmer empty states on /termine and /aktuelles
No functional changes: all interaction logic (nav menus, forms, booking,
CMS data fetching) is untouched, only markup and styling.
Adds a first-party analytics system with no third-party trackers and no
persistent per-visitor identifiers: events are grouped into sessions via a
daily-rotating pseudonymous hash (IP+UA+host, HMAC-salted, never stored raw).
- New "Analytics" section in the Payload admin, gated by a canViewAnalytics
permission on Users, following the existing custom-admin-view pattern
used by the calendar feature
- Sessions, page views, unique visitors, top/entry/exit pages, events,
device/browser breakdown, date range filter with period comparison
- Raw events and daily aggregate rollups as their own collections, with
configurable retention and a cron endpoint that rolls up before purging
- Cookie consent banner (necessary/preferences/statistics) with categories
and copy editable from a new CMS global; a track() helper that is a
complete no-op without statistics consent, so nothing is ever sent
before a visitor opts in
- track() calls wired into the booking flow, contact form, and navigation
- Restrict meetingPassword field so it isn't leaked via the public REST/GraphQL API
- Fix booking slot computation to use Europe/Berlin time instead of the server's UTC clock
- Reset email verification when a customer changes their email address
- Fix ICS calendar injection via unescaped carriage returns in event descriptions
- Bind WebRTC meeting kicks to a persistent client id so they survive a rejoin
- Move the meeting signaling token out of the WebSocket query string into the first message
- Prevent duplicate signaling connections from leaking when the same participant reconnects
- Use the rightmost X-Forwarded-For entry for rate limiting (single trusted reverse proxy)
- Use constant-time comparison for the cron endpoint's bearer token
- Remove SVG from allowed Media upload types (stored-XSS risk, unused anyway)
- Add baseline security headers and a CSP to next.config.ts
- Fix CI/CD script injection via unsanitized git ref names in release.yml
- Customer accounts now require email verification (hashed, single-use,
time-limited tokens) before they can request/confirm bookings, with
resend flows on login/account/booking widget and rate limiting.
- Admins get a private, rotatable iCalendar (ICS) subscription feed of
their confirmed bookings and public events, timezone-correct for
Europe/Berlin including DST, never exposing meeting passwords.
- Adds a full SEO layer: per-page canonical/OG/Twitter metadata with
CMS-editable overrides and content-derived fallbacks, a dynamic
sitemap.xml and robots.txt driven by real published content, JSON-LD
(Organization/LocalBusiness, WebSite, WebPage, BreadcrumbList, Service,
Event, BlogPosting) that never fabricates data, and a CMS-managed
redirect table for changed slugs.
- Global ANOUMA-naming audit: the brand name is never used to label
personal account/calendar areas anywhere in the app, CMS, or emails.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- setup.sh: interactive/non-interactive one-shot installer (build, DB
healthcheck, migrate, seed, start), idempotent secret generation, NPM
reverse-proxy network auto-detection and optional join, optional
AUTO_UPDATE cron install.
- update.sh: release-tag-gated updates only (never bare main), DB backup
with retention before every update, lock file against concurrent runs,
automatic code rollback on failed post-update healthcheck.
- Dockerfile: multi-stage build, non-root user, built-in HEALTHCHECK against
the new /api/health route, wholesale COPY so new source dirs (e.g.
scripts/) never silently go missing at runtime.
- docker-compose.yml: internal anouma-network (configurable), named volume
for Postgres, app depends_on postgres healthy, no unnecessary published
ports; docker-compose.override.yml.example documents joining an existing
NPM network without ever touching NPM itself.
- Fix host-detection: isHost was Boolean(user), wrongly granting host
privileges to logged-in customers; now checks user.collection === "users".
- Wire configurable STUN/TURN servers through to the WebRTC client
(lib/meeting/iceServers.ts) so a TURN server can be added later via env
vars only, no code changes.
- DEPLOYMENT.md, updated README.md and .env.example documenting the whole
flow: NPM integration, env vars, WebRTC, updates, backups, rollback.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Next.js 16 App Router site with the ANOUMA design system
- Payload CMS (PostgreSQL) for offers, events, posts and page content
- WebRTC video-call system with custom signaling server
- SMTP email reminders and booking-request notifications
- Customer accounts, calendar-based availability, and booking workflow