diff --git a/.env.example b/.env.example
index e577343..b89e61c 100644
--- a/.env.example
+++ b/.env.example
@@ -15,6 +15,8 @@ PHP_CLI_SERVER_WORKERS=4
BCRYPT_ROUNDS=12
+CIPHERSWEET_KEY=
+
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
diff --git a/database/migrations/2026_02_12_221059_create_sessions_table.php b/database/migrations/2026_02_12_221059_create_sessions_table.php
new file mode 100644
index 0000000..f60625b
--- /dev/null
+++ b/database/migrations/2026_02_12_221059_create_sessions_table.php
@@ -0,0 +1,31 @@
+string('id')->primary();
+ $table->foreignId('user_id')->nullable()->index();
+ $table->string('ip_address', 45)->nullable();
+ $table->text('user_agent')->nullable();
+ $table->longText('payload');
+ $table->integer('last_activity')->index();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('sessions');
+ }
+};
diff --git a/resources/views/components/meetup-popup.blade.php b/resources/views/components/meetup-popup.blade.php
index 7e5fdb3..d83eb29 100644
--- a/resources/views/components/meetup-popup.blade.php
+++ b/resources/views/components/meetup-popup.blade.php
@@ -17,12 +17,12 @@
- {{ $meetup->nextEvent['start']->format('d.m.Y') }}
+ {{ $meetup->nextEvent['start']->asDate() }}
- {{ $meetup->nextEvent['start']->format('H:i') }} Uhr
+ {{ $meetup->nextEvent['start']->asTime() }} Uhr
@if($meetup->nextEvent['location'])
diff --git a/tests/Feature/MeetupPopupTimezoneTest.php b/tests/Feature/MeetupPopupTimezoneTest.php
new file mode 100644
index 0000000..3813ccc
--- /dev/null
+++ b/tests/Feature/MeetupPopupTimezoneTest.php
@@ -0,0 +1,61 @@
+ 'Europe/Berlin']);
+
+ $country = Country::factory()->create();
+ $city = City::factory()->create(['country_id' => $country->id]);
+ $meetup = Meetup::factory()->create(['city_id' => $city->id, 'intro' => 'Test intro']);
+
+ MeetupEvent::factory()->create([
+ 'meetup_id' => $meetup->id,
+ 'start' => '2026-02-19 16:30:00', // UTC
+ 'location' => 'Test Location',
+ ]);
+
+ $meetup->load(['meetupEvents' => function ($query) {
+ $query->where('start', '>=', now())->orderBy('start')->limit(1);
+ }]);
+
+ $html = view('components.meetup-popup', [
+ 'meetup' => $meetup,
+ 'url' => 'https://example.com',
+ 'eventUrl' => 'https://example.com/event',
+ ])->render();
+
+ // 16:30 UTC = 17:30 CET (Europe/Berlin in winter)
+ expect($html)->toContain('17:30 Uhr')
+ ->and($html)->not->toContain('16:30 Uhr');
+});
+
+it('displays event date converted to user timezone in meetup popup', function () {
+ config(['app.user-timezone' => 'Europe/Berlin']);
+
+ $country = Country::factory()->create();
+ $city = City::factory()->create(['country_id' => $country->id]);
+ $meetup = Meetup::factory()->create(['city_id' => $city->id]);
+
+ MeetupEvent::factory()->create([
+ 'meetup_id' => $meetup->id,
+ 'start' => '2026-02-19 23:30:00', // UTC - next day in Berlin
+ 'location' => 'Test Location',
+ ]);
+
+ $meetup->load(['meetupEvents' => function ($query) {
+ $query->where('start', '>=', now())->orderBy('start')->limit(1);
+ }]);
+
+ $html = view('components.meetup-popup', [
+ 'meetup' => $meetup,
+ 'url' => 'https://example.com',
+ 'eventUrl' => null,
+ ])->render();
+
+ // 23:30 UTC on Feb 19 = 00:30 CET on Feb 20 in Europe/Berlin
+ expect($html)->toContain('20. Februar 2026');
+});