Ein Marktplatz, kein Streaming-Dienst. Der Unterschied zählt architektonisch.
Der Betreiber baute keinen Streaming-Dienst, bei dem Künstler für Reichweite hochladen und der Umsatz später als Werbeanteil eintrifft. Künstler besitzen ihre Inhalte. Hörer bezahlen dafür. Die Plattform ist ein Marktplatz: Produktlistings, Warenkorb, Checkout, Bestellverlauf, Verkaufsberichte. Das Geschäftsmodell lebt in diesem Ablauf.
Diese Unterscheidung formt die Architektur um. Das schwierigste Problem eines Streaming-Dienstes ist der Ingest-Durchsatz und die Wiedergabelatenz. Das schwierigste Problem eines Marktplatzes ist die Commerce-Oberfläche: gleichzeitige Warenkorboperationen, Bestellkonsistenz, ein Checkout, der keinen Kauf verliert, wenn ein Hintergrund-Worker langsam ist. Wenn man die falsch macht, verliert man echte Transaktionen von Künstlern, die einer neuen Plattform ohnehin skeptisch gegenüberstehen.
Der Betreiber hatte außerdem einen Plan für einen Mobile-Client — iOS und Android, später gebaut — und wollte, dass die API-Ebene dafür bereit war. Nicht nachgerüstet. Von Anfang an bereit, mit versionierten, DTO-getriebenen Endpunkten und einer klaren Admin-/Mobile-Trennung. Die Mobile-App ging im 2022er-Fenster nicht live. Die API-Ebene tat es.
Das Briefing: eine vollständige Commerce-Oberfläche für einen künstlereigenen Katalog, ein asynchroner Kern, der den Checkout nicht durch Hintergrundarbeit blockiert, und eine API-Ebene, die nicht neu durchdacht werden muss, wenn der Mobile-Client ankommt.
Zwei Ebenen, ein Message-Bus und drei Speicher mit klar getrennten Aufgaben.
Das System teilte sich vom ersten Tag an in zwei Symfony-Anwendungen. Das Monorepo — die Admin- und Web-UI — übernahm die Verwaltung von Künstlerprofilen, Produktlistings, Artwork-Uploads und das Back-Office des Betreibers. Die API-Ebene wurde separat gebaut, als DTO-versionierter REST-Dienst mit den Route-Namensräumen /Mobile/v1/ und /Admin/v1/, 96 Mobile-Endpunkte und 130 Admin-Endpunkte, dokumentiert und bereit für den Mobile-Client, wann immer er ankäme.
Warenkorb- und Bestellabläufe laufen über Symfony Messenger, nicht über synchrone Schreibvorgänge. AddToCartController versendet eine Nachricht; der Handler verarbeitet die Warenkorbmutation asynchron. Bestelldatensätze — Order und ProductOrder, mit Menge und Gesamtkosten pro Zeile erfasst — folgen demselben Muster. Der Checkout blockiert nicht auf Telemetrie-Schreibvorgängen, Artwork-Verarbeitung oder irgendetwas anderem, das auf dem Bus läuft. Die operative Datenbank bleibt schnell, weil das Schreib-Fan-out gesteuert wird.
Drei Speicher, jeder mit einer einzigen Verantwortung. PostgreSQL ist der kanonische Status: 25 Entitäten, über 40 Indizes auf den heißen Tabellen — Nutzer, Produkte, Bestellungen, Warenkorbartikel, Genres, Tags, Künstler-zu-Produkt-Beziehungen. Redis betreibt sowohl den Messenger-Queue-Broker als auch die Cache-Schicht für heiße Lesezugriffe. InfluxDB hält die Nutzeraktions-Telemetrie. Hochfrequente Verhaltensereignisse berühren nie die operative Datenbank.
Künstlerprofile und Produktbeschreibungen — Albumtitel, Tracknamen, Genre-Bezeichnungen, News-Beiträge — sind auf Schema-Ebene übersetzbar über KnpLabs DoctrineBehaviors. Einen Sprachraum hinzuzufügen ist eine Datenmigration, keine Code-Änderung. Die Web-UI nutzte Plyr für Audio- und Videowiedergabe; CropperJS übernahm das Zuschneiden und Hochladen von Artwork inline.
- F · 01Warenkorb und Checkout über Messenger
- Warenkorbmutationen und Bestellverarbeitung laufen über Symfony Messenger, nicht über synchrone Schreibvorgänge. Der Checkout bestätigt sofort; der Bus übernimmt das Schreib-Fan-out.
- F · 02Zwei-Ebenen-Architektur
- Monorepo (Admin- und Web-UI) und ein separater DTO-versionierter API-Dienst mit den Namensräumen /Mobile/v1/ und /Admin/v1/ — 96 Mobile-Endpunkte und 130 Admin-Endpunkte — gebaut, bevor der Mobile-Client existierte.
- F · 03Drei-Speicher-Trennung
- PostgreSQL für den kanonischen Status (25 Entitäten, 40+ Indizes), Redis für Queue-Broker und Cache, InfluxDB für Nutzeraktions-Telemetrie. Jeder Speicher hat eine Aufgabe.
- F · 04Übersetzbare Inhalte auf Schema-Ebene
- KnpLabs DoctrineBehaviors auf Produktbeschreibungen, Künstlerprofilen, Genre-Bezeichnungen und News. Einen Sprachraum hinzuzufügen ist eine Migration, keine Code-Änderung.
- F · 05InfluxDB-Telemetrie-Pipeline
- Nutzeraktions-Ereignisse werden über Messenger-Handler an InfluxDB geleitet. Die Pipeline ist für vollständige Wiedergabe-, Scrub- und Skip-Telemetrie konzipiert, ohne die operative Datenbank zu berühren.
- F · 06Asynchrone Bestellverarbeitung
- Die Entitäten Order und ProductOrder erfassen Käufe mit Menge und Kosten pro Zeile. Bestellmutationen fließen über den Message-Bus, sodass Commerce-Operationen einander nicht behindern.
Der Warenkorb läuft über den Bus. Die API existiert vor der App, die sie aufrufen wird.
Die Entscheidung, Warenkorbmutationen über Symfony Messenger statt über synchrone Schreibvorgänge zu leiten, ging nicht um Skalierung. Sie ging um Korrektheit. Warenkorboperationen in einem Marktplatz umfassen Bestandsprüfungen, Produktstatus-Validierung und die Behandlung gleichzeitiger Sessions. Diese auf den Message-Bus zu legen entkoppelt die nutzerseitige Bestätigung vom Schreib-Fan-out. Der Hörer erhält eine Antwort; die Plattform holt auf. Die operative Datenbank rennt nie gegen die Commerce-Oberfläche.
Dasselbe Prinzip zieht sich bis zur Wiedergabe durch. PlayFileHandler und PlayedFileService entkoppeln Wiedergabeereignisse von der operativen Datenbank. Nutzeraktions-Telemetrie schreibt über den Message-Bus in InfluxDB — insgesamt 21 Handler über die API-Ebene. Die InfluxDB-Pipeline ist für vollständige Wiedergabe-, Scrub- und Skip-Telemetrie konzipiert; das Verdrahten dieser zusätzlichen Ereignisse ist der nächste Schritt, den der Betreiber tun kann, ohne irgendetwas neu zu architektonisieren.
Drei Speicher sind die Antwort, wenn jeder Speicher seinen Platz verdient, indem er die Aufgabe macht, die er am besten kann — und nichts sonst.
Die API-Ebene war für 2022 bewusst überdimensioniert. /Mobile/v1/ existierte mit 96 Endpunkten, bevor eine einzige Zeile Mobile-App-Code geschrieben war. Der Mobile-Client ging im 2022er-Fenster nicht live, aber der Betreiber erbte einen API-Dienst, der bereits versioniert, dokumentiert und von der Admin-Oberfläche getrennt war. Die Kosten, es später zu tun — mit einem Live-Produkt, echten Nutzerdaten und einem abgedrifteten Schema — sind nicht vergleichbar mit den Kosten, es einmal am Anfang zu tun.
Acht Monate. Drei Repos. Eine Commerce-Oberfläche, die der Betreiber erweitern kann.
Acht Monate aktive Entwicklung. 494 Commits über drei Repositories — das Monorepo, die API-Ebene und eine minimale HTML/Gulp-Landingsite. Das System ging mit einer vollständigen Künstler-zu-Hörer-Commerce-Oberfläche live: Produktlistings, Warenkorb, Checkout, Bestellverlauf und Verkaufsberichte. Die asynchrone Architektur — Messenger-Bus, Redis-Broker, InfluxDB-Telemetrie-Pipeline — war ab dem ersten öffentlichen Release in Produktion.
Der Mobile-Client war die eine geplante Oberfläche, die im 2022er-Fenster nicht live ging. Die API-Ebene, die gebaut wurde, um ihn zu empfangen, ist intakt. Der /Mobile/v1/-Namensraum, die DTO-Verträge, das Auth-Handling — all das wartet auf den Client, nicht umgekehrt.
Die Architektur, die der Betreiber erbte, hat drei klare Grenzen: Postgres für den Status, Redis für Queue und Cache, InfluxDB für Zeitreihen. Jede kann unabhängig ausfallen, aktualisiert oder skaliert werden. Der nächste Ingenieur braucht keine sechsstündige Einarbeitung. Das interessante Problem — die asynchrone Commerce-Oberfläche — ist gelöst. Alles danach ist Produktarbeit.
Wir haben für den Mobile-Client gebaut, bevor er existierte. Wenn er live geht, wird die Plattform es nicht bemerken.
