Mennova
Alle cases

Mektep

Mobiele app & API

In deze case laat ik zien hoe ik voor Mektep, een islamitische leerkring in Rijswijk, een app voor aanwezigheidsregistratie heb gebouwd.

Deelnemers checken met één tik in bij de les en sparen punten, en beheerders plannen lessen en volgen de opkomst vanuit dezelfde app.

Beeld van Mektep
Type
Mobiele appBackend-APIAdmin-dashboard
Mijn rol
Software-architectFull-stack developerCI/CDProduct ownerMobile developer
Tijdlijn
2026 – heden
Opdrachtgever
Mektep

Uitdagingen en doelen

Mektep begon in 2023 als een groep vrienden die samen lessen volgde en groeide uit tot een gemeenschap met vijf lessen per week, apart voor mannen en vrouwen. De aanwezigheid werd op papier bijgehouden en veel afstemming liep via WhatsApp-groepen.

Ik heb bewust klein gestart: eerst een app voor aanwezigheidsregistratie met punten, zodat deelnemers een reden hebben om op tijd te komen. Gebedstijden, donaties, een puntenwinkel en vragen aan de hoca zijn al gebouwd, maar staan in de eerste versie nog uit.

Het doel: minder papier en WhatsApp-chaos, en een helder beeld van de opkomst per les.

Planningsportaal op laptop en telefoon
Beheerders zien per week hoeveel deelnemers er waren en wie te laat kwam, zonder papieren lijsten.

Architectuur

De backend is opgezet zodat nieuwe modules erbij kunnen zonder dat de kern verandert. Daarbij stonden vier uitgangspunten centraal:

  • 01Gescheiden lagen
  • 02Rollen en rechten
  • 03Modules achter een schakelaar
  • 04Één app voor iedereen

De Flutter-app praat met één ASP.NET Core API, opgedeeld in Domain, Application, Infrastructure en Api, met MariaDB als database. Achtergronddiensten versturen pushmeldingen via Firebase en aanwezigheidsrapporten per e-mail. Het diagram toont de app, de API en de externe diensten.

Architectuurdiagram met links de Mektep-app, het beheer en Postman, in het midden de API en de achtergronddiensten, en rechts MariaDB, Google en Apple, Firebase en e-mail.
Één API bedient zowel de deelnemers als de beheerders; meldingen en rapporten draaien als achtergronddiensten.

Technieken

De backend is gebouwd in C# met ASP.NET Core op .NET 10, met Entity Framework Core op MariaDB en ASP.NET Core Identity met JWT voor inloggen via e-mail, Google of Apple.

De regels voor pushmeldingen zijn een pure functie zonder database of netwerk, zodat elk tijdvenster met een gewone test te controleren is. QuestPDF maakt de aanwezigheidsrapporten die beheerders dagelijks, wekelijks, maandelijks en per kwartaal per e-mail krijgen.

De app is gemaakt in Flutter en Dart en draait op iOS en Android, in het Turks, Nederlands en Engels. Firebase Cloud Messaging verstuurt de herinneringen voor en na de les.

De API draait in Docker-containers op een eigen server met Coolify, met een aparte test- en productieomgeving.

  • C#
  • .NET
  • ASP.NET
  • Entity Framework Core
  • MariaDB
  • JSON Web Tokens
  • Flutter
  • Dart
  • Firebase
  • Docker
  • Coolify
  • GitHub Actions
  • Codemagic
  • xUnit
  • Postman
  • Trello

Agile / Scrum

Ontwikkelproces

Ik werk in sprints, met de taken en wensen van Mektep op een Trello-bord. Elke sprint levert een werkende versie op, die eerst op de testomgeving en als interne testbuild wordt uitgeprobeerd.

De eerste versie in de App Store en Google Play doet bewust maar één ding goed: aanwezigheid en punten. Wat er verder al gebouwd is, staat achter een schakelaar in de app, zodat een module later aan kan zonder dat de rest verandert.

Sprint01en weer opnieuw ↻
  1. Planning
  2. Analyseren
  3. Ontwerpen
  4. Implementeren
  5. Testen
  6. Onderhouden

Implementatie

Elke functie is van begin tot eind gebouwd: domeinmodel, API-endpoint, tests en het scherm in de app. Een check-in telt alleen als de les actief is, het de juiste dag en groep is en de deelnemer binnen de ingestelde straal rond Mektep staat.

Het beheer zit in dezelfde app, met een stappenplan voor nieuwe lessen, sjablonen met spreker en wekelijks terugkerende lessen.

Code-editor naast het planningsportaal
Alle voorwaarden voor een geldige check-in staan op één plek in de backend, zodat de app ze niet kan omzeilen.
Een terminal met de uitvoer van flutter test: testbestanden voor beheer, instellingen, meldingen en inloggen, afgesloten met "All tests passed!".
Alle 358 Flutter-tests slagen voordat Codemagic een nieuwe build maakt.

Testen

De API wordt getest met xUnit: API-tests starten de echte applicatie tegen een SQLite-database en controleren onder meer de meldingsregels, de rapporten en de puntentelling.

De Flutter-app heeft ruim 350 widget- en unittests, en flutter analyze en flutter test draaien bij elke build. Samen bewaken ze vooral de lastige randgevallen, zoals te laat inchecken, tijdvensters rond de les en de overgang naar zomertijd.

Continuous development & integration

Bij iedere push en pull request bouwt GitHub Actions de API en draait alle tests. Alleen als alles groen is, wordt de nieuwe versie via Coolify uitgerold: de test-branch naar de testomgeving, main naar productie. De app en de API hebben elk een eigen pipeline, zodat een fout in de één de ander niet blokkeert.

Codemagic bouwt de app voor iOS en Android. Een push naar test levert een interne testbuild op in TestFlight en Google Play. Een versietag start de productiebuild, die controleert of het versienummer klopt en de build klaarzet in beide stores, waarna ik de publicatie zelf goedkeur.

Twee pipelines: GitHub Actions bouwt en test de API en rolt uit via Coolify, Codemagic bouwt en test de app en zet builds klaar in TestFlight en Google Play.
API en app hebben elk een eigen pipeline, allebei met tests vóór elke uitrol.

01 / 03

Screenshots

Deelnemers en beheerders gebruiken dezelfde app; wie beheerrechten heeft, krijgt er een beheermenu bij.

mektep.mennova.nl

Verder kijken

Meer case studies

Bekijk alle cases

Een goed begin

Heb jij een digitaal vraagstuk dat verder mag?

Vertel me waar je aan werkt. Dan verken ik samen met jou wat er technisch nodig is om vooruit te komen.

Plan een kennismaking
vraag.tsroute.tscontact.ts

// Van vraag naar richtingconst route = { inzicht: true, richting: true, volgendeStap: 'helder',}plan(route)[klaar] tijd voor een kennismaking.