Vom leeren Bildschirm zum ersten Kunden live — in acht Tagen.
Fit in de Buurt ist eine Lead-Plattform für lokale Fitnessstudios: Landingpages die konvertieren, ein Portal zur Nachverfolgung angerufener Leads, ein Postleitzahl-Verzeichnis und die Fakturierung drumherum. Design, Bau, Datenbank, Hosting und Betrieb — solo gebaut.
Live auf fitindebuurt.nl · Row-Level-Security auf allem Privaten · Next.js 16, React 19, Supabase
Das Problem
Ein kleines Fitnessstudio wirbt lokal, schickt Menschen auf sein Instagram oder eine allgemeine Website und verliert sie dort. Wer doch reagiert, kommt über eine DM, eine Mail oder eine Nachricht; die Inhaberin merkt sich im Kopf, wen sie zurückrufen muss. Zwei Tage später ist die Hälfte vergessen und das Interesse weg.
Die drei Dinge, die es dafür gibt, lösen jeweils nur einen Teil. Ein Website-Baukasten liefert eine Seite ohne Nachfassen. Ein CRM ist zu schwer für jemanden mit einer Handvoll Leads pro Monat. Ein Linktree bietet keinerlei Einblick. Und alles, was funktioniert, legt die personenbezogenen Daten ihrer Kunden an einen Ort, über den sie keine Kontrolle hat.
Was daraus wurde
Eine Plattform, die drei Arten von Besuchern zugleich bedient — den Sportler, das Studio und den Betreiber.
Für den Sportler
Die Startseite ist ein Verzeichnis: Postleitzahl eingeben und sehen, welche Studios, Fitnesscenter, Salons und Praxen am nächsten liegen — mit Entfernung, Bewertungen und einem Button zum Buchungssystem oder zur Lead-Seite. Ohne Cookies, ohne Konto, ohne dass wir speichern, wonach jemand sucht.
Für das Studio
Eine eigene Lead-Seite auf name.fitindebuurt.nl und fitindebuurt.nl/name, aus Blöcken gebaut und auf die Corporate Identity abgestimmt. Wer seine Nummer hinterlässt, landet sofort im Portal, mit einer Mail dazu. Im Portal steht eine Liste: wen rufe ich an. Pro Lead werden Anrufversuche erfasst, mit Notiz snoozen, als gewonnen oder verworfen markieren.
Für den Betreiber
Ein Editor, in dem ich eine Kundenseite aufbaue und veröffentliche, Statistik pro Version dieser Seite und Fakturierung mit Abonnements, Nummerierung, PDFs und einem nächtlichen Cronjob.
Es gibt nirgends einen Anruf-Button oder einen tel:-Link. Das ist die ganze Idee: Ein Besucher hinterlässt seine Daten und das Studio ruft zurück. So weiß die Inhaberin, wer interessiert war — auch wenn das Gespräch nicht sofort klappt.
Vier Entscheidungen, die das Projekt prägen
Entscheidungen, die sich durch die gesamte Codebasis ziehen — und den Unterschied zwischen fertig und hingeschludert machen.
Die Trennung zwischen Kunden steckt in der Datenbank, nicht in der Oberfläche
Jede Seite hat einen Eigentümer. Row-Level-Security in Postgres entscheidet, wer welche Zeile sieht; die App kann es nicht umgehen, ich auch nicht. Eine Testsuite versucht mit echten Zugangsdaten zweier Eigentümer, gegenseitig Leads zu lesen, zu ändern und zu löschen. Ohne diesen grünen Test geht nichts live.
Der Inhalt einer Seite steht an zwei Stellen, mit Absicht
Die Vorlage ist eine typisierte Datei, die mit satisfies LandingPagina endet — fehlt ein Text, schlägt der Build fehl. Was ich im Editor ändere, wird als Overlay in der Datenbank gespeichert und über die Vorlage gerendert. So behalte ich die Garantien des Compilers und kann Texte ändern, ohne zu deployen.
Veröffentlicht wird unter einem Namen, Zahlen gehören zu einer Version
Jede Veröffentlichung ist eine unveränderliche Zeile in pagina_versies. Die Tageszähler merken sich pro Version das Gezählte, also sehe ich, was "Kürzere Hero" gegenüber "Sommeraktion" brachte, und stelle eine alte Version mit einem Klick als Entwurf wieder her.
Alles auf Niederländisch, bis in die Datenbank
Spalten heißen belpogingen, snooze_tot, weggedrukt_op. Das liest sich für den Kunden und für mich gleich und hält den Abstand klein zwischen dem, was wir im Gespräch sagen, und dem, was im Code steht.
Drei Teile zum Hervorheben
Die Stellen, in die die meiste Denk- und Bauzeit floss.
Der Seiten-Editor
Links eine Live-Vorschau, rechts die Seite von oben nach unten: pro Block ein Panel mit allem, was dazugehört. Texte bearbeitest du in der Vorschau selbst — zeigen, klicken, tippen — und ein Besucher bekommt exakt dasselbe HTML. Die Akzentfarbe steht in einer CSS-Variablen; color-mix leitet fünf Töne ab, sodass jeder Block zu jeder CI passt.
Das Postleitzahl-Verzeichnis
Postleitzahlen gehen an den Locatieserver des Kadasters (PDOK): offen, gratis, ohne Schlüssel. Das Ergebnis speichern wir in einer eigenen Tabelle, ein zweiter Besucher mit derselben PLZ kostet keine Anfrage. Postgres berechnet die Entfernung und liefert nur Studios, die jede Bedingung erfüllen. Vom Besucher bewahren wir nichts: kein Cookie, keine IP.
Fakturierung
Abonnements pro Kunde, automatische Entwürfe aus einem nächtlichen Lauf, eine Rechnungsnummernreihe, die nicht springen darf, Beträge in Cent, MwSt. pro Zeile und ein PDF im Speicher. Eine gesendete Rechnung ist eingefroren: Datenbank-Trigger verweigern jede Änderung, weil eine gesendete Rechnung sieben Jahre gleich bleiben muss.
So etwas für Ihr Unternehmen nötig?
Wie es zusammengesetzt ist
Ein Next.js-Projekt bedient vier Arten von Besuchern, getrennt mit Route-Gruppen: das Verzeichnis, die Marketingseiten, die Kunden-Landingpages und die eingeloggte Seite. Subdomains laufen über proxy.ts, das die Supabase-Session auffrischt und alles hinter dem Login abschließt.
| Schicht | Wahl |
|---|---|
| App | Next.js 16 (App Router), React 19, TypeScript strict |
| Styling | Tailwind CSS 4, eigene Komponenten, vollständig niederländische Oberfläche |
| Daten + Auth | Supabase (Postgres, Auth, Storage), Region Frankfurt |
| Validierung | Zod, auf beiden Seiten und auf den Umgebungsvariablen |
| Resend, fünf transaktionale Mails mit einer Gestaltung | |
| @react-pdf/renderer, Rechnungen in Supabase Storage | |
| Hosting | Vercel, Wildcard *.fitindebuurt.nl, Cronjobs, Preview pro Push |
| Secrets | Doppler; kein Schlüssel im Repo |
| Monitoring | Sentry, nur in Produktion |
- Zwei nächtliche Jobs auf Vercel hinter einem gemeinsamen Geheimnis: 06:00 Fakturierung, 04:00 Aufräumen abgelaufener Anfragen.
- Keine Namen, Telefonnummern oder E-Mail-Adressen in Logs oder Fehlermeldungen, keine IP-Adressen in der Statistik.
- Leads werden ausschließlich serverseitig geschrieben — der Browser hat kein Schreibrecht auf die Datenbank.
- Ein gesnoozter Lead kommt von selbst zurück: Snooze ist kein Status, sondern ein Datum, kein Hintergrundjob, der stillstehen kann.
Qualität und Arbeitsweise
Ein Befehl ist das Tor: npm run check führt Typecheck, ESLint ohne Warnungen, Prettier, alle Unit-Tests und einen vollständigen Build aus. Was da nicht durchkommt, gilt nicht als fertig. Husky und lint-staged tun dasselbe bei jedem Commit, GitHub Actions wiederholt es bei jedem Push.
| Was | Umfang |
|---|---|
| Code | 265 Dateien, ± 33.000 Zeilen TypeScript |
| Datenbank | 27 Migrationen, 20 Tabellen, RLS auf allem Privaten |
| Unit-Tests | 412, in 37 Dateien |
| Browser-Tests (Playwright) | 52, in 9 Dateien |
| Vorlagen und Blöcke | 8 Vorlagen, 12 wiederverwendbare Blöcke |
| Commits | 94, in acht Tagen |
Browser-Tests tun, was ein Mensch tut
Einloggen, einen Lead hereinholen, ihn snoozen, einen Block im Editor abschalten, veröffentlichen und prüfen, dass sich die öffentliche Seite mitändert. Genau dort sitzen die Fehler, die Typecheck und Unit-Tests nicht sehen.
Auffindbarkeit ist an vier Stellen festgelegt
robots.ts (mit dreiundzwanzig namentlich genannten AI-Crawlern), eine Sitemap, die Kundenseiten aus der Datenbank zieht, ein generiertes /llms.txt mit der ganzen Site in Markdown und strukturierte Daten pro Seitentyp — nie mehr als auf der Seite selbst steht.
Mit AI-Unterstützung gebaut, aber nicht auf gut Glück
Jeder Teil wurde zuerst als Plan im Repo ausgeschrieben — warum, welche Phasen, welche Abwägungen — und dann gebaut. Feste Vereinbarungen stehen in einer Regeldatei, die jede Session mitliest. Die Tests, die Typen und Row-Level-Security sind die Bremse.
Wo es jetzt steht
Die Site läuft, der erste echte Kunde ist live und im Verzeichnis, und die Fakturierung steht bereit für ihr erstes Abonnement.
- Kartenansicht und eigene Übersichtsseiten pro Art und Ort
- Verifizierte Google-Bewertungen
- Export von Leads
- Zwei-Faktor-Authentifizierung
- A/B-Tests über zwei veröffentlichte Versionen zugleich
Von der Idee zur Live-Plattform
Maßgeschneiderte Software, die bleibt.
Eine Lead-Plattform, ein Portal, ein Webshop oder ein internes Tool — gebaut mit Tests, Typen und Datenschutz als Fundament. Lassen Sie uns besprechen, was Sie brauchen.







