- 🔄 Added `x-effect` to lock page scrolling during login progress.
- 🛡️ Disabled login button and added loading indicators when `nostrLoginInProgress`.
- 🖼️ Introduced full-viewport progress overlay with accessible attributes and transitions.
- 🌐 Updated translations for signing states and instructions.
- 🛡️ Added `nostrLoginInProgress` flag to pause `wire:poll` during Nostr login round-trip.
- 🔄 Removed redundant `Session::regenerate()` to avoid session ID conflicts.
- 🪲 Improved error handling for signature serialization and Nostr signer unavailability.
- 🛡️ Avoided redundant `Session::regenerate` call as `Auth::loginUsingId` already updates the session ID.
- 🚀 Replaced `wire:navigate` with a full-page redirect to ensure a fresh CSRF token for Livewire actions.
- 🔄 `requestNostrChallenge` now issues a new challenge when needed.
- 🛡️ Enhanced fallback logic in `nostrLogin.js` to ensure robust challenge retrieval.
- ✅ Added test coverage for fresh challenge issuance.
- 🛡️ Added validation for missing or invalid `challenge`.
- ⚠️ Added error handling for absent or non-functional Nostr signer.
- 🔄 Ensured plain serialization of signed events for Livewire compatibility.
- 🪲 Improved error messages for better user feedback.
✨ **Tests:** Added helper function `makeSignedNostrLoginEvent` for generating NIP-42 signed login events. Updated related tests in `Feature/Auth/NostrLoginTest.php` to use this helper.
🚀 **Livewire Testing:** Enhanced authorization checks and added specific creator-based mounts for `meetups.edit`. Improved tests for `MeetupMountTest` and `EditMeetupTest`.
🎨 **Style:** Standardized `request()->route()` to lowercase country codes across multiple Blade templates for consistency.
🛠️ **Config:** Updated `vite.config.js` formatting for improved readability in ignored paths.
- Trust the Forge reverse proxy and force https URLs in production so
generated absolute URLs match the actual TLS termination.
- Reject Nostr profile photo URLs that aren't http(s) or that resolve to
loopback / private (RFC1918) addresses to close an SSRF vector in
FetchNostrProfileJob.
- Tighten image upload validation across meetup, course, and lecturer
create/edit components: explicit mimes whitelist (jpeg, png, webp),
max 5 MiB, and dimension cap of 4000x4000.
- Replace the silent "skip if exists" branch in LnurlAuthController with
updateOrCreate so concurrent callers cannot race on the k1 record.
- Validate github_data on Meetup edit, decoding the JSON, and keep only
the whitelisted keys (top, left, state) with strict type coercion to
prevent storing arbitrary attacker-controlled JSON.
- Add 60 req/min throttle to the public API group and a stricter 10 req/min
throttle to POST /highscores.
- Replace mass-assigned $guarded=[] with explicit $fillable on User, Meetup,
Course, Lecturer, and SelfHostedService. created_by stays out of the
whitelist; the existing creating() hooks continue to populate it.
- Require authenticated user on Api/MeetupController::index instead of
trusting the user_id query parameter (IDOR).
- Constrain the /img and /img-public route paths to a safe character set
and reject any path containing ".." in ImageController.
- Add rel="noopener noreferrer" to every target="_blank" link on the meetup
and course landing pages.
- Remove unauthenticated /test route that dispatched FetchNostrProfileJob
for a hardcoded user (routes/web.php).
- Enforce created_by ownership check in meetup and lecturer Livewire edit
components; mirror the existing services/edit pattern.
- Replace blind-trust nostrLoggedIn handler with NIP-42-style signed event
verification: server-issued challenge stored in session, client signs a
kind:22242 event, server verifies signature via swentel/nostr-php and
derives npub. Challenge is single-use with 5-minute TTL.
- Validate the ?my[] parameter on the calendar download endpoint as an
array of integers and intersect with the authenticated user's meetups.

In den Modals der Map Points auf der Karte müssen die Uhrzeiten von UTC in die User Zeitzone umgeschrieben werden.
- **Removed:** `docker-compose.yml`, Sail-specific Dockerfiles, and related scripts for PHP 8.3 setup.
- **Updated:** Documentation to reflect a shift from Docker to a direct PHP-based local development workflow.
- **Removed:** `laravel/sail` dependency from `composer.lock`.
- **Implemented:** `#[Locked]` Livewire attribute across components for read-only properties.
- **Added:** Feature tests to ensure locked properties cannot be tampered with.
- **Removed:** Unused feature and component tests to clean up the codebase.
- **Added:** `RecurrenceType` enum for handling event recurrence modes.
- **Introduced:** City, Country, and Meetup factories for test data generation.
- **Implemented:** Migration to support recurring event fields in `meetup_events` table.
- **Enhanced:** Livewire meetup events creation with recurrence validation and preview logic.
- **Updated:** PHPUnit test suite configuration and composer dependencies for `pestphp/pest@v4.3`.
- **Refined:** SEO configuration (`favicon`) to standardize icon format.
- Replaced `state` and `computed` with `Livewire\Component` implementations in `language/selector.blade.php` for enhanced maintainability.
- Adjusted `login.blade.php` syntax for dynamic href generation and removed commented-out sign-up link.
- Added unique `wire:key` attributes to iterable elements for enhanced performance and reactivity.
- Simplified controller routing and corrected indentation in `web.php`, improving clarity.
- Added `LnurlAuthController` to handle LNURL authentication flow with signature verification, user creation, and session expiry checks.
- Integrated authentication error polling in `nostrLogin.js`.
- Added `LoginKeyFactory` for testing and database seed purposes.
- Created feature tests (`LnurlAuthTest`) to validate LNURL callback, error responses, and session handling.
- Extended `login.blade.php` with dynamic error handling and reset logic for expired sessions.
- Introduced `livewire/livewire` v4 dependency.
- Added `config/livewire.php` for Livewire customization.
- Adjusted `login.blade.php` language fallback logic for session handling.
- Created new Blade layouts (`error.blade.php`, `auth.blade.php`, `app.blade.php`) for unified component architecture.
- Update select options with localized names (`Einundzwanzig Community`, `Allgemeine Bitcoin Community`).
- Wrap the heading text on the landing page with `__()` for proper translation.
🛠️ Add “Keine” placeholder option to community select
✏️ Translate community values (“bitcoin”, “einundzwanzig”) on landing page
🌍 Update German locale strings for community names