Skip to content
← All projects

Gado Imkerei

Website and shop for an apiary in Däniken, Switzerland: from the cart to the paid order.

Role
Sole developer, commissioned by an external client
Period
July to September 2026
  • React 19
  • TypeScript
  • Tailwind CSS v4
  • Supabase
  • Postgres
  • Row Level Security
  • Deno
  • Stripe
  • Resend
  • ASPSMS
  • Vercel

What it does

Beyond the first paragraph this page is still in German. A full translation is on its way.

An apiary that had sold at the farm gate and by word of mouth needed a presence people can also order from, without turning into an operation somebody has to run every day. What came out of it is the complete purchase path: cart, checkout with pickup or shipping, Stripe Checkout with card and TWINT, customer accounts, order notifications by e-mail and SMS, and a protected report for the client. Halfway through, the scope changed: shipping and online payment arrived after the pickup checkout already stood, which is the part a side project cannot simulate.

Eine Imkerei verkaufte bis dahin ab Hof und über Zurufe. Gesucht war ein Auftritt, über den auch bestellt werden kann, ohne dass daraus ein Betrieb wird, den jemand täglich bedienen muss.

Entstanden ist der vollständige Kaufweg: Warenkorb, Kasse mit Abholung oder Versand, Bestellung per Formular oder WhatsApp, Stripe Checkout mit Karte und TWINT, Kundenkonto, Bestellmeldung per E-Mail und SMS und eine geschützte Auswertung für die Kundin. Dazu die Schweizer Rechtstexte, die ein Verkauf an Konsumenten verlangt.

Mitten im Projekt änderte sich der Umfang: Versand und Online-Zahlung kamen dazu, nachdem die Kasse für Abholung bereits stand. Aus der One-Page-Site wurde ein Shop mit Datenbank, Zahlungsanbieter und Meldewegen. Das ist der Teil, der sich in einem Eigenprojekt nicht simulieren lässt: Der Entwurf muss eine Änderung aushalten, die man sich nicht ausgesucht hat.

Numbers

lines of code
~8000 lines of code
payment methods: card, TWINT, cash
3 payment methods: card, TWINT, cash
external client
1 external client

Screenshots

Hero: Ort, Nutzen, Kaufweg und Vertrauen in drei Sekunden, ein starkes Foto statt Slideshow.
Sorten mit Jahrgang, Verfügbarkeit und Preis, ein eigenes Foto pro Ernte.
Kasse: Abholung oder Versand, Zahlung online oder vor Ort, Bestellung mit oder ohne Konto.
Mobil: Text und Schaltfläche ohne Scrollen sichtbar und tippbar.

Eine Lücke in der eigenen Insert-Policy, selbst gefunden

Bei einem Sicherheitsdurchgang gegen die eigene Datenbank liess sich über den öffentlichen anon-Key eine Bestellung mit dem Status "bezahlt" und beliebigem Betrag anlegen, und die Datenbank antwortete mit 201. Row Level Security war aktiv, aber die Insert-Policy prüfte nur, wer schreiben darf, nicht was geschrieben wird. Die Policy verlangt seither einen definierten Anfangszustand; "bezahlt" kann ausschliesslich der signierte Stripe-Webhook setzen. Die eigentliche Lehre steckt nicht im Fix, sondern in der Frage, die ihn gefunden hat: Nicht "ist RLS an?", sondern "was kann jemand mit dem Schlüssel tun, der ohnehin im Browser liegt?".

Stack

Frontend
  • React 19
  • TypeScript (strict)
  • Vite 8
  • Tailwind CSS v4
  • shadcn auf Base UI
  • lucide-react
  • Fontsource
Backend
  • Supabase
  • Postgres mit Row Level Security
  • Auth mit eigenen Mail-Vorlagen
  • vier Edge Functions in Deno
  • SQL-Migrationen über die Supabase CLI
  • Region Zürich
Payment and messaging
  • Stripe Checkout mit Karte und TWINT
  • signierte Webhooks
  • Erstattung
  • Resend auf eigener Domain
  • ASPSMS
  • WhatsApp-Deeplinks
Quality and operations
  • ESLint
  • tsc als Build-Gate
  • eigene Prüfskripte vor jedem Build
  • Vercel mit SPA-Rewrites
  • WebP-Bildpipeline

Status and reading

Delivered, live since September 2026 at gadoimkerei.ch. Repository private, access on request.