Projectoverzicht
Jepta is een hyperlokaal sociaal netwerk dat om je woonplek is gebouwd. In plaats van een wereldwijde volgersgrafiek ordent het mensen op nabijheid: chats die aan een straatadres of een gebouw hangen, groepschats voor de mensen die dat delen, en kanalen van de bakker, de werkplaats of de vereniging een paar honderd meter verderop. Alles in de app — de chats die je krijgt aangeboden, de kanalen in de feed, de berichten die je als eerste ziet — is gerangschikt op afstand tot waar je bent.
Netgineers GmbH kwam bij ons met het product gedefinieerd en de backend onderweg, en had de mobiele kant nodig: één Flutter-codebase voor iOS en Android, voor een product met een ongewoon breed oppervlak voor een eerste release.

Onboarding

Locatietoestemming

Chatlijst

Kanaalfeed

Kanaalinformatie

Kanaalchat

Nieuw bericht
De uitdaging
Twee dingen maakten dit meer dan een standaardklus.
De omvang van het schermoppervlak
Jepta is niet één functie met instellingen eromheen. Directe chats, groepschats, adreschats, een kanaalfeed, kanaalprofielen met openingstijden en fotogalerijen, gesprekken van kanaal naar gebruiker, een berichtopsteller met reactie-instellingen per bericht, een activiteitentab, een profieltab, zoeken, contacten toevoegen via QR-code, locatie- en toestemmingsstromen — allemaal in de eerste release, binnen zes maanden. Bij dat aantal houden schermen op zelfstandige eenheden werk te zijn: zonder gedeeld skelet sleept elk nieuw scherm zijn eigen navigatiegrillen, zijn eigen laad- en lege toestanden en zijn eigen kopie van dezelfde lijst mee.
Overal realtime
Chat is de voor de hand liggende plek waar WebSocket-verbindingen opduiken, maar in Jepta blijven ze daar niet toe beperkt. Een kanaalbericht dat binnenkomt, een reactieteller die beweegt, een ongelezen-badge op de chattab, een bericht dat als gelezen wordt gemarkeerd — dezelfde live verbinding drijft ze allemaal aan, ook op schermen waar de gebruiker op dat moment niet naar kijkt. Dat per scherm afhandelen had een verbinding per scherm betekend, en staat die het zodra de gebruiker van tab wisselt met zichzelf oneens is.
Onze aanpak
We behandelden beide problemen als één: bouw eerst de gedeelde delen, en laat schermen daarna dun zijn.
Eén realtimelaag, veel afnemers
De WebSocket-verbinding leeft onder de UI als één client die zijn eigen levenscyclus bezit — verbinden, authenticeren, hartslag, opnieuw verbinden met uitstel, opnieuw abonneren. Schermen openen geen sockets; ze abonneren zich op getypeerde gebeurtenisstromen en krijgen updates aangereikt. Berichten die worden verstuurd terwijl de verbinding weg is, komen in een wachtrij en worden bij herverbinding weggeschreven in plaats van verloren te gaan, en de afleverstatus (verstuurd, afgeleverd, gelezen) wordt bijgehouden als onderdeel van het berichtmodel in plaats van afgeleid uit wat toevallig binnenkwam. Doordat de laag gedeeld is, zijn een bericht dat landt in een chat die de gebruiker openheeft en een ongelezen-badge die oploopt op een tab waar hij niet naar kijkt dezelfde gebeurtenis, één keer afgehandeld.
Een schermskelet in plaats van scherm-voor-scherm handwerk
Bij zoveel oppervlakken zat de winst in ze uniform maken: één navigatiegrafiek met getypeerde routes, één State management-patroon dat in elke functie op dezelfde manier is toegepast, en een gedeelde set lijst-, laad-, lege en foutschermen. Nieuwe schermen waren grotendeels samenstelling — en dat maakte het volume behapbaar binnen de planning, en hield de app samenhangend in plaats van dat ze eruitzag als twintig schermen van verschillende handen.
Locatie als volwaardige invoer
Nabijheid is geen filter dat op de feed is geschroefd, het is het ordenende principe van het product, dus de locatielaag moest betrouwbaar zijn: toestemmingsstromen die netjes teruggrijpen als een gebruiker nee zegt, gecachte coördinaten zodat de feed nooit leeg is terwijl er een positiebepaling loopt, en afstand getoond dicht bij waar de content staat ("5 km verderop" in een kanaalkop), zodat de rangschikking leesbaar is in plaats van raadselachtig.
Resultaat
Jepta verscheen binnen het venster van zes maanden op iOS en Android vanuit één Flutter-codebase, met de volledige functieset intact — chats, kanalen, berichten, reacties en de locatiebewuste feed in de eerste release in plaats van verdeeld over meerdere.
De architectuur is het deel dat de deadline overleefde. Doordat de realtimelaag, de navigatiegrafiek en het statepatroon één keer zijn gebouwd en hergebruikt, bleef een scherm toevoegen na de lancering een kleine wijziging in plaats van een nieuwe integratie met de socket, de router en de cache. Voor een product waarvan de roadmap "meer oppervlakken" luidt, is dat het verschil dat zich opstapelt.
Zes maanden voor een app van deze omvang was het deel dat me zorgen baarde. Jepta is buurtchats, ondernemerskanalen, berichten, reacties en een feed die zich herordent rond waar je toevallig staat — een lange lijst schermen, een vaste datum, en de reële verwachting dat de helft naar een tweede release zou opschuiven.
Nerdy Production bouwde eerst de gedeelde fundamenten — één realtimelaag, één navigatiemodel — en daarna was elk nieuw scherm goedkoop. We lanceerden op iOS en Android met de volledige functieset, chat is vanaf dag één betrouwbaar geweest, en de app sindsdien uitbreiden is een klein klusje in plaats van een project. We kregen het product dat we hadden gespecificeerd, op de datum die we hadden gespecificeerd.

Veelgestelde vragen
Jepta is gebouwd als onderdeel van onze dienst Flutter-appontwikkeling — dezelfde praktijk die achter ons overige realtime Flutter-werk zit.
