Registrierungs-System: Mini SQL + OData V4 API #2

Open
opened 2026-08-02 16:39:41 +02:00 by Simon · 0 comments
Owner

Plan: Sichere Registrierungsverwaltung für die EJUN-Seite

Problem

Aktuell ist die Registrierungsseite (registrierung.html) ein toter Endpunkt. Interessierte Mitglieder müssen eine E-Mail schreiben — das ist umständlich, schwer zu tracken und skaliert nicht.

Ziel

Ein sicheres, DSGVO-konformes System mit:

  1. Mini SQL (PostgreSQL) für die Speicherung der Registrierungsdaten
  2. OData V4 API für einfachste Abfragen und Verwaltung
  3. Frontend-Formular auf der EJUN-Seite
  4. Admin-Oberfläche für das EJUN-Team

Architektur

EJUN-Seite (Feigro/Forgejo)
    │
    ▼
[Formular] → [API Gateway / Backend]
                    │
                    ▼
            [PostgreSQL] (Coolify deployed)
                    │
                    ▼
            [OData V4 API] (Abfrage/Verwaltung)

Komponenten

  1. PostgreSQL — Die Datenbank, gehostet via Coolify auf 10.10.10.170
  2. OData V4 API — Lightweight REST-Service mit OData-Support (z.B. FastAPI + odata-python oder .NET Minimal API)
  3. Registrierungsformular — Frontend auf registrierung.html
  4. Admin-Seite — Einfache Übersicht aller Registrierungen

Datenmodell (Schema)

Tabelle: registrations

Spalte Typ Beschreibung
id SERIAL PK Auto-increment Primärschlüssel
created_at TIMESTAMP WITH TIME ZONE Registrierungszeitpunkt
updated_at TIMESTAMP WITH TIME ZONE Letztes Update
name VARCHAR(200) Vollname (Pflicht)
plz VARCHAR(10) Postleitzahl
ort VARCHAR(200) Wohnort
email VARCHAR(300) E-Mail-Adresse (optional)
telefon VARCHAR(50) Telefonnummer (optional)
unterschriftensammlung BOOLEAN Stimmt für Unterschriftensammlung zu
treffen BOOLEAN Möchte an Treffen teilnehmen
newsletter BOOLEAN Will Newsletter erhalten
aktive_hilfe BOOLEAN Möchte aktiv helfen (Protest, etc.)
anmerkung TEXT Freitext-Feld
status VARCHAR(20) new, confirmed, rejected
bestaetigt_am TIMESTAMP WITH TIME ZONE Zeitpunkt der Bestätigung
bestaetigt_durch VARCHAR(100) Wer hat bestätigt (Admin-Name)
ip_hash CHAR(64) SHA-256 Hash der IP (DSGVO-konform, nicht reversibel)

Indexes

CREATE INDEX idx_registrations_status ON registrations(status);
CREATE INDEX idx_registrations_ort ON registrations(ort);
CREATE INDEX idx_registrations_created_at ON registrations(created_at DESC);
CREATE INDEX idx_registrations_plz ON registrations(plz);

OData V4 API Endpunkte

Basis-URL: https://registrierung.ejun.de/odata

Alle Registrierungen lesen

GET /odata/registrations

Mit Query-Parametern:

  • $filter=status eq 'new' — nur neue Einträge
  • $filter=ort eq 'Laberweinting' — nach Ort filtern
  • $filter=created_at ge 2026-07-01 — ab Datum
  • $orderby=created_at desc — sortiert
  • $top=50&$skip=0 — Pagination
  • $count=true — Gesamtanzahl

Einzelnen Eintrag lesen

GET /odata/registrations(1)

Neuer Eintrag erstellen

POST /odata/registrations
Content-Type: application/json

{
  "name": "Max Mustermann",
  "plz": "84082",
  "ort": "Laberweinting",
  "email": "max@beispiel.de",
  "unterschriftensammlung": true,
  "treffen": true,
  "newsletter": false,
  "aktive_hilfe": false
}

Status aktualisieren

PATCH /odata/registrations(1)
Content-Type: application/json

{
  "status": "confirmed",
  "bestaetigt_am": "2026-08-02T15:00:00+02:00",
  "bestaetigt_durch": "Simon"
}

Export als CSV

GET /odata/registrations/$export?format=csv

Frontend-Formular (registrierung.html)

Felder (vereinfacht):

  1. Name * (Pflicht) — Textinput
  2. PLZ * (Pflicht) — Textinput, 5-stellig, Regex-Validierung
  3. Ort * (Pflicht) — Textinput
  4. E-Mail — optional, Email-Validierung
  5. Telefon — optional, Format: +49... oder 0...
  6. Interessen (Checkboxen):
    • Unterschriftensammlung
    • Treffen besuchen
    • Newsletter erhalten
    • Aktive Hilfe (Demonstrationen, etc.)
  7. Anmerkung — optional, Textarea
  8. DSGWO-Einwilligung * (Pflicht) — Checkbox mit Link zum Datenschutz

Spam-Schutz:

  • Cloudflare Turnstile (kostenlos, kein Google-Datenabfluss)
  • Oder hCaptcha (open-source Alternative)

DSGVO-Checkliste

  • Daten auf eigenem Server (10.10.10.170) — keine externe Verarbeitung
  • IP-Adresse gehasht (SHA-256), nicht reversibel
  • Einwilligungs-Checkbox für jede Datenverarbeitung
  • Datenschutzerklärung aktualisiert
  • Löschkonzept: Daten nach 2 Jahren nach Projektende automatisch löschen
  • HTTPS-only (via Coolify Let's Encrypt)
  • OData API mit Basic Auth oder Token-basiert absichern

Tech-Stack-Empfehlung

PostgreSQL

  • Via Coolify als managed Service deployen
  • Backup: Daily via Coolify, 7 Tage Retention

OData V4 API Backend

Option A: FastAPI + fastapi-odata (Python)

# pip install fastapi fastapi-odata uvicorn psycopg2-binary
from fastapi import FastAPI
from fastapi_odata import ODataRouter

app = FastAPI()
router = ODataRouter(model=Registration, prefix="/odata")
app.include_router(router)

Vorteile: Python (bekannt), schnell, einfach
Nachteile: fastapi-odata noch relativ neu

Option B: .NET Minimal API + Microsoft.OData.Core

// Native OData V4 Support
builder.Services.AddOData();
app.MapODataServiceRoute("odata", "odata", model);

Vorteile: Vollständiges OData V4, gut dokumentiert
Nachteile: .NET Runtime nötig

Option C: Django + django-extensions / django-orm

  • Django hat eingebaute Admin-Oberfläche
  • Mit django-filter und django-rest-framework kann man OData-ähnliche Queries bauen
    Vorteile: Komplettes Admin-Dashboard out-of-the-box
    Nachteile: Kein echtes OData V4

Empfohlen: Option A (FastAPI) — weil Python, schnell zu deployen via Coolify, und mit fastapi-odata oder odpy echte OData V4 Support.


Implementierungsplan

Phase 1: Infrastruktur (Coolify)

  1. PostgreSQL-Service in Coolify anlegen
  2. Domain/Subdomain einrichten (registrierung.ejun.de oder api.buergerinitiative-ejun.de)
  3. Let's Encrypt SSL konfigurieren

Phase 2: OData API Backend

  1. FastAPI-Projekt mit OData-Support erstellen
  2. Datenbank-Model definieren (SQLAlchemy)
  3. CRUD-Endpunkte implementieren
  4. Authentifizierung für Admin-Endpoints
  5. IP-Hashing und DSGVO-Felder

Phase 3: Frontend-Formular

  1. Registrierungsformular in registrierung.html integrieren
  2. Cloudflare Turnstile oder hCaptcha einbauen
  3. Formular-Validierung (client + server)
  4. Bestätigungs-E-Mail bei Submission

Phase 4: Admin-Dashboard

  1. Einfache Übersicht aller Registrierungen
  2. Status-Management (new/confirmed/rejected)
  3. Suchfunktion und Filter
  4. CSV-Export
  5. Wöchentliche Zusammenfassung per Cron-Job

Phase 5: Automatisierung

  1. Automatische Bestätigungs-E-Mail
  2. Wöchentliche Zusammenfassung an EJUN-Team
  3. Daten-Löschung nach Ablauf (nach 2 Jahren)

Kosten

  • PostgreSQL: Kostenlos (eigener Server)
  • Coolify SSL: Kostenlos (Let's Encrypt)
  • Cloudflare Turnstile: Kostenlos
  • hCaptcha: Kostenlos (open-source)
  • Domain/Subdomain: Bereits vorhanden (buergerinitiative-ejun.de)

Gesamtkosten: ~0 €/Monat


Offene Fragen

  1. Welche Domain? registrierung.ejun.de oder /api Subpath?
  2. Auth für Admin-Dashboard? Einfaches Password oder OAuth?
  3. Bestätigungs-E-Mail? SMTP-Server (Mailgun, SendGrid) oder einfach Paperless als "Ersatz"?
  4. Löschfristen? Wie lange Daten behalten?
  5. Unterschriften-Sammlung separat? Oder direkt im Formular sammeln?

Nächste Schritte

  1. Schema und API-Design finalisieren (dieses Dokument)
  2. In Coolify PostgreSQL deployen
  3. OData API Backend implementieren
  4. Registrierungsformular erstellen
  5. Admin-Dashboard bauen
  6. Testphase + Datenschutzprüfung
# Plan: Sichere Registrierungsverwaltung für die EJUN-Seite ## Problem Aktuell ist die Registrierungsseite (`registrierung.html`) ein toter Endpunkt. Interessierte Mitglieder müssen eine E-Mail schreiben — das ist umständlich, schwer zu tracken und skaliert nicht. ## Ziel Ein sicheres, DSGVO-konformes System mit: 1. **Mini SQL** (PostgreSQL) für die Speicherung der Registrierungsdaten 2. **OData V4 API** für einfachste Abfragen und Verwaltung 3. Frontend-Formular auf der EJUN-Seite 4. Admin-Oberfläche für das EJUN-Team --- ## Architektur ``` EJUN-Seite (Feigro/Forgejo) │ ▼ [Formular] → [API Gateway / Backend] │ ▼ [PostgreSQL] (Coolify deployed) │ ▼ [OData V4 API] (Abfrage/Verwaltung) ``` ### Komponenten 1. **PostgreSQL** — Die Datenbank, gehostet via Coolify auf 10.10.10.170 2. **OData V4 API** — Lightweight REST-Service mit OData-Support (z.B. FastAPI + odata-python oder .NET Minimal API) 3. **Registrierungsformular** — Frontend auf `registrierung.html` 4. **Admin-Seite** — Einfache Übersicht aller Registrierungen --- ## Datenmodell (Schema) ### Tabelle: `registrations` | Spalte | Typ | Beschreibung | |--------|-----|-------------| | `id` | SERIAL PK | Auto-increment Primärschlüssel | | `created_at` | TIMESTAMP WITH TIME ZONE | Registrierungszeitpunkt | | `updated_at` | TIMESTAMP WITH TIME ZONE | Letztes Update | | `name` | VARCHAR(200) | Vollname (Pflicht) | | `plz` | VARCHAR(10) | Postleitzahl | | `ort` | VARCHAR(200) | Wohnort | | `email` | VARCHAR(300) | E-Mail-Adresse (optional) | | `telefon` | VARCHAR(50) | Telefonnummer (optional) | | `unterschriftensammlung` | BOOLEAN | Stimmt für Unterschriftensammlung zu | | `treffen` | BOOLEAN | Möchte an Treffen teilnehmen | | `newsletter` | BOOLEAN | Will Newsletter erhalten | | `aktive_hilfe` | BOOLEAN | Möchte aktiv helfen (Protest, etc.) | | `anmerkung` | TEXT | Freitext-Feld | | `status` | VARCHAR(20) | `new`, `confirmed`, `rejected` | | `bestaetigt_am` | TIMESTAMP WITH TIME ZONE | Zeitpunkt der Bestätigung | | `bestaetigt_durch` | VARCHAR(100) | Wer hat bestätigt (Admin-Name) | | `ip_hash` | CHAR(64) | SHA-256 Hash der IP (DSGVO-konform, nicht reversibel) | ### Indexes ```sql CREATE INDEX idx_registrations_status ON registrations(status); CREATE INDEX idx_registrations_ort ON registrations(ort); CREATE INDEX idx_registrations_created_at ON registrations(created_at DESC); CREATE INDEX idx_registrations_plz ON registrations(plz); ``` --- ## OData V4 API Endpunkte ### Basis-URL: `https://registrierung.ejun.de/odata` #### Alle Registrierungen lesen ``` GET /odata/registrations ``` Mit Query-Parametern: - `$filter=status eq 'new'` — nur neue Einträge - `$filter=ort eq 'Laberweinting'` — nach Ort filtern - `$filter=created_at ge 2026-07-01` — ab Datum - `$orderby=created_at desc` — sortiert - `$top=50&$skip=0` — Pagination - `$count=true` — Gesamtanzahl #### Einzelnen Eintrag lesen ``` GET /odata/registrations(1) ``` #### Neuer Eintrag erstellen ``` POST /odata/registrations Content-Type: application/json { "name": "Max Mustermann", "plz": "84082", "ort": "Laberweinting", "email": "max@beispiel.de", "unterschriftensammlung": true, "treffen": true, "newsletter": false, "aktive_hilfe": false } ``` #### Status aktualisieren ``` PATCH /odata/registrations(1) Content-Type: application/json { "status": "confirmed", "bestaetigt_am": "2026-08-02T15:00:00+02:00", "bestaetigt_durch": "Simon" } ``` #### Export als CSV ``` GET /odata/registrations/$export?format=csv ``` --- ## Frontend-Formular (`registrierung.html`) ### Felder (vereinfacht): 1. **Name** * (Pflicht) — Textinput 2. **PLZ** * (Pflicht) — Textinput, 5-stellig, Regex-Validierung 3. **Ort** * (Pflicht) — Textinput 4. **E-Mail** — optional, Email-Validierung 5. **Telefon** — optional, Format: +49... oder 0... 6. **Interessen** (Checkboxen): - [ ] Unterschriftensammlung - [ ] Treffen besuchen - [ ] Newsletter erhalten - [ ] Aktive Hilfe (Demonstrationen, etc.) 7. **Anmerkung** — optional, Textarea 8. **DSGWO-Einwilligung** * (Pflicht) — Checkbox mit Link zum Datenschutz ### Spam-Schutz: - Cloudflare Turnstile (kostenlos, kein Google-Datenabfluss) - Oder hCaptcha (open-source Alternative) --- ## DSGVO-Checkliste - [x] Daten auf eigenem Server (10.10.10.170) — keine externe Verarbeitung - [x] IP-Adresse gehasht (SHA-256), nicht reversibel - [x] Einwilligungs-Checkbox für jede Datenverarbeitung - [ ] Datenschutzerklärung aktualisiert - [ ] Löschkonzept: Daten nach 2 Jahren nach Projektende automatisch löschen - [x] HTTPS-only (via Coolify Let's Encrypt) - [x] OData API mit Basic Auth oder Token-basiert absichern --- ## Tech-Stack-Empfehlung ### PostgreSQL - Via Coolify als managed Service deployen - Backup: Daily via Coolify, 7 Tage Retention ### OData V4 API Backend **Option A: FastAPI + fastapi-odata (Python)** ```python # pip install fastapi fastapi-odata uvicorn psycopg2-binary from fastapi import FastAPI from fastapi_odata import ODataRouter app = FastAPI() router = ODataRouter(model=Registration, prefix="/odata") app.include_router(router) ``` **Vorteile:** Python (bekannt), schnell, einfach **Nachteile:** fastapi-odata noch relativ neu **Option B: .NET Minimal API + Microsoft.OData.Core** ```csharp // Native OData V4 Support builder.Services.AddOData(); app.MapODataServiceRoute("odata", "odata", model); ``` **Vorteile:** Vollständiges OData V4, gut dokumentiert **Nachteile:** .NET Runtime nötig **Option C: Django + django-extensions / django-orm** - Django hat eingebaute Admin-Oberfläche - Mit `django-filter` und `django-rest-framework` kann man OData-ähnliche Queries bauen **Vorteile:** Komplettes Admin-Dashboard out-of-the-box **Nachteile:** Kein echtes OData V4 ### Empfohlen: **Option A (FastAPI)** — weil Python, schnell zu deployen via Coolify, und mit `fastapi-odata` oder `odpy` echte OData V4 Support. --- ## Implementierungsplan ### Phase 1: Infrastruktur (Coolify) 1. PostgreSQL-Service in Coolify anlegen 2. Domain/Subdomain einrichten (`registrierung.ejun.de` oder `api.buergerinitiative-ejun.de`) 3. Let's Encrypt SSL konfigurieren ### Phase 2: OData API Backend 1. FastAPI-Projekt mit OData-Support erstellen 2. Datenbank-Model definieren (SQLAlchemy) 3. CRUD-Endpunkte implementieren 4. Authentifizierung für Admin-Endpoints 5. IP-Hashing und DSGVO-Felder ### Phase 3: Frontend-Formular 1. Registrierungsformular in `registrierung.html` integrieren 2. Cloudflare Turnstile oder hCaptcha einbauen 3. Formular-Validierung (client + server) 4. Bestätigungs-E-Mail bei Submission ### Phase 4: Admin-Dashboard 1. Einfache Übersicht aller Registrierungen 2. Status-Management (new/confirmed/rejected) 3. Suchfunktion und Filter 4. CSV-Export 5. Wöchentliche Zusammenfassung per Cron-Job ### Phase 5: Automatisierung 1. Automatische Bestätigungs-E-Mail 2. Wöchentliche Zusammenfassung an EJUN-Team 3. Daten-Löschung nach Ablauf (nach 2 Jahren) --- ## Kosten - **PostgreSQL:** Kostenlos (eigener Server) - **Coolify SSL:** Kostenlos (Let's Encrypt) - **Cloudflare Turnstile:** Kostenlos - **hCaptcha:** Kostenlos (open-source) - **Domain/Subdomain:** Bereits vorhanden (`buergerinitiative-ejun.de`) **Gesamtkosten: ~0 €/Monat** --- ## Offene Fragen 1. **Welche Domain?** `registrierung.ejun.de` oder `/api` Subpath? 2. **Auth für Admin-Dashboard?** Einfaches Password oder OAuth? 3. **Bestätigungs-E-Mail?** SMTP-Server (Mailgun, SendGrid) oder einfach Paperless als "Ersatz"? 4. **Löschfristen?** Wie lange Daten behalten? 5. **Unterschriften-Sammlung separat?** Oder direkt im Formular sammeln? --- ## Nächste Schritte 1. Schema und API-Design finalisieren (dieses Dokument) 2. In Coolify PostgreSQL deployen 3. OData API Backend implementieren 4. Registrierungsformular erstellen 5. Admin-Dashboard bauen 6. Testphase + Datenschutzprüfung
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Simon/ejun-page#2
No description provided.