- Add PUT /auth/password for setting/changing passwords (handles both
first-time set for magic link/OAuth users and change for password users)
- Generate random medieval display names (e.g. Gaukler1025) for new
magic link and OAuth users instead of leaving display_name empty
- Add has_password field to ProfileData response
maxSurge=1 requires a second pod during rollout, but the tenant
ResourceQuota (1 CPU limit) is already at 900m — the extra 250m
exceeds the cap and the pod can't schedule, causing a 5min timeout.
Switch to maxSurge=0/maxUnavailable=1 (kill-then-start) to stay
within quota. Matches the web deployment strategy.
The public Search and admin List handlers share structure but use
different types (SearchParams/AdminSearchParams, MarketSummary/
AdminMarketSummary). This is intentional, not a refactoring target.
- Add SMTP_PORT, SMTP_FROM, ADMIN_EMAIL, FRONTEND_URL to ConfigMap
- Add Helm-managed SMTP secret for credentials (host, user, password)
- Wire Woodpecker secrets into deploy step via --set flags
- SMTP secret conditionally created only when values are provided
Add styled HTML email templates for market submission notifications
and magic link authentication, matching the frontend's forest green
and gold design language.
- Template engine using go:embed with clone-per-content pattern
- Multipart/alternative MIME (text/plain + text/html) in SMTPSender
- Base layout: dark green header, gold accent, parchment tones
- Market submission template with details table and admin CTA
- Magic link template with CTA button and fallback URL
- Wire email sending into MagicLinkHandler (replaces TODO)
- Add FRONTEND_URL config for template links
- Admin CRUD endpoints for markets with role-based middleware
- Anonymous market submission with Cloudflare Turnstile verification
- SMTP email notifications on new submissions (LogSender fallback)
- Market status workflow (pending/approved/rejected) with admin notes
- Nullable location column for submissions without coordinates
- CLI tool for promoting users to admin role
- Slug generation package extracted from seed
- Rate limiting on submission endpoint (3/hour per IP)
- Mailpit added to docker-compose for local email testing
- Reduced from 312 to 272 markets (removed 39 unverified/unconfirmed entries)
- All 272 markets now have real descriptions sourced from official websites
- Added admission prices (adult/child cents + notes) where available
- Added street addresses and corrected venue names
- Added opening hours for markets where published
- Updated websites to full https:// URLs
- Updated seedMarket struct with new fields: Street, Description,
AdmissionAdultCents, AdmissionChildCents, AdmissionNotes
- Seed INSERT now uses description/admission from JSON instead of
generating template descriptions; falls back to generated desc if empty
- Added jsonString() helper for SQL-safe JSON encoding
Single-replica deployment with tight CPU quota (1 core) cannot run two
pods simultaneously during a rolling update. Recreate kills the old pod
before starting the new one.
Scrape marktkalendarium.de for 2026 market data and replace the
placeholder seed with real events across DE/AT/CH.
- Embed 311 markets as JSON with name, dates, city, zip, venue,
organizer and website
- Geocode coordinates via Nominatim with caching and rate limiting
- Auto-derive Bundesland from postal code prefix
- Generate descriptions based on event type keywords
- Support DATABASE_URL env var for direct production seeding
Tenant SA lacks dragonflydb.io CRD permissions. Use a standard
Valkey Deployment+Service instead. Also re-enable CNPG (created
via kubectl), migrate job, and add seccompProfile to migrate pod.
- Disable revive exported/package-comments rules (style, not correctness)
- Use errors.Is instead of == for pgx.ErrNoRows comparisons
- Use errors.As instead of type assertion on validator errors
- Use http.NewRequestWithContext instead of client.Get (noctx)
- Check resp.Body.Close error return (errcheck)
- Run gofmt on files with formatting drift