Bon Dossier werd niet ingewikkeld door een complexe gebruikersinterface. De uitdaging zat in de werkelijkheid, die zich niet netjes in gestructureerde gegevens laat vangen. Bonnen zijn smal, gebogen, vervaagd of gevouwen, worden bij slecht licht gefotografeerd en zijn in allerlei talen gedrukt. Ze bevatten btw-overzichten, loyaliteitsinformatie, betaalterminalgegevens, kortingen, terugbetalingen, nummers die op barcodes lijken en totalen die soms over meerdere regels zijn verdeeld. Een eenvoudige OCR-demonstratie kan tekst herkennen. Een app voor dagelijks gebruik moet bepalen welke tekst de juiste gegevens weergeeft.
Het project groeide daarom door drie praktische versies heen. Dit waren geen louter commerciële releases, maar ontwikkelfasen: eerst de basis, daarna de herkenningssoftware en ten slotte het platform voor productie. Elke versie loste een ander soort probleem op en maakte een volgende laag aan complexiteit zichtbaar.
Versie 1
De basis
Een Swift-package, domeinmodel, parser, exportlaag en SwiftUI-interface maakten bongegevens testbaar voordat de camera- en synchronisatielagen bestonden.
Versie 2
De herkenningssoftware
Vision OCR, Core ML-classificatiemodellen, lay-outzones op basis van YOLO, het samenstellen van artikelregels, validatiecontroles en lokaal leren vervingen de eenvoudige eerste parser.
Versie 3
Het productieplatform
Core Data, CloudKit, back-ups, deelextensies, exports, archiefmetadata, macOS, controles en trainingsapps maakten van de herkenningssoftware een product.
De eerste randvoorwaarde: privé, lokaal en controleerbaar
De belangrijkste architectuurkeuze kwam vóór de scanner: ReceiptVault moest bruikbaar zijn zonder persoonlijke financiële documenten naar een server te uploaden. Daarmee viel de eenvoudige route af om afbeeldingen naar een online OCR- of taalmodeldienst te sturen. De productie-app zou vertrouwen op Apple Vision, VisionKit, Core ML, Swift-parsers en vaste validatieregels, volledig lokaal uitgevoerd. iCloud kon het privéarchief van de gebruiker synchroniseren, maar er zou geen Bon Dossier-backend komen.
Die privacykeuze bepaalde alle latere processen. Trainingsgegevens werden als lokaal projectmateriaal behandeld. Correcties uit controles werden als lokale voorbeelden bewaard. Kandidaatmodellen werden pas in gebruik genomen na rapportages en regressiecontroles. Zelfs de laag met Apple Foundation Models werd ontworpen als een optionele lokale controlestap, met strikte JSON-schemavalidatie en terugval op het meegeleverde bonmodel.
Versie 1: eerst de basis, daarna de camera
De eerste versie was bewust weinig spectaculair. We begonnen niet met een camerascherm in de hoop dat de rest vanzelf zou volgen, maar met een testbaar Swift-package: ReceiptVaultCore. Dat bevatte het domeinmodel, de bonparser, categorisering, duplicaatdetectie, exportcode en later ook het grootste deel van de herkennings- en opslaglogica. Het eerste doel was eenvoudig: een uitvoerbaar en testbaar datamodel voor bonnen, zonder afhankelijkheid van de simulator, cameratoestemming of live OCR.
Het kernmodel groeide rond ParsedReceipt: verkoper, adres, aankoopdatum, valuta, totaal, subtotaal, belasting, betaalwijze, bonnummer, OCR-tekst, notities, artikelregels, scanbestanden en controlestatus. Daarna volgden TSV- en Excel-export, groepering van duplicaten, categorieherkenning, herinneringen voor termijnen en kwaliteitsvalidatie. De interface kon nu met bonnen als volwaardige records werken, in plaats van met losse OCR-teksten.
De SwiftUI-interface volgde hetzelfde principe. Op iPhone kwamen tabbladen voor Archief, Scannen, Inzichten en Instellingen. De iPad kreeg een zijbalk met gesplitste navigatie. We bouwden schermen met systeemcomponenten zoals TabView, NavigationStack, NavigationSplitView, List en Section, in plaats van een eigen interfaceframework. Zo bleef de app aansluiten op het platform, toegankelijk en toetsbaar.
De eerste belangrijke proceskeuze: behandel de app als een product van kleine, controleerbare lagen. Tests van het domeinmodel gingen vooraf aan camera-integratie. Het parsergedrag werd vastgelegd met vaste testvoorbeelden. Scripts genereerden en beschermden het Xcode-project. Bouw- en testcommando’s werden vastgelegd, zodat het project reproduceerbaar was en niet afhankelijk van handmatig bijsturen in Xcode.
Hulpmiddelen in versie 1
- Swift 6 en SwiftPM voor de gedeelde kernmodule.
- Generatie van het Xcode-project met Ruby-scripts, inclusief beveiligingen rond het synchroniseren van bronbestanden.
- XCTest voor regressiecontroles van de parser, exports, het archief en de broncode.
- Bouwscripts voor controle op iPhone- en iPad-simulators.
- Vaste bonafbeeldingen en gereconstrueerde teksten om parserwijzigingen meetbaar te maken.
- Een bijgehouden implementatieoverzicht met afgerond werk, lopend werk en blokkades.
Een vroege technische hindernis was het uiteenlopen van ontwikkelgereedschap: de geïnstalleerde Swift-versie op de commandoregel sloot niet altijd aan op de Xcode SDK. De oplossing was expliciet en herhaalbaar: xcrun swift test gebruiken en packagecommando’s uitvoeren met de door Xcode geselecteerde toolchain. Dat klinkt alledaags, maar voorkwam dat omgevingsfouten ten onrechte als fouten in de app werden gezien.
Versie 2: van OCR-tekst naar begrip van bonnen
De tweede versie begon toen duidelijk werd dat OCR alleen geen product oplevert. Apple Vision kan veel regels van een bon lezen, maar weet niet welk bedrag het eindtotaal is, welke regel de btw-grondslag bevat, welk bedrag een korting is, welke datum van de betaalterminal komt of waar de artikelregels beginnen. Bon Dossier had software nodig die de betekenis van een bon kon herkennen.
Het scanproces gebruikte VisionKit om documenten vast te leggen op iPhone en iPad. Originele scans bleven als bestanden bewaard, terwijl OCR en verdere verwerking bijgesneden of gedraaide versies konden gebruiken. OCR-uitvoer werd invoer voor de volgende stap, geen vaststaand resultaat. Herkende regels, tekstkaders, betrouwbaarheidsscores en later ook documentstructuur gingen naar een gecombineerde verwerkingsketen: lokale Core ML-modellen stelden rollen en gebieden voor, Swift-parsers bouwden mogelijke uitkomsten op en vaste validatieregels bepaalden welke uitkomst acceptabel was.
Daardoor veranderde het project van een app met parserregels in een offline machinelearningsysteem. De codebase kreeg scripts voor het voorbereiden van eerste labels, trainen van regelclassificatiemodellen, detectoren en lokalisatiemodellen, samenstellen van YOLO-datasets, beoordelen van onbekende lay-outs, maken van negatieve voorbeelden zonder bon, controleren van labelstructuren, afleiden van specialistische datasets en uitvoeren van controles na training. De productie-app bleef lokaal en werkte volgens vaste regels, maar het ontwikkelproces werd een herhaalde cyclus van meten, isoleren, labelen, trainen, vergelijken en toelaten tot gebruik.
De herkenningsketen
| Laag | Doel | Voorbeelden van hulpmiddelen |
|---|
| Vastleggen | Bonafbeeldingen maken en de originelen behouden voor latere controle, delen en back-ups. | VisionKit, AVFoundation, scancontrole in SwiftUI en functies voor bijsnijden en draaien. |
| Tekstextractie | OCR-regels, hun positie en afmetingen, betrouwbaarheid en documentstructuren herkennen. | Apple Vision OCR, een vaste lijst met herkenningstalen voor bonnen en waar beschikbaar documentstructuur in iOS 26. |
| Lay-out | Het bonpapier en gebieden voor verkoper, artikelen, totaal, btw en betaling vinden. | YOLO/Ultralytics-training, Core ML-exports van lokalisatiemodellen, structuurcontroles en kwaliteitsbeoordeling van gebieden. |
| Betekenis | Regels en bedragen indelen als verkoper, artikel, totaal, btw, betaling, metadata of te negeren inhoud. | Create ML/Core ML-classificatiemodellen, een JSON-terugvalmodel, modellen die veldkandidaten rangschikken en gespecialiseerde modellen per gebied. |
| Samenstellen | Artikelregels, totalen, btw-specificaties en betaalgegevens opbouwen uit onvolmaakte herkende regels. | Swift-parsers, een samensteller van artikelregels, een parser die gebieden als uitgangspunt neemt en controles om tussen mogelijke artikelregels te kiezen. |
| Validatie | Alleen uitkomsten aanvaarden waarbij de bedragen kloppen en terminalgegevens, barcodes en belastingregels niet verkeerd worden geïnterpreteerd. | Kwaliteitsvalidatie, valutadetectie, controles op bedragen inclusief btw, controle van het eindtotaal en vaste regressievoorbeelden. |
De belangrijkste technische omslag: validatie kreeg het laatste woord
Een model kan voorstellen doen en een parser kan informatie afleiden. Maar de bedragen op de bon moeten uiteindelijk kloppen. Bon Dossier gebruikte daarom rekenkundige validatie als beslissende controle: artikelbedragen moeten aansluiten op het eindtotaal, btw mag niet dubbel worden geteld, subtotalen en belastinggrondslagen mogen niet voorrang krijgen boven het eindtotaal en betaal- of kaartgegevens mogen niet als aankoopbedragen worden beschouwd.
Die regel bracht subtiele fouten aan het licht. Voor Europese bonnen met bedragen inclusief btw is de juiste controle meestal total == sum(items), niet total == items + tax. De tweede berekening telt de btw dubbel en kan daardoor juist het verkeerde totaal goedkeuren. Het herstellen van die ene regel bracht het systeem voor veel bonnen van “lijkt aannemelijk” naar “klopt rekenkundig”.
Andere verbeteringen waren even concreet: kortingsoverzichten overschreven het eindtotaal niet meer, kolomkoppen zoals “Prijs” en “Totaal” veroorzaakten geen verwarring meer tussen artikelprijzen en het bontotaal, btw-grondslagen kregen geen voorrang meer boven betaalde totalen en een label “Totaal” met het bedrag op de volgende regel kreeg een eigen afhandeling. Dit waren geen cosmetische parseraanpassingen, maar correcties in hoe de app de werkelijkheid interpreteert.
Trainingsgegevens zonder onszelf voor de gek te houden
Het project gebruikte verschillende soorten labels, omdat niet alle trainingsvoorbeelden even betrouwbaar zijn. Handmatig goedgekeurde labels kregen de status gold. Voorbeelden uit Vision en appback-ups werden behandeld als bootstrap- of silver-gegevens. Handmatige correcties werden als herleidbare voorbeelden opgeslagen. De productieverwerking mocht goedgekeurde YOLO-labels uitdrukkelijk niet overschrijven. Kandidaatmodellen moesten worden beoordeeld op vaste, gescheiden validatie- en testsets.
Dat was nodig, omdat een systeem voor bonherkenning gemakkelijk ongemerkt te sterk op de trainingsvoorbeelden wordt afgestemd. Een vastgelegde fout maakte de training van gebiedsspecialisten zelfs betekenisloos: de invoer bevatte een kenmerk dat het verwachte label al weggaf. Het model kreeg zo het antwoord terug als invoer. De oplossing verwijderde dit label uit zowel trainings- als productie-invoer, zodat specialistische modellen hun score met echte kenmerken moesten verdienen. Een andere opschoning verwijderde vaste uitzonderingen voor verkopers en aliassen voor OCR-herkenningsfouten. Het resultaat was eerlijker en tijdelijk lastiger, maar maakte resterende problemen zichtbaar in plaats van ze met kunstgrepen te verbergen.
Voorbeelden van gemeten modelkwaliteit tijdens het project
- Een actuele benchmark op het apparaat omvatte 728 bonnen en 35.361 OCR-regels.
- Bij 545 van de 546 beoordeelde bonnen kwamen de parserresultaten overeen met de gecontroleerde verwachte uitkomsten; bij één bon week de herkende datum nog af.
- De vastgelegde nauwkeurigheid van regelclassificatie was 96,3 procent.
- De gemiddelde parsertijd lag rond 47,5 ms, met een p95 van ongeveer 81,4 ms in de lokale verwerking zonder netwerk.
- De ambitie voor de release bleef hoger: automatisering rond 99 procent vereist meer gecontroleerde echte bonnen en labels voor artikelregels.
Versie 3: van herkenningssoftware naar product
De derde versie draaide om alles wat slimme herkenningssoftware bruikbaar maakt: opslag, synchronisatie, zoeken, bestandsimport, back-ups, exports, instellingen, privacymanifesten, App Store-informatie, toegankelijkheid, prestaties, vertalingen, macOS en beheergereedschap. Hier lopen veel prototypes vast, omdat productontwikkeling vaak juist bestaat uit werk dat gebruikers pas opmerken als het misgaat.
De opslag begon met een lokaal JSON-archief: eenvoudig, inspecteerbaar en snel aan te passen. Dat paste bij de eerste fase, maar was onvoldoende voor een privéarchief op iPhone en iPad. De productieopzet kreeg een repository-abstractie, met Core Data als primaire opslag en NSPersistentCloudKitContainer voor private iCloud-synchronisatie. Het ontwerp hield originele scanbestanden, controlesommen, miniaturen en bonmetadata bewust bij elkaar. Een bon werd niet behandeld alsof het alleen een tabelrij was.
Ook het archief werd meer dan een lijst. Het kreeg een indeling die op Mail lijkt: Alle bonnen, mappen, slimme mappen, markeringen, gericht zoeken, selecteren, verplaatsen, exporteren en doorgeven aan Mail. Import werd uitgebreid naar Bestanden, Mail, afbeeldingen, pdf’s en tekst. App Intents en deeplinks konden gebruikers naar Archief, Scannen, Inzichten en Instellingen leiden. Dankzij Spotlight en de deelextensie werden bonnen onderdeel van het systeem, in plaats van gegevens die in één app opgesloten zitten.
Core Data en CloudKit: de lastige punten zaten in de praktijk
De keuze voor Core Data was praktisch. SwiftData is prettig voor prototypes, maar ReceiptVault had expliciete controle over migraties, verwerking van binaire bestanden, aanknopingspunten voor CloudKit-diagnostiek, conflictafhandeling en ruimte voor jarenlange schemaontwikkeling nodig. Core Data bood die mogelijkheden. De interface kon met een heldere repository-interface blijven werken, terwijl de opslaglaag migratie vanuit JSON en herstel van ontbrekende scanbestanden afhandelde.
De risico’s bij ingebruikname waren reëel. Het initialiseren van het CloudKit-schema moest ook programmatisch gedefinieerde entiteiten omvatten, zoals bonrecords, scanbestanden, mappen, markeringen en slimme mappen. Lege schema’s veroorzaakten gedeeltelijke fouten. Voor productiebuilds moest het CloudKit-schema naar de productieomgeving worden overgezet. Release-entitlements moesten productie-APNs gebruiken voor stille synchronisatiemeldingen. Dit zijn geen aansprekende problemen, maar ze bepalen of synchronisatie bij echte gebruikers werkt.
Back-ups, exports en de gevolgen van originele scans
Bon Dossier bewaart financiële gegevens. Export en back-ups mochten daarom geen sluitpost zijn. De app kreeg TSV-export, echte XLSX-export, export van gefilterde archieven en geselecteerde bonnen, handmatige back-ups en herstel, en deelmenu’s. Ook bleven de originele scanpagina’s bewaard, in plaats van het bewijs na de herkenning weg te gooien. Dat is een juiste productkeuze, maar vraagt extra werk aan prestaties en opslag.
Een productiecontrole maakte de afweging duidelijk: scanbeelden zowel op schijf als via externe binaire opslag van Core Data bewaren, verdubbelt de lokale opslag. Volledige JSON-back-ups met ingesloten afbeeldingen kunnen het geheugengebruik sterk laten oplopen, doordat alle scanbytes tegelijk in het geheugen komen. De oplossingsrichting was even duidelijk: zwaar repository- en back-upwerk van de hoofdthread halen, grote back-ups streamen of in delen verwerken, miniaturen cachen en bewust kiezen of Core Data of het bestandssysteem de centrale opslag voor scanbytes is.
De macOS-versie werd meer dan een viewer
Het plan voor macOS was bewust ambitieus: geen aanvulling waarmee alleen kon worden gelezen, maar een native desktopversie van ReceiptVault met hetzelfde privé-iCloud-archief en dezelfde kernlogica. De interface heeft drie kolommen: zijbalk, bonnenlijst en detailpaneel. De Mac-versie hergebruikt de gedeelde kern, OCR/ML-verwerking, archief-, export-, back-up- en synchronisatielogica. Presentatie, commando’s, bestandsimport en camera-opnamen worden aangepast aan de conventies van macOS.
Dat vroeg om extra voorzieningen: macOS-entitlements, App Sandbox, toegang tot door de gebruiker geselecteerde bestanden, cameratoestemmingsteksten, menucommando’s, voorbereiding voor Continuïteitscamera, native importvensters en keuzes rond een App Store-release voor meerdere platforms. Het bewees ook de waarde van ReceiptVaultCore als afzonderlijke kern. De platforminterfaces mogen verschillen; de logica voor bonherkenning hoort gedeeld te blijven.
De ontwikkelprocessen achter het werk
Het project bleef beheersbaar doordat het niet als één grote hoeveelheid functiewerk werd uitgevoerd. We werkten met oplevering per laag, broncodecontroles, lokale scripts, vaste testvoorbeelden, modelrapportages en gedocumenteerde toelatingscriteria. Sommige van de belangrijkste resultaten waren geen zichtbare schermen, maar scripts en rapporten die het werk meetbaar maakten.
Bouwen en controleren
SwiftPM-tests, simulatorbuilds, tests die broncode beschermen, controles van de projectgenerator, vertaalcontroles, CI-scripts en handmatige controle van schermafbeeldingen hielden het product op koers.
Gegevens en machinelearning
De verwerkingsketen hield gold-, silver- en bootstrap-labels gescheiden, bewaarde bijbehorende metadata in aparte bestanden, controleerde YOLO-structuren, trainde lokale modellen en liet modelbestanden pas na vergelijking door naar de volgende fase.
Het product robuuster maken
Prestatiecontroles, een privacy-inventaris, App Store-informatie, toegankelijkheidscontroles, synchronisatiediagnostiek en controles op releaseblokkades maakten verborgen fouten zichtbaar.
Voorbeelden van hulpmiddelen en technieken
- Swift en SwiftUI: interfaces voor iPhone, iPad en macOS met native lijsten, gesplitste weergaven, instellingen en deelprocessen.
- SwiftPM: een gedeelde kernmodule en een uitvoerbare ML-tool om bedrijfslogica buiten de app zelf te kunnen testen.
- XCTest: tests voor de parser, het archief, back-ups, export, vertalingen, broncodebescherming, App Intents en afspraken rond ML-modellen.
- Apple Vision en VisionKit: scans vastleggen, OCR, de positie en afmetingen van tekstregels en documentstructuur uitlezen.
- Core ML en Create ML: modellen voor bondetectie, gebiedslokalisatie, classificatie, rangschikking van veldkandidaten en lokale herkenning van regelrollen.
- YOLO en Ultralytics: experimenten met lay-outgebieden, gebiedslabels en modelexports voor bonpapier en inhoudsgebieden.
- Python-, Swift- en Ruby-scripts: datasets voorbereiden, projecten genereren, modellen trainen, controles en rapportages uitvoeren en bestanden synchroniseren.
- Core Data en CloudKit: privéarchiefopslag met synchronisatie, migratie vanuit JSON en het synchroniseren van scanbestanden.
- CryptoKit: SHA-256-controlesommen voor de integriteit van scanbestanden en een toekomstige basis voor versleutelde back-ups.
- Integratie met het app-ecosysteem: de deelextensie, documentimport, App Intents, deeplinks, Spotlight-records, exportfuncties in de stijl van Mail en handmatige back-ups.
De hindernissen en hun oplossingen
| Hindernis | Waarom dit belangrijk was | Oplossingsrichting |
|---|
| OCR leverde tekst, geen vaststaande feiten. | Bontotalen, btw-grondslagen, betaalregels en barcodenummers leken als losse tekenreeksen op elkaar. | Combineer tekstposities uit OCR, rollen uit Core ML, de context van gebieden en vaste validatieregels. |
| Artikelregels hadden een onregelmatige structuur. | Omschrijvingen, aantallen en prijzen stonden vaak in afzonderlijke kolommen of beeldblokken. | Stel artikelregels samen, gebruik artikelgebieden en voeg controles toe die tussen mogelijke regels kiezen op basis van de som van bedragen. |
| Modellen konden ongemerkt overfitten. | Gelekte labels en vaste uitzonderingen voor verkopers maakten de scores beter dan het werkelijke gedrag. | Verwijder antwoorden uit de invoer, scheid labels naar betrouwbaarheid en vervang kunstgrepen door opgeslagen correcties en algemene filters. |
| CloudKit-synchronisatie vereiste een nauwkeurige productieconfiguratie. | Een ontbrekend productieschema of verkeerde APNs-entitlement kan synchronisatie laten mislukken terwijl de appcode correct is. | Voeg expliciete schema-initialisatie, releasecontroles en TestFlight-tests op meerdere apparaten toe. |
| Originele scans legden druk op geheugen en opslag. | Grote bonnen, back-ups en dubbel opgeslagen afbeeldingen konden de interface laten vastlopen of geheugengebruik sterk verhogen. | Cache miniaturen, verplaats repositorywerk van de hoofdthread, stream back-ups en maak de scanopslag doelmatiger. |
| Releasevereisten waren gemakkelijk te onderschatten. | Privacymanifesten, entitlements, gegevensbescherming en App Store-informatie kunnen upload of beoordeling blokkeren. | Controleer de gereedheid voor productie vóór de laatste ontwikkelfase, niet pas nadat de app is gebouwd. |
Waarom dit zo’n grote technische inspanning vergde
De moeilijkheid zat niet in één algoritme, maar in het aantal overgangen dat tegelijk betrouwbaar moest zijn. Een scan moest een OCR-resultaat worden. Dat resultaat moest een bon worden. Die bon moest doorzoekbaar, exporteerbaar, synchroniseerbaar, herstelbaar en uitlegbaar zijn. De herkenning moest verbeteren zonder privégegevens te lekken of van een server afhankelijk te worden. De interface moest rustig en passend bij het platform blijven, terwijl de onderliggende verwerking meer op documentonderzoek leek dan op het uitlezen van een formulier.
Elke versie liet zien hoeveel meer er mogelijk en nodig was dan in de vorige. Versie 1 bewees dat de app als een helder opgebouwd Swift-product kon bestaan. Versie 2 liet zien dat bonherkenning een echte lokale ML- en validatieketen nodig had. Versie 3 maakte duidelijk dat herkenningssoftware pas een product wordt als opslag, synchronisatie, import, export, privacy, prestaties en releaseprocessen betrouwbaar zijn.
Die ontwikkeling is terug te zien in de codebase: een gedeelde kernmodule, app-interface, scannerservices, archiefweergaven, Core Data-repositories, CloudKit-configuratie, afspraken rond ML-modellen, modelcaches, trainingsscripts, uitvoerscripts voor productieverwerking, App Store-documentatie, prestatiecontroles en tientallen gerichte tests. Het resultaat is geen dunne laag rond OCR, maar een platform voor lokale bonherkenning dat het verschil tussen tekst en bewijs moest leren.
Wat we meenemen naar vergelijkbare projecten
- Begin met een goed testbare kern. Camera-opnamen en OCR-resultaten bevatten fouten en ruis. Een domeinmodel en tests met vaste voorbeeldgegevens geven het project een betrouwbare basis.
- Gebruik OCR als aanwijzing, niet als definitief resultaat. De positie en afmetingen van tekst, de betrouwbaarheid van de herkenning, de indeling van de bon en de controle van bedragen bepalen samen of de uitkomst klopt.
- Laat het model voorstellen doen en valideer wat de app overneemt. Vaste validatieregels moeten bepalen of de herkende bongegevens betrouwbaar genoeg zijn.
- Voorkom dat hoge trainingsscores een vertekend beeld geven. Voorkom dat verwachte antwoorden in de invoer terechtkomen, dat vaste uitzonderingen de scores kunstmatig verhogen of dat validatiegegevens bij de training worden gebruikt.
- Houd vanaf het begin rekening met afbeeldingsbestanden. Het bewaren van originele afbeeldingen heeft gevolgen voor opslag, back-ups, synchronisatie en prestaties.
- Controleer de productieconfiguratie net zo zorgvuldig als de code. Entitlements, privacymanifesten en CloudKit-schema’s maken deel uit van de app.
- Beperk de platformspecifieke interface tot wat daar nodig is. Dankzij een gedeelde kern konden we iPhone, iPad en macOS ondersteunen zonder de logica voor bonherkenning voor elk platform opnieuw te bouwen.
De ontwikkeling van Bon Dossier laat zien dat betrouwbare lokale herkenning niet uit één functie bestaat. De betrouwbaarheid moet in iedere stap kloppen: vastleggen, OCR, lay-outanalyse, classificatie, parsing, validatie, opslag, synchronisatie, export en zorgvuldig uitbrengen van releases. Als één stap faalt, ervaart de gebruiker het hele systeem als onjuist. Als iedere stap betrouwbaar is, wordt een onregelmatige papieren bon bruikbare privé-informatie.