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

Onboarding

Locatietoestemming

Locatietoestemming

Chatlijst

Chatlijst

Kanaalfeed

Kanaalfeed

Kanaalinformatie

Kanaalinformatie

Kanaalchat

Kanaalchat

Nieuw bericht

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 -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 -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.

Evgeny Syrtsov
Evgeny Syrtsov
CEO, Netgineers GmbH

Veelgestelde vragen

Jepta is een hyperlokale communicatieapp voor Duitse buurten. Het ordent mensen op nabijheid in plaats van via een wereldwijde volgersgrafiek: chats die aan een straatadres of een gebouw hangen, groepschats voor de mensen die er een delen, en kanalen van lokale ondernemers zoals een bakker of een werkplaats. De chats, kanalen en berichten die een gebruiker te zien krijgt, zijn gerangschikt op afstand tot waar hij is.
Bouw eerst de gedeelde delen en houd de schermen dun. Bij Jepta betekende dat één navigatiegrafiek met getypeerde routes, één patroon voor statebeheer dat in elke functie op dezelfde manier is toegepast, en een gedeelde set lijst-, laad-, lege en foutschermen. Nieuwe schermen worden dan grotendeels samenstelling in plaats van nieuwe integraties, en dat houdt het volume behapbaar binnen een deadline en voorkomt dat de app eruitziet als twintig schermen van verschillende handen.
Zet één verbinding onder de UI als één client die zijn eigen levenscyclus bezit: verbinden, authenticeren, hartslag, opnieuw verbinden met uitstel, opnieuw abonneren. Schermen openen geen eigen sockets; ze abonneren zich op getypeerde gebeurtenisstromen en krijgen updates aangereikt. Een bericht dat in een open chat binnenkomt en een ongelezen-badge die oploopt op een tab waar niemand naar kijkt, zijn dan dezelfde gebeurtenis die één keer wordt afgehandeld, in plaats van één verbinding per scherm en staat die het met zichzelf oneens is.
Die komen in een wachtrij en worden bij herverbinding weggeschreven in plaats van verloren te gaan. De afleverstatus — verstuurd, afgeleverd, gelezen — wordt bijgehouden als onderdeel van het berichtmodel in plaats van afgeleid uit wat toevallig binnenkwam, zodat de interface de werkelijke status van een bericht toont en geen gok daarover.
Jepta verscheen in zes maanden op iOS en Android vanuit één Flutter-codebase, met chats, kanalen, berichten, reacties en de locatiebewuste feed allemaal in de eerste release in plaats van verdeeld over meerdere. De planning hield stand doordat de realtimelaag, de navigatiegrafiek en het statepatroon één keer zijn gebouwd en over elk scherm zijn hergebruikt.
Ja, en bij Jepta is nabijheid het ordenende principe in plaats van een filter dat op de feed wordt toegepast. Dat stelt echte eisen aan de locatielaag: toestemmingsstromen die netjes teruggrijpen als een gebruiker weigert, gecachte coördinaten zodat de feed nooit leeg is terwijl er een positiebepaling loopt, en de afstand getoond naast de content waarop ze slaat, zodat de rangschikking leesbaar is in plaats van raadselachtig.

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