Zum Hauptinhalt
Zurück zu Projekten
LedIn Burada logo

LedIn Burada

Unternehmenskatalog

Architekturdiagramm von LedIn Burada LedIn Burada Katalog var, sepet yok — sitenin işi ziyaretçiyi konuşmaya çevirmek Kapsam kararı mimariyi belirledi: ödeme yoksa oturum, sepet ve stok kilidi de yok. YÖNETİM TARAFI Admin paneli ürün · müşteri · satış · talep Neon Postgres · Drizzle ORM 5 tablo · 5 migration görseller Vercel Blob'da build generateStaticParams ürün listesi veritabanından okunur her ürün için statik sayfa üretilir yeni ürün = yeni dağıtım ziyaretçi isteği DB'ye hiç ulaşmaz Statik vitrin 25 rota · kategori ve ürün sayfaları özel imalat · projeler · hakkımızda fiyat gösterimi yok üyelik yok Dönüşüm: WhatsApp / telefon tek hedef — teklif konuşması başlatmak iletişim formu Turnstile arkasında Kapsam dışı bırakılanlar — ve neden Sepet, ödeme, üyelik, fiyat listesi. İş modeli saf B2B imalat: sipariş ölçüyle ve konuşmayla alınıyor, rafta duran bir ürünle değil. Sepet eklemek satmayan bir akışa stok, ödeme ve iade yükü getirirdi. Yayın anahtarı NEXT_PUBLIC_COMING_SOON Açıkken site tek ekrana iner: marka, kısa açıklama ve doğrudan iletişim. Uygulamanın geri kalanı yerinde durur. Böylece alan adı, içerik hazır olmadan da tek anahtarla açılabiliyor — ayrı bir "yakında" sitesi bakmak gerekmiyor. Bedeli Statik üretim, katalog tazeliğini dağıtıma bağlar: paneldeki bir düzeltme yeni bir build alınana kadar vitrine yansımaz. Katalog nadiren değiştiği için kabul edildi; günde birkaç kez değişen bir katalogda bu karar yanlış olurdu.
Katalog ohne Warenkorb. Das Admin-Panel verwaltet fünf Tabellen auf Neon Postgres; beim Build liest generateStaticParams die Produktliste aus der Datenbank und erzeugt pro Produkt eine statische Seite — eine Besucheranfrage erreicht die Datenbank nie. Der Schaufensterbereich mit 25 Routen hat ein einziges Ziel: ein Angebotsgespräch über WhatsApp oder Telefon zu starten. Der Preis: eine Korrektur im Panel erscheint erst nach dem nächsten Deployment.

Katalogseite und Verwaltungspanel für einen LED-Leuchtenhersteller aus İzmir. Bewusst ohne Warenkorb und Bezahlung: Die Seite soll interessierte Besucher in ein Verkaufsgespräch per WhatsApp oder Telefon bringen.

Verwendete Technologien

  • Next.js 16
  • TypeScript
  • Drizzle ORM
  • Neon Postgres
  • Vercel Blob
  • Zod
  • jose
  • Turnstile

Hauptmerkmale

  • Eine Umfangsentscheidung: kein Warenkorb, keine Zahlung, keine Konten, keine Preisanzeige
  • Produktseiten entstehen zur Build-Zeit aus Datenbanklesevorgängen
  • Produkte, Kundschaft, Verkäufe und Anfragen werden im Verwaltungspanel gepflegt
  • Ein Veröffentlichungsschalter, der über eine einzige Umgebungsvariable auf- und zugeht
  • Kontaktformular hinter Turnstile, serverseitig geprüft
  • Bilder liegen im Objektspeicher statt im Repository; die Maße werden beim Upload gelesen

Entwicklungszeit

3 Monate

Problem

Der Betrieb ist reine B2B-Fertigung: Ein Elektrobetrieb oder ein Auftragnehmer liefert die Maße, es wird gefertigt, und das Produkt geht an dessen eigene Kundschaft. Direktverkauf an Endverbraucher gibt es nicht. In einem solchen Geschäft ist die Standardantwort — "fügen wir der Unternehmensseite E-Commerce hinzu" — nicht nur unnötig, sondern schädlich: Sie lädt Bestand, Zahlung, Rückgabe und eine Preisliste auf einen Ablauf, der nichts verkauft, und beschädigt durch öffentliche Preise zugleich die Verhandlungsgrundlage. Das eigentliche Problem ist nicht der Verkauf, sondern Vertrauen zu schaffen und ein Gespräch zu beginnen. Der zweite Punkt war das Timing: Die Domain war vorhanden, der Inhalt nicht fertig — und die Seite musste dennoch etwas zeigen.

Nutzer

Drei Besuchertypen, ein Konversionsziel. Elektrobetriebe und Elektro-Auftragnehmer: bestellen wiederholt, suchen im Katalog Produkttyp und technische Angaben, den Preis holen sie ohnehin im Gespräch. Architektinnen und Projektverantwortliche: schauen weniger auf Standardprodukte als auf die Kapazität für Sonderanfertigung. Die Endkundschaft des Elektrobetriebs: sieht die Seite als Vertrauensreferenz — der Betrieb zeigt sie ihr. Im Panel gibt es genau eine Person: die Inhaberseite, die Produkte und eingehende Anfragen pflegt.

Meine Rolle

Einzelner Entwickler. Die Umfangsentscheidung selbst, Datenmodell, Katalog und Struktur der statischen Erzeugung, Verwaltungspanel, Anfrageablauf und Bereitstellung.

Architektur

Next.js 16 App Router, Neon Postgres und Drizzle. Die Anwendung ist zweigeteilt: die öffentliche Website und das Panel unter `/admin`. Produkt- und Kategorieseiten entstehen über `generateStaticParams` zur Build-Zeit, und die Parameterliste wird aus der Datenbank gelesen — die statische Ausgabe leitet sich also aus den Inhalten des Panels ab. In diesem Entwurf erreicht eine Besucheranfrage die Datenbank nie; nur das Kontaktformular schreibt auf den Server. Die Panel-Seite ist vollständig dynamisch: Produkt- und Variantendefinitionen, Kundendatensätze, Verkäufe und Verkaufspositionen, eingehende Anfragen. Bilder liegen im Objektspeicher; ihre Maße werden beim Upload gelesen und in den Datensatz geschrieben, sodass die Seitenverhältnisse beim Rendern bekannt sind. Die Sitzung wird in einem signierten Token geführt. Der Veröffentlichungsschalter ist eine einzige Umgebungsvariable: Ist er aktiv, reduziert sich die Anwendung auf einen Bildschirm, während der Rest der Struktur bestehen bleibt.

Zentrale Entscheidungen

  1. Warenkorb, Zahlung und Konten blieben außerhalb des Umfangs

    Die Begründung ist kaufmännisch, nicht technisch: In diesem Geschäft entsteht ein Auftrag über Maße und ein Gespräch, nicht über ein Produkt im Regal. Ein Warenkorb hätte Bestandsabgleich, Zahlungsanbindung, Rückgabeprozess und Preistransparenz auf einen Ablauf geladen, der zum Verkauf nichts beiträgt. Der engere Umfang hat die Architektur direkt vereinfacht: keine Sitzung auf Besucherseite, kein Warenkorbzustand, keine Bestandssperre.

    KompromissDie Website ist für sich kein Vertriebskanal; Konversion ist nur bis zum Klick messbar, alles danach passiert im WhatsApp-Gespräch und hinterlässt im System keine Spur. Ob aus einer Anfrage ein Auftrag wurde, lässt sich im Panel nicht ablesen und wird von Hand nachgehalten.

  2. Produktseiten werden aus der Datenbank gelesen und statisch erzeugt

    Der Katalog ändert sich selten, und der Besucherverkehr besteht ausschließlich aus Lesevorgängen. Seiten zur Build-Zeit zu erzeugen, beseitigt die Datenbankverbindung zur Laufzeit: Eine Besucheranfrage geht nie an die Datenbank, also sind Verbindungspooling, Kaltstarts und Abfragelatenz auf Besucherseite kein Thema.

    KompromissDie Aktualität des Katalogs hängt an der Bereitstellung: Ein im Panel korrigierter Tippfehler erreicht die Website erst mit dem nächsten Build. Das ist vertretbar, weil sich der Katalog selten ändert; bei einem Katalog, der sich mehrmals täglich ändert, wäre dieselbe Entscheidung falsch.

  3. Der Veröffentlichungsschalter ist eine einzige Umgebungsvariable

    Die Domain sollte nicht leer stehen, solange der Inhalt unfertig war. Statt eine eigene "Demnächst"-Seite aufzusetzen, kam ein Schalter in die Anwendung: Ist er aktiv, reduziert sich die Seite auf einen Bildschirm — Marke, kurze Beschreibung, direkter Kontakt — ist er aus, öffnet sich die vollständige Website. Es gibt kein zweites Projekt zu pflegen.

    KompromissDie Anwendung trägt zwei Erscheinungsbilder, und eines davon wird im Alltag nie geöffnet; ein defekter Demnächst-Modus fiele erst beim Einschalten auf. Da der Schalter eine clientseitig sichtbare Variable ist, ist er zudem keine Sicherheitsgrenze, sondern nur ein Anzeigeschalter.

  4. Bildmaße werden beim Upload gelesen und in den Datensatz geschrieben

    Bei einem Leuchtenprodukt leistet das Bild mehr als der Text, und die Seite besteht überwiegend aus Bildern. Weil die Maßangabe im Datensatz steht, ist das Seitenverhältnis beim Rendern bekannt, und vor dem Laden verschiebt sich nichts. Die Alternative — das Bild bei jedem Seitenbau zu vermessen — hätte die Build-Zeit direkt proportional zur Bildanzahl wachsen lassen.

    KompromissDie Maßangabe beruht auf einer einzigen Messung beim Upload; wird ein Bild im Objektspeicher extern ersetzt, bleibt das gespeicherte Maß still falsch. Einen Job, der neu misst, gibt es nicht.

Technologiewahl

Drizzle und Neon halten das vom Panel benötigte relationale Modell — Produkt, Kundschaft, Verkauf, Verkaufsposition — samt Migrationshistorie lesbar. Der Objektspeicher hält Bilder aus Repository und Datenbank heraus, ohne die Build-Ausgabe aufzublähen. Für Sitzungen genügte ein signiertes Token statt eines vollständigen Auth-Frameworks: Das Panel hat eine Nutzerklasse und braucht weder Registrierung noch Passwort-Reset noch Anbieter-Login — eine Abhängigkeit mitzuschleppen, die nicht genutzt wird, lohnt nicht. Turnstile schützt das Kontaktformular, weil es der einzige Konversionspunkt ist. Zod arbeitet sowohl bei Formulareingaben als auch bei der Prüfung der Umgebungsvariablen.

Sicherheit

Das Panel ist durch ein signiertes Sitzungstoken geschützt, und die Panel-Routen sind vollständig von der Website getrennt. Das Kontaktformular liegt hinter Turnstile, geprüft wird serverseitig — ein vom Client geliefertes Prüfergebnis wird für sich nicht akzeptiert. Der Schreibpfad ist Server Action → Zod → Drizzle; einen anderen Schreibpfad gibt es auf Besucherseite nicht. Kunden- und Verkaufsdatensätze sind nur im Panel sichtbar; keine öffentliche Seite liest diese Tabellen, und die statische Erzeugung berührt sie überhaupt nicht. Umgebungsvariablen werden mit Zod geprüft.

Performance

Für dieses Projekt liegt keine gespeicherte, mit Datum versehene Lighthouse-Ausgabe vor, deshalb steht hier kein Seitengeschwindigkeits-Score. Das strukturelle Maß lautet: Auf Besucherseite gibt es zur Laufzeit keine Datenbankabfrage, die Seiten werden als Build-Ergebnis ausgeliefert. Da die Seitenverhältnisse aus dem Datensatz gelesen werden, entsteht beim Laden kein Layout-Sprung. Eine Bundle-Analyse liegt als fertiges Kommando im Repository.

Ergebnisse

Aktive Entwicklung
2026-06 → 2026-08 · 63 Commits
TypeScript-Quelldateien
116
Schema
5 Tabellen · 5 Migrationen — Produkt, Kundschaft, Verkauf, Verkaufsposition, Kontaktanfrage
Routen
25 Seiten — Katalog, Sonderanfertigung, Projekte und Verwaltungspanel
Architekturgarantie
Eine Besucheranfrage erreicht die Datenbank nie; der gesamte Lesepfad ist Build-Ergebnis
Architekturgarantie
Bei aktivem Veröffentlichungsschalter reduziert sich die Seite auf einen Bildschirm; ein zweites Projekt wird nicht gepflegt

Was ich heute anders machen würde

In diesem Repository gibt es keine automatischen Tests, und am stärksten fehlt das an der Verbindung zwischen statischer Erzeugung und Panel: Nichts prüft, ob ein im Panel depubliziertes Produkt bis zum nächsten Build noch auf der Website steht. Heute würde ich zumindest die Funktion, die die Erzeugungsparameter liefert, rein machen und testen — genau das, was ich bei Ustura mit der Verfügbarkeitsberechnung getan habe, wo eine reine Funktion Sonderfälle mit einem einzigen Aufruf prüfbar machte. Der zweite Punkt ist der Umfang: Ich stehe dazu, Warenkorb und Zahlung wegzulassen, doch ob aus einer Anfrage ein Auftrag wurde, ist im System unsichtbar. Heute würde ich der Anfrage ein einfaches Statusfeld geben; das wäre kein CRM, sondern das Festhalten des Gesprächsergebnisses — die Statushistorie der Buchungen bei VAP Turizm leistet genau das.

Finden wir gemeinsam den richtigen Einstieg

Sagen Sie mir, was Sie bauen möchten; ich sage Ihnen vorab, wie lange es dauert und was der sinnvolle erste Schritt ist.