FHIR voor
de keten.
Dart voor
de ervaring.
Verplaats de appgerichte mapping naar een
centraal uitrolbare BFF. Geef Flutter precies
het model dat het scherm nodig heeft.
We willen hetzelfde.
De vraag is waar het draait.
“Het schone model bestaat al.
De bouw ervan is het probleem.”Appointment Details v3 · pagina 2
FHIR → adapter in Flutter → model
Bronregels in de backend. Mappingcode in een gedeelde client-adapter.
FHIR → Dart BFF → model → Flutter
Dezelfde heldere grens, met appgerichte mapping die centraal kan worden uitgerold.
Van FHIR-lijsten
naar één schermwaarde.
// Polikliniek · regel 86
return serviceCategory
?.firstOrNull
?.coding
?.firstOrNull
?.display
?.trim();
// Telefoonfallback · regel 65
fallbackPhoneNumber:
subagendaHCSResource
?.telecom?.firstOrNull?.value,Vaak een lijst met één item
FHIR-velden zoals telecom en coding zijn arrays. In onze praktijk bevatten ze vaak maar één waarde.
Dezelfde mapping in de BFF
Bij meerdere waarden pakken we hier de eerste. Diezelfde firstOrNull kan in de BFF blijven staan.
Flutter ontvangt het resultaat
Het DTO bevat de gekozen schermwaarde. Een compatibele mappingwijziging kan via een serverdeploy beschikbaar komen.
De app regisseert
een kleine integratieketen.
Daarna pas samenvoegen tot AppointmentDetails.
Deze regie kan op de server. De app vraagt om afspraakdetails; de BFF kent de benodigde bronnen en hun afhankelijkheden.
De winst zit in de uitrol.
toestellen, meerdere appversies
Een fix in de client-mapper gaat mee in een apprelease. Het bereik volgt de update-adoptie.
centraal beheerde service
Een compatibele mappingfix kan via een BFF-deploy beschikbaar komen bij de volgende fetch.
Het platform spreekt FHIR.
De BFF hoort bij mobile.
FHIR-dataplatform
HiX / Sanday
FHIR-API voor afnemers
Bronregels en autorisatie
platformcontract
Dart Frog BFF
FHIR ophalen en mappen
Appgericht DTO-contract
Bearer-token doorgeven
Dart-modellen
Flutter-app
Schermen en interactie
Lokalisatie en UI-state
Device- en offlinegedrag
Ruimte voor andere afnemers
Andere partijen kunnen dezelfde FHIR-API gebruiken, met een eigen adapter of BFF voor hun eigen appmodel.
De vraag rond funding
Het platformcontract blijft FHIR; de DTO-vertaling hoort bij de afnemer. Past deze grens bij de financieringsvoorwaarden?
De BFF geeft het Bearer-token door. .NET valideert het JWT en de patiënt-/node-toegang; 401/403 gaat terug naar de app.
Een dunne app.
Een duidelijke verdeling.
FHIR-backend
Backend-teamWat betekent de bron?
Normalisatie van HiX/Sanday, relaties, profielen en domeinregels. .NET verzorgt JWT-validatie, patiënt-/node-autorisatie en mutaties.
betekenis van afspraakstatus
Dart BFF
Mobile-teamWat heeft deze ervaring nodig?
Token doorgeven, toegestane brondata combineren en mappen. Appgerichte veldselectie, fallbacks en stabiele sectiestatussen.
één contactveld voor dit scherm
Flutter
Mobile-teamHoe ervaart de patiënt dit?
Weergave, lokalisatie, loading, interactie, lokale cache en device-permissies. De app blijft verantwoordelijk voor goede UX.
een afspraak in de kalender
Betere FHIR-queries helpen.
Ook achter een BFF.
Includes + veldselectie
_include volgt bestaande referenties. _elements selecteert in R4 top-level velden, niet de included resources.
&-include-elements=…De V3-uitbreiding kan ook includes minimaliseren, zodra de backend dit expliciete custom contract ondersteunt.
Meerdere servercalls
De BFF gebruikt de beschikbare endpoints. Onafhankelijke calls kunnen parallel; afhankelijke calls blijven geordend.
FHIR- en CMS-data samenstellen via de bestaande backend. Token-doorgifte, capabilities en paginering zijn bij uitwerking te toetsen.
446 bytes is niet
de businesscase.
De conclusie van V3 is terecht:
kies hier op onderhoudbaarheid.
Overgenomen uit de aangeleverde PDF; niet opnieuw gemeten.
extra body-overdracht voor custom FHIR versus DTO bij 1 Mbit/s.
Niet gemeten in deze PoC:
de volledige appflow, productie-I/O, een extra BFF-hop en Dart op een toestel.
De CPU-metingen zijn Node-hostmetingen. Ze bewijzen geen mobiele snelheidswinst. Een praktijktest zou de echte keten moeten meten, inclusief de extra hop.
Waarom een Dart-server
naast onze .NET-backend?
.NET beheert FHIR en domeinregels. De Dart BFF geeft het mobile-team een eigen appcontract.
De kennis is al in het team
Mobile-developers kennen Dart. Dezelfde taal voor app en BFF verlaagt de instap en vermindert overdracht voor appgerichte wijzigingen.
Exact hetzelfde DTO-package
Server en app delen velden, nullability en JSON-codecs. Eén Dart-definitie, direct aan beide kanten te importeren.
Mapping en tests hergebruiken
Bestaande pure-Dart-logica en testfixtures kunnen na ontkoppeling meeverhuizen. De bronkennis blijft bij dezelfde developers.
@JsonSerializable()
class AppointmentDetailsDto {
// Constructor en codegen weggelaten
final String appointmentId;
final String? polyclinic;
final String? phoneNumber;
}Dart Frog maakt de HTTP-laag concreet: routes, middleware en dependency injection. De reden voor Dart is teamkennis en codehergebruik.
Samen ontwikkelen.
Onafhankelijk uitrollen.
├── app/ Flutter ├── server/ Dart Frog │ └── routes/v1/ │ └── appointment/ └── packages/ └── contracts/ ├── lib/ Gedeelde DTO’s └── test/ Contracttests
Eén wijziging in context
DTO, mapper en consument in dezelfde pull request beoordelen.
Een smalle gedeelde kern
Contracten zonder Flutter-, FHIR- of serverdependencies. UI-state en bronadapters blijven in hun eigen laag.
Twee releasepaden
App naar de stores; server naar het platform. CI controleert ook eerder uitgeleverde contracten.
Eén repository.
Meerdere versies in het wild.
/v1/…/details
Een nieuwe mapper, dezelfde
afgesproken veldbetekenis.
Daarna de app die nieuwe optionele velden gebruikt. Oudere apps blijven werken.
Compatibel toevoegen
Optionele velden en defaults. Onbekende enumwaarden expliciet afhandelen.
Breuken versioneren
Een andere betekenis of vereist veld vraagt migratie, eventueel een nieuw endpoint.
Oude clients testen
Golden JSON-fixtures én oude codecs. Ondersteuningsvenster baseren op appadoptie.
Eén foutcontract voor de app.
Bronkennis op de server.
De app kan vandaag al deelresultaten tonen. De BFF centraliseert de vertaling van bronfouten.
Verschillende oorzaken
Timeoutbij ophalen videolinkHTTP 503van de achterliggende APIDe BFF bepaalt: tijdelijk niet beschikbaar. Een geslaagde lookup zonder link is juist absent.
Eén appgerichte foutcode
{
"video": {
"status": "unavailable",
"errorCode": "VIDEO_UNAVAILABLE",
"retryable": true
}
}De overige afspraakdetails worden gewoon meegeleverd.
Reageren op dat contract
- Behoud de afspraakdetails.
- Toon een eigen vertaalde melding voor de videolink.
- Bied opnieuw laden aan als
retryablewaar is.
De app blijft ook netwerkfouten naar de BFF zelf afhandelen.
Nieuwe bronfout? Pas de vertaling centraal aan. Zolang het foutcontract gelijk blijft, hebben ondersteunde apps daarvoor geen nieuwe release nodig.
De argumenten staan.
De grens kan een stap opschuiven.
“Het vlakke model bestaat al.”p. 2 en 11
Precies. Behoud het repositorycontract en vervang de implementatie erachter. De winst zit in het opbouwen en uitrollen.
“De prestatiewinst is marginaal.”p. 23
Eens, voor deze fixture. Maak wijzigbaarheid, foutdiagnose en release-afhankelijkheid de hoofdcriteria.
“Een SDK bundelt de FHIR-kennis.”p. 12 en 17
Dat helpt. Als de mapper in de app draait, blijft een mapperfix een apprelease. Dezelfde helpers kunnen ook in de BFF draaien.
“Een extra service kost beheer.”p. 17
Dat is de echte tegenprestatie. Vergelijk die met clientcompatibiliteit, custom querycontracten en de tijd om fixes uit te rollen.
Een service erbij
moet zijn plek verdienen.
Een extra hop
Meet end-to-end p50/p95. Draai dicht bij de backend, begrens fan-out en stel per bron timeouts in.
Een extra storingspunt
Healthchecks, traces, capaciteitsgrenzen en rollback. Mobile beheert de service samen met platform.
Toegang blijft in .NET
BFF geeft Bearer-token door. .NET valideert JWT en patiënt-/node-toegang. Een 401/403 gaat terug naar de app.
Een extra contract
Onderhoud oudere clients. Begin zonder persistente patiëntcache; log metadata en foutcodes, geen payloads of tokens.
Dart-kennis verlaagt de instap, niet de operationele verantwoordelijkheid. Benoem een service-eigenaar en maak beheerkosten onderdeel van het besluit.
Een pilot kan de afweging
concreet maken.
Als we deze richting kansrijk vinden, biedt Appointment Details een afgebakende casus om de meerwaarde te toetsen.
Afbakenen
Kies samen representatieve afspraken en bronregels. Bepaal welke vragen een proef moet beantwoorden.
MOGELIJKE TOETS · SCOPEUitproberen
Eén gedeeld DTO en één BFF-route achter de bestaande repositorygrens, met beschikbare endpoints.
MOGELIJKE TOETS · HAALBAARHEIDVergelijken
Vergelijk schermuitkomsten, oudere clients en de hele keten. Probeer een mappingfix zonder apprelease.
MOGELIJKE TOETS · MEERWAARDEAfwegen
Leg onderhoudswinst naast beheer en kosten. Bepaal samen welk vervolg de uitkomsten rechtvaardigen.
MOGELIJKE TOETS · VERVOLGHier moet de BFF
het verschil maken.
Gelijke betekenis
Dezelfde bedoelde schermvelden, met expliciete bronprioriteiten. Toets dit op representatieve afspraken en ontbrekende data.
BETROUWBAARHEID BEHOUDENEen fix zonder apprelease
Een compatibele mappingfix via een serverdeploy. Maak zichtbaar wat dit oplevert in doorlooptijd, bereik en rollback.
SNELLER KUNNEN CORRIGERENEen acceptabele keten
Vergelijk calls, gzip-bytes, foutpercentage en p50/p95 op dezelfde toestellen en scenario’s, inclusief BFF-hop.
DE PATIËNTERVARING BEWAKENBeheer dat past
Weeg de verwachte onderhoudswinst af tegen hosting, observability, incidentrespons en het eigenaarschap van de service.
BATEN EN KOSTEN SAMEN AFWEGENGeef de mapping
een eigen
releaseknop.
Willen we appgerichte mapping
centraal beheren, met het mobile-team
als eigenaar van het contract?
Als we die meerwaarde herkennen,
kunnen we samen bepalen of een
kleine pilot de juiste vervolgstap is.
De concrete aanknopingspunten.
lib/repositories/appointments/appointments_repository/models/appointment_details.dart:7–70
Polikliniek, instructie, tijdvenster, resources en een telefoongetter met locatieprioriteit.
lib/repositories/appointments/api_appointments_repository/api_appointments_repository.dart:439–595
Twee parallelle ophaalfasen, conditionele HealthcareService-fallbacks en de mapping naar AppointmentDetails.
lib/repositories/appointments/api_appointments_repository/extensions.dart:33–242
Participant-selectie op display, eerste coding/telecom, sentinel-tekst, tijdvensterprioriteit en CMS-requests.
lib/features/appointments_details/bloc/appointment_details_bloc.dart:47–125, 280–347
Details, check-in en samenvatting worden gestart; locatie volgt met een afzonderlijke laad- en foutstatus.
lib/services/appointments/models/responses/appointment_location_route_response.dart:14–36
De parser ondersteunt tijdelijk zowel een object als een array-wrapped object uit verschillende backendversies.
Voortbouwen op V3.
| V3-pagina | Wat het voorstel laat zien | Vertaling naar dit voorstel |
|---|---|---|
| 2–4, 11–15 | Een vlak model, één mappinggrens en expliciete selectie zijn wenselijk. | Behoud de modelgrens; draai de appgerichte mapper op de server. |
| 5–10 | Includes vragen echte relaties. R4-veldselectie is beperkt. Custom include-selectie is nog te bouwen. | Gebruik beschikbare calls; verbeter upstream-queries zonder het appcontract te wijzigen. |
| 16–17 | De doorsnede is begrensd. Een BFF heeft extra service- en contractkosten. | Toets bij uitwerking de afgesproken read-scope en neem operationeel beheer mee. |
| 18–23 | Synthetische payloads; CPU op Node-hosts. Geen Dart-toestel- of productie-I/O-metingen. | Gebruik de getallen als context. Meet bij een praktijktest de echte keten, ook tegenover de SDK-route. |
| 24–25 | Klein beginnen, repositorycontract behouden en gefaseerd invoeren. | Een mogelijke aanpak als we besluiten deze richting te beproeven. |
De afweging gaat over de locatie en het eigenaarschap van de mapping. FHIR-normalisatie, heldere contracten en goede tests helpen beide routes.
Een DTO dat de bedoeling vertelt.
/v1/nodes/{nodeId}/appointments/{id}/detailsVOORGESTELD{
"appointmentId": "demo-42",
"nodeId": "demo-node",
"polyclinic": "Cardiologie",
"phoneNumber": null,
"importantInformation": "Neem uw overzicht mee.",
"timeFrame": "exact",
"video": {
"status": "unavailable",
"url": null,
"errorCode": "VIDEO_UNAVAILABLE",
"retryable": true
},
"education": {
"status": "ready",
"items": []
}
}Een schets, geen afgerond API.
Bij verdere uitwerking leggen we velden, typen, foutcodes en secties vast. Ook tijdzone-, null- en enumgedrag hoort bij het contract.
JWT-validatie blijft in .NET.
De BFF geeft de Authorization-header door bij elke patiëntgebonden backendcall. .NET controleert token en patiënt-/node-toegang; 401/403 wordt doorgegeven.
Model en weergave blijven apart.
Het gedeelde DTO is het transportcontract. De app kan dit dun omzetten naar het bestaande domeinmodel en eigen UI-state.
Onderbouwd waar het kan.
Meetbaar waar het moet.
Patient App
Lokale broncode, HEAD b7db10c73, gelezen op 9 november 2026. Paden en regels staan in bijlage A.
Appointment Details v3
Aangeleverde PDF-inhoud, 25 pagina’s. Referentiebranch volgens het document: develop a557ea3.
Technische documentatie
60.000 toestellen is input van het team, geen vastgesteld aantal actieve gebruikers of gelijktijdige requests.
212 keer firstOrNull in 79 bestanden is een teksttelling in lib/**/*.dart, exclusief *.g.dart, *.freezed.dart en *.mocks.dart. Dit is geen telling van fouten.
Benchmarkgetallen zijn overgenomen uit V3. Er is geen live backendbenchmark of Dart Frog-prototype uitgevoerd voor dit deck.
De architectuur en vervolgstappen zijn voorstellen. Een eventuele pilot kan onderbouwen of de winst opweegt tegen de extra service.