Zum Inhalt
Ein System übernehmen, das jemand anderer gebaut hat
Bl. 11
2026
laufend

IKAZE

Eine zweisprachige Vereinsplattform, in der kein Fakt zweimal steht — und ein Test, der bei jedem Commit prüft, ob die Angaben noch gelten.

www.ikaze-africa.org →

Startseite, deutsche Fläche
Startseite, deutsche Fläche

Projektprofil

Eine Vereinswebsite ist selten technisch schwierig. Schwierig ist, dass sie drei Dinge gleichzeitig sein muss: ein Rechtsdokument, eine Förderakte und eine Vertriebsunterlage. Dieselbe Seite bedient vier Gruppen mit gegensätzlichen Erwartungen — wer Mitglied werden will, soll in fünf Sekunden verstehen, worum es geht; ein möglicher Sponsor sucht belastbare Angaben; eine Förderstelle sucht Statuten, Registernummer und Vorstand in höchstens zwei Klicks; und der ehrenamtliche Vorstand, der die Seite pflegt, braucht vor allem, dass nichts kaputtgehen kann. Der entscheidende Punkt: Sponsor und Förderstelle prüfen dieselben Angaben, und beide prüfen sie gegen andere Quellen. Daraus folgt die zentrale Entwurfsentscheidung — jeder Fakt darf nur an einer einzigen Stelle stehen.

40
URLs in der Sitemap — zwanzig Pfade in zwei Sprachen
148
Testfälle: 101 Integration, 47 im Browser
Auftraggeber
IKAZE — Ruandas Kulturverein, Wien · gemeinnützig, gegründet 2019
Zeitraum
Live seit Juni 2026 · betreut bis Ende 2026, Verlängerung jährlich
Bearbeitung
Sebastian Kern
Umfang
Zwanzig Seitenpfade in zwei Sprachen · Formularstrecken für Kontakt, Mitgliedschaft, Sponsoring, Event-Anmeldung, Bewerbung und Partneranfrage
Redaktionell
Termine, Bilder, Partner, Paketmodelle, Rechtstexte, Logo und Sponsoring-PDF — Änderung ohne Auslieferung
Betrieb
Docker · Coolify · Hetzner, Deutschland
Bewusst nicht
Kein Analytics, keine Tracking-Cookies, kein CDN, kein Komponenten-Baukasten
Stand der Angaben
2. August 2026
Leistung
Architektur, Entwicklung, Betrieb, Redaktions-Einschulung, SEO
Stack
Next.js 16 · React 19 · TypeScript · Payload CMS 3 · PostgreSQL 16 · Tailwind v4 · Resend · Coolify

Leistungsumfang

  • Zweisprachige Plattform, Deutsch und Englisch als vollwertige Flächen — nicht als übersetzte Zweitfassung
  • Redaktionssystem, das der Vorstand ohne uns bedient: Payload läuft innerhalb der Anwendung, nicht daneben — eine Codebasis, eine Auslieferung, eine Datenbank
  • Sechs Formularstrecken mit serverseitiger Prüfung, jede auf das für sie zuständige Postfach
  • Ein Test, der bei jedem Commit nicht das Verhalten prüft, sondern die Aussagen: Er durchsucht Code, Konfiguration, Redaktionsinhalte und öffentliche Dateien nach Angaben, die nicht mehr gelten dürfen — und gleicht gegen die laufende Datenbank ab, dass die Postfächer des Vereins nicht zu einem zusammenfallen
  • Vereinskennzahlen sind technisch an ihren Stichtag gebunden: Fehlt er, liefert die Funktion gar nichts. Den Stichtag zu löschen ist damit der Weg, die Zahlen zurückzuziehen — es gibt keine Feldkombination, die eine nackte Zahl veröffentlicht
  • Partner erscheinen erst öffentlich, wenn im CMS die schriftliche Freigabe vermerkt ist. Ein Verhandlungsstand kann technisch nicht versehentlich publik werden
  • Jede Datenmigration prüft vorher, ob der gespeicherte Wert noch der bekannte alte ist. Hat der Vorstand selbst eingegriffen, bleibt sein Wert stehen und es wird protokolliert — beim Produktionsdeploy Ende Juli trat genau dieser Fall ein
  • Betriebs-Runbook mit Fehlerkatalog und eine offene Aufgabenliste — samt der Einträge, von denen wir dem Verein ausdrücklich abgeraten haben
01

Vier Zielgruppen, die Gegensätzliches wollen

Dieselbe Website muss vier Gruppen bedienen. Wer Mitglied werden will, soll in fünf Sekunden verstehen, worum es geht. Ein Unternehmen, das Sponsor werden könnte, sucht Seriosität und belastbare Angaben. Eine Förderstelle sucht Statuten, Vereinsregisternummer und Vorstand — in höchstens zwei Klicks. Und der ehrenamtliche Vorstand, der die Seite pflegt, braucht vor allem eines: dass nichts kaputtgehen kann.

Der interessante Teil: Sponsor und Förderstelle prüfen dieselben Angaben, und beide prüfen sie gegen andere Quellen. Daraus folgt die zentrale Entwurfsentscheidung des Projekts — jeder Fakt darf nur an einer einzigen Stelle stehen.

02

Ein Fakt, eine Stelle

Die Anschrift des Vereins stand über Monate auf sechs Flächen: Fußzeile, Impressum, Kontaktseite, strukturierte Daten, E-Mail-Fußzeilen, Statuten-Zusammenfassung. Sie war formal korrekt aus dem Vereinsregister übernommen — und trotzdem ein Datenschutzproblem, weil es die Privatwohnung eines Vorstandsmitglieds war, weltweit indexiert und maschinenlesbar.

Der schnelle Weg wäre gewesen, sie an sechs Stellen zu ersetzen. Der handwerkliche Weg war, die Struktur so zu ändern, dass es sechs Stellen nicht mehr geben kann. Die Anschrift steht seither in genau einem Code-Literal und im CMS.

Die Datenmigration, die die alte Adresse aus der Produktionsdatenbank entfernt, hat bewusst keinen Rollback. Der Kommentar im Code sagt, warum: Einen Rechtstext zurückzurollen würde die Privatadresse wieder veröffentlichen.

03

Ein Test, der Aussagen prüft statt Verhalten

Übliche Tests prüfen, ob Software funktioniert. Dieser prüft, ob sie die Wahrheit sagt.

Bei jedem Commit durchsucht er das gesamte Projekt — Code, Konfiguration, Dokumentation, öffentliche Dateien — nach Angaben, die nicht mehr gelten dürfen: zurückgezogene Kennzahlen, eine Privatanschrift, stillgelegte E-Mail-Domains, überholte Programmtermine. Zusätzlich prüft er gegen die laufende Datenbank, dass die beiden Postfächer des Vereins nicht zu einem zusammenfallen und dass jedes Formular auf das für es zuständige verweist.

Der Kommentar im Kopf der Datei benennt den Anlass ohne Beschönigung: Jeder dieser Fakten war irgendwann falsch veröffentlicht, und jeder wurde auf dieselbe Weise falsch — der Wert stand an mehr als einer Stelle, und nur eine wurde aktualisiert.

Bei einem Verein, dessen Website Förderanträge und Sponsorenprüfungen trägt, ist das die relevantere Frage.

04

Das ehrliche Nein

Auf der Startseite standen drei Kennzahlen: Veranstaltungen, Teilnehmende, ehrenamtliche Stunden. Bei der Prüfung stellte sich heraus, dass für keine der drei eine Quelle existierte. Gleichzeitig lag die Seite Unternehmen vor, die gerade über eine Partnerschaft entschieden.

Wir haben nicht empfohlen, die Zahlen vorsichtiger zu formulieren. Wir haben empfohlen, sie zu entfernen.

Einen Tag später benannte der Vorstand die Quelle: eigene Vereinsaufzeichnungen, gültig zum Jahresende 2025. Die Zahlen sind seither wieder freigegeben und stehen wieder auf der Seite — aber der Stichtag ist jetzt Teil der Zahl, nicht eine Fußnote daneben. Die höhere, aktuellere Schätzung bleibt ungedruckt, bis das Veranstaltungsregister gefüllt und beschlossen ist.

Technisch ist der Stichtag keine Redaktionsdisziplin, sondern eine Bedingung: Fehlt er, liefert die Funktion, die den Block rendert, gar nichts zurück. Den Stichtag zu löschen ist damit der Weg, die Zahlen zurückzuziehen. Es gibt keine Feldkombination, die eine nackte Zahl veröffentlicht.

Das ist der Punkt. Eine Zahl zu löschen ist eine Geste. Eine Zahl zu löschen, eine Quelle zu verlangen, sie zu bekommen und die Zahl mit Stichtag zurückzustellen, ist ein Verfahren — und ein Verfahren kann ein Kunde übernehmen.

05

Dreimal dieselbe Lehre, jedes Mal eine Ebene weiter außen

Der Test war dreimal grün, während die ausgelieferte Seite falsch war.

Beim ersten Mal durchsuchte er alle Dateien im Projekt. Eine Datenbankspalte ist keine Datei — die Privatanschrift stand zwei Tage länger auf der Live-Seite, als sie im Code existierte. Beim zweiten Mal las er zusätzlich die redaktionellen Grundtexte. Eine Projektseite ist kein Grundtext — dort stand ein Postfach, das es nie gegeben hat. Beim dritten Mal las er auch Projekte, Termine und Stimmen. Eine Liste hatte einen Eintrag zu wenig — sechs Kennzahlen ohne Quelle standen drei Monate auf genau der Seite, die eine Förderstelle öffnet.

Jedes Mal war die Prüfung genau dort gründlich, wo beim Schreiben jemand hingedacht hatte.

Die Konsequenz aus dem dritten Mal war nicht, die Liste zu ergänzen. Es gibt jetzt genau eine Stelle im System, an der eine Vereinszahl stehen kann, und sie kann ohne ihren Stichtag nichts anzeigen. Das zweite Feld wurde nicht abgesichert, sondern gelöscht. Und der Test prüft die Abwesenheit dieses Feldes strukturell statt textlich — ein Textmuster erwischt ein leeres Zahlenfeld erst, wenn schon jemand Zahlen hineingeschrieben hat.

Das ist die ehrliche Fassung: Der Anspruch stimmt nicht, weil jemand von Anfang an klug war. Er stimmt, weil dreimal derselbe Fehler passiert ist und beim dritten Mal die Struktur geändert wurde statt der Regel.

06

Was ein Test nicht findet

Ein Test erwischt, was schon einmal falsch war. Er erwischt nicht, was noch nie jemand hinterfragt hat.

Zwei Sätze standen monatelang auf der Seite, beide aus der ersten Befüllung der Datenbank, beide nie gegen eine Quelle geprüft. Der eine beschrieb eine Tätigkeit, die es so nicht gab. Der andere berührte eine rechtliche Frage, die der Verein gar nicht beantworten konnte. Niemand hatte sie je für prüfbedürftig gehalten — der eine klang selbstverständlich, der andere nach Formalie.

Aufgefallen sind sie, weil wir vor einer Textänderung gelesen haben, was dort eigentlich steht, und beim Vorstand nachgefragt haben. Beide sind seither weg.

Dafür gibt es kein Werkzeug. Es gibt nur die Gewohnheit, den Kunden nach der Quelle zu fragen — und die Bereitschaft, den Satz zu streichen, wenn keine kommt.

07

Was die Seite bewusst nicht sagt

Eine Reihe von Angaben rund um das Programm ist im Vorstand noch nicht entschieden. Für keine davon gibt es ein CMS-Feld. Sie sind nicht „noch leer", sie sind nicht vorgesehen. Ergänzt wird, wenn entschieden ist — und dann zusammen mit dem Feld.

Das ist die unbequemere Variante. Ein leeres Feld ist bequem: Es sieht nach Vollständigkeit aus und wartet. Es lädt aber auch dazu ein, mit einem Platzhalter gefüllt zu werden, und ein Platzhalter auf einer Seite, die Förderstellen lesen, ist eine Angabe ohne Beschluss.

Genauso bei Partnern: Ein Partner erscheint erst öffentlich, wenn im CMS die schriftliche Freigabe vermerkt ist. Ein Verhandlungsstand kann technisch nicht versehentlich publik werden.

08

Handwerk im Detail

Die Workshop-Tage stehen auf der Seite als „Fr., 23. + Sa., 24. Oktober 2026". Nicht als „23.–24. Oktober". Ein Gedankenstrich liest sich als durchgehende Spanne und verspricht damit ein Wochenende, das es nicht gibt — die beiden Tage sind zwei getrennte Termine mit zwei Anmeldungen.

Solche Entscheidungen schreibt niemand in ein Briefing. Sie fallen auf, wenn dieselbe Person den Text liest und die Seite baut.

Ein zweites Beispiel derselben Art: Payload speichert Datumsangaben in UTC. Auf einem Server, der in UTC läuft, würde ein Wiener Beginn um 18:00 als „16:00" erscheinen — und zwar korrekt gespeichert und trotzdem falsch angezeigt. Die Anzeigezone ist deshalb fest auf Europa/Wien verdrahtet, Sommerzeit inklusive.

09

Betrieb, ohne Abhängigkeit von uns

Eine Codebasis, ein Deployment, eine Datenbank. Payload läuft innerhalb der Next.js-Anwendung, nicht daneben. Für einen Verein, der keinen zweiten Dienstleister für ein Backend betreiben will, ist das der entscheidende Unterschied.

Termine, Bilder, Partner, Rechtstexte, Logo und Sponsoring-PDF sind CMS-Felder. Änderungen brauchen kein Deployment und keinen Anruf bei uns.

Jede Datenmigration prüft vorher, ob der gespeicherte Wert noch der bekannte alte ist. Hat der Vorstand im Verwaltungsbereich selbst eingegriffen, bleibt sein Wert unangetastet und es wird protokolliert. Beim Produktionsdeploy Ende Juli trat genau dieser Fall ein: Ein Schritt korrigierte, ein zweiter fand die bereits vom Vorstand vorgenommene Korrektur und ließ sie stehen.

Kein Baukasten, kein Framework-Zoo, keine proprietäre Plattform: gängige Technologien, ein reproduzierbares Deployment, ein versioniertes Betriebs-Runbook mit Fehlerkatalog, eine laufende Aufgabenliste — samt der Einträge, die wir dem Verein ausdrücklich abgeraten haben. Was ein Nachfolger wissen muss, steht geschrieben und nicht in unseren Köpfen.

Einblicke

8 Aufnahmen · seitlich ziehen

Leitentscheidungen

Wesentliche Entscheidungen, ihre naheliegenden Alternativen und die Gründe dahinter.

Jeder Fakt an genau einer Stelle
statt die Angabe überall dort pflegen, wo sie gebraucht wird

Die Anschrift des Vereins stand über Monate auf sechs Flächen — Fußzeile, Impressum, Kontaktseite, strukturierte Daten, E-Mail-Fußzeilen, Statuten-Zusammenfassung. Formal korrekt aus dem Vereinsregister übernommen, und trotzdem ein Datenschutzproblem: Es war die Privatwohnung eines Vorstandsmitglieds, weltweit indexiert. Der schnelle Weg wäre gewesen, sie an sechs Stellen zu ersetzen. Der handwerkliche Weg war, die Struktur so zu ändern, dass es sechs Stellen nicht mehr gibt.

Die Migration, die die alte Anschrift entfernt, hat keinen Rollback
statt jede Migration umkehrbar halten

Umkehrbarkeit ist die Regel, und hier war sie falsch: Einen Rechtstext zurückzurollen würde die Privatadresse wieder veröffentlichen. Der Kommentar im Code sagt genau das — eine Ausnahme, die begründet dasteht, statt still zu passieren.

Ein Test, der Aussagen prüft statt Verhalten
statt redaktionelle Sorgfalt und ein Vier-Augen-Prinzip

Übliche Tests prüfen, ob Software funktioniert. Bei einem Verein, dessen Website Förderanträge und Sponsorenprüfungen trägt, ist die relevantere Frage, ob sie die Wahrheit sagt. Jeder der geprüften Fakten war irgendwann falsch veröffentlicht — und jeder auf dieselbe Weise: Der Wert stand an mehr als einer Stelle, und nur eine wurde aktualisiert.

Kein CMS-Feld für Unentschiedenes
statt das Feld anlegen und leer lassen

Ein leeres Feld ist bequem: Es sieht nach Vollständigkeit aus und wartet. Es lädt aber auch dazu ein, mit einem Platzhalter gefüllt zu werden — und ein Platzhalter auf einer Seite, die Förderstellen lesen, ist eine Angabe ohne Beschluss. Ergänzt wird, wenn entschieden ist, und dann zusammen mit dem Feld.

Payload innerhalb der Next.js-Anwendung
statt ein eigenes Backend neben dem Frontend

Eine Codebasis, eine Auslieferung, eine Datenbank. Für einen Verein, der keinen zweiten Dienstleister für ein Backend betreiben will, ist das der entscheidende Unterschied.

Kein Analytics, kein Tracking, kein CDN
statt die übliche Grundausstattung einer Vereinsseite

Der Verein hat sich dagegen entschieden. Nebeneffekt: Weil nichts getrackt wird, braucht die Seite keine Zustimmung abzufragen — ein Hinweis auf die technisch notwendigen Cookies reicht. Der Preis ist, dass es keine Reichweitendaten gibt.

Anzeigezeitzone fest auf Europa/Wien
statt die Serverzeit verwenden

Payload speichert Datumsangaben in UTC. Auf einem Server, der in UTC läuft, erschiene ein Wiener Beginn um 18:00 als „16:00" — korrekt gespeichert und trotzdem falsch angezeigt.

Zwei Veranstaltungstage mit Plus statt mit Gedankenstrich
statt „23.–24. Oktober"

Ein Gedankenstrich liest sich als durchgehende Spanne und verspricht ein Wochenende, das es nicht gibt — es sind zwei getrennte Termine mit zwei Anmeldungen. Solche Entscheidungen schreibt niemand in ein Briefing; sie fallen auf, wenn dieselbe Person den Text liest und die Seite baut.

Nachweise

URLs in der Sitemap
40
Seitenpfade, in zwei Sprachen
20
JSON-LD-Blöcke — Organization, Event, FAQPage
3
Apex-Weiterleitung auf den kanonischen Host
HTTP 301
Commits
124
Datenbank-Migrationen, alle inkrementell
20
Integrationstests
101
Tests im Browser
47
Typfehler (tsc --noEmit)
0
Analytics, Tracking-Cookies, CDN
0

Live-Abruf gegen www.ikaze-africa.org am 02.08.2026, Repository-Werte zum selben Datum. Kein Lighthouse-Lauf, keine Antwortzeiten, kein Barrierefreiheits-Audit — was nicht gemessen wurde, steht hier nicht. Die Seite entwickelt sich weiter; die Zahlen sind ein Messpunkt mit Datum, kein Dauerzustand.

Was wir nicht behaupten

  • Keine Reichweitenzahlen. Der Verein hat sich gegen Analytics entschieden — also gibt es hier keine Besucher-, Konversions- oder Reichweitenzahlen.
  • Keine Aussage zur Geschwindigkeit. Wir haben keinen Lighthouse-Lauf gemacht. Also steht hier keiner.
  • Nicht „barrierefrei". Kontrast- und Fokusregeln stehen verbindlich im Design-System, WCAG 2.1 AA ist das Ziel. Ein Audit hat nicht stattgefunden — bis es das hat, ist das ein Wort, das wir nicht verwenden.
  • Nicht „wir haben den Verein digitalisiert". Der Verein hat sich digitalisiert. Wir haben das System gebaut und die Redaktion übergeben.
  • Nicht „ein Test macht das unmöglich". Der Test hat die Lücke nicht verhindert, er hat sie gefunden — dreimal, siehe oben. Die stärkere Aussage ist auch die ehrlichere.
  • Kein Kundenzitat. Es liegt keines vor, und ein selbst formuliertes wäre keins.