Files
2026-08-04 09:32:59 +02:00

800 lines
45 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Bürgerabstimmung — Whitepaper
**Digitale Bürgerbeteiligung mit dem Personalausweis. Themen einbringen, abstimmen, gemeinsam prüfen.**
| | |
|---|---|
| Arbeitstitel / Marke | **Bürgerabstimmung** |
| Domain (vorgeschlagen) | **buergerabstimmung.de** (Alternativen: buergerabstimmung.eu, abstimmungsportal.de) |
| Status | Konzept & technischer Prototyp (Testbetrieb, keine offizielle Seite einer Behörde) |
| Sprachen | Deutsch (Standard), Englisch |
| Version | 1.0 · August 2026 |
> **Wichtiger Hinweis:** Bürgerabstimmung ist ein privates Konzept- und Demonstrationsprojekt.
> Es ist **keine offizielle Seite der Bundesregierung oder einer Behörde** und erhebt
> nicht den Anspruch, staatliche Verfahren rechtlich zu ersetzen. Der Prototyp zeigt,
> wie eine solche Plattform funktionieren könnte. Solange der Testbetrieb läuft, zeigt
> die Seite dauerhaft ein entsprechendes Hinweisbanner an (im Code über die
> Konfigurationsvariable `show_test_banner = true` gesteuert). Eine frische
> Installation startet im **Testmodus**; er wird über die Oberfläche beendet und
> löscht dabei alle bis dahin entstandenen Testdaten (Kapitel 5.3b).
---
## 1. Zusammenfassung
Bürgerabstimmung ist eine Plattform für direkte, fortlaufende Bürgerbeteiligung. Jede Person
mit deutschem Personalausweis kann:
- **Themen einbringen** — maximal eines pro Tag, mit Ziel, Begründung, Kategorie und
räumlicher Ebene (Landkreis/kreisfreie Stadt, Bundesland, Deutschland; die
Gemeindeebene folgt in der Ausbaustufe),
- **abstimmen** — dafür oder dagegen; wer sich enthält, stimmt schlicht nicht ab,
- **rechtswidrige Inhalte melden** — geprüft nicht von einer Redaktion, sondern von
einer zufällig ausgelosten **Bürger-Jury** (1 % aller aktiven Ausweis-Pseudonyme),
- **seine Gesamtansicht abrufen** — durch Auflegen des Ausweises (NFC) erscheinen alle
eigenen Themen, Stimmen und Favoriten.
Die Identität wird ausschließlich über die **eID-Funktion des Personalausweises**
nachgewiesen: Der Chip beweist kryptographisch die Echtheit der Karte (privater
Schlüssel im Chip). Die Plattform kennt als Identität nur den **öffentlichen
Schlüssel** — keinen Namen, keine Adresse, kein Geburtsdatum, kein abgeleitetes
Pseudonym. Eine Karte = ein Konto. Das persönliche Profil wird an diesen
öffentlichen Schlüssel **verschlüsselt** und vom Server **signiert**
(manipulationssicher); die Stimmen werden **unverkettbar** gespeichert, sodass
niemand rückschließen kann, wer wie gestimmt hat.
Die Plattform ist bewusst **schlicht und amtlich-neutral** gestaltet, funktioniert
gleichwertig auf Smartphone und PC, passt sich hellem und dunklem Systemdesign an und
ist auch an öffentlichen Geräten (z. B. in Gemeindebüros oder Bibliotheken) nutzbar —
für Menschen ohne eigenes Gerät.
---
## 2. Marke, Domain, Gestaltung
### 2.1 Name
**Bürgerabstimmung** — bewusst **kein Kunstwort und keine Marke**, sondern die
schlichte Sachbezeichnung: Bürgerinnen und Bürger stimmen ab. So würde eine
Verwaltung die Sache benennen, und genau das ist der Zweck des Namens — er
verspricht nichts, was er nicht ist.
Bewusst **nicht** gewählt wurden „Wahl…“ und „Bürgerentscheid“: Beides sind
rechtlich belegte Begriffe für verbindliche Verfahren nach Wahl- und
Gemeinderecht. Diese Plattform ist ein Meinungsbildungs-Kanal **ohne
Rechtsverbindlichkeit**; ein Name aus dem Wahlrecht würde eine Wirkung
suggerieren, die sie nicht hat.
Zugleich ist der Name **nicht mit staatlichen Kennzeichen verwechselbar**: kein
Bundesadler, keine Bundesfarben-Imitation, kein „bund.de“-Look. Vor einem echten
Betrieb sind Marken- und Domainrecherche erforderlich — die reine
Sachbezeichnung ist als Wortmarke voraussichtlich nicht schutzfähig, was für
diesen Zweck kein Nachteil ist.
### 2.2 Domain
Vorschlag: **buergerabstimmung.de** (Sachbezeichnung, aussprechbar, .de passt
zum Zweck). Ausweichoptionen: buergerabstimmung.eu, buerger-abstimmung.de,
abstimmungsportal.de. Im Auslieferungszustand ist in der Konfiguration **keine
Domain eingetragen** — sie wird erst beim Aufsetzen gesetzt.
### 2.3 Gestaltungsprinzipien
1. **Schlicht wie eine App:** ruhige graue Fläche, weiße Karten mit weichen
Ecken, Haarlinien statt Rahmen, Systemschrift, **ein** blauer Akzent —
die Formensprache verbreiteter Messenger-/Systemoberflächen (iOS, Signal).
Keine Verläufe, keine Deko-Effekte, keine „KI-Regenbogen“-Ästhetik; Rot
bleibt destruktiven Aktionen (Löschen) vorbehalten, Gelb allein dem
Testbetrieb-Banner.
2. **Keine KI-Hinweistexte** auf der Seite. Die Seite spricht als Produkt, nüchtern
und in Sie-Form. Es steht nur Text da, der eine Entscheidung trägt:
Erklärsätze unter selbsterklärenden Überschriften, Wiederholungen von Zahlen
und Beschriftungen wie „Eingebracht am“ entfallen.
3. **Hell/Dunkel automatisch:** Das Design folgt ausschließlich der
Systemeinstellung (`prefers-color-scheme`) — es wird bewusst nichts im
Browser gespeichert, auch keine Design-Präferenz.
4. **Symbolhafter Einstieg:** Beim Sitzungsbeginn nur der Schriftzug und die
Sprachwahl — **Deutsch/English als Knöpfe mit Flagge**, ohne Bildmarke; die
Anmeldung führt ein Ausweis-Piktogramm mit NFC-Wellen an, Text bleibt
minimal. Die Kopfzeile der Seite trägt weder Wortmarke noch Anmeldestatus,
sondern nur die nötigen Bedienelemente; die Fußzeile nur Impressum und
Datenschutz. Das Impressum trägt im Prototyp bewusst nur einen Platzhalter
(ein `*` als Überschrift und als Text) — es ist vor einem echten Betrieb mit
den Pflichtangaben des Betreibers zu füllen, die Datenschutzerklärung ist an
den tatsächlichen Betrieb anzupassen.
**Bildmarke (Tab-/App-Icon):** ein **Häkchen im Feld** — scharfe Kanten,
keine abgerundeten Ecken, keine Farbe. Als SVG folgt es der
Systemeinstellung (schwarze Fläche mit weißem Kreuz im Hellmodus, weiße
Fläche mit schwarzem Kreuz im Dunkelmodus); PNG und ICO für Safari/iOS
liefern dieselbe Marke als geschlossene dunkle Kachel.
5. **Responsiv:** eine Codebasis für Smartphone, Tablet, PC und Terminals. Die
**tragenden** Funktionen — anmelden, Thema einbringen, abstimmen, melden,
Jury — laufen ohne JavaScript; alle Fenster sind `:target`-Dialoge, alle
Eingaben normale Formulare. JavaScript ergänzt: Countdown, NFC-Auslösung,
die stufige Geltungsbereichs-Auswahl, die Live-Zahlen und den Hinweis auf
ähnliche Themen. **Eine Ausnahme:** die `profil.yaml` wird ausschließlich per
`fetch` geladen — ohne JavaScript gibt es keine Selbstauskunft. Das ist vor
einem Echtbetrieb zu ergänzen.
6. **Testbetrieb-Banner:** Solange die Konfigurationsvariable
`show_test_banner` auf `true` steht (Auslieferungszustand), zeigt jede Seite oben
ein deutliches Banner: *„Testbetrieb — keine offizielle Seite der
Bundesregierung oder einer Behörde.“* Der **Testmodus** selbst ist keine
Variable, sondern ein Zustand der Installation (Kapitel 5.3b).
7. **Barrierearmut:** semantisches HTML, Tastaturbedienung, ausreichende Kontraste.
Die Abstimmungsbalken nutzen **Akzentblau gegen Neutralgrau** — auf
Farbfehlsichtigkeit geprüft (CVD-Abstand ΔE 18,3 hell / 16,6 dunkel) — und
tragen immer Beschriftung samt Prozentwert; Bedeutung hängt nie an Farbe
allein. Vollständige BITV-Konformität ist Ziel der Ausbaustufe.
---
## 3. Leitidee und Einordnung
Bürgerabstimmung versteht sich als **ständiger Meinungsbildungs-Kanal**: Statt alle vier
Jahre ein Kreuz zu machen, können Bürgerinnen und Bürger laufend Anliegen einbringen
und gewichten — von der Radweg-Frage in der Gemeinde bis zur bundespolitischen
Grundsatzfrage. Die Ergebnisse sind ein präzises, manipulationsarmes Stimmungsbild,
das Politik auf allen Ebenen nutzen kann.
Bewusste Abgrenzung:
- Bürgerabstimmung **ersetzt keine rechtlich bindenden Verfahren** (Wahlen, Volksentscheide).
Ergebnisse sind Meinungsbilder; eine rechtliche Bindung wäre ein politischer
Folgeschritt, kein technischer.
- Die Plattform ist **strikt neutral**: Zum Start existieren ausschließlich
Kategorien über das gesamte politische Spektrum, keine vorbefüllten Themen
(siehe 6.3); die Moderation erfolgt durch geloste Jurys nach
strafrechtlichen — nicht politischen — Kriterien.
---
## 4. Zugänge und Zielgruppen
- **Smartphone:** Ausweis per NFC ans Gerät halten, PIN in der eID-App eingeben,
fertig. Der Browser selbst berührt die Karte nie.
- **PC:** eID-Client (z. B. AusweisApp) mit USB-Kartenleser oder gekoppeltem
Smartphone als Leser.
- **Öffentliche Geräte:** Gemeinden, Bürgerbüros und Bibliotheken können Terminals
bereitstellen. Dafür ausgelegt: kurze Sitzungen, automatische Abmeldung nach
Inaktivität, keine lokalen Datenspuren, prominenter Abmelden-Knopf.
- **Fremde Geräte:** Da die Anmeldung nur mit physischer Karte + PIN funktioniert und
keine Passwörter existieren, kann bedenkenlos das Gerät einer anderen Person
genutzt werden.
Sprachen: **Deutsch und Englisch**. Die Wahl erfolgt beim Sitzungsbeginn,
gilt für die Sitzung und wird **nirgends gespeichert** — weder im Browser noch
am Konto. Ohne aufgelegten Ausweis ist die Seite nicht sichtbar (nur Anmeldung
und Rechtliches sind offen).
---
## 5. Identität: die eID des Personalausweises
### 5.1 Prinzip
Jeder deutsche Personalausweis (seit 2010) enthält einen Chip mit
Online-Ausweisfunktion (eID). Die Echtheit beweist der Chip kryptographisch: Er
besitzt **private Schlüssel, die das Chipmaterial nie verlassen**, und die Gegenseite
prüft die zugehörigen Zertifikate gegen die **staatliche Zertifikatskette** (Country
Verifying CA / Document Verifier, BSI-Standards TR-03110, TR-03130). Kopierte oder
gefälschte Karten fallen bei dieser Prüfung durch.
Für Bürgerabstimmung entscheidend ist die Funktion **„dienstespezifisches Kennzeichen“
(Restricted Identification)**: Der Chip errechnet pro Dienst ein stabiles Pseudonym.
- Dasselbe Pseudonym bei jedem Anhalten derselben Karte bei Bürgerabstimmung → **ein
Konto pro Karte**, Wiedererkennung ohne Klarnamen.
- Ein anderes Pseudonym bei jedem anderen Dienst → **keine Verkettbarkeit** über
Dienste hinweg.
- Bürgerabstimmung fragt **keine** Klardaten ab (kein Name, keine Anschrift, kein
Geburtsdatum). Es wird auch **kein eigenes Pseudonym erzeugt oder
zugeordnet**: Identität ist unmittelbar der öffentliche Schlüssel („on
the go“); Stimmen werden auf dem Server direkt für diesen Schlüssel
eingetragen.
### 5.2 Ablauf (Produktion)
1. Nutzer wählt „Ausweis auflegen“. Die Plattform startet über den eID-Client
(AusweisApp, Schnittstelle nach TR-03124) eine Authentisierung beim zugelassenen
**eID-Server** (TR-03130).
2. Nutzer hält die Karte an das NFC-Smartphone bzw. den Kartenleser und gibt die
sechsstellige **Ausweis-PIN** ein.
3. Chip und eID-Server authentisieren sich gegenseitig (PACE, Terminal- und
Chip-Authentisierung); der eID-Server prüft Echtheit und Sperrliste und übermittelt
Bürgerabstimmung **nur das Pseudonym**.
4. Bürgerabstimmung nimmt den geprüften öffentlichen Schlüssel unmittelbar als Kennung und meldet die Sitzung an.
Voraussetzung für den Echtbetrieb ist ein **Berechtigungszertifikat** der
Vergabestelle für Berechtigungszertifikate (Bundesverwaltungsamt) mit dem
Berechtigungsumfang „pseudonymer Zugang“ sowie ein zertifizierter eID-Server
(eigenbetrieben oder als Dienstleistung).
### 5.3 Prototyp (dieses Repository)
Der Prototyp bildet das Verfahren originalgetreu nach: Eine simulierte
Testkarte im Browser übernimmt die Rolle des Chips und hält ein echtes
Ed25519-Schlüsselpaar (libsodium). Beim „Ausweis auflegen“ signiert der
private Schlüssel eine Zufallsnachricht; der Server prüft die Signatur
gegen den öffentlichen Schlüssel und leitet daraus das Pseudonym ab.
**Zwei getrennte Vorgänge:**
1. **Profil laden (initiales Anhalten):** Die statische Challenge ist der
öffentliche Schlüssel selbst, zeitgebunden versiegelt. Der Server öffnet
den Nachweis mit dem öffentlichen Schlüssel und liefert die
**profil.yaml** (alle eigenen Stimmen, Themen, Favoriten, Jury-Status)
in den Browser; der Abmelde-Knopf löscht sie dort wieder. Der Nachweis
ist **TOTP-artig zeitbegrenzt** (5-Minuten-Fenster, Anmeldung gilt
höchstens zwei Fenster) — danach ist erneutes Anhalten nötig.
2. **Stimmabgabe und jede andere Änderung (unabhängig davon):** Die Karte
erstellt je Vorgang einen **versiegelten Umschlag** (kombinierte
Signatur über Aktion + Zeitfenster + Zufallswert); der Server
**öffnet ihn mit dem öffentlichen Schlüssel** und trägt die Stimme für
genau diesen Schlüssel ein. Derselbe Vorgang ergibt zu anderer Zeit
einen anderen Umschlag; alte Umschläge verfallen.
Zusätzlich trägt jedes Formular ein **Einmal-Token** (beim Einlösen
verbraucht — Wiederholungen laufen ins Leere), und im Browser liegt außer
der Sitzungs-ID nur die bewusst geladene profil.yaml. Am Smartphone ist
der NFC-Leser auf der Anmeldeseite automatisch scharf: Das Auflegen des
(echten) Personalausweises löst die Anmeldung direkt aus (Web NFC; der
Knopf bleibt Rückfall und Berechtigungsgeste).
### 5.3b Testmodus als Zustand, nicht als Variable
Eine frische Installation startet **im Testmodus**. Er ist kein Schalter in
der Konfigurationsdatei, sondern ein Zustand in der Datenbank
(`schema_info.test_mode`), damit eine Vorführung ohne Codeänderung möglich
ist und der Übergang in den Echtbetrieb protokolliert wird.
- **Im Testmodus** zeigt die Anmeldeseite **genau einen Knopf**. Er erzeugt
eine zufällige, als gültig behandelte Sitzung; Ausweis-Aufforderungen bei
Änderungen entfallen. Das Banner bleibt unabhängig davon sichtbar.
- **Beendet wird er über die Oberfläche**: Der Chip „Testmodus“ in der
Kopfzeile führt auf die Seite **„Echtbetrieb einrichten“** (Kapitel 5.3c).
Dort wird der Zugang für den Echtbetrieb festgelegt, geprüft und
umgeschaltet. Das Umschalten **löscht alle im Testbetrieb entstandenen
Daten** — Themen, Stimmen, Merkzettel, Meldungen, Jury-Sitze, Konten und die
im Testmodus erzeugten Ausweis-Schlüssel. Kategorien, System-Konto und eine
echte Freigabeliste bleiben. Der Schritt ist bewusst nicht umkehrbar.
- **Danach** existiert kein Weg mehr in die Anwendung, der ohne Ausweis
auskommt: Die Anmeldeseite bietet nur noch die Ausweis-Apps an, und die
Einrichtungsseite ist geschlossen.
### 5.3c Einrichtung des Echtbetriebs aus der Anwendung heraus
Der Übergang vom Testbetrieb zum Echtbetrieb ist kein Eingriff in den
Quelltext, sondern ein geführter Schritt in der Oberfläche. Die Seite
„Echtbetrieb einrichten“ leistet dreierlei:
1. **Voraussetzungen prüfen.** Sie zeigt, ob das Datenverzeichnis beschreibbar
ist, HTTPS anliegt, die Kryptographie-Erweiterung vorhanden ist, der
Zugriffsschutz greift und wie viele Ausweis-Schlüssel freigegeben sind.
2. **Zugang festlegen.** Zur Wahl stehen der **eigene eID-Server** (Anmeldung
über die Ausweis-App; setzt Berechtigungszertifikat und einen Server nach
TR-03130 voraus) und die **eigene Trust-Liste** (Anmeldung nur mit
Schlüsseln aus der Freigabeliste, befüllt über eine Abgleich-Adresse oder
`issue-card`). Erfasst werden SOAP-Adresse, Client-Zertifikat und
-Schlüssel, die Aktivierungsadresse der Ausweis-App, die Abgleich-Adresse
der Freigabeliste und die Startadresse von Nect. Ein Knopf **prüft die
Verbindung** zum eID-Server, bevor irgendetwas verändert wird.
3. **Umschalten.** Erst wenn die Eingaben gültig sind, der eID-Server
antwortet und der **Einrichtungsschlüssel** stimmt, werden die Einstellungen
nach `data/config.yaml` (Rechte 0600, vom Web nicht erreichbar)
geschrieben, die Testdaten gelöscht und der Echtbetrieb dauerhaft
aktiviert.
Der **Einrichtungsschlüssel** steht in `data/setup.token` und ist nur über
Dateizugriff oder `php index.php setup-token` lesbar. Damit kann das
Umschalten nur, wer den Server betreibt — nicht jeder, der sich im Testbetrieb
per Knopfdruck eine Sitzung erzeugen kann. Nach dem Umschalten wird die Datei
gelöscht.
Die Einstellungen aus `config.yaml` überlagern beim Start die Vorgaben im
Quelltext; übernommen wird ausschließlich eine feste Liste erlaubter
Schlüssel. `php index.php config` zeigt den wirksamen Stand.
Der Wechsel auf einen echten eID-Server ersetzt nur den Karten-Block; Regeln
und Abläufe bleiben identisch.
### 5.3d Anbindung der AusweisApp (TR-03124/TR-03130)
Die Anmeldung mit der AusweisApp ist direkt eingebaut und braucht auf der
Serverseite nichts als den Webserver und diese Datei:
1. Der Knopf „Mit AusweisApp anmelden“ leitet den Browser auf die
**Aktivierungsadresse des eID-Clients** nach TR-03124:
`http://127.0.0.1:24727/eID-Client?tcTokenURL=…`. Die AusweisApp — am PC wie
am Smartphone — fängt diese Adresse ab.
2. Die App holt das **tcToken** unter `/eid/tctoken` ab. Sie tut das als
eigener HTTP-Client **ohne Browser-Cookie**; deshalb trägt die tcTokenURL
einen **Einmal-Nonce** (10 Minuten gültig), der Browsersitzung und
Ausweis-Vorgang verbindet.
3. Mit hinterlegtem **eID-Server** (TR-03130, `eid_server_url`) fordert der
Server dort per `useID` eine Sitzung an und liefert der App ServerAddress,
SessionIdentifier und RefreshAddress. Die App liest den Chip PIN-geschützt
aus und schickt den Browser zurück auf `/eid/callback`.
4. **Ohne** eID-Server liefert das tcToken bewusst nur eine
`CommunicationErrorAddress`. Die AusweisApp bricht sauber ab, der Browser
kehrt zurück — **angemeldet wird niemand**. Das ist die ehrliche Grenze:
Einen eID-Server darf nur betreiben, wer ein **Berechtigungszertifikat des
BVA** besitzt (Kapitel 5.3e).
### 5.3e Autorisierte Schlüssel (Freigabeliste) und ehrliche Grenzen der eID
Anmelden kann sich ausschließlich, wessen **öffentlicher Schlüssel in einer
serverseitigen Allowlist** steht (`data/authorized_keys.yaml`) und wer den
passenden **privaten Schlüssel** besitzt (zeitgebundene Signatur-Challenge).
Damit ist ausgeschlossen, dass ein Knopfdruck ohne Ausweis oder mit einem
fremden/gefälschten Schlüssel Zugang gewährt (fail-closed).
Ehrliche Einordnung zur oft gewünschten „Liste aller Ausweis-Schlüssel“:
Eine solche staatliche Liste **existiert nicht** und wäre auch nicht
wünschenswert (sie wäre ein Register der kryptographischen Identität aller
Bürgerinnen und Bürger). Der Personalausweis weist sich stattdessen über die
**BSI-Zertifikatskette** (TR-03110: Chip-Authentisierung gegen CVCA/DV) aus,
geprüft durch einen zertifizierten **eID-Server** (TR-03130); das Auslesen des
Chips erfolgt PIN-geschützt ausschließlich über die **AusweisApp** (ein Browser
kann den Chip nicht lesen). Im Prototyp ist die Allowlist deshalb der
Platzhalter für genau diese Vertrauensprüfung: Der Modus `eid` übergibt an den
eID-Server/die AusweisApp; der Modus `demo` nutzt per `issue-card` ausgegebene,
autorisierte Test-Ausweise. Die Funktion `sync-keys` ist der Anschlusspunkt für
eine eigene Trust-Liste bzw. eID-Server-Anbindung kein Zugriff auf ein
Behördenregister.
### 5.4 Grenzen und Missbrauchsszenarien
- **Karte ≠ Person am Gerät:** Wie bei jeder eID-Nutzung kann eine Person freiwillig
ihre Karte + PIN einer anderen überlassen. Das ist rechtswidrig, skaliert aber
schlecht (physische Karte nötig) — genau dadurch werden Bot-Netze und
Massen-Manipulation wirksam verhindert.
- **Verlorene/gesperrte Ausweise** fallen über die Sperrlistenprüfung des eID-Servers
heraus.
- **Alters-/Staatsangehörigkeitsfragen:** Die eID steht auch Unions­bürgern (eAT,
eID-Karte) offen; ob deren Teilnahme gewünscht ist, ist eine politische
Konfigurationsentscheidung (Berechtigungszertifikat kann die Kartentypen
einschränken). Der Prototyp behandelt alle Karten gleich.
---
## 6. Funktionen im Einzelnen
### 6.1 Themen einbringen — „1 Thema pro Tag“
- Jedes Pseudonym kann **ein Thema pro Kalendertag** (Zeitzone Europe/Berlin)
erstellen; um **00:00 Uhr** beginnt der nächste Tag. Die Regel ist zusätzlich zur
Anwendungslogik als **Datenbank-Constraint** verankert (UNIQUE über Autor +
Erstelldatum) — sie kann also auch durch Programmierfehler nicht umgangen werden.
- Pflichtfelder beim Erstellen:
- **Titel** (kurz, prägnant),
- **Ziel** — was soll konkret erreicht werden?
- **Begründung** — warum?
- **Kategorie** (siehe 6.3),
- **Geltungsbereich** — eine hierarchische **Auswahl statt Freitext**,
wie auf Behördenseiten: Deutschland → Bundesland → Landkreis/kreisfreie
Stadt (eingebaute Gebietsliste mit allen 16 Ländern und rund 400
Kreisen; die Gemeindeebene folgt in der Ausbaustufe über das amtliche
Gemeindeverzeichnis, ARS/Destatis).
- **Themen sind nach Veröffentlichung unveränderlich.** Es gibt keinen
Bearbeiten-Weg — weder in der Oberfläche noch als Route. Damit ist die stille
Umdeutung einer laufenden Abstimmung ausgeschlossen: Woran abgestimmt wurde,
steht fest. Wer sich vertan hat, archiviert das Thema (solange noch keine
Stimme abgegeben ist) und bringt es neu ein. Eine spätere Ausbaustufe könnte
Korrekturen mit sichtbarer Versionsanzeige erlauben.
### 6.2 Abstimmen
- Pro Thema und Ausweis genau eine Stimme: **dafür** oder **dagegen**.
- **Neutral = nicht abstimmen.** Enthaltung wird nicht als eigene Stimmart gezählt.
- Die eigene Stimme ist **24 Stunden lang** änderbar oder zurückziehbar; danach
ist sie fest (auf der Hauptseite als eigene Gruppe „kürzlich abgestimmt,
noch änderbar“ sichtbar).
- **Stimmen sind unverkettbar gespeichert:** In der Datenbank steht kein
Ausweis-Bezug, sondern nur ein HMAC aus Thema + öffentlichem Schlüssel mit
serverseitigem Geheimnis. Doppelstimmen sind ausgeschlossen, doch ohne das
Geheimnis lässt sich nicht rückschließen, welcher Ausweis wie gestimmt hat.
- **Abstimmungsende je Thema — Datum, Zielwert oder beides:** Beim Einbringen
sind zwei Bedingungen ankreuzbar: ein **Enddatum** und ein **Zielwert**
(Einheit „X Stimmen“ für eine feste Zahl oder „% Stimmen“ für einen Anteil
der registrierten Ausweise).
Gesetzt werden darf eine von beiden **oder beide zugleich** — dann endet die
Abstimmung, **was zuerst eintritt**. Prozentangaben werden beim Anlegen in
eine absolute Zahl umgerechnet, damit das Ziel im Verlauf nicht mit der
Nutzerzahl wandert. Für **jeden** Zielwert gilt zusätzlich eine Untergrenze
von 10 Stimmen — auch ein ausdrücklich kleinerer Wert wird stillschweigend
darauf angehoben. Danach ist das Thema beendet.
- **Themen werden nie gelöscht.** Es gibt keinen Löschweg für Verfasser. Ein
Thema, zu dem **noch niemand abgestimmt** hat, lässt sich **archivieren**:
Es verschwindet aus Listen, Suche und Ähnlichkeitsabgleich, ist nicht mehr
wählbar und nicht mehr meldbar, bleibt aber unter
seiner Adresse erhalten und trägt dort die Kennzeichnung „Archiviert“.
- **Abgestimmte Themen bleiben unverändert bestehen.** Sobald die erste Stimme
abgegeben ist, entfällt auch das Archivieren — der Knopf ist dann schlicht
nicht mehr da. Damit bleibt jedes Thema, über das abgestimmt wurde, dauerhaft
nachvollziehbar. (Davon unberührt ist die Entfernung durch eine Bürger-Jury
nach festgestelltem Gesetzesverstoß, Kapitel 7.)
- **Gleiche Titel sind erlaubt, aber sichtbar.** Beim Einbringen zeigt das
Formular schon während des Tippens, ob es bereits ähnliche Themen gibt, und
verlinkt sie; einbringen lässt sich das Thema trotzdem. Auf der Themenseite
steht dieselbe Liste unter „Ähnliche Themen“. Der Abgleich vergleicht die
bedeutungstragenden Wörter des Titels, nicht die Zeichenkette.
- **Ergebnisse aktualisieren sich ohne Neuladen.** Ein schlanker JSON-Endpunkt
liefert Stimmenstände; Liste und Themenseite schreiben Balken, Zahlen und
Anteile im Hintergrund fort (alle zwölf Sekunden und beim Zurückkehren auf
den Tab). Ohne JavaScript bleibt der beim Aufruf gerenderte Stand stehen —
die Seite funktioniert weiterhin vollständig.
- Die Darstellung ist überall dieselbe und bewusst knapp: ein Balken, darunter
„Dafür n / x %“ und „Dagegen n / y %“ — in der Liste als Haarlinie, auf der
Themenseite kräftiger.
- **Drei Symbole oben rechts am Thema**, auf einer Höhe mit den Schildern für
Kategorie und Gebiet: ein **Lesezeichen** zum Merken (Thema, Kategorie,
Gebiet), eine **Archivbox** für den Verfasser eines Themas ohne Stimmen und
eine **rote Flagge** zum Melden. Die Flagge fehlt beim eigenen Thema und bei
beendeten Abstimmungen; läuft bereits eine Meldung, steht sie unterlegt und
ohne Funktion da. Beschriftungen tragen die Symbole nur als `title` und
`aria-label`.
- **Auf der Themenseite steht der eigene Stand in den Knöpfen, nicht in einem
Satz.** Dort gibt es keinen erklärenden Text zur eigenen Stimme; ihr Zustand
ist an den beiden Knöpfen ablesbar: beide grau, solange nicht gewählt wurde; die gewählte Seite
blau, solange sie sich noch ändern lässt; nach Ablauf der 24 Stunden und bei
beendeter Abstimmung die gewählte Seite blass-blau, die andere abgedunkelt,
beide nicht mehr bedienbar. Serverseitig wird eine dann noch abgesetzte
Stimme unabhängig davon abgewiesen. In der **Themenliste** und in der Gruppe
„kürzlich abgestimmt“ steht die eigene Stimme dagegen weiterhin als Text
(„Ihre Stimme: Dafür“, dort mit Frist) — Knöpfe, an denen man sie ablesen
könnte, gibt es dort nicht.
### 6.3 Kategorien — Neutralität durch Breite, keine vorbefüllten Themen
Damit die Plattform von Beginn an nicht als politisch gefärbt wahrgenommen wird,
gilt das **Breitenprinzip auf Kategorien-Ebene**: Zum Start existieren
ausschließlich die Kategorien — bewusst viele, quer über das gesamte politische
Spektrum. **Themen werden nicht vorbefüllt**; jeder einzelne Inhalt der
Plattform stammt aus der Bürgerschaft. So kann keine Startauswahl als
redaktionelle oder politische Setzung gelesen werden.
Kategorien (Start-Satz, erweiterbar):
Umwelt & Klima · Energie · Wirtschaft & Mittelstand · Arbeit & Soziales · Rente &
Alterssicherung · Gesundheit & Pflege · Bildung & Forschung · Familie & Jugend ·
Migration & Integration · Innere Sicherheit · Justiz & Bürgerrechte · Digitales &
Verwaltung · Verkehr & Infrastruktur · Wohnen & Mieten · Landwirtschaft & Ernährung ·
Finanzen & Steuern · Europa & Außenpolitik · Verteidigung · Kultur, Medien & Sport ·
Verbraucherschutz · Kommunales & Ehrenamt · Demokratie & Beteiligung
### 6.4 Merkzettel und eigener Stand
- **Einzelne Themen, Kategorien und Gebiete lassen sich merken**: Am Thema
steht dafür ein **Lesezeichen-Symbol**, das ein kleines Auswahlfeld mit drei
Einträgen öffnet — dieses Thema, seine Kategorie, sein Gebiet. Gemerktes ist
im Feld hervorgehoben und wird durch erneutes Antippen wieder entfernt.
Gemerkte Themen führen direkt zurück zum Thema, gemerkte Kategorien und
Gebiete filtern die Themenliste; alles ist am Schlüssel gespeichert und steht
auf jedem Gerät bereit.
- **Alles auf einer Seite.** Es gibt keine getrennte Unterseite „Meine
Übersicht“ mehr; `/me` und `/topics` führen auf dieselbe Hauptseite. Dort
stehen übereinander: Merkzettel-Chips, die Gruppe „kürzlich abgestimmt (noch
änderbar)“ mit der eigenen Stimme und der Frist, und die Themenliste. Eine
anstehende Jury-Aufgabe wird über einen Hinweis in der Kopfzeile und eine
Weiterleitung auf `/jury` erzwungen.
- Der vollständige eigene Stand — Stimmen, eingebrachte Themen, Merkzettel,
Meldungen, Jury-Zuteilungen — wird zusätzlich als **profil.yaml** ausgeliefert
(Kapitel 5.3), verschlüsselt an den eigenen Ausweis-Schlüssel.
### 6.5 Sprache
Deutsch ist Standard; Englisch vollwertig verfügbar. Die Wahl wird in der Sitzung
und — bei angemeldeten Nutzern — **am Pseudonym** gespeichert.
---
## 7. Meldung rechtswidriger Inhalte und Bürger-Jury
### 7.1 Grundsatz: Recht statt Richtung
Gemeldet werden können **mutmaßlich rechtswidrige Inhalte** — nicht politische
Meinungen. Zur Einordnung, weil danach oft gefragt wird: Auch extreme politische
Auffassungen sind in Deutschland **nicht als solche strafbar**; die
Meinungsfreiheit (Art. 5 GG) schützt auch scharfe und radikale Positionen. Strafbar
sind konkrete Delikte — und nur an diesen wird gemessen.
Eine Meldung besteht deshalb aus genau **einem Grund: dem Verstoß gegen ein
Gesetz**. Es gibt **keinen Auffangtatbestand** und **keinen Freitext** — es
wird ausschließlich am zitierten Gesetz bewertet. Beim Melden führt ein Suchfeld
(Schlagwort oder Paragraphennummer) zum eingebauten Register; der gewählte
Paragraph wird **wortgleich (1:1) zitiert** und der Jury unverändert vorgelegt.
Das Register umfasst im Prototyp **neun Tatbestände** des Strafgesetzbuchs:
| Norm | Tatbestand |
|---|---|
| § 130 Abs. 1 StGB | Volksverhetzung |
| § 86a Abs. 1 StGB | Verwenden von Kennzeichen verfassungswidriger und terroristischer Organisationen |
| § 111 Abs. 1 StGB | Öffentliche Aufforderung zu Straftaten |
| § 185 StGB | Beleidigung |
| § 186 StGB | Üble Nachrede |
| § 187 StGB | Verleumdung |
| § 240 Abs. 1 StGB | Nötigung |
| § 241 Abs. 1 StGB | Bedrohung |
| § 126a Abs. 1 StGB | Gefährdendes Verbreiten personenbezogener Daten |
Das Register ist erweiterbar; die hinterlegten Volltexte sind vor einem
Echtbetrieb wortgleich gegen gesetze-im-internet.de abzugleichen.
### 7.2 Bürger-Jury statt Redaktionsmoderation
Über die Meldung entscheidet keine Redaktion, sondern eine **zufällig geloste Jury
aus der Nutzerschaft** — das Losverfahren (wie beim Schöffenamt) macht gezielte
Beeinflussung praktisch unmöglich.
**Auswahl:**
- **1 % aller bereits auf der Plattform verwendeten Ausweis-Pseudonyme** wird per
kryptographisch sicherem Zufall (CSPRNG) gezogen. Die Mindestgröße
(Standard: 5) ist ein **Zielwert, keine Untergrenze**: Sind weniger geeignete
Personen verfügbar, besteht die Jury eben aus weniger — notfalls aus zweien.
Ebenso kann das Quorum unter den Standardwert 3 fallen, weil es auf die
tatsächliche Jurygröße gedeckelt wird. Bei kleiner Nutzerschaft entscheiden
also sehr wenige; das ist eine bewusste Abwägung zugunsten der
Funktionsfähigkeit und vor einem Echtbetrieb zu überdenken.
- **Ausgeschlossen** sind: Pseudonyme, die bereits einer **laufenden** Meldung als
Jury zugeteilt sind; die meldende Person; die Autorin/der Autor des gemeldeten
Themas; sowie Pseudonyme in der **Karenzzeit** — wer eine abgeschlossene
Jury-Runde hinter sich hat, ist erst **nach 3 Tagen** wieder losbar.
**Ablauf und Fristen (alle Zeiten Europe/Berlin):**
1. Meldung wird erstellt → Jury wird sofort gelost, die Abstimmung **startet zur
nächsten Mitternacht (00:00)**.
2. Ab Start läuft die reguläre Abstimmungsfrist von **24 Stunden**.
3. Nach Ablauf der 24 Stunden wird entschieden, **sofern mindestens 0,5 %** (bezogen
auf die Nutzerschaft, d. h. die Hälfte der Jury; Mindestquorum konfigurierbar)
ihre Stimme abgegeben haben.
4. Ist das Quorum nicht erreicht, **läuft die Meldung weiter**, bis es erreicht ist;
dann wird unmittelbar entschieden.
**Stimmoptionen der Jury:** *bestätigen* (Inhalt verstößt), *ablehnen* (kein
Verstoß), *Enthaltung* (zählt für das Quorum, nicht für die Mehrheit).
**Entscheidung:** einfache Mehrheit bestätigen > ablehnen → Inhalt wird entfernt
(Platzhalterseite „nach Gemeinschaftsprüfung entfernt“); sonst bleibt er stehen.
Bei Gleichstand bleibt der Inhalt stehen (im Zweifel für die Meinungsfreiheit).
**Mitwirkungspflicht:** Wer ausgelost wurde und noch nicht abgestimmt hat, wird beim
**nächsten Anhalten des Ausweises** (Sitzungsbeginn) zuerst zur Jury-Entscheidung
geführt und kann die übrigen Funktionen erst danach nutzen — oder wartet, bis die
Meldung abgeschlossen ist. Enthaltung ist ausdrücklich zulässig; niemand wird zu
einem inhaltlichen Urteil gezwungen.
**Schutz vor Melde-Missbrauch:** je Pseudonym maximal 3 Meldungen pro Tag; je Thema
höchstens **eine offene** Meldung (weitere Meldungen desselben Themas werden auf die
laufende Prüfung verwiesen); dasselbe Pseudonym kann dasselbe Thema nur einmal
melden. Alle Grenzwerte sind serverseitig durchgesetzt.
### 7.3 Grenzen des Verfahrens
Die Bürger-Jury ist eine **Plattform-Moderation**, kein Strafverfahren. Offenkundig
strafbare Inhalte können unabhängig vom Juryergebnis zusätzlich den
Strafverfolgungsbehörden gemeldet werden; gesetzliche Melde- und Löschpflichten
(insb. **Digital Services Act**, ggf. NetzDG-Nachfolgeregeln) gelten neben dem
Juryverfahren und erfordern im Echtbetrieb einen benannten Zustellungsbevollmächtigten
und Melde­wege für Behörden. Das ist im Betriebskonzept der Ausbaustufe zu verankern.
---
## 8. Sicherheitsarchitektur
Bürgerabstimmung wäre im Echtbetrieb ein **hochwertiges Angriffsziel** (politische
Stimmungsbilder, staatsnahe Wahrnehmung). Der Prototyp ist deshalb von Grund auf
konservativ gebaut: wenig Code, wenig Abhängigkeiten, restriktive Standardwerte.
### 8.1 Prinzipien
- **Datenminimierung als Verteidigung:** Was nicht gespeichert ist, kann nicht
gestohlen werden. Keine Namen, keine E-Mail-Adressen, keine Passwörter, keine
Klar-IP-Adressen in der Datenbank.
- **Keine fremden Laufzeit-Abhängigkeiten:** Der Prototyp nutzt ausschließlich
PHP-Bordmittel (kein Framework, kein Composer-Paket, kein CDN, keine externen
Fonts/Skripte). Das eliminiert Lieferketten-Risiken und macht den gesamten Code
in einem Durchgang auditierbar.
- **Sichere Standardwerte:** Testbanner an, Mock-eID nur explizit, restriktivste
HTTP-Header, alle Grenzwerte serverseitig.
- **Tiefenstaffelung:** Kernregeln (1 Thema/Tag, eine Stimme pro Thema, eine offene
Meldung pro Thema, ein Juror nur einmal je Meldung) sind zusätzlich zur
Anwendungslogik als **Datenbank-Constraints** erzwungen.
### 8.2 Maßnahmen im Code (Prototyp)
| Bereich | Maßnahme |
|---|---|
| SQL | Ausschließlich PDO-**Prepared Statements**, kein String-SQL mit Nutzerdaten |
| XSS | Konsequentes Output-Escaping (`htmlspecialchars`, ENT_QUOTES) in allen Templates; CSS und JavaScript werden als eigene Routen ausgeliefert. Ausnahmen ohne CSP-Bezug: das Icon-SVG trägt einen eigenen `<style>`-Block, die beiden Notfallseiten vor dem Start nutzen Inline-Styles |
| CSP | `default-src 'none'` + explizite Freigaben nur für eigene Skripte/Styles/Bilder; `frame-ancestors 'none'`, `base-uri 'none'`, `form-action 'self'` |
| Clickjacking | `X-Frame-Options: DENY` + CSP frame-ancestors |
| Weitere Header | `X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`, restriktive `Permissions-Policy`, COOP/CORP; HSTS im HTTPS-Betrieb |
| CSRF/Replay | **Einmal-Token** auf jedem POST-Formular: beim Einlösen verbraucht — jede Aktion ist genau einmal gültig |
| Sessions | HttpOnly, SameSite, Secure (bei HTTPS), ID-Rotation bei An-/Abmeldung, Inaktivitäts- (30 min) und absolutes Timeout (8 h) — wichtig für öffentliche Terminals |
| Identität | Der öffentliche Ausweis-Schlüssel selbst ist die Kennung — kein abgeleitetes Pseudonym. Das Server-Geheimnis (`data/secret.key`, 0600) wird beim ersten Start erzeugt und nur für die Stimmen-Marker und die Ratenbegrenzung verwendet |
| Zufall | Jury-Losverfahren mit CSPRNG (`random_int`, Fisher-Yates), nicht mit SQL-`RANDOM()` |
| Rate-Limits | Serverseitig je Pseudonym bzw. gehashter IP: Anmeldeversuche, Stimmen, Meldungen, Formular-POSTs |
| Eingaben | Whitelist-Validierung (Enums, Längen, UTF-8-Prüfung, Kontrollzeichen-Filter); keine Datei-Uploads |
| Fehlerbilder | Keine Stacktraces oder Pfade nach außen; generische Fehlerseiten; Sicherheitsereignisse werden ohne personenbezogene Daten protokolliert |
| Struktur | Eine Datei im Webroot; Datenbank, Geheimnisse und Logs liegen in `data/` **innerhalb** des Webroots und sind über eine eigene `.htaccess` sowie eine 404-Regel in der Anwendung gesperrt. Ein Verzeichnis außerhalb des Webroots wäre stärker und ist für den Echtbetrieb zu empfehlen |
| Betrieb | Selbsttest (`php index.php selftest`, 122 Prüfungen) deckt die Kernregeln automatisiert ab: Tagesgrenze, Abstimmungsende, Jury-Ausschlüsse, Quorum, Fristen, Karenz, Freigabeliste, Dauerhaftigkeit abgestimmter Themen, Archivierung, Ähnlichkeitssuche, Einrichtung des Echtbetriebs, Sprachtabellen |
### 8.3 Bedrohungsmodell (Auszug)
| Bedrohung | Antwort |
|---|---|
| Bot-/Sockenpuppen-Armeen | eID: eine physische Karte = ein Konto; ohne Karte keine Stimme |
| Stimmenkauf/-zwang im großen Stil | Physische Karte + PIN nötig; skaliert schlecht; rechtlich sanktioniert |
| Manipulation der Jury-Auswahl | CSPRNG-Losung serverseitig; Ausschlusslisten; keine Selbstmeldung zur Jury möglich |
| Melde-Spam zur Zensur | Tageslimit, eine offene Meldung je Thema, Quorum + Mehrheit nötig, Gleichstand erhält Inhalt |
| SQL-Injection / XSS / CSRF | Siehe 8.2 — durchgängig parametrisiert, escaped, tokenisiert |
| Session-Diebstahl am Terminal | Kurze Timeouts, Abmelde-Knopf, HttpOnly-Cookies. Im Browser liegt außer dem Sitzungs-Cookie nur die `profil.yaml` im `sessionStorage`; „Abmelden“ löscht sie |
| Datenbank-Diebstahl | Enthält öffentliche Ausweis-Schlüssel, Themen und Stimmen — keine Klaridentitäten. Die Stimmen sind ohne das Server-Geheimnis nicht zuordenbar; wer Datenbank **und** `secret.key` erbeutet, kann die Zuordnung berechnen |
| Lieferkette (Pakete/CDN) | Keine externen Abhängigkeiten im Prototyp |
| DDoS / Lastspitzen | Ausbaustufe: CDN/Anycast vor statischen Assets, horizontale Skalierung, siehe 10.3 |
### 8.4 Echtbetrieb zusätzlich (Pflichtprogramm)
TLS ausschließlich (HSTS + Preload), getrennte Umgebungen, Härtung nach
BSI-IT-Grundschutz, externe Penetrationstests **vor** Start, laufendes
Schwachstellen-Management + Bug-Bounty, signierte Deployments, Backups mit
Wiederanlaufübungen, 24/7-Monitoring, DDoS-Schutz, und ein unabhängiges
Sicherheits-Audit des Jury-Losverfahrens (nachvollziehbare, aber nicht
vorhersagbare Ziehung — z. B. via veröffentlichtem Ziehungs-Commitment).
---
## 9. Datenschutz (DSGVO)
- **Datenminimierung:** gespeichert werden nur: der öffentliche Ausweis-Schlüssel
als Kennung, Zeitstempel, eigene Themen, Merkzettel, Meldungen und
Jury-Zuteilungen. Stimmen liegen **ohne Bezug zum Ausweis** (HMAC-Marker).
Die gewählte **Sprache wird nicht gespeichert** — sie gilt nur für die
laufende Sitzung; die Spalte in der Kontozeile trägt lediglich den Standardwert
aus der Anlage. Keine Klaridentität, keine IP-Adressen im Klartext (nur
kurzlebige Hashes für Rate-Limits), keine Tracker, keine Cookies außer dem
Sitzungs-Cookie.
- **Rechtsgrundlage** (Echtbetrieb): Art. 6 Abs. 1 lit. a/e DSGVO je nach
Trägerschaft; eID-Nutzung nach eIDAS/PAuswG mit Berechtigungszertifikat.
- **Betroffenenrechte — Stand im Prototyp, ehrlich:** Die *Auskunft* ist
umgesetzt: die **profil.yaml** enthält den vollständigen eigenen Stand, an den
eigenen Ausweis-Schlüssel verschlüsselt. Sie wird allerdings **nur per
JavaScript** abgerufen — ohne JavaScript gibt es keine Selbstauskunft.
Die *Löschung* ist als Routine vorhanden und automatisiert geprüft
(`account_delete` löscht die Kontozeile, wodurch Merkzettel, Meldungen und
Jury-Sitze per Fremdschlüssel mit entfernt werden, und hängt eingebrachte
Themen an ein System-Konto um; **abgegebene Stimmen bleiben erhalten**, weil
sie keinen Bezug zum Ausweis tragen und nach dem Löschen niemandem mehr
zuzuordnen sind). Sie hat in dieser Fassung **keine Schaltfläche** in der
Oberfläche — der Löschbereich wurde entfernt. **Vor einem Echtbetrieb ist
dafür zwingend ein Weg in der Oberfläche zu ergänzen**, sonst ist Art. 17
DSGVO nicht erfüllt.
- **Speicherbegrenzung:** Rate-Limit-Einträge verfallen automatisch;
Sicherheitslogs ohne Personenbezug.
- Für den Echtbetrieb: Datenschutz-Folgenabschätzung (Art. 35 DSGVO) zwingend,
benannte(r) DSB, Verzeichnis von Verarbeitungstätigkeiten.
---
## 10. Technik
### 10.1 Prototyp-Stack
- **PHP ≥ 8.0** (strict types, harte Versionssperre beim Start), keine externen Pakete.
- **SQLite** (WAL-Modus) als Prototyp-Datenbank — eine Datei, einfach zu prüfen;
die Datenzugriffsschicht ist so geschrieben, dass PostgreSQL in der Ausbaustufe
ein Austausch der Verbindung ist.
- **Server-gerendertes HTML**, genau eine CSS- und eine JS-Datei, dazu das
Icon — alles aus derselben Datei ausgeliefert. Hell/Dunkel ist reines CSS,
dafür gibt es kein Skript.
- Betrieb hinter Apache/nginx mit gesperrtem `data/` oder für Demos mit
dem eingebauten PHP-Server.
### 10.2 Hintergrundläufe
Zustandswechsel (Meldung „wartet“ → „läuft“ um 00:00, Entscheidung nach 24 h +
Quorum, Karenzzeiten) verarbeitet ein idempotenter **Maintenance-Tick**: er läuft
per Cron (`php index.php cron`) **und** zusätzlich beiläufig bei Seitenaufrufen (auf 30 Sekunden gedrosselt),
sodass der Prototyp auch ohne Cron korrekt bleibt.
### 10.3 Skalierungspfad
PostgreSQL + Read-Replicas → zustandslose PHP-Knoten hinter Load-Balancer →
CDN für Assets → Warteschlange für Jury-Benachrichtigungen → mandantenfähige
Gebietsdaten (amtliche Gemeindeschlüssel AGS/ARS statt Freitext-Gebieten).
---
## 11. Parameter (konfigurierbar)
| Parameter | Standard | Bedeutung |
|---|---|---|
| `show_test_banner` | **true** | Testbetrieb-Banner auf jeder Seite |
| `eid_mode` | `demo` | `demo` (ausgegebene Test-Ausweise) oder `eid` (nur Ausweis-Apps) |
| `eid_client_url` | `http://127.0.0.1:24727/eID-Client` | Aktivierungsadresse des eID-Clients (TR-03124) |
| `eid_server_url` | leer | SOAP-Endpunkt des eigenen eID-Servers (TR-03130); leer = fail-closed |
| `data/config.yaml` | fehlt | von der Einrichtungsseite geschriebene Überlagerung der Vorgaben |
| `default_lang` | `de` | Standardsprache |
| `jury_share` | 1 % | Anteil der Nutzerschaft je Jury |
| `jury_min` | 5 | Mindest-Jurygröße |
| `quorum_share` | 0,5 % | Quorum als Anteil der Nutzerschaft |
| `quorum_min` | 3 | Mindest-Quorum |
| `report_vote_hours` | 24 | Reguläre Jury-Abstimmungsdauer |
| `jury_cooldown_days` | 3 | Karenz nach abgeschlossener Jury-Runde |
| `reports_per_day` | 3 | Meldungen je Pseudonym und Tag |
| `timezone` | Europe/Berlin | Bezugszeitzone aller Tagesgrenzen |
---
## 12. Roadmap
1. **Prototyp (dieses Repository):** vollständige Fachlogik mit Mock-eID,
Zwei-Sprachen-UI, Jury-Verfahren, Selbsttests.
2. **Pilot:** Anbindung echter eID-Server (Berechtigungszertifikat, AusweisApp-Flow),
externes Sicherheits-Audit + Pentest, DSFA, Barrierefreiheit nach BITV,
PostgreSQL.
3. **Kommunal-Pilotgemeinden:** Terminals in Bürgerbüros, amtliche Gebietsschlüssel,
Auswertungs-Exporte für Räte und Verwaltungen.
4. **Ausbau:** Delegations-/Sachverständigen-Funktionen, strukturierte
Ergebnisberichte an Parlamente, offene Schnittstellen (Open Data) mit
Differential-Privacy-Schutz kleiner Gebiete.
---
## 13. Offene Punkte
- Marken-/Domainrecherche „Bürgerabstimmung“ und finale Namensentscheidung.
- Trägerschaft und Finanzierung (Verein/Stiftung empfohlen: neutralitätssichernd).
- Rechtsgutachten: eID-Berechtigungsumfang, DSA-Pflichtenkatalog, Jugendliche
(Ausweispflicht ab 16 — Teilnahmealter ist Konfigurationsfrage).
- Verifizierbare Jury-Ziehung (öffentliches Commitment-Verfahren) — Konzept in 8.4
skizziert, Umsetzung in der Pilotphase.
---
## Anhang: Installation und Betrieb
Der technische Prototyp ist **eine einzige Datei**. Es genügt ein Webserver
mit PHP — kein Framework, kein Paketmanager, keine externen Dienste.
1. `index.php` in das Webverzeichnis legen (Hauptverzeichnis oder Unterordner;
der Basispfad wird erkannt).
2. PHP **8.0 oder neuer** mit `pdo_sqlite`, `mbstring` und `sodium` — alle drei
gehören zur Standardausstattung.
3. Seite aufrufen. Beim ersten Aufruf legt die Datei selbst an: `data/`
(SQLite-Datenbank, Server-Geheimnis, Protokolle, Zugriffssperre),
`.htaccess` (saubere Adressen und Schutz interner Dateien) und `robots.txt`.
Meldet die Seite „Fast geschafft“, fehlen dem Verzeichnis Schreibrechte
(755/775 setzen, neu laden). Ohne `.htaccess`-Unterstützung — etwa unter nginx —
arbeitet die Anwendung über automatisch erzeugte `/index.php/…`-Adressen
weiter; eine gleichwertige `try_files`-Regel stellt die sauberen Adressen her.
Dort ist zusätzlich `/data/` zu sperren — die Anwendung selbst beantwortet
jede Anfrage auf diesen Pfad mit 404, ausgeliefert würde sie sonst am
PHP-Prozess vorbei.
Der Auslieferungszustand ist der **Testmodus** (Kapitel 5.3b): ein Knopf meldet
ohne Ausweis an, damit sich die Plattform vorführen lässt. Über den Chip
„Testmodus“ führt die Seite **„Echtbetrieb einrichten“** (Kapitel 5.3c) durch
Prüfung, Zugangswahl und Umschaltung; sie schreibt die Einstellungen nach
`data/config.yaml`, löscht alle Testdaten und aktiviert dauerhaft die strenge
Ausweisprüfung. Der dafür nötige Einrichtungsschlüssel steht in
`data/setup.token`.
Wartung und Prüfung laufen über dieselbe Datei auf der Kommandozeile:
| Aufruf | Zweck |
|---|---|
| `php index.php selftest` | 122 automatisierte Prüfungen der Fachregeln |
| `php index.php cron` | Wartungslauf (sonst beiläufig bei Seitenaufrufen) |
| `php index.php seed 400` | Demo-Stimmen, anonym wie im Echtbetrieb |
| `php index.php jurysim` | Demo-Jury stimmt in laufenden Prüfungen ab |
| `php index.php issue-card 3` | autorisierte Demo-Ausweise samt Abhol-Verweis |
| `php index.php sync-keys` | Freigabeliste aus der konfigurierten Trust-Liste |
| `php index.php setup-token` | Einrichtungsschlüssel für die Umschaltung anzeigen |
| `php index.php config` | wirksame Einstellungen aus `data/config.yaml` anzeigen |
| `php -S 127.0.0.1:8080 index.php` | lokale Vorführung ohne Webserver |