No description
  • TypeScript 95%
  • JavaScript 2.7%
  • PLpgSQL 1%
  • CSS 1%
  • Shell 0.3%
Find a file
2026-06-16 14:23:06 +02:00
.github/workflows Tests ergänzt und kleine Korrekturen 2026-06-12 10:00:15 +02:00
db Bug-Fixing und Übersetzung 2026-06-16 14:23:06 +02:00
public Bug-Fixing und Übersetzung 2026-06-16 14:23:06 +02:00
scripts Veranstaltungen kommentieren, Umfragen anlegen, etc. 2026-06-15 15:44:32 +02:00
src Bug-Fixing und Übersetzung 2026-06-16 14:23:06 +02:00
supabase/functions/send-email Berechtigungen, Editoren, etc verbessert 2026-06-14 15:16:38 +02:00
tests Berechtigungen, Editoren, etc verbessert 2026-06-14 15:16:38 +02:00
.env.example initial 2026-06-07 23:31:35 +02:00
.gitignore Tests ergänzt und kleine Korrekturen 2026-06-12 10:00:15 +02:00
CHANGELOG.md Mitveranstalter per E-Mail hinzufügen mit Auto-Verknüpfung & Magic-Link-Einladung 2026-06-10 23:10:06 +02:00
next.config.mjs initial 2026-06-07 23:31:35 +02:00
package.json Veranstaltungen kommentieren, Umfragen anlegen, etc. 2026-06-15 15:44:32 +02:00
playwright.config.ts Tests ergänzt und kleine Korrekturen 2026-06-12 10:00:15 +02:00
pnpm-lock.yaml Tests ergänzt und kleine Korrekturen 2026-06-12 10:00:15 +02:00
postcss.config.mjs initial 2026-06-07 23:31:35 +02:00
README.md Tests ergänzt und kleine Korrekturen 2026-06-12 10:00:15 +02:00
tailwind.config.ts Berechtigungen, Editoren, etc verbessert 2026-06-14 15:16:38 +02:00
tsconfig.json initial 2026-06-07 23:31:35 +02:00
vercel.json Veranstaltungen: Funktionalitäten ergänzt 2026-06-15 23:11:44 +02:00

Bündnis Ost Event-Plattform

Eine offene, gemeinschaftlich betriebene Web-Plattform für Veranstaltungen, Bündnisse und Initiativen in Ostdeutschland. Veranstalter:innen können Events anlegen, sich gegenseitig als Mitwirkende verknüpfen, und die Community kann sich bei MachBar-Veranstaltungen als Helfer:innen eintragen.

„Ostsicht schärfen, Netzwerke stärken. Finde Veranstaltungen, Bündnisse und Initiativen in deiner Region oder trage dein eigenes Event ein."


Inhaltsverzeichnis

  1. Was ist Bündnis Ost?
  2. Hauptfunktionen
  3. Tech-Stack (Übersicht)
  4. Tech-Stack (detailliert)
  5. Architektur
  6. Datenbank
  7. Authentifizierung & Rollen
  8. Projektstruktur
  9. Lokale Entwicklung
  10. Datenbank-Migrationen
  11. Deployment
  12. API-Übersicht
  13. Sicherheit
  14. Mitwirken
  15. Lizenz

Was ist Bündnis Ost?

Bündnis Ost ist eine offene Event-Plattform, die sich auf demokratische Veranstaltungen, zivilgesellschaftliche Bündnisse und lokale Initiativen in Ostdeutschland konzentriert. Sie wurde konzipiert als:

  • Zentrale Anlaufstelle für politische und kulturelle Veranstaltungen in der Region
  • Mitmach-Plattform jede:r kann eigene Events anlegen
  • Netzwerk-Tool für Bündnisse und Initiativen
  • MachBar-Plattform ein spezieller Veranstaltungsmodus, bei dem Helfer:innen für Aufgaben gesucht werden

Die Plattform ist seit Juni 2026 in Betrieb und wird kontinuierlich weiterentwickelt.


Hauptfunktionen

Für Besucher:innen

  • Veranstaltungen entdecken mit Filter nach Modus (Standard / MachBar) und Sortierung nach Datum
  • Detail-Ansicht mit Karte, Beschreibung, Veranstalter, Teilnahme-Optionen
  • MachBar-Anmeldung: Bei MachBar-Veranstaltungen kann man sich als Helfer:in eintragen
  • Geschichten lesen kurze Artikel, Berichte und persönliche Beiträge
  • Netzwerk durchsuchen Übersicht von Bündnissen, Vereinen und Initiativen
  • Dark Mode umschaltbarer Theme-Toggle (Sonne/Mond) als iOS-Style Schalter
  • Mobile-First optimiert für Smartphones, eigener Bottom-Nav mit Aktions-Button

Für Veranstalter:innen

  • 10-Schritt-Wizard zum Erstellen einer Veranstaltung mit:
    • Modus-Auswahl (Standard / MachBar)
    • Standort mit interaktiver Leaflet-Karte + Adress-Suche via Nominatim
    • TipTap-basierter Rich-Text-Editor für die Beschreibung
    • Datum & Uhrzeit mit „Ende offen"-Option
    • Kontaktdaten, Mitveranstalter (Co-Organisatoren), Social-Media-Links
    • Cover-Bild (Upload in Supabase Storage oder URL)
  • Mitveranstalter hinzufügen verknüpfbar mit bestehenden Plattform-Konten via User-Autocomplete
  • Eigene Veranstaltungen bearbeiten/löschen unter /my-events
  • Story-Editor für eigene Artikel/Beiträge

Für Mitwirkende (Co-Organisatoren)

  • Mit Konto verknüpfte Mitveranstalter können die Veranstaltung selbst bearbeiten
  • Eigene Rolle wird in der Edit-Ansicht angezeigt

Für Admins/Moderatoren

  • Admin-Panel mit Sidebar-Navigation (öffnet sich auf Mobile als Slide-in-Sheet)
  • Dashboard mit Statistiken, Schnellzugriff, letzter Aktivität
  • Moderations-Bereich: Reports prüfen, Kommentare ausblenden
  • User-Verwaltung: Rollen ändern, Konten sperren/löschen
  • Story-Verwaltung, Widget-Konfiguration, Keyword-Filter (Wortfilter für Inhalts-Moderation)
  • Audit-Log der Admin-Aktionen
  • Changelog die Plattform dokumentiert ihre eigene Entwicklung mit

Plattform-Features

  • Öffentlicher Changelog unter /changelog mit Versions-Historie
  • Barrierefreiheits-Erklärung (Barrierefreiheits-Page)
  • Impressum und Datenschutz-Erklärung
  • Hilfe-Sektion für User-Guidance
  • Multi-Step-Wizard mit Validierung, Auto-Save im LocalStorage, Progress-Tracking

Tech-Stack (Übersicht)

Hier eine kurze Erklärung für alle, die nicht aus der Webentwicklung kommen:

Was ist eine Web-App?

Eine moderne Webanwendung läuft im Browser (Chrome, Firefox, Safari…), aber große Teile der Logik passieren auf einem Server. Das Frontend ist das, was der User sieht und anklickt; das Backend verwaltet Daten, Logik und Sicherheit.

Was wurde hier gebaut?

Bereich Technologie Was es macht (einfach erklärt)
Frontend Next.js + React Das sichtbare Interface Buttons, Formulare, Seiten
Programmiersprache TypeScript JavaScript mit Typen-Checking verhindert Tippfehler
Styling Tailwind CSS Werkzeug für saubere, konsistente Optik
Datenbank Supabase (= PostgreSQL) Speichert alle Daten (Events, User, Geschichten…)
Authentifizierung Supabase Auth (Magic-Link / OTP) User können sich ohne Passwort per E-Mail anmelden
Storage Supabase Storage Speichert Cover-Bilder für Events und Stories
Karten Leaflet + OpenStreetMap Interaktive Karte im Veranstaltungs-Wizard
Reich-Text-Editor TipTap WYSIWYG-Editor für Beschreibungen
Animationen Framer Motion Sanfte Übergänge und Bewegungen
Icons Lucide Über 1000 moderne Icons (React)
Validierung Zod Prüft Formular-Eingaben auf Korrektheit
Geocoding Nominatim (OpenStreetMap) Wandelt Adressen in Karten-Koordinaten um
Sprache Deutsch (User-Interface)

Tech-Stack (detailliert)

Frontend Framework

  • Next.js 15.5.19 React-Framework mit Server-Side-Rendering, App-Router, File-Based-Routing, optimierten Bundles
  • React 19.2.7 Library für deklarative UI-Komponenten
  • TypeScript 5.6.3 Strenge Typisierung, strict mode

Styling

UI & Interaktion

Karten & Geocoding

  • Leaflet 1.9.4 + react-leaflet 5.0.0 Interaktive Karte
  • OpenStreetMap Tiles Kartendaten (kein API-Key nötig)
  • Nominatim API Adress→Koordinaten-Suche (eigener Server-Endpoint: /api/geocode)

Rich-Text-Editor

  • TipTap 2.27.2 + Erweiterungen:
    • @tiptap/starter-kit Basis-Editor mit Paragraphen, Headings, Listen
    • @tiptap/extension-link Links einfügen
    • @tiptap/extension-image Bilder im Text

Backend & Datenbank

  • Supabase v2 Self-Hosted oder Cloud PostgreSQL mit:
    • PostgREST Automatische REST-API aus der DB
    • Supabase Auth Magic-Link, OTP, JWT
    • Supabase Storage S3-kompatibler Object-Storage
    • Supabase SSR 0.5.2 Server-Side-Rendering-Adapter
  • pg 8.21.0 Direkter Postgres-Treiber (für Migrations)
  • PL/pgSQL Trigger, Functions, RLS-Policies in der DB

Validierung

  • Zod 3.23.8 TypeScript-first Schema-Validierung
  • Eigene Validatoren für URLs, E-Mails, deutsche PLZ

Daten-Management

Entwicklung & Build

  • Node.js (LTS) JavaScript-Runtime
  • pnpm Package-Manager (schneller, effizienter als npm)
  • ESLint 9.15.0 + eslint-config-next Linting
  • dotenv 16.4.5 .env.local-Loader

Authentifizierung Details

Die Plattform nutzt passwortlose Anmeldung:

  1. User gibt E-Mail-Adresse ein
  2. System sendet einen 6-stelligen OTP-Code (One-Time-Password) per Mail
  3. Alternativ: Magic-Link (direkter Login-Link)
  4. Bei Bedarf: Passwort-Reset per Mail

Implementiert über die profiles-Tabelle, die per Postgres-Trigger bei jeder neuen Auth-User-Erstellung automatisch mit Rollen-Eintrag angelegt wird.


Architektur

Server-Architektur

┌──────────────────────────────────────────────────────────────┐
│                         Browser (Client)                    │
│  React 19 + Next.js Client Components + Tailwind             │
└──────────────────────────────────────────────────────────────┘
                              ↓ HTTPS
┌──────────────────────────────────────────────────────────────┐
│                  Next.js 15 Server (Node.js)                 │
│  ┌────────────────┐  ┌─────────────────┐  ┌──────────────┐    │
│  │  Server        │  │  Server Actions │  │  API Routes  │    │
│  │  Components    │  │  (Form-Mut.)    │  │  (REST)      │    │
│  └────────────────┘  └─────────────────┘  └──────────────┘    │
│         ↓                     ↓                    ↓          │
│  ┌────────────────────────────────────────────────────────┐  │
│  │         Supabase JS Client (anon + cookie auth)        │  │
│  └────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────┘
                              ↓ SQL over TLS
┌──────────────────────────────────────────────────────────────┐
│                  Supabase (PostgreSQL 15+)                    │
│  ┌──────────────┐  ┌─────────────┐  ┌────────────────────┐    │
│  │   Tables     │  │     RLS     │  │  PL/pgSQL          │    │
│  │  + Indices   │  │   Policies  │  │  Functions /       │    │
│  │              │  │             │  │  Triggers          │    │
│  └──────────────┘  └─────────────┘  └────────────────────┘    │
│  ┌──────────────┐  ┌─────────────┐                          │
│  │  PostgREST   │  │   Storage   │  (Cover-Bilder,         │
│  │  (Auto-API)  │  │  (S3-API)   │   Avatare, Story-Media) │
│  └──────────────┘  └─────────────┘                          │
└──────────────────────────────────────────────────────────────┘

Wichtige Architektur-Entscheidungen

  1. Next.js App-Router mit Server Components für Datenladen, Client Components für Interaktivität
  2. Row-Level-Security (RLS) auf jeder Tabelle keine Business-Logik im Middleware-Layer
  3. SECURITY DEFINER-Funktionen für komplexe Berechtigungsprüfungen (vermeidet RLS-Rekursionen)
  4. Storage-URLs statt Buckets in DB: Cover-Bilder werden in event-covers Bucket gespeichert, URL in Tabelle referenziert
  5. Magic-Link-Auth statt klassischer Username/Passwort niedrigere Hürde für neue User
  6. Multi-Step-Wizard statt langer Formulare bessere UX, schrittweise Validierung
  7. Changelog im UI (/changelog) und im Code (CHANGELOG.md) dokumentiert jede Änderung

Datenbank

Schema-Übersicht

Die DB besteht aus 18 Kern-Tabellen und mehreren Helper-Tabellen:

Tabelle Zweck
profiles User-Profile (1:1 mit Supabase Auth) mit Rolle (user/moderator/admin/editor)
events Veranstaltungen mit Modus (standard/machbar), Adresse, Datum, Veranstalter
event_registrations Anmeldungen zu Events (interne/externe)
event_comments Kommentare unter Events
event_updates Veranstalter-Updates / Änderungs-Historie
machbar_tasks Aufgaben innerhalb einer MachBar-Veranstaltung
machbar_signups User-Anmeldungen für konkrete Aufgaben
stories Geschichten / Blog-Posts mit Cover-Bild und Rich-Text-Body
story_media Bilder/Videos pro Story
story_social_links Social-Media-Verknüpfungen pro Story
co_organizers Mitveranstalter (verknüpfbar mit User-Konto via user_id)
social_links Social-Media-Links pro Event (Instagram, Mastodon…)
network_entries Netzwerk-Einträge (Bündnisse, Initiativen)
event_reports Missbrauchsmeldungen
filtered_keywords Wort-Filter für Auto-Moderation
widgets Dashboard-Widgets (Admin)
changelog_entries Versions-Einträge für die öffentliche Changelog-Page
event_attendees MachBar-Anmeldungen „Ich bin dabei"

Migrationen

Das Projekt nutzt ein nummeriertes Migrations-System: db/migrations/0001_*.sql bis db/migrations/0032_*.sql. Jede Migration ist idempotent (verwendet if exists / create or replace), sodass sie mehrfach ausgeführt werden kann.

pnpm db:push läuft alle SQL-Files alphabetisch gegen die Supabase-DB.

Row-Level-Security (RLS) Policies

Jede Tabelle hat mehrere Policies für SELECT/INSERT/UPDATE/DELETE. Beispiele:

  • Events: User sehen veröffentlichte Events, Ersteller sehen alle eigenen, Admins/Moderatoren sehen alles
  • Stories: Ähnlich veröffentlichte sichtbar, Autoren + Editors sehen eigene Drafts
  • Co-Organizers: Veranstalter verwalten ihre Co-Organisatoren, Admins/Moderatoren alles
  • Event-Attendees: User sehen nur eigene, Veranstalter + Co-Organisatoren sehen alle

Rekursions-Schutz: Wo Policies sich gegenseitig referenzieren würden, kommen SECURITY DEFINER-Funktionen zum Einsatz (siehe Migration 0032).


Authentifizierung & Rollen

Rollenmodell

Rolle Berechtigungen
user (default) Eigene Events anlegen, Events ansehen, Stories lesen, sich für MachBar-Veranstaltungen eintragen
editor Wie User + Stories verfassen und veröffentlichen
moderator Wie Editor + Missbrauchsmeldungen prüfen, Kommentare ausblenden, Events prüfen
admin Wie Moderator + User-Verwaltung, alle Events/Stories bearbeiten, Plattform-Konfiguration

Auth-Flow

  1. User gibt E-Mail ein → System sendet OTP-Code (6-stellig) per Mail
  2. Alternativ: Magic-Link direkt im Postfach
  3. Bei Supabase wird ein auth.users-Eintrag erzeugt
  4. Postgres-Trigger legt automatisch einen Eintrag in profiles mit Rolle user an
  5. JWT-Token wird in HTTP-only-Cookies gespeichert
  6. Bei jedem Request wird der User per Cookie identifiziert

Sicherheits-Layer

  • RLS = Source-of-Truth für Berechtigungen (nicht Middleware!)
  • JWT mit kurzer Lebensdauer, automatische Refresh
  • HTTP-only + SameSite=Lax Cookies verhindern XSS-Cookie-Stealing
  • CORS strikt konfiguriert
  • Rate-Limiting (geplant für nächste Version)

Projektstruktur

app/
├── db/
│   └── migrations/             # 32 SQL-Migrations-Dateien
├── scripts/
│   └── db-push.mjs            # Migration-Runner
├── src/
│   ├── app/                    # Next.js App-Router
│   │   ├── (public routes)
│   │   │   ├── page.tsx       # Home / Landing
│   │   │   ├── events/        # Event-Listing + Detail + Create
│   │   │   ├── stories/       # Stories-Listing + Detail + Create/Edit
│   │   │   ├── network/       # Netzwerk-Listing
│   │   │   ├── about/ hilfe/ impressum/ datenschutz/ barrierefreiheit/
│   │   │   ├── changelog/     # Öffentlicher Changelog
│   │   │   └── login/         # Auth-Pages
│   │   ├── (authenticated routes)
│   │   │   ├── my-events/     # Eigene Events verwalten
│   │   │   ├── profile/       # Eigenes Profil
│   │   │   └── admin/         # Admin-Panel
│   │   ├── api/                # REST-API-Endpoints
│   │   │   ├── auth/          # signin, signup, otp, reset
│   │   │   ├── events/        # CRUD + co-organizers, social-links, attendees
│   │   │   ├── stories/       # CRUD + media, social-links
│   │   │   ├── admin/         # Admin-spezifische Endpoints
│   │   │   ├── geocode/       # Nominatim-Proxy
│   │   │   └── profiles/      # User-Suche
│   │   ├── layout.tsx         # Root-Layout mit Theme-Provider
│   │   ├── globals.css        # Globale Styles, CSS-Variablen
│   │   ├── icon.svg           # Favicon (auto-generiert)
│   │   └── apple-icon.svg     # Apple Touch-Icon
│   ├── components/
│   │   ├── layout/             # Header, Footer, BottomNav, ThemeToggle
│   │   ├── event/              # EventCard, EventWizard, EventShareBar
│   │   ├── story/              # StoryCard, StoryEditor
│   │   ├── network/            # NetworkCard
│   │   ├── editor/             # RichTextEditor (TipTap)
│   │   ├── map/                # MapPicker (Leaflet)
│   │   ├── admin/              # AdminShell, AdminMobileNav
│   │   ├── auth/               # Auth-spezifische Komponenten
│   │   ├── profile/            # Profil-Komponenten
│   │   ├── shared/             # Geteilte Komponenten
│   │   └── ui/                 # Generische UI-Bausteine (Button, Input, Card, Badge…)
│   ├── lib/
│   │   ├── auth/               # Session-Helper, Organizer-Context
│   │   ├── logging/            # Strukturiertes Logging (pino)
│   │   ├── supabase/           # Client-Setups (server, client, service-role)
│   │   ├── validation/         # Zod-Schemas + Wizard-Validator
│   │   ├── api/                # safeFetch-Helper für API-Calls
│   │   ├── motion.ts           # Framer-Motion Easings
│   │   └── utils/              # cn(), date-format, etc.
│   ├── types/                  # TypeScript-Types (Database-Types)
│   └── middleware.ts           # Auth-Middleware für geschützte Routen
├── package.json
├── next.config.mjs
├── tailwind.config.ts
├── tsconfig.json
└── CHANGELOG.md

Konventionen

  • Jede Page in app/src/app/... = eine URL-Route
  • page.tsx = die Page selbst
  • layout.tsx = Wrapper, der alle Child-Pages umschließt
  • loading.tsx = Suspense-Fallback
  • error.tsx = Error-Boundary
  • not-found.tsx = 404-Handler
  • API-Routes = route.ts mit exportierten HTTP-Method-Handlern

Lokale Entwicklung

Voraussetzungen

  • Node.js 18.17+ (empfohlen: 20 LTS)
  • pnpm 10+ (npm install -g pnpm)
  • Git
  • Supabase-Konto (Free Tier reicht) ODER lokale Postgres-Instanz

Schritt 1: Repository klonen

git clone <repository-url> buendnis-ost
cd buendnis-ost/app

Schritt 2: Dependencies installieren

pnpm install

Schritt 3: Supabase-Projekt erstellen

  1. Gehe zu supabase.com und erstelle ein neues Projekt
  2. Notiere dir:
    • Project URL (https://xyz.supabase.co)
    • Anon Key (öffentlich, im Browser sichtbar)
    • Service Role Key (geheim, nur serverseitig)
    • Database Password (für direkten DB-Zugriff)

Schritt 4: Environment-Variablen konfigurieren

Erstelle app/.env.local:

# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xyz.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ...
SUPABASE_PROJECT_REF=xyz
SUPABASE_DB_PASSWORD=...

# Optional
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Erstelle auch app/.mavis/secrets/buendnis-ost.env (für pnpm db:push):

SUPABASE_PROJECT_REF=xyz
SUPABASE_DB_PASSWORD=...
SUPABASE_SERVICE_ROLE_KEY=eyJ...

Schritt 5: Datenbank-Migrationen ausführen

pnpm db:push

Dies führt alle 32 SQL-Migrations-Dateien gegen deine Supabase-DB aus.

Schritt 6: Dev-Server starten

pnpm dev

Die App läuft jetzt auf http://localhost:3000.

Schritt 7: Type-Check & Build

# TypeScript-Validierung
pnpm typecheck

# Production-Build
pnpm build

# Linting
pnpm lint

Häufige Probleme

Problem Lösung
relation does not exist pnpm db:push ausführen
permission denied for table RLS-Policies prüfen, ggf. als service_role anmelden
Cookie ... has been rejected for invalid domain .env.local prüfen, NEXT_PUBLIC_SITE_URL setzen
404 auf /icon.svg Browser-Cache leeren, Dev-Server neu starten
infinite recursion detected in policy Sicherstellen, dass Migration 0032 ausgeführt wurde

Datenbank-Migrationen

Eine neue Migration hinzufügen

  1. Erstelle app/db/migrations/00XX_beschreibung.sql (nächste freie Nummer)
  2. Schreibe idempotentes SQL: create table if not exists, drop policy if exists, create or replace function
  3. Teste mit pnpm db:push
  4. Trage den Changelog-Eintrag in app/CHANGELOG.md und ggf. als changelog_entries-Eintrag in der Migration ein
  5. Committe mit aussagekräftiger Message

Konventionen

  • Niemals eine bestehende Migration ändern, nachdem sie gepusht wurde
  • Wenn ein Fix nötig ist: neue Migration erstellen
  • Eine thematische Änderung pro Migration (z.B. „neue Tabelle", „neue RLS-Policy", „neue Spalte")
  • NOTIFY pgrst, 'reload schema' am Ende, damit PostgREST das Schema neu lädt

Testing (E2E)

Die Plattform nutzt Playwright für End-to-End-Tests mit echtem Browser-Rendering, plus einen strukturierten winston-Logger für detaillierte Test-Reports.

Test-Suiten

Datei Zweck Anzahl Tests
tests/e2e/01-public-pages.spec.ts Smoke-Tests: Home, Events, Stories, Network, Changelog, Impressum, Datenschutz, Barrierefreiheit, Hilfe ~15
tests/e2e/02-auth.spec.ts Login-Page, Magic-Link-Flow, Session-Persistenz, geschützte Routen, Admin-Zugriff ~7
tests/e2e/03-event-wizard.spec.ts 10-Schritte-Event-Erstellung, Hybrid-Standort, max_participants ~4
tests/e2e/04-features.spec.ts Co-Org-E-Mail-Verknüpfung, MachBar-Anmeldung, Theme-Toggle ~7
tests/e2e/05-mobile.spec.ts Mobile Bottom-Nav, Sticky-Header, kein horizontaler Scroll ~3
tests/e2e/06-api.spec.ts Direkte API-Tests (ohne Browser): 401/400-Checks, Geocoding ~5

Schnellstart

cd app

# 1. Test-User anlegen (idempotent, einmalig)
node -e "
import('./scripts/_setup_test_users.mjs').then(m => m.default());
" || true

# 2. Alle Browser installieren
pnpm exec playwright install chromium firefox webkit

# 3. Tests starten (Dev-Server läuft automatisch)
pnpm test

# 4. Nur Chromium (schnell)
pnpm test:chromium

# 5. Mit UI
pnpm test:ui

# 6. Mit sichtbarem Browser
pnpm test:headed

# 7. HTML-Report öffnen
pnpm test:report

Test-Output

Während eines Test-Runs werden drei Arten von Output erzeugt:

1. Log-Dateien (tests/log/)

  • test-runner-w{0..N}.log pro Worker, mit allen Events (Start, Schritte, Browser-Console, Network)
  • test-run-<timestamp>.log persistent pro Run, mit vollständigem Debug-Output
  • Format: [Timestamp] [LEVEL] Message {"meta": "json"}

Beispiel:

[2026-06-10 23:28:45.426] [INFO ] ▶ STEP START: API: profile-search unauthorized
[2026-06-10 23:28:45.592] [INFO ] ◀ STEP END: API: profile-search unauthorized {"duration":"167ms","status":401}
[2026-06-10 23:28:45.601] [INFO ] ✓ 01-public-pages > Public Page lädt: /events {"duration":"1189ms"}

2. HTML-Report (tests/reports/html/index.html)

  • Interaktiver Report mit allen Tests, Traces, Videos, Screenshots
  • pnpm test:report öffnet ihn im Browser

3. Screenshots & Traces

  • tests/screenshots/ Screenshot pro Test (zur visuellen Verifikation)
  • tests/traces/ Playwright-Trace (für Debugging fehlgeschlagener Tests)

Test-Architektur

tests/helpers/logger.ts Strukturierter Logger (winston)

  • logger.info(), .warn(), .error(), .debug() Standard-API
  • testStep('Name') bündelt mehrere Logs zu einem benannten Test-Schritt mit Timing
  • summary sammelt Test-Ergebnisse, gibt finale Zusammenfassung aus
  • TestSummary.printSummary() Tabelle mit Pass/Fail/Skip-Counts am Test-Run-Ende

tests/helpers/auth.ts Auth-Helper

  • magicLinkSignIn(email) generiert Magic-Link via service-role, loggt User ein, gibt Storage-State zurück
  • ensureTestUsers() legt test-admin@, test-moderator@, test-user@buendnisost.local an
  • getAdminClient() Service-Role-Client (Bypass RLS, für Test-Setup)

tests/helpers/fixtures.ts Custom Fixtures

  • basePage / baseContext frischer Browser ohne Login
  • adminPage / moderatorPage / userPage bereits eingeloggte Pages
  • Automatisches Console- und Network-Logging
  • Test-Summary-Tracking via test.afterEach()
  • Cleanup: löscht Test-Daten mit Prefix [E2E] in test.afterAll()

playwright.config.ts Konfiguration

  • 5 Projekte: chromium, firefox, webkit, mobile-chrome (Pixel 7), mobile-safari (iPhone 15)
  • Parallel-Tests lokal (default), 1 Worker in CI für Stabilität
  • Auto-Server: pnpm dev startet vor Tests
  • Trace + Video nur bei Failures
  • HTML-, JSON-, JUnit-Reporter

Was wird getestet?

Kern-Funktionalität (jeder Commit sollte diese Tests bestehen):

  • Alle Public-Pages laden (200, korrekter Title, kein Console-Error)
  • Auth: Magic-Link-Request, Session-Persistenz, geschützte Routen
  • Event-Wizard: kompletter 10-Schritte-Flow, Hybrid-Standort, max_participants
  • Co-Org-E-Mail: Auto-Verknüpfung existierender Konten, Magic-Link-Einladung für externe
  • MachBar: "Ich bin dabei"-Button, Anmeldung, Liste
  • Theme-Toggle: Light/Dark-Mode, localStorage-Persistenz
  • Mobile: Sticky-Header, Bottom-Nav, kein horizontaler Scroll
  • API: 401/400/500-Checks, Geocoding, Profile-Lookup

Cleanup: Test-Daten mit Prefix [E2E] werden nach jedem Run aus der DB entfernt (Events soft-deleted, Stories status=deleted).

CI-Integration

.github/workflows/e2e.yml läuft die Tests automatisch bei jedem Push/PR auf main oder develop:

  1. Setup Node 20 + pnpm 10
  2. Install Dependencies
  3. Install Playwright-Browser (chromium, firefox, webkit + OS-Dependencies)
  4. Build (pnpm build)
  5. Run E2E Tests (chromium only für Geschwindigkeit)
  6. Upload Artifacts (HTML-Report, Logs, Traces)

Reports werden als GitHub-Artifacts für 14 Tage gespeichert.

Eigene Tests schreiben

import { test, expect } from '../helpers/fixtures';
import { testStep } from '../helpers/logger';

test('Mein neuer Test', async ({ adminPage }) => {
  const step = testStep('Beschreibung');
  
  await adminPage.goto('/admin');
  // ... Test-Logik
  
  step.end({ status: 'PASS' });
});

Tipps:

  • Nutze adminPage / userPage für authentifizierte Tests
  • Nutze testStep() für aussagekräftige Step-Logs
  • Cleanup: Daten mit Prefix [E2E] werden automatisch entfernt
  • Mobile-Tests: nutze testInfo.project.name.includes('mobile') für konditionale Logik

Deployment

Empfohlene Plattformen

  • Vercel First-Class-Support für Next.js
  • Netlify Ebenfalls gute Next.js-Unterstützung
  • Eigener Node.js-Server via pnpm build && pnpm start

Vercel-Deployment

  1. Vercel-Konto mit GitHub verbinden
  2. Repository importieren
  3. Build-Settings:
    • Framework: Next.js
    • Build Command: cd app && pnpm install && pnpm build
    • Output Directory: app/.next
    • Install Command: cd app && pnpm install
  4. Environment-Variablen aus .env.local in Vercel-Dashboard übertragen
  5. Erstes Deployment: Migrations manuell via Supabase-Studio oder pnpm db:push ausführen
  6. Custom Domain (optional): in Vercel-Settings hinzufügen

Pre-Deployment-Checklist

  • pnpm build läuft ohne Fehler durch
  • pnpm typecheck ist sauber
  • Alle Migrations sind in der Supabase-DB angewendet
  • NEXT_PUBLIC_SITE_URL zeigt auf die Production-Domain
  • Supabase Email-Templates sind für die eigene Domain konfiguriert
  • CORS in Supabase erlaubt die Production-Domain
  • Redirect-URLs in Supabase Auth sind gesetzt

API-Übersicht

Alle API-Endpoints leben unter /api/... und nutzen den Next.js Route Handler. Vollständige OpenAPI-Dokumentation ist geplant.

Auth

Method Path Zweck
POST /api/auth/signin OTP-Code anfordern
POST /api/auth/otp-verify OTP-Code prüfen, Session erstellen
POST /api/auth/magic-link Magic-Link per Mail senden
POST /api/auth/signup Neuen Account anlegen
POST /api/auth/signout Session beenden
POST /api/auth/reset-password Passwort-Reset anfordern

Events

Method Path Zweck
GET /api/events Events auflisten (mit Filtern)
POST /api/events Event erstellen
GET /api/events/[id]/co-organizers Mitveranstalter auflisten
POST /api/events/[id]/co-organizers Mitveranstalter hinzufügen
PATCH/DELETE /api/events/[id]/co-organizers/[coId] Mitveranstalter bearbeiten/löschen
GET /api/events/[id]/attendees MachBar-Anmeldungen (nur Veranstalter)
POST /api/events/[id]/attendees Selbst anmelden (MachBar)
GET/PATCH/DELETE /api/events/[id]/attendees/me Eigene Anmeldung verwalten
POST /api/events/upload Cover-Bild hochladen
GET /api/geocode?q=... Adresse → Koordinaten (Nominatim-Proxy)

Stories

Method Path Zweck
GET/POST /api/stories Stories listen/erstellen
GET/PATCH/DELETE /api/stories/[id] Einzelne Story verwalten
POST /api/stories/upload Story-Media hochladen
GET/POST/DELETE /api/stories/media/[id] Story-Media verwalten
GET/POST/DELETE /api/stories/social-links/[id] Story-Social-Links verwalten

Profile & Suche

Method Path Zweck
GET /api/profile Eigenes Profil abrufen/aktualisieren
GET /api/profiles/search?q=... User-Autocomplete (für Mitveranstalter-Auswahl)

Admin

Method Path Zweck
GET/PATCH/DELETE /api/admin/users[/{id}] User-Verwaltung
GET/PATCH/DELETE /api/admin/events/{id} Event-Verwaltung
GET/PATCH/DELETE /api/admin/keywords[/{id}] Wort-Filter
GET/PATCH/DELETE /api/admin/widgets[/{id}] Dashboard-Widgets
GET/POST/PATCH/DELETE /api/admin/network[/{id}] Netzwerk-Einträge
POST /api/admin/network/{id}/approve / reject Netzwerk-Freigabe
POST /api/admin/reports/{id}/resolve Report abschließen
POST /api/admin/reports/{id}/event/{eventId}/hide Event verbergen

Alle geschützten Endpoints erfordern ein gültiges JWT-Cookie. Fehler werden im JSON-Format zurückgegeben:

{ "error": "Beschreibung", "requestId": "req_abc123" }

Sicherheit

Verteidigungs-Linien

  1. JWT-Auth (Supabase Auth, automatische Rotation)
  2. HTTP-only Cookies mit SameSite=Lax (kein XSS-Cookie-Stealing)
  3. Row-Level-Security auf Datenbank-Ebene (Defense in Depth)
  4. Zod-Validierung aller API-Inputs (verhindert Injection & Bad-Data)
  5. CORS strikt konfiguriert
  6. Rate-Limiting (geplant)
  7. Content-Security-Policy (geplant)
  8. Storage-Policies auf Supabase-Buckets (User können nur eigene Bilder hochladen)

Bekannte Limitierungen (geplant zu beheben)

  • Kein Captcha auf Auth-Endpoints (Anfälligkeit für Spam)
  • Kein explizites Rate-Limiting (Supabase hat built-in, aber fein-granular fehlt)
  • CSP-Header sind nicht gesetzt
  • Audit-Log ist nur für Admin-Aktionen, nicht für User-Aktionen

Daten-Backup

  • Supabase Cloud: automatische tägliche Backups (7 Tage Retention im Free Tier)
  • Für kritische Daten: wöchentlicher Export via pg_dump empfohlen

Mitwirken

Code-Stil

  • TypeScript strict mode keine any, keine @ts-ignore ohne Kommentar
  • Tailwind only kein separates CSS, außer in globals.css für Base-Layer
  • Komponenten klein und fokussiert eine Komponente, eine Verantwortlichkeit
  • Server Components first Client Components nur wenn nötig (Interaktivität, Browser-APIs)
  • i18n-ready alle User-Strings in deutscher Sprache; Architektur erlaubt spätere Lokalisierung

Commit-Konventionen

  • Deutsch oder Englisch egal, aber konsistent pro Projekt
  • Präfixe für Kategorien: feat:, fix:, chore:, docs:, refactor:, style:
  • Beispiele:
    • feat: MachBar-Anmeldung implementieren
    • fix: RLS-Rekursion in events-Policies auflösen
    • chore: Next.js auf 15.5.19 updaten

Pull-Request-Workflow

  1. Branch erstellen: git checkout -b feat/mein-feature
  2. Änderungen committen mit aussagekräftigen Messages
  3. Sicherstellen, dass pnpm typecheck und pnpm build durchlaufen
  4. Falls DB-Änderungen: Migration hinzufügen + in PR-Beschreibung dokumentieren
  5. PR erstellen mit Beschreibung (Was? Warum? Wie getestet?)
  6. Review abwarten

Issue-Triagen

  • Bugs: bitte mit Reproduktions-Schritten, Browser, OS, Screenshot
  • Feature-Wünsche: gerne mit Use-Case und Mockups
  • Sicherheitslücken: bitte nicht öffentlich, sondern direkt per Mail an die Maintainer

Lizenz

MIT License siehe LICENSE-Datei (zu erstellen).

Kurzfassung: Du darfst den Code nutzen, verändern, weitergeben solange der Copyright-Hinweis und die Lizenz mitgegeben werden. Keine Haftung, keine Garantie.


Anhänge

A. Datenbank-Schema visualisiert

profiles ─┐
          ├─< events ─< co_organizers >─ profiles
          │     │       (mit user_id-Verknüpfung)
          │     ├─< event_registrations >─ profiles
          │     ├─< event_comments >─ profiles
          │     ├─< event_updates
          │     ├─< event_reports
          │     ├─< event_attendees >─ profiles
          │     ├─< machbar_tasks ─< machbar_signups >─ profiles
          │     ├─< social_links
          │     └─< cover_image_url (Storage)
          │
          ├─< stories ─< story_media
          │          └─< story_social_links
          │
          └─< network_entries
              (mit approval-status)

changelog_entries (public read, admin/mod write)
filtered_keywords (admin manage)
widgets (admin manage)

B. Rollen-Hierarchie

                ┌──────────┐
                │  admin   │  (alle Rechte)
                └─────┬────┘
              ┌───────┴───────┐
          ┌───┴────┐    ┌─────┴────┐
          │moderator│   │  editor  │  (Stories verwalten)
          └────┬────┘    └────┬────┘
               │               │
               └───────┬───────┘
                       │
                  ┌────┴────┐
                  │  user   │  (Default)
                  └─────────┘

C. Farbschema

Die Plattform nutzt drei Brand-Farben (HSL-definiert in globals.css):

  • Primary Blue (217 91% 60%) Hauptaktionen, Links
  • Magenta/Pink (338 65% 38%) MachBar-Veranstaltungen, sekundäre Aktionen
  • Red (0 84% 60%) Fehler, destruktive Aktionen

Plus Dark Mode mit angepassten Kontrasten für Lesbarkeit.

D. Performance-Optimierungen

  • Server Components für datenintensive Pages (kein JS-Bundle für nicht-interaktive Inhalte)
  • React Query für Client-Side-Caching wo nötig
  • Image-Optimierung via Next.js <Image>-Komponente
  • Code-Splitting automatisch durch Next.js
  • Font-Loading via next/font (kein FOUT)
  • Critical CSS automatisch inline durch Next.js
  • Bundle-Größen werden im Build-Report überwacht (siehe pnpm build-Output)

Kontakt

  • Issues: GitHub-Issues
  • Diskussionen: GitHub-Discussions
  • Sicherheit: siehe SECURITY.md (geplant)
  • E-Mail: siehe Plattform-Impressum unter /impressum

Letzte Aktualisierung: Juni 2026 Version: 0.1.0 (siehe CHANGELOG.md für Details)