*Deze lijst is op 2026-09-19 teruggebracht van 6676 naar een paar honderd
regels: alle afgeronde taken en sessieverslagen zijn eruit gehaald. Ze staan in
de git-historie (commit 92225d0 is de laatste versie met alles erin) en de
blijvende inzichten staan in CLAUDE.md. Alles hieronder is open werk.
Staat iets er niet meer in, dan is het klaar of afgewezen — niet opnieuw
agenderen.*
Voor een nieuwe sessie: pak een taak uit "Claude — open" hieronder, zet er
meteen — bezig achter in dit bestand (een echte Edit, niet pas bij het
afsluiten; andere sessies delen deze working directory), en verifieer elke
builder-wijziging met een verse export. Taken onder "Bob — open" niet zelf
oppakken.
| # | Taak | Kort |
|---|---|---|
| 91 | Uitleg op de aanmaakpagina's — bezig (Claude, sessie 2026-09-19 taak 91/87) | Pagina A op 3 restpunten na af; pagina B 4 van 7 secties open. Volledig recept + teksten hieronder. Begin hier. |
| 87 | Klikbare link naar /nl/ondernemers — bezig (Claude, samen met 91) |
Eén Text in linkstijl onder de horeca-dropdown; hoort bij 91 |
| Pagina "Mijn aanmeldingen" | ⚠️ Al geclaimd door de sessie 'taken-B1-B7' — niet oppakken | |
| 65 | Functionele doorloop van de release-build | Build draait al op emulator-5556; de checklist is nog niet afgelopen |
| P2-45c | Chiplabels op Home korter | Ze wrappen met de kalenderknop erbij naar twee regels |
| 76 | Linkerpadding op de horeca-agendakaart | Klein, cosmetisch |
| G0.6 | Play-screenshots schieten | Browserloos op beide AVD's, ±10 min — zeg het en het gebeurt |
| # | Taak | Waarom nu |
|---|---|---|
| B1 | App-icoon: PNG 1024×1024, transparant, beeldmerk op ±60 % | 🔴 Blokkeert. Op een toestel staat nu "itgaanskrant.co" |
| G | Google Play-checklist G0–G4 | Volledige checklist hieronder, afvinkbaar |
| 66 | Crashlytics bewijzen | Custom action ligt klaar; jij kijkt in Firebase |
| 89a | HeaderButtonsComponentCopy verwijderen |
Vangnet van taak 89, mag weg |
| P2-42 | Agenda als eerste tab op de zaakpagina | Besluit + uitvoering; slepen lukt Claude niet |
| P2-45b | Annuleren van de datumkiezer zet het filter op vandaag | Besluit: laten of fixen |
| P1-17 | Engelse vertalingen, één ronde | 46 velden op de twee aanmaakpagina's + 3 losse |
| Bij livegang | Zes schakelaars en opruimklussen | Eigen blok hieronder |
| Drupal | P1-42, P2-24, taak 28/32, taak 56, P2-25 | Eigen blokken hieronder |
#
✅ Klaar en export-geverifieerd 2026-09-18/19 op uitgaansevenementAanmaken
(dart analyze 0 errors): alle zeven hulpteksten staan er, elk direct ónder
zijn sectiekop, in 12 px / secondaryText, mét Nederlandse én Engelse vertaling.
Sleutels: ohgppxt2 (Wat), fbkrt89w (Uw Horecagelegenheid), j68hqlk7
(Categorie), f8hii0ci (Wanneer), len3npim (Organisatie), rj9dgdp7 (Entree),
nvi2k89n (Media). Ook gedaan: Titel * / Title * (vc80d3lh) en
Datum * / Date * (xceonmpt — die stond in het Engels nog op "Datum", dus dit
dicht meteen een P1-17-gat).
Nog open op pagina A (klein):
hintText Kies je horecagelegenheid * (nhnxstvm);Text ónder de horeca-hulptekst, in linkstijl
(secondary + onderstreept) met een Launch URL naar
https://uitgaanskrant.com/nl/ondernemers — "Nog geen zaak aangemeld? Dat doe
je op uitgaanskrant.com." De sectieregel die er nu staat noemt die zin al, dus
hem weghalen zodra de link er staat.Pagina B (stadsactiviteitAanmaken): 3 van de 7 secties af —
export-geverifieerd, dart analyze 0 errors. Klaar met NL+EN én stijl
(bodySmall + secondaryText): evhqyjou (Wat), i0ij4drx (Categorie),
e1nwfbwv (Wanneer). Nog te doen op pagina B: de vier hulpregels voor
Waar, Organisatie, Entree en Media, het intro-blok, en Titel *
(xorq08j5) + Datum * (dfa8vusy, EN staat daar nu nog op het Nederlandse
"Datum" — meteen een P1-17-gat om te dichten). Teksten NL+EN staan
kant-en-klaar in de tabel hieronder.
#
Per sectie, en houd je aan de losse tool-aanroepen, anders gaat het mis:
zoom van de boom: hij verschuift tijdens het dupliceren, en
een klik op de oude y-positie pakt dan het origineel. Dat is in deze sessie
drie keer gebeurd (Categorie, Wanneer, Media) en kost telkens een
reparatieronde waarin je de twee teksten weer omwisselt.triple_click in aanroep A, ctrl+a + type in aanroep B.
Eén batch werkt niet — de eerste triple_click na een nieuwe selectie landt niet.Headline Small +
Noto Serif zijn). Daarna alleen nog Text Color → Secondary Text.
Copy/Paste Widget Style uit het contextmenu werkt níet — niet opnieuw proberen.grep -n "getText(" -A1 <widget>.dart | grep "/\*" geeft alle teksten in
documentvolgorde, dus je ziet meteen of kop en hulptekst in de goede volgorde
staan.Twee dingen die deze sessie niet werkten en waar je geen tijd in moet steken: het tree-zoekveld raakte na ~20 minuten bewerken zijn filterfunctie kwijt (een paginaherlaad herstelt dat), en Ctrl+D / Ctrl+Shift+C/V doen niets.
(Oorspronkelijke opdracht en alle teksten hieronder ongewijzigd.)
Bob 2026-09-18: "we moeten uitleg op de evenementen/activiteiten aanmaken
pagina maken." Nu staat er nergens wat verplicht is, wat een veld betekent, of
wat er ná indienen gebeurt — de verplichte velden zijn alléén in de custom
action afgedwongen (evenementCreate / stadsactiviteitCreate), dus de
gebruiker ziet pas ná indienen "Titel is verplicht".
Gekozen opzet (Bob akkoord): intro-blok bovenaan + één regel hulptekst onder
elke bestaande sectiekop + * achter de verplichte labels. Géén info-icoontjes
met tooltip (op mobiel een extra tik, en je ziet niet dát er uitleg is), en géén
losse lap tekst bovenaan (wordt weggescrold). Per-veld-uitleg (laag 3) en echte
veldvalidatie vóór indienen zijn bewust buiten scope gehouden.
Bouwtechnisch: losse Text-widgets, géén herbruikbaar component met een
tekst-parameter — een parameterwaarde valt buiten het vertaalsysteem, een
Text krijgt een eigen sleutel en is dus via het globe-icoontje te vertalen.
Eén Text opmaken (stijl bodySmall, kleur secondaryText, 12px), dan
Duplicate per sectie en in de kaart-Column direct ónder de sectiekop zetten.
Reken op ±16 Text-widgets over beide pagina's.
⚠️ Een duplicaat erft de Engelse vertaling van het origineel (zie P1-17) —
zet de EN dus per widget opnieuw via het globe-icoontje, en verifieer met een
verse export, niet met het paneel ("ziet er opgeslagen uit"-patroon).
Belangrijkste zin van de hele taak — de categorie. Bob expliciet: de
categorie bepaalt in welke overzichten het item terechtkomt. Dat is geen
stijlpunt maar hard gedrag: flutterflowmobiel1 verdeelt over displays
services_1…7 per categorie, dus een item zónder categorie komt in geen enkele
tab (dat was precies de bevinding van taak 28: 6 van de 7 onzichtbare events
hadden geen categorie).
Stand per 2026-09-19, gemeten op een verse export (niet gebouwd, alleen geteld):
* achter Titel,
Datum en de hint Kies je horecagelegenheid.*.#
uitgaansevenementAanmakenIntro-blok, bovenaan (boven de kaart "Wat"):
Regel onder elke sectiekop:
| Sectie | NL | EN |
|---|---|---|
| Wat | Geef een korte, herkenbare titel. De omschrijving verschijnt op de detailpagina van het evenement. | Give it a short, recognisable title. The description appears on the event's detail page. |
| Uw Horecagelegenheid | Kies de zaak waar het evenement plaatsvindt. Je ziet hier alleen zaken die op jouw account staan. Nog geen zaak aangemeld? Dat doe je op uitgaanskrant.com. | Choose the venue where the event takes place. You only see venues linked to your account. No venue yet? You can add one on uitgaanskrant.com. |
| Categorie evenement | Let op: de categorie bepaalt in welke overzichten je evenement verschijnt. Kies er minstens één — zonder categorie is je evenement nergens terug te vinden. | Note: the category decides which listings your event appears in. Pick at least one — without a category your event won't show up anywhere. |
| Wanneer | De begindatum is verplicht. Vul een einddatum alleen in bij een evenement dat meerdere dagen duurt. | The start date is required. Only fill in an end date for an event that runs several days. |
| Organisatie | Optioneel. Een website of ticketlink tonen we als knop bij je evenement. | Optional. A website or ticket link is shown as a button on your event. |
| Entree | Laat leeg als er geen entree wordt geheven. Vul de prijs in als bedrag, bijvoorbeeld 7,50. | Leave empty if there's no admission charge. Enter the price as an amount, for example 7.50. |
| Media | Eén logo en meerdere foto's. Tik nogmaals op "Foto's kiezen" om er een toe te voegen; de vorige blijft staan. | One logo and several photos. Tap "Choose photos" again to add another; the previous one stays. |
Verplicht markeren met * (verplicht volgens evenementCreate:
horecagelegenheid, titel, datum-start):
labelText Titel (vc80d3lh) → Titel *labelText Datum (xceonmpt) → Datum *hintText Kies je horecagelegenheid (nhnxstvm) → Kies je horecagelegenheid *De regel bij "Uw Horecagelegenheid" overlapt bewust met taak 87 — bouw die
twee samen, dan is één van beide de link-variant (Launch URL naar
https://uitgaanskrant.com/nl/ondernemers) en hoeft de zin er niet twee keer
te staan.
#
stadsactiviteitAanmakenIntro-blok, bovenaan:
Regel onder elke sectiekop:
| Sectie | NL | EN |
|---|---|---|
| Wat | Geef een korte, herkenbare titel. De omschrijving verschijnt op de detailpagina van de activiteit. | Give it a short, recognisable title. The description appears on the activity's detail page. |
| Categorie evenement | Let op: de categorie bepaalt in welke overzichten je activiteit verschijnt. Kies er minstens één — zonder categorie is je activiteit nergens terug te vinden. | Note: the category decides which listings your activity appears in. Pick at least one — without a category your activity won't show up anywhere. |
| Wanneer | De begindatum is verplicht. Vul een einddatum alleen in bij een activiteit die meerdere dagen duurt. | The start date is required. Only fill in an end date for an activity that runs several days. |
| Waar | Kies eerst de plaats waar de activiteit plaatsvindt — dat is verplicht. Adres, postcode en plaatsnaam daaronder zijn het bezoekadres en optioneel. | First choose the town where the activity takes place — that one is required. The address, postcode and town name below are the visiting address and optional. |
| Organisatie | Optioneel. De naam van de organisator en een contactadres of website waar bezoekers terechtkunnen. | Optional. The organiser's name and a contact address or website for visitors. |
| Entree | Laat leeg als er geen entree wordt geheven. Vul de prijs in als bedrag, bijvoorbeeld 7,50. | Leave empty if there's no admission charge. Enter the price as an amount, for example 7.50. |
| Media | Eén logo en meerdere foto's. Tik nogmaals op "Foto's kiezen" om er een toe te voegen; de vorige blijft staan. | One logo and several photos. Tap "Choose photos" again to add another; the previous one stays. |
Verplicht markeren met * (verplicht volgens stadsactiviteitCreate:
titel, plaats-tid, datum-start):
labelText Titel (xorq08j5) → Titel *labelText Datum (dfa8vusy) → Datum ** op de vier Waar-dropdowns — welke van de twee routes ("Mijn
gemeenten" óf de cascade provincie/gemeente/plaats) je gebruikt is vrij; de
sectieregel hierboven zegt daarom dat de plaats verplicht is.⚠️ Verwarring die de sectieregel bij "Waar" bewust opheldert: er staan hier
twee dingen die "plaats" heten. De verplichte waarde is de plaats-tid uit de
dropdowns (createPlaatsID); het tekstveld met label Plaats (825wzmk4,
hint Plaats activiteit) is gewoon een regel van het bezoekadres en is
#
Bob 2026-09-17: "we moeten nog ergens kwijt dat we uitleggen waar je een horecagelegenheid kunt aanmaken. Kan alleen via de website." Nu staat dat nergens — niet in de app en niet op de helppagina.
Waarom dit er echt toe doet: uitgaansevenementAanmaken heeft een dropdown
"Uw Horecagelegenheid" (sleutel rqx6m3yf) die gevuld wordt uit
mijn_horecagelegenheden. Wie nog geen zaak heeft, ziet daar een lege
dropdown en kan dus geen evenement indienen — zonder dat er ook maar iets
uitlegt waarom, of wat hij dan wél moet doen. Dat is nu een doodlopende weg.
Twee plekken, in deze volgorde:
/nl/support/mobieleapp (Drupal, Bob). Eigen kopje, bv. "Je
zaak aanmelden": een horecagelegenheid maak je aan op de website, niet in de
app; daarna verschijnt hij in de app onder Uw Horecagelegenheid en kun je er
evenementen bij indienen. URL gevonden door Claude 2026-09-18:
https://uitgaanskrant.com/nl/ondernemers (anoniem 200) — daar staat
"Hoe werkt het?" met account aanmaken → onderneming claimen óf toevoegen →
evenementen aanmaken, mét een link naar /nl/node/add/horecagelegenheid.
De helppagina heeft al de zin "Horecagelegenheden toevoegen kan op dit moment
alleen via de website", maar zonder link — die zin moet dus alleen nog naar
/nl/ondernemers gaan wijzen. Bob bevestigt of dit de bedoelde pagina is.uitgaansevenementAanmaken (Claude,
builder). Eén Text onder de dropdown, stijl secondary + onderstreept
(zelfde als de andere links in de app), met een Launch URL naar die pagina:
"Nog geen zaak aangemeld? Dat doe je op uitgaanskrant.com." Engelse
vertaling meteen meegeven. Eventueel met een Visibility-conditie zodat hij
alleen verschijnt bij een lege lijst — maar hem altijd tonen mag ook en is
veel minder bouwwerk.Zelfde afweging geldt voor stadsactiviteitAanmaken: check bij het bouwen even
of die pagina hetzelfde probleem heeft (stadsrechten i.p.v. een zaak).
⚠️ Deel B is geclaimd — niet ook oppakken. Deel A (beide Drupal-endpoints)
draait op productie, getest 2026-09-19: A1 geeft 122 aanmeldingen voor
bobhoreca, A2 geeft 200 op eigen nodes en 403 op andermans (bevestigd op
vier vreemde nids). ?limit= en ?page= werken allebei.
⚠️ Default limit is 50 — de app-lijst moet dus pagineren.
Bob 2026-09-18: "Ziet een horecagelegenheid-eigenaar of stadsrechten-eigenaar ook een overzicht van hun zelf aangemaakte dingen? En ik wil er een knop achter, klone, waardoor het formulier met de eerdere gegevens wordt gevuld."
Antwoord op de eerste vraag: nee, dat bestaat nog niet. Gemeten 2026-09-18 op
de export: de enige "mijn"-endpoints zijn mijn_horecagelegenheden.json (vult de
dropdown op uitgaansevenementAanmaken) en mijn_stadsrechten.json. Er is geen
enkele call die teruggeeft wat deze gebruiker heeft aangemaakt. Na het indienen
van een evenement verdwijnt het dus uit beeld: de gebruiker kan niet zien of het
erop staat, niet of het al goedgekeurd is, en niets hergebruiken.
A · Drupal (Bob) — twee endpoints, allebei sessie-geauthenticeerd
mijn_aanmeldingen.json (zelfde auth-patroon als
mijn_horecagelegenheden.json). Alle nodes van type go_out_event en
activity met uid = huidige gebruiker, nieuwste eerst. Per rij: nid,
type, title, datum_start (rauw yyyy-MM-dd HH:mm:ss), status (0/1),
plaats, logo (URL, voor een thumbnail).aanmelding_kloonbron.json?nid=X — sessie-auth plus een
eigenaarscheck ($node->uid == $user->uid, anders 403; zonder die check kan
iemand andermans gegevens uitlezen). Levert de rauwe waarden, niet de
weergavewaarden: horecagelegenheid_nid, titel, omschrijving (rauwe body),
entree_tid, entreeprijs, toelichting_entree, tickets_url,
website_url, categorie_tids (lijst), logo_fid, fotos_fids (lijst).Waarom A2 een eigen endpoint moet zijn en flutterflow_events.json niet
volstaat — gemeten op nid 214439: die view geeft categorie als labels
(['Tweedehands markt']) i.p.v. tids, logo/fotos als URL's i.p.v.
fids, datum als zaterdag 19 sep, 9:00 (geen jaar, niet parseerbaar),
website verpakt in een <a href=...>-tag, en er zit geen entree-tid in.
Daar is geen formulier mee te vullen.
Open vraag voor Bob: mag een kloon dezelfde fid's hergebruiken (dan moet
file_usage_add() meelopen voor de nieuwe node), of moet de gebruiker opnieuw
uploaden? Hergebruiken is voor de gebruiker veel prettiger — dat is juist de
helft van de winst van klonen.
B · App (Claude, builder)
MijnAanmeldingen met de standaard header + Drawer
(recept staat in CLAUDE.md), een StaggeredView over A1 met Cross Axis Count
1/1/2/3 en een Empty List Widget. Per kaart: titel, datum, statuslabel
("Gepubliceerd" bij status: 1, "Wacht op goedkeuring" bij 0) en twee
knoppen: Bekijken (Navigate → EventCurrent met nid) en Klonen.ListTile erbij,
binnen de bestaande userSessionid-login-guard. Dupliceer een bestaande
rij (Ctrl+D) — dat is hier het bewezen patroon, Insert Widget niet.uitgaansevenementAanmaken. Niet via een page state die je in On Page Load
vult: Initial Option Value van een dropdown wordt tijdens de eerste build
geëvalueerd en On Page Load draait pas in een addPostFrameCallback — dan is
de FormFieldController al met de lege waarde geïnitialiseerd (staat zo in
CLAUDE.md).Nieuwe parameters op uitgaansevenementAanmaken, allemaal niet-verplicht
(een verplichte parameter genereert een ! en laat de gewone "nieuw"-route
crashen): kloonHorecaNid, kloonTitel, kloonOmschrijving, kloonEntreeTid,
kloonEntreeprijs, kloonToelichting, kloonTicketsUrl, kloonWebsiteUrl
(String), kloonCategorieTids + kloonFotosFids (List), kloonLogoFid.
Binden: elke TextField → Initial Value, elke dropdown → Initial Option
Value.
Bewust NIET klonen: de twee datumvelden. Je kloont juist om hetzelfde evenement op een níeuwe datum te zetten, dus een overgenomen datum is per definitie fout en moet alsnog weg. Twee lege datumvelden zijn meteen ook de rem tegen per ongeluk twee keer exact dezelfde aanmelding publiceren.
Volgorde. A1 + B1 + B2 (het overzicht) is op zichzelf al waardevol en veel kleiner dan de kloonknop — lever dat als eerste op, A2 + B3 daarna. Zonder het overzicht heeft de kloonknop trouwens geen plek om te staan.
Twee valkuilen vooraf. (1) De List<String>-parameters zijn het fragiele
deel: een List-typed argument dat op Unset blijft staan blokkeert de héle
export met een generieke 400 (zie CLAUDE.md) — loopt dat vast, dan is het een
Bob-stukje. (2) stadsactiviteitAanmaken heeft exact hetzelfde formulierpatroon;
bouw eerst evenementen helemaal af en kopieer daarna pas, niet allebei tegelijk.
HorecagelegenheidCurrent: Agenda als eerste tab · Eigenaar: Bob
(besluit + uitvoering). Agenda staat nu als 4e tab. Tabs herordenen lukt
niet via de widget tree (bewezen 2026-09-17): een Tab-node op de
TabBar-rij droppen geeft "Tab can only be added to TabBar", en op een
andere Tab-rij droppen verplaatst alleen de Tab en niet zijn TabBar Page,
waarna het canvas breekt. Opties: (a) jij probeert het slepen in je eigen
browser, (b) de tab blijft achteraan, (c) Claude bouwt de inhoud van de
tabben over — dat laatste is fors werk. Zeg welke.*Opgesteld 2026-09-19. Account aangemaakt 2026-09-18 als Organisatie (Digital Force); wacht op verificatie. Vervangt taak 63 (a-i) en punt 2 van "Bob's 7" — die twee niet meer los afwerken. Vink hier af.*
Bevestigd via Google's eigen documentatie, 2026-09-19:
#
android/key.properties, want android/app/build.gradle:80 staat nog op
signingConfig signingConfigs.debug — daarmee kun je niet uploaden.project.pbxproj beweegt mee in elke export.#
com.uitgaanskrant.app — onveranderlijk na de eerste
upload, dus controleer 'm.#
https://uitgaanskrant.com/nl/support/privacybeleid
(anoniem 200, gemeten 2026-09-16).https://uitgaanskrant.com/nl/support/mobieleapp
⚠️ NIET /nl/account-verwijderen — die geeft anoniem 403 en reviewers
openen 'm uitgelogd. Taak 85 heeft de in-app-knop al naar dezelfde URL gezet.INTERNET, CAMERA, READ_EXTERNAL_STORAGE,
WRITE_EXTERNAL_STORAGE, plus via AdMob/Firebase ACCESS_NETWORK_STATE,
WAKE_LOCK, FOREGROUND_SERVICE, AD_ID en drie ACCESS_ADSERVICES_*.
Declareren: Advertising ID → JA (verplicht, AD_ID staat erin),
crashlogs/diagnostiek (Crashlytics), gebruikersnaam/e-mail (login), en
foto's (camera + galerij, voor de aanmaakpagina's). Transport is
versleuteld en verwijdering is mogelijk → beide aanvinken.#
assets/images/app_launcher_icon.png
(het volvlakse), niet de adaptive foreground.#
1.0.0+1
(pubspec.yaml:18). Bij de FlutterFlow-route: App Settings → App Details.flutter_launcher_icons wél? Lokaal
gebouwd draagt het bestand anders het Flutter-vogeltje. Niet aannemen.mijn_aanmeldingen.json en aanmelding_kloonbron.json zijn geplaatst en
getest. Details staan in het 88-blok hierboven; deze taak is klaar.
De keten werkt, end-to-end gemeten op een profile-build op emulator-5554:
tik op Crashtest → FirebaseCrashlyticsTestCrash in logcat, proces weg →
app opnieuw geopend → Making request to crashlyticsreports-pa.googleapis.com
→ Status Code: 200. Het rapport is dus daadwerkelijk verstuurd.
🔴 En meteen de verklaring waarom er nooit een crash in het dashboard stond:
Bob's netwerk-DNS (192.168.8.220) blokkeert crashlyticsreports-pa.googleapis.com
(antwoordt 0.0.0.0). Elk rapport vanaf dit netwerk verdween in een sinkhole.
De koppeling was al die tijd in orde. Details + de omzeiling staan in
CLAUDE.md. emulator-5554 staat nu op private DNS (dns.google) zodat
Crashlytics daar werkt — terugzetten met
adb shell settings put global private_dns_mode off.
Voor Bob, in Firebase: zie het antwoord in de chat — kort: Crashlytics
openen, wachten tot de eerste crash het dashboard "activeert", en controleren
dat het bundle_id com.uitgaanskrant.app is. Daarna de Crashtest-knop weer
weghalen.
⚠️ Bob's huidige knop hangt aan de UITLOG-keten. De Duplicate nam alle
zeven uitlog-acties mee en crashlyticsTest staat er als achtste achter; je
wordt dus eerst uitgelogd en naar Login gestuurd, en pas daarna crasht hij. Het
werkt, maar voor een schone stack trace: Actions → Edit → acties 1 t/m 7
verwijderen (⋮ → Delete Action).
Nog open (los van deze taak): main.dart:44 zet alléén
FlutterError.onError. Er is geen PlatformDispatcher.instance.onError,
dus een fout in een async custom action buiten het framework wordt niet
gerapporteerd. Eén regel, maar main.dart is gegenereerd — moet via
FlutterFlow's Final Actions/custom-code-hook.
crashlytics_test.dart — één custom action crashlyticsTest(String? modus),
argument mag Unset blijven (String mag dat; alleen een List-typed argument
blokkeert de export). Drie standen: Unset → echte crash, melding → niet-fatale
melding, flutter → via de FlutterError.onError-koppeling uit main.dart.
Gemeten gat in de huidige opzet: main.dart:44 zet alléén
FlutterError.onError. Er is geen PlatformDispatcher.instance.onError,
dus een fout in een async custom action buiten het framework wordt niet
gerapporteerd. Zeg het als dat erbij moet — dat is één regel in main.dart,
maar main.dart is gegenereerd, dus het moet via FlutterFlow's
Final Actions/custom-code-hook, niet lokaal.
Verwachting bij het testen: een echte crash wordt pas bij de volgende
start van de app geüpload. Een melding gaat meteen weg en verschijnt onder
Non-fatals. Reken op ~5 minuten tot het in het dashboard staat.
Eerste echte --release-build ooit, uit een verse export mét --include-assets
(/tmp/ff-rel, fvm use 3.35.7 -f, dart analyze 0 errors), geïnstalleerd op
emulator-5556 (telefoon; 5554 was bezet door de sessie van taak 89).
dumpsys bevestigt flags=0x0 — geen DEBUGGABLE, dus een echte release.
✅ Wat goed gaat. De app start schoon op: 0 FATAL, 0 E/flutter in
logcat over de hele sessie. Data laadt (Amsterdam, slider, kaarten met foto's),
Nederlandse locale klopt, zoekveld + datumchips + vijf tabs staan er, en alle
iconen renderen — óók het enige FontAwesome-icoon (flagCheckered bij
Activiteiten in het menu), dat de tree-shaking dus overleeft. Het
tree-shaking-risico uit de oorspronkelijke taakomschrijving is hiermee van tafel:
er zijn 0 dynamisch opgebouwde IconData( in de hele levende code, en
fa-solid-900.ttf krimpt netjes van 419 KB naar 1248 bytes.
Screenshots: scratchpad/rel-home.png, rel-menu.png.
🔴 BLOKKEREND — een lokaal gebouwde release draagt het Flutter-standaardicoon.
Het blauwe Flutter-vogeltje, niet het rode merkicoon. Hard aangetoond, niet
afgeleid: het icoon uit app-release.apk is pixel-identiek aan de
Flutter-default (68 % #40c0e0, 31 % dekking) terwijl app_launcher_icon.jpg
83 % #a00000 en 100 % dekking heeft; visueel bevestigd, het is letterlijk het
Flutter-logo.
Oorzaak. Een verse export heeft android:icon="@mipmap/ic_launcher", alleen
de default ic_launcher.png (md5 57838d52…), geen mipmap-anydpi-v26/ en
geen values/colors.xml. Het blok flutter_launcher_icons: in pubspec.yaml
is wél correct ingevuld (image_path, adaptive_icon_background: '#9a141d'),
maar niemand voert die generator uit — flutter build doet dat niet.
Fix, één commando in de exportmap vóór het bouwen:
fvm flutter pub run flutter_launcher_icons
Dat herschrijft het manifest naar @mipmap/launcher_icon, genereert de
merkiconen, mipmap-anydpi-v26/launcher_icon.xml en colors.xml. Na die stap
opnieuw gebouwd en geverifieerd: aapt2 dump badging geeft dan
application-icon-640:'res/IO.xml' (een adaptive icon) i.p.v. een PNG.
⚠️ Open vraag die iemand met Play-toegang moet beantwoorden: doet FlutterFlow's eigen Deploy-pipeline (de AAB die je daar downloadt) deze stap wél? Waarschijnlijk, maar niet te meten vanaf hier. Controleer het icoon dus op het artefact dat je daadwerkelijk uploadt, niet op dit lokale experiment. Bouw je lokaal, dan is de generator-stap verplicht.
🟠 Het adaptive icon snijdt de merknaam af — "itgaanskrant.co". Ook ná de
generator. adaptive_icon_foreground wijst naar een JPEG (1408×1408), en een
JPEG kan geen transparantie hebben: de gegenereerde
drawable-xxxhdpi/ic_launcher_foreground.png is 432×432 met 0 % transparante
pixels en de buitenste 17 % is 100 % ondoorzichtig. Android toont van een
foreground alleen de middelste ~66 % en maskeert die rond. Gevolg: de
achtergrondkleur #9a141d is nooit zichtbaar (de foreground dekt alles af) en de
witte pil met de naam loopt aan beide kanten van het icoon af — de U en de
m vallen weg. Gerenderde preview: scratchpad/adaptive-zoals-android-toont.png
naast icoon-bron.png.
Fix: lever als adaptive_icon_foreground een PNG met transparantie waarin
alleen het beeldmerk op ±60 % van het vlak staat, gecentreerd; de rest
transparant. image_path (het gewone icoon) mag het huidige volvlakse plaatje
blijven. Hoort bij dezelfde ronde als taak 79.
Kleine waarnemingen, geen actie nodig tenzij je wilt:
ACCESS_NETWORK_STATE, WAKE_LOCK, FOREGROUND_SERVICE, AD_ID en drie
ACCESS_ADSERVICES_* — die komen uit AdMob/Firebase. Relevant voor taak 63(h):
Advertising ID → ja is dus verplicht, dat klopt met wat daar staat.fundingchoicesmessages.google.com te bereiken). Raakt P1-50 — de SDK is er,
alleen de flow niet.status:
activated en het juiste bundle_id. Dat is nog geen bewezen crashrapport
(P1-60), maar de koppeling leeft.rel-menu.png.Wat nog niet gedaan is van deze taak: de volledige functionele doorloop (zaakpagina, hartje, login, Favorieten, evenement aanmaken, vliegtuigmodus,
#
SliderUitgaanComponentSmallCurrent en
PUitgaantabelKaartComponentOrgineelMetKaartjeerin; pagina's
KanwegTestUpload en Event (die laatste weigert structureel, laten
staan); custom function dISABLEdatumVoorApi (hernoemd, nog steeds dood).
Weg zijn sinds 2026-09-16/17: drawerComponentCopy,
kanweghorecagelegenheidCurrentCopy, KanwegHorecagelegenhedenOverzicht,
KanwegHomeCopy, HeaderButtonsComponentCopymethartje, de drie
KaartTabel/Slider-comps, KanwaegSelectStateDropDownComponentCopy,
KanwegHomeUitgaantabelKaartComponentCopy, KanwegHeaderButtonsComponentCopy,
FavorietenCopy, HorecagelegenhedenOverzichtCopy/Copy2/Copy2Copy,
Kanweg, KanwegHorecagelegenhedenOverzichtSortPage. dart analyze op
die export: 0 errors.custom_cronapi() staat "after 30 days", in
custom_delete_expired_events_callback() staat $date->modify('- 360 days').
Met 16.065 events in de voorraad is dat geen detail. Er zit bovendien een
range(0, 500) op: max 500 verwijderingen per cronrun, wat bij de huidige
importsnelheid mogelijk niet meer volstaat. Besluit welke van de twee klopt,
maak description en code gelijk, en hernoem $date_after_30.Show Test Ads uitzetten (App Settings → AdMob). Staat nu AAN,
dus de banner op pUitgaanPage toont testadvertenties en levert niets op.
De GDPR-consentflow staat sinds 2026-09-15 wél goed (adMobRequestConsent()
in main.dart), dus het is alleen deze schakelaar nog.stadsactiviteitAanmaken (27) en
uitgaansevenementAanmaken (19), plus de twee nieuwe teksten uit taak 22
op SelectStateDropDownComponent: "Gemeente volgen" (nosgkxy0) en de
uitlegzin "Bij favoriete gemeenten krijg je een agenda per mail met daarin
alle evenementen uit die favoriete gemeenten." (24bdnkhi), en sinds
2026-09-15 ook "Je volgt deze gemeente" (elx7kse2) — let op: die kreeg
door Duplicate de verkeerde EN-tekst "Add to favorites" mee, dus niet
leeg maar fout; nosgkxy0 staat in EN ook nog op "Add to favorites" en
hoort "Follow municipality" te worden.Titels met spaties vooraan/achteraan opschonen (was P1-47, verbreed
2026-09-11). Bob mat op devbob 100+ horecagelegenheid-nodes met een
gewone ASCII-spatie vóór de titel (LIMIT 100 liep vol, dus het werkelijke
aantal is hoger); ook tabs (nid 49539) en spaties áchteraan (49512) komen
voor. MySQL sorteert op de rauwe node.title, dus elke zo'n node valt
buiten de alfabetische volgorde — terwijl de JSON schoon oogt, want
_custom_clean_html poetst ná de query. Bob's besluit 2026-09-11: de
impact is nu te groot, we lopen de namen door bij de livegang. Te
verifiëren op productie met de telquery hieronder; de drie losse titels uit
taak 16 zijn daar al gefixt, de rest vermoedelijk niet.
drush @prod sqlq "SELECT type, COUNT(*) FROM node WHERE title <> TRIM(BOTH ' ' FROM TRIM(BOTH CHAR(9) FROM TRIM(BOTH CHAR(10) FROM TRIM(BOTH CHAR(13) FROM TRIM(BOTH ' ' FROM title))))) GROUP BY type;"
De fix is een UPDATE met diezelfde genestelde TRIM op node én
node_revision, idempotent, met vooraf een sql-dump van die twee
tabellen. URL-aliassen blijven ongemoeid.
P2-7 · opruimronde, 23 dode eenheden (Bob 2026-09-13: naar livegang).
⚠️ Twee nieuwe sinds 17 sep, allebei van Claude: de pagina
favorietenCopy2 (oefenkopie van Favorieten, gemaakt om de
Wrap-Widget-route voor taak 77 veilig uit te proberen — zie de les in
CLAUDE.md) en het component
HorecagelegenheidEventTabelComponentCopy, dat bij een hernoeming
...Current werd (controleer of de oude map nog in lib/ of git staat).
Claude gooit niets weg, dus beide staan er tot jij ze opruimt.
Moet in de builder gebeuren, niet met git rm — anders staat alles na de
volgende export terug. 9 componenten: header_buttons_component_copymethartje,
kaart_slider_uitgaan_s_comp, kaart_tabel_uitgaan_comp,
kaart_tabel_uitgaan_s_comp, slider_uitgaan_component_small_current,
kanwaeg_select_state_drop_down_component_copy,
kanweg_home_uitgaantabel_kaart_component_copy, drawer_component_copy,
p_uitgaantabel_kaart_component_orgineel_met_kaartjeerin. 12 pagina's:
Event, FavorietenCopy, HorecagelegenhedenOverzichtCopy,
HorecagelegenhedenOverzichtCopy2, HorecagelegenhedenOverzichtCopy2Copy,
Kanweg, KanwegHomeCopy, KanwegHorecagelegenhedenOverzichtSortPage,
KanwegTestUpload, KanwegHorecagelegenhedenOverzicht,
KanweghorecagelegenhedenOverzichtCurrentCopy, KanweghorecagelegenheidCurrentCopy.
Begin met drawer_component_copy en kanweghorecagelegenheid_current_copy —
die twee houden KanwegHorecagelegenhedenOverzicht als enige nog in leven.
⚠️ HorecagelegenhedenOverzichtCopy2 pas weggooien als P2-6 af is (het is de
intacte momentopname waaruit het herstel van 09-01 is afgeleid), en de pagina
Event weigerde in augustus élke wijziging met "Invalid Action" — lukt die na
één poging niet, laten staan.
P1-30 · Cloudflare rate limiting aanzetten, en dan óók de twee
rate-limiting-vinkjes weghalen uit de custom rule flutterflow.
P2-25 · Cleanup custom.module — debugging alleen op devbob · Eigenaar:
Bob (Drupal-code, aangemaakt 2026-09-14). Vóór livegang moet de custom
module (custom.module + custom.evenementen_aanmaken.inc en de overige
.inc-bestanden die de flutterdrup-Services-resources voeden) goed
werken zonder overbodig te loggen. Nu zit er debug-uitvoer in die
tijdens het bouwen van P2-15/de favorieten handig was, maar op productie
alleen de watchdog/dblog volschrijft. Bewust pas aan het einde doen,
na de laatste functionele Drupal-wijzigingen — anders raak je de
debug-info kwijt terwijl je 'm nog nodig hebt.
Aanpak:
watchdog(...)/dpm(...)/error_log(...)/
drupal_set_message(...)-debugregels in de custom module
(grep -n "watchdog\|dpm(\|error_log\|drupal_set_message" custom.module *.inc).WATCHDOG_ERROR/WATCHDOG_WARNING)
en debug/trace (request-body dumps, "resource aangeroepen"-regels,
tussenwaarden).custom_debug (variable_get('custom_debug',
FALSE)) in een kleine helper _custom_debug($msg, $vars), zodat het
op productie standaard uit staat en op devbob met één
drush vset custom_debug 1 weer aan kan. Geen debug-code weghalen die
bij een storing op productie nog nuttig kan zijn — alleen uitzetten.print_r (r.791) en een print_r binnen
_custom_debug_watchdog (r.1948, gaat via de debug-schakelaar). Niets
dat de JSON kan vervuilen. Oud: nalopen dat er geen print/var_dump/dd() meer in staat die de
JSON-respons kan vervuilen (de app parst de body strikt; één regel
ervoor breekt getJsonField)._cb=$RANDOM-recept in CLAUDE.md) én dat de dblog na een testronde
in de app schoon blijft.
Hoort samen met P1-30 (Cloudflare) in dezelfde livegang-ronde.Max items + tab 6 (P2-24 A en C) — geparkeerd, zie daar. Melden bij FlutterFlow-support is de enige overgebleven route.
Afgerond 2026-09-11: taak 18 (route van drawer-item Horeca en van de
knop Alle horecagelegenheden omgezet naar horecagelegenhedenOverzichtCurrent,
beide met de plaats-binding op gemeenteSelectId opnieuw gezet — die wist
FlutterFlow bij een paginawissel; oude pagina hernoemd en naar kanweg
verplaatst) en taak 22 (label + uitlegzin bij het gemeentehartje, allebei
achter de login-guard).
Afgerond 2026-09-10: taak 16 (drie titels met onzichtbaar teken — geverifieerd: "Café Arnhem" staat nu alfabetisch juist), taak 17 (contentfoutjes), P0-13 (login-guards op de hartjes), P1-48 (lege-staat op de Home-tabs), en de horeca-sortering (alfabetisch, live).
#
P1-42. De uitgaanslijsten tonen
overwegend verlopen evenementen. Gevonden 2026-09-05 (Claude, live
curl tijdens P2-1-onderzoek), geldt voor flutterflowmobiel1
services_1/2/3 — de views waar Home zijn tabs mee vult.
page=40 levert nog steeds 25
items (eind mei), page=80 idem (half mei). Met infinite scroll aan
scrollt een gebruiker dus de geschiedenis in.created DESC (zichtbaar in Bob's
view-export van flutterflowmobiel_establishment_info, en het gedrag
van flutterflowmobiel1 past daarbij) — dus op wanneer iemand het
evenement invoerde, niet op wanneer het plaatsvindt. Dat verklaart
ook waarom de volgorde binnen een pagina rommelig is (95 van de 149
opeenvolgende paren staan op datum, de rest niet).datum >= vandaag én sorteer
oplopend op de datum-veldwaarde i.p.v. created DESC. Dan staat
het eerstvolgende evenement bovenaan en loopt scrollen de toekomst in.flutterflowmobiel1 filtert >= -2 hours en sorteert oplopend. Dit
punt gaat dus nog alleen over de vraag of dat overal doorwerkt.Audit afgerond 2026-09-06 (P1-43, Claude — live curl, 6 pagina's =
150 items per display, peildatum 6 sep 2026). Het probleem is NIET
beperkt tot services_1/2/3 — het raakt elke evenementenlijst in de app:
| view / display | waar in de app | verlopen | volgorde |
|---|---|---|---|
flutterflowmobiel1 services_1 |
Home-slider | 135/150 (90%) | 97/149 paren oplopend |
flutterflowmobiel1 services_2 |
Home-tabs (alle vijf, zie P1-44) | 142/150 (94%) | 87/149 |
flutterflowmobiel1 services_3 |
Uitgaan-tab + P-pagina's | 143/150 (95%) | 100/149 |
flutterflowmobiel1 services_4 |
Activiteiten-tab | 150/150 (100%) | 75/149 |
flutterflowmobiel1 services_5 |
Cultuur & Info-tab | 142/150 (94%) | 87/149 |
flutterflowmobiel1 services_6 |
Films-tab | 150/150 (100%) | 84/149 |
flutterflowmobiel1 services_7 |
Jeugd-tab | 149/150 (99%) | 89/149 |
flutterflow_events services_1 |
evenement-detail (op nid) | 117/150 (78%) | 102/149 |
flutterflowmobiel_establishment_events |
horeca-detail, agenda van de zaak | 42/97 (43%) | niet chronologisch |
flutterflowmobiel_establishments |
horeca-overzicht | n.v.t. (geen datum) | nid aflopend = nieuwste zaak eerst |
flutterfavorietenagenda |
Favorieten tab 1 | niet gemeten | niet gemeten |
Wat daar per regel bij hoort:
townid erbij wordt het erger, niet beter. services_3 met
townid=25434 (Arnhem) geeft over de volledige paginering 177
evenementen, waarvan 0 toekomstig; oudste 25 oktober 2025. Dat is
deels een inhoudsgat (Willemeen en Theater a/d Rijn hebben in
establishment_events óók geen toekomstige data), maar door
created DESC krijgt de bezoeker wel een pagina die volledig uit
verleden bestaat, zonder enige aanwijzing dat dat zo is.favorieten_agenda.json een 403 met body
["Toegang geweigerd voor gebruiker anonymous"]. drupalRequest maakt
daar (sinds de wijziging van 2026-08-17) een lege [] van, dus de app
crasht niet — maar een verlopen sessie ziet er in de app uit als "je
hebt geen favorieten", zonder melding. Klein los punt, niet dringend.audit/measure.py + run1..8.py); het is 20 regels en zo weer
opgetuigd — jaartal komt uit het /20xx/-segment van het url-veld,
want datum bevat geen jaar.Wat dit betekent voor de ingreep in Drupal: het is één patroon over
alle displays van flutterflowmobiel1 heen, plus
flutterflowmobiel_establishment_events. Zelfde fix (filter
datum >= vandaag, sorteren oplopend op de datumveldwaarde) op alle
zeven displays + de zaak-agenda in één ronde, en apart de vraag of het
horeca-overzicht niet gewoon alfabetisch moet.
P1-45 · Eigenaar: Bob (Drupal/views) — één restpunt: services_4 visueel
nakijken. Alle meetbare displays van flutterflowmobiel1 geven categorie
inmiddels als array (hermeten 12 en 13 sep). Alleen services_4
(stadsactiviteiten) is niet te meten omdat hij landelijk 0 items heeft; leg de
veldinstelling van categorie daar één keer visueel gelijk aan services_1.
Ter herinnering waarom het ertoe doet: HomeUitgaantabelKaartComponent doet
getJsonField(item, r'$.categorie').toList(), en op een String is dat een
stille NoSuchMethodError (grijs blok i.p.v. labels). De custom function
categorieAlsLijst mag blijven staan maar is niet te binden in Generate
Dynamic Children.
P2-24.
Pagina: horecagelegenhedenOverzichtCurrent. P2-6 heeft het zoekveld op 5
van de 6 tabs werkend en live op een toestel bevestigd (zie het
✅-blok bij P2-6). Dit zijn de punten die nog over zijn; ze hebben allemaal
Bob nodig — óf omdat Claude er aantoonbaar niet doorheen komt, óf omdat er een
keuze in zit. Het werkende recept per StaggeredView en alle valkuilen
staan bij P2-6; niet opnieuw uitzoeken.
⛔ A en C zijn geblokkeerd door één en dezelfde oorzaak — lees dit eerst (2026-09-09, Claude, hard gemeten).
Het Generate Dynamic Children-paneel schrijft op deze pagina niets meer weg. Dat is een nieuwe, veel bruikbaardere diagnose dan het oude verhaal ("de bron Custom Functions rendert zijn optielijst niet") — dat was een symptoom, niet de oorzaak. Het bewijs:
1000. Een verse export toonde in beide
gevallen onveranderd .take(25), zes keer. Leeg én een getal komen dus
allebei niet door — het ligt niet aan een lege waarde.Variable Name-veld, én via een selectiewissel in de widget tree: alle
drie geen verschil.TextFields (punt E) kwam op dezelfde dag wél gewoon door, net als de
hernummering van textController1 → textController die FlutterFlow
daarbij zelf doorvoerde.Gevolg: zowel punt A (tab 6 koppelen) als punt C (Max Items weghalen)
lopen via dit paneel en zijn daarmee niet uitvoerbaar. Bob heeft A twee keer
geprobeerd, Claude ~15 keer plus zes keer op Max Items; het bestand kwam elke
keer byte-identiek terug uit de export.
Duplicaat-test GEDAAN 2026-09-10 (Bob's akkoord) — en die werkt NIET.
Duplicate Page op Copy3 gaf horecagelegenhedenOverzichtCurrentCopy.
Daar meteen dezelfde ingreep geprobeerd: Max Items van 25 naar leeg op de
eerste StaggeredView; de UI toonde weer netjes "Leave empty for no
limit…". Verse export: 6× .take(25), precies als in het origineel.
De blokkade zit dus niet in de opgeslagen pagina-data — een verse
kopie erft 'm gewoon. Daarmee vervalt de beste hypothese en is er geen
route meer die Claude of Bob in de builder kan proberen.
⚠️ Opruimen: horecagelegenhedenOverzichtCurrentCopy moet weg (Bob —
Claude verwijdert niets). De pagina heeft verder niets gedaan en wordt
nergens naartoe genavigeerd; hij bestaat alleen als restant van deze test.
Toevoegen aan P2-7.
Wat dan wel: Bob's terugvaloptie van 2026-09-10 — "laten we dat probleem, max items, even voor wat het is; moeten we dat een punt maken voor de livegang." Dus A en C blijven open als livegang-punt. De enige overgebleven route is een melding bij FlutterFlow-support, want dit is aantoonbaar een bug aan hun kant: hetzelfde paneel accepteerde deze wijzigingen in september nog wél, en een ander paneel op precies dezelfde widget (Empty List Widget, zie P1-46) schrijft gewoon weg.
A. Tab 6 (Verhuur, catering) alsnog koppelen. De enige StaggeredView die
nog op de rauwe API-respons staat; alle andere vijf draaien op
filterHorecagelegenheden(...). Recept staat bij P2-6, met
items = alleVerhuurCatering.
⚠️ Claude komt hier niet doorheen — twee sessies, ~15 pogingen: in de
Set-Variable-dialoog van uitgerekend deze ene StaggeredView rendert de bron
Custom Functions zijn optielijst nooit. Uitklappen lukt (chevron slaat om),
maar de rij filterHorecagelegenheden eronder verschijnt niet — niet na
hoveren, niet na blind klikken op de verwachte positie, niet na de dialoog te
sluiten en te heropenen, en niet na een volledige herlaad van de builder. Op
de andere vijf tabs werkte exact dezelfde reeks wél. Niets kapot: de tab staat
gewoon nog op zijn oorspronkelijke binding en werkt zoals voorheen.
B. Categoriedropdown (was P2-6 stap 4) — eerst een ontwerpkeuze van Bob,
daarna kan Claude bouwen. Er is een custom function nodig die de unieke
categorie-waarden uit de dataset haalt. Claude heeft die bewust nog NIET
aangemaakt: er zit een productkeuze in, en een eenmaal aangemaakte custom
function kan Claude niet meer verwijderen (staande regel). Twee varianten:
alleXxx-lijsten +
TabBar Current Index (Widget State) + het pad = 8 argumenten. De
dropdown toont precies de categorieën van de zichtbare tab. Nadeel: 8
bindingen in juist die dialoog die bij punt A vastliep.Column is bewezen werkend, net als bij het zoekveld).
⚠️ categorie is in de API een LIJST, geen string — bevestigd 2026-09-05
met curl op Arnhem (townid=25434): "categorie": ["Bioscoop"]. De bestaande
filterHorecagelegenheden gaat daar al goed mee om, maar de nieuwe
unieke-categorieën-functie moet de binnenlijst plat slaan en niet
.toString() op het hele veld doen — anders krijg je opties als [Bioscoop]
die nooit matchen. Aantallen in Arnhem: Activiteiten 2 items / 2 categorieën,
Eetgelegenheden 20 / 19, Uitgaan 4 / 4.C. Max Items staat per tab op 25 — Bob's besluit 2026-09-09: weghalen.
⛔ Geblokkeerd, zie het kader hierboven. Dit is een ECHTE blocker, geen
cosmetiek. Gemeten op productie in Amsterdam (townid=28695):
| tab | items | zichtbaar met take(25) |
|---|---|---|
| Eetgelegenheden | 245 | 25 |
| Uitgaan | 75 | 25 |
| Activiteiten | 42 | 25 |
| Overnachten | 42 | 25 |
| Verhuur, catering | 24 | 24 |
| Cultuur | 14 | 14 |
⚠️ CORRECTIE 2026-09-10 op een eerdere bewering hier: het zoekveld
doorzoekt WÉL de volledige lijst. De gegenereerde code is
filterHorecagelegenheden(<volledige lijst>, zoekterm, …).toList().take(25).toList()
— dus eerst filteren over alle 245, dán afkappen. Zoek je "pizza" in
Amsterdam, dan worden alle 245 doorzocht en zie je de eerste 25 treffers.
De eerdere formulering "het zoekveld doorzoekt alleen die 25" was fout.
Wat er wél overblijft: zonder zoekterm zie je 25 van de 245 en kun je
niet doorbladeren, want deze pagina heeft geen pager — geverifieerd: 0
PagedMasonryGridView, 0 PagingController, 0 infinite scroll, zes
gewone MasonryGridView. De infinite scroll is er bij P2-6 bewust
uitgehaald omdat client-side filteren de volledige dataset nodig heeft.
In Amsterdam/Eetgelegenheden zijn 220 zaken dus alleen via het zoekveld
bereikbaar, niet door te scrollen.
(Een eerdere inschatting "je merkt er weinig van" was gebaseerd op Arnhem,
grootste tab 20 items. Te klein om iets over limieten te zeggen; gebruik
voortaan Amsterdam.)
Haalbare verzachting zolang take(25) vastzit — voorstel voor Bob:
sorteer de lijst in fetchAlleHorecagelegenheden (een custom action,
en de Custom Code-editor werkt gewoon). Nu is de volgorde die van de view
(nid aflopend), dus je krijgt 25 min of meer willekeurige zaken.
Alfabetisch gesorteerd krijg je 25 voorspelbare, en samen met het zoekveld
is dat werkbaar. Dit dekt meteen de openstaande wens "Horeca-overzicht
sorteren" (zie de wachtrij bovenaan) zónder dat de Drupal-view aangepast
hoeft te worden.
Weghalen is veilig zodra het kan: er is al een harde begrenzing elders
(fetchAlleHorecagelegenheden loopt door API-pagina's van 100 met
maxPaginas = 10, dus max 1000 per tab), en alle zes de grids zijn
MasonryGridView.builder — lazy, dus alleen zichtbare kaarten worden
gebouwd. Er is geen paginering/infinite scroll meer op deze pagina (0
PagingControllers); dat is bewust, want client-side filteren kan alleen met
de volledige dataset. Wil je ooit strakker begrenzen, doe dat in
maxPaginas, niet in de weergavelimiet.
D. Route omzetten (was P2-6 stap 7) — bewust uitgesteld tot A en B klaar
zijn. Twee Navigate To-wijzigingen naar horecagelegenhedenOverzichtCurrent:
lib/shared/drawer_component/drawer_component_widget.dart en
lib/horecagelegenhedenoverzicht/horecagelegenheid_current/horecagelegenheid_current_widget.dart.
Daarna wordt de oude HorecagelegenhedenOverzicht een orphan → toevoegen aan
P2-7. Ook Copy3 heet dan nog "Copy3" terwijl het de levende pagina is;
hernoemen of niet is Bob's keuze.
E. Twee lege TextField-placeholders opruimen. In tab 0 (Activiteiten) en
tab 1 (Cultuur) staat nog het oude, ongebonden TextField met hint letterlijk
"TextField". Op een toestel is dat een zwevend wit vak dat half over de
TabBar valt — lelijk en verwarrend naast het echte zoekveld. De eerdere
afspraak "laten staan tot P2-6 ze van een echte binding voorziet" is hiermee
afgehandeld: het echte zoekveld staat nu bóven de TabBar, dus deze twee zijn
overbodig. Claude verwijdert niets.
F. Duplicaten in Drupal (los van de app, eigen afweging). Voor Arnhem/Eetgelegenheden staan dezelfde zaken dubbel in de view, met verschillende categorie-sets: nid 53455 en 50584 heten allebei "New York Pizza Arnhem Zuid", nid 53454 en 50583 allebei "New York Pizza Arnhem Centrum". De app toont ze dus terecht dubbel; het zit in de data.
Niet oplosbaar, geaccepteerd: FlutterFlow zet op de On Change-trigger
zelf een EasyDebounce van 2000 ms en die is nergens instelbaar (geen
debounce-eigenschap op het widget, en de trigger-/actiemenu's bieden 'm
niet). Live merkbaar: de lijst ververst ~2 s nadat je stopt met typen. Werkt
correct, voelt traag.
Volledig doorgemeten 2026-09-12 20:50, terwijl je import liep (2963 unieke
events op dat moment). Methode: alle zeven displays volledig gepagineerd en de
nids vergeleken met de complete voorraad uit flutterflow_events.
| aantal | |
|---|---|
| komende events (start ≥ nu − 2 uur) | 58 |
| zichtbaar in minstens één tab | 51 |
| in geen enkele tab | 7 (12%) |
De zeven, om na te lopen:
13 sep 14:00 nid 214441 Zeddam Ferme Jongus – Nederpop op volle kracht!
13 sep 15:30 nid 214463 Den Haag Dr Ewa Woydyłło (Unique Performance)
15 sep 20:30 nid 214456 Rotterdam She Her Her Hers
15 sep 21:00 nid 214455 Rotterdam Renny Conti
19 sep 09:00 nid 214439 Alblasserdam Brocante Markt Klein Frankrijk
20 sep 13:30 nid 214474 Almere-Stad Het Danspaleis
23 sep 20:30 nid 214476 Amersfoort Feest
Zes daarvan hebben helemaal geen categorie; de zevende (214439) heeft
Tweedehands markt, en dat is de enige categorie in de hele voorraad die geen
enkele display raakt.
Categorie → tab, zoals het nu feitelijk werkt (gemeten, niet uit de viewconfig afgelezen):
| categorie | komt in |
|---|---|
| Voorstelling (41x) | Uitgaan, Cultuur & Info, Films |
| Theater (35x) | Uitgaan, Cultuur & Info, Films, Jeugd |
| Muziek (28x) | Uitgaan, Cultuur & Info |
| Cabaret (21x), Toneel (9x), Theatercollege (3x), Circus (3x), Stand-up comedy (3x) | alleen Cultuur & Info |
| Kindvriendelijk (16x), Jeugd (12x), Muziektheater (4x) | Cultuur & Info, Jeugd |
| Dansvoorstelling (4x), Film (4x) | Cultuur & Info, Films |
| Live/Concert (8x), Pop (2x), Rock/Punk (2x), Dance/House (2x) | alleen Uitgaan |
| Tweedehands markt (1x) | nergens |
Goed nieuws: er is dus maar één categorie zonder tab. Het echte lek zijn de events zónder categorie.
Twee dingen te beslissen:
⚠️ Let op bij het narekenen: classificeer op datum + tijd, niet op datum
alleen. Ik telde eerst 10 onzichtbare events; drie daarvan waren van vandaag en
al begonnen (10:00 en 14:00, gemeten om 20:50) en worden dus terecht door het
>= -2 hours-filter weggelaten. Op datum alleen lijken die ten onrechte
"toekomstig".
📌 services_4 (Activiteiten) staat op 0 en dekt geen enkele categorie — dat
zijn stadsactiviteiten, die worden handmatig aangemaakt en niet geïmporteerd.
Geen bug.
#
launchURL-aanroepen in
levende code hangen achter een guard op de rauwe waarde, niet op een
valueOrDefault.EstablishmentInfo geeft precies één rij per zaak (60 Amsterdamse zaken
getest). De zes $[:].veld-knoppen op de detailpagina leunen daarop; let op
zodra er een multi-value veld aan die view wordt toegevoegd.categorie is op alle zeven flutterflowmobiel1-
displays altijd een lijst (65 records gemeten).SliderUitgaanComponentSmallCurrent negeert zijn eigen
townid/displayid (P1-44-patroon), maar heeft nul gebruikers — geen
impact, alleen niet inzetten zonder dat eerst te repareren.fillColor op de twee aanmaakpagina's is al goed: zowel
stadsactiviteitAanmaken (18 widgets) als uitgaansevenementAanmaken (11)
staat volledig op primaryBackground. Het in CLAUDE.md voorspelde
secondaryBackground-defaultprobleem is dus niet meer aanwezig.$.categorie is op de Home-displays nooit leeg of afwezig (services_1/3/5,
Amsterdam, 25 items elk: altijd een lijst). De .toList() zonder true op
home_uitgaantabel_kaart_component_widget.dart:651 kan daardoor in de praktijk
niet crashen — events zonder categorie halen de displays sowieso niet.EvenementInfo (6 van de 12,
nagemeten en juist), de wees hierboven, en
HorecagelegenheidoverzichtKaart.nid (restant van het verwijderde hartje).node.title, een spatie komt
vóór de A). De eerste kaarten die een gebruiker ziet zijn dus willekeurig.android/ heeft geen ongecommitte
wijzigingen meer en de vastgelegde waarden zijn minSdkVersion
flutter.minSdkVersion (= 24) en tasks.register("clean", Delete) — precies
de moderne variant. Het punt is dus vanzelf beslecht; niemand hoeft hier nog
iets aan te doen.flutterflowmobiel1 opruimen (was taak 46): GESCHRAPT op Bob's verzoek.
services_2 bestaat nog (25 items) maar heet "ongebruikt" en blijft staan
tot een schoonmaakronde.| 09-13 | 09-14 | |
|---|---|---|
unieke events (flutterflow_events) |
9625 | 16.065 (18.207 rijen) |
| toekomstige events | 38 | 6.202 |
| laatste datum in voorraad | 25 sep | 10 jan 2027 |
| per maand | — | sep 1487 · okt 2297 · nov 1412 · dec 894 · jan 112 |
Het contentgat is dicht — de import levert nu maanden vooruit. De zeven
flutterflowmobiel1-displays zijn schoon: 0–5 verlopen items per display op
duizenden rijen (Uitgaan 3275, Cultuur 4654, Films 702, Jeugd 535,
Activiteiten 100). P1-42 (lijsten vol verlopen events) is daarmee feitelijk
opgelost.
Wat nog niet in de app komt: 622 van de 6.202 komende events (10%).
HTML-entiteiten (taak 29): titels en adressen zijn nu schoon (0 van 6.202
komende events). body heeft er nog 2.570, maar die gaat in de app door de
custom widget FromHTML en rendert dus goed. Enige rest: 55 records met een
entiteit in categorie (Hiphop/Rap/R&B, DJ's) — die staan
letterlijk in het groene label. Kleine Drupal-fix op het categorie-veld van
flutterflow_events.
Duplicaten (taak 30): 2.095 nids komen meer dan één keer terug (2.142 overtollige rijen) — onveranderd, en nog steeds onzichtbaar in de app.
Meetscript: fetch.py + analyse.py (Nederlands én Engels datumformaat,
jaar uit de weekdag) — stond in de scratchpad van deze sessie; recept staat in
CLAUDE.md.
#
flutterflow_events — bekend, geen impactNid 214439 ("Brocante Markt Klein Frankrijk") komt 14 keer identiek terug
in flutterflow_events; 214441 en 214420 elk 3x, 214367 2x. Op 2026-09-12
onveranderd (18 overtollige rijen op 2025).
✅ Maar het bereikt de app niet. Nagemeten 2026-09-12:
flutterflowmobiel1 heeft géén duplicaten: services_1/2/3/5/7 geven
allemaal evenveel rijen als unieke nids. Node 214439 komt er zelfs
helemaal niet in voor (zijn categorie "Tweedehands markt" valt onder geen
enkele display — dat is taak 28, niet deze).flutterflow_events wordt door de app alléén per nid bevraagd
(EvenementCall.call(nid: ...), vanuit evenement_component en
event_current). Er wordt nergens een lijst uit opgebouwd: de twee
iteraties in dat component lopen over fotoos en categories binnen één
event, niet over de rijen.Gevolg: geen zichtbare schade, geen haast. Het blijft wel iets om te weten:
bouwt er ooit iemand een lijst op deze view, dan komt zo'n node 14x in beeld.
De oorzaak is het klassieke Views-patroon "een veld met meerdere waarden krijgt
een eigen rij" — kijk op node 214439 welk veld 14 waarden heeft en zet
Multiple field settings → Display all values in the same row aan.