Bläddra i källkod

TASKS.md: reviewsessie 2026-08-12 - nieuwe P0-7 (horecagelegenheid-infodata structureel leeg op 2 geteste gelegenheden), P1-20 (Home terug-knop-regressie via gedeelde HeaderButtonsComponentWidget, blokkeert soms hamburger), P1-21 (AdBanner op PUitgaanPage toont developer-debugtekst), P1-22 (decodeUtf8:false op alle API-calls -> emoji worden '?'); P1-19 uitgebreid met 8 nieuw gevonden zusterinstanties van de tag-Row-overflow-bug (Home/PUitgaanPage/EventCurrent/HorecagelegenheidCurrent); P1-13 live herbevestigd nog open; kruisverwijzingen bij P0-5 (hardcoded Basic-Auth) en P1-6.

CLAUDE.md: eerder vandaag (2026-08-11) toegevoegde documentatie (workflow-volgordevoorkeur, widget-tree-nesting-vuistregel, ConditionalBuilder-klikpad, List-Contains-Item-patroon) alsnog gecommit - was blijven staan als ongecommitte wijziging van een eerdere sessie.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
bob 1 månad sedan
förälder
incheckning
28b1213aa3
2 ändrade filer med 329 tillägg och 14 borttagningar
  1. 49 0
      CLAUDE.md
  2. 280 14
      TASKS.md

+ 49 - 0
CLAUDE.md

@@ -112,6 +112,12 @@ bekende clipping-gevallen).
    pre-verifiëren (is hij nog steeds nodig, of intussen al door iemand
    anders/een eerdere sessie opgelost?) — scheelt een aparte
    heen-en-weer ronde.
+6. **Bob's expliciete volgorde-voorkeur (2026-08-11): eerst de
+   volgende taak geven, dán pas de vorige verifiëren** — niet
+   andersom. Bob wil na het melden van "gedaan" meteen door kunnen
+   bouwen i.p.v. te wachten tot Claude klaar is met verifiëren; de
+   verificatie van de zojuist afgeronde stap mag daarna, gerust
+   gecombineerd met de volgende voortgangsmelding.
 6. Bob geeft na afronding van een cluster ook een eigen commit in
    FlutterFlow's interne versiebeheer ("main"/"Synced" bovenin) — los
    vangnet naast Claude's export-verificatie.
@@ -352,6 +358,49 @@ dat al bevestigd werkt.
 
 ## FlutterFlow-builder: bekende problemen & patronen
 
+**Widget Tree-nesting nooit uit een codefragment afleiden — altijd de
+tree/screenshot als bron van waarheid gebruiken.** Bevestigde misser
+(2026-08-11, `HorecagelegenheidoverzichtKaartWidget`): op basis van een
+gedeeltelijke `Read` (alleen regels 280-343) leek de hartje-
+`AlignedTooltip` genest in de `Stack` (samen met de afbeelding/
+categorie-tags), puur op basis van de zichtbare inspringing in dat
+fragment. Bob's eigen widget-tree-screenshot liet zien dat `Tooltip`
+in werkelijkheid een **directe sibling van `Stack`** is (beide
+rechtstreeks kind van `Row`), niet genest erin — de inspringing in een
+afgekapt codefragment is geen betrouwbare graadmeter voor nesting
+zonder de volledige haakjes-balans te checken. **Vuistregel:** geef
+builder-pad-instructies pas na het zien van een tree-screenshot (of een
+volledige, haakjes-sluitende `Read` van het component), niet op basis
+van een korte code-`grep`/fragment-inferentie — bij twijfel eerst om een
+screenshot vragen i.p.v. te gokken.
+
+**ConditionalBuilder instellen na een Wrap Widget: klik op de
+`ConditionalBuilder`-rij zelf, niet op `If`.** Na "Wrap Widget →
+ConditionalBuilder" selecteert de builder automatisch de `If`-tak
+(teal gemarkeerd) zodat je meteen widgets in de THEN-kant kan zetten —
+maar dat rechterpaneel toont dan de If-tak-eigenschappen, niet de
+conditie zelf. Klik op de **`ConditionalBuilder`**-rij (één niveau
+hoger in de tree) om de sectie **"Conditions" → "Add Condition" →
+"Single Condition"** (First Value/Operator/Second Value) te krijgen.
+
+**Checken of een `List<String>` App State-variabele een waarde bevat
+("bevat dit item?"): geen aparte condition-operator, maar een
+transform binnen "Set from Variable".** Bevestigd 2026-08-11 op
+`favorieteHorecaNids` (First Value van een Single Condition, Type:
+Boolean): klik het Value-icoontje → **Set from Variable** → kies de
+App State-lijst-variabele als bron → het **"Available Options"**-dropdownmenu
+(zelfde UI-plek als de al bekende JSON-Path-optie, zie hieronder) biedt
+dan lijst-transforms: **List Contains Item**, Filter List Items, Item at
+Index, First Few Items, Is Set and Not Empty, Sort List Items, Unique
+List Items, Number of Items. Kies **"List Contains Item"** → vul het
+item-veld dat verschijnt met de te zoeken waarde (bv. een Component
+Parameter zoals `nid`) → dit levert een Boolean terug. Terug in de
+Single Condition: Operator **"Equal to"**, Second Value = literal
+**`true`**. **Dit patroon komt vaker terug** (favoriete-lijst-checks op
+meerdere plekken) — niet opnieuw naar een "Contains"-operator in de
+conditie zelf zoeken, die bestaat niet; ga altijd via deze
+Set-from-Variable-transform-route op de lijst-variabele.
+
 **Rechterpaneel-clipping: gebruik de "Search properties..."-zoekbalk
 i.p.v. scrollen.** Het rechterpaneel (Widget Tree → property-editor)
 scrollt via browser-automation vaak niet (muiswiel-events lijken geen

+ 280 - 14
TASKS.md

@@ -1,11 +1,34 @@
 # Uitgaanskrant — takenlijst
 
-Bijgewerkt: 2026-08-10, avond (Claude, live pair-sessie met Bob in de
-builder). Zie `CLAUDE.md` voor werkinstructies/conventies. Elke
-openstaande taak hieronder is zelfstandig te begrijpen zonder de chat
-gelezen te hebben waarin hij ontstond.
+Bijgewerkt: 2026-08-12 (Claude, "ogen van een gebruiker"-reviewsessie).
+Zie `CLAUDE.md` voor werkinstructies/conventies. Elke openstaande taak
+hieronder is zelfstandig te begrijpen zonder de chat gelezen te hebben
+waarin hij ontstond.
 
-**Deze sessie (2026-08-10, avond):** live pair-sessie — Bob deed alle
+**Deze sessie (2026-08-12, review):** volledige gebruikersdoorloop op
+een **verse build** (`ff-run-fvm.sh`, geïnstalleerde app was nog van
+2026-08-09 en dus stale t.o.v. alle fixes van 2026-08-10/11) langs de
+5 gevraagde gebieden: overzichtspagina (Home), horecaoverzicht
+(`HorecagelegenhedenOverzicht`), evenement (`EventCurrent` +
+`EvenementHorecagelegenheid`), pagina (`PUitgaanPage`) en
+horecagelegenheidpagina (`HorecagelegenheidCurrent`), gecombineerd met
+een code-audit van diezelfde bestanden. **4 nieuwe bevindingen
+toegevoegd:** nieuwe **P0-7** (horecagelegenheid-infodata blijkt
+structureel leeg — bevestigd op 2 verschillende gelegenheden, geen
+toeval), nieuwe **P1-20** (Home's al-verwijderd-gewaande terugknop is
+terug via een hergebruikt component en blokkeert soms de hamburger),
+nieuwe **P1-21** (AdBanner op `PUitgaanPage` toont developer-debugtekst
+aan echte gebruikers), nieuwe **P1-22** (`decodeUtf8: false` op alle
+API-calls → emoji in Drupal-content worden `?`-tekens). **P1-19**
+uitgebreid met 8 nieuw gevonden zusterinstanties van hetzelfde
+"kale Row zonder Wrap"-categorietag-patroon, nu bevestigd op exact de
+pagina's uit deze review (Home, PUitgaanPage, EventCurrent,
+HorecagelegenheidCurrent). **P1-13 live herbevestigd** — nog steeds
+kapot (1529px-overflow op de Activiteiten-tab), geen voortgang t.o.v.
+2026-08-10. Zie de individuele taken hieronder voor bewijsvoering
+(screenshots/log-regels/broncoderegels).
+
+**Eerdere sessie (2026-08-10, avond):** live pair-sessie — Bob deed alle
 builder-edits zelf, Claude gaf per punt de exacte stappen en
 verifieerde daarna elke edit met een verse `flutterflow export-code`
 + grep (niet op de builder-UI zelf vertrouwd). **9 taken écht afgerond
@@ -189,7 +212,89 @@ favorieten drawer-link + 3-tabblad-pagina, hartje op horeca-kaart +
   `kanweg`-testpagina) bevestigt.
 
 **P0-5 · Eigenaar: Bob.** Drupal: anonieme leestoegang onderzoeken
-voor browse-endpoints. Drupal-niveau, geen Claude-taak.
+voor browse-endpoints. Drupal-niveau, geen Claude-taak. **Bijvangst
+2026-08-12 (Claude, code-audit):** alle API-calls in `api_calls.dart`
+(o.a. `EstablishmentInfoCall`, `EstablishmentsCall`) sturen een
+**hardcoded Basic-Auth-header mee** (`Authorization: Basic
+Ym9iOnNlcmhpaQ==`, decodeert naar `bob:serhii`) — dit staat letterlijk
+in de gecompileerde APK en is dus met een gratis decompiler
+(bv. `jadx`) door iedereen uit te lezen. Neem dit mee in de
+P0-5-afweging: als het achterliggende Drupal-account meer kan dan
+alleen lezen (bv. schrijven t.b.v. de favorieten-sync uit P1-7), is dit
+een device-brede, niet-intrekbare credential zolang de app in de wild
+is. Oplossing hangt af van wat P0-5 uitwijst (anonieme leestoegang zou
+dit hele Basic-Auth-blok overbodig maken).
+
+**P0-7 · Eigenaar: Onbepaald (onderzoek nodig vóór builder-fix).**
+Horecagelegenheid-infodata (titel/inhoud/logo) komt **structureel niet
+aan** — bevestigd 2026-08-12 op een verse build, live op 2 verschillende
+gelegenheden (niet 1 incident):
+- **`HorecagelegenheidCurrent`** (horecagelegenheidpagina, bereikt via
+  `HorecagelegenhedenOverzicht` → kaart tikken): zowel bij "De Beun"
+  (Heiloo) als "Hotel Den Helder" bleef de infosectie **permanent**
+  (8+ seconden gewacht, geen verandering) op de letterlijke
+  design-time placeholders staan: kop toont **"title"**, body toont
+  **"content"**, logo toont een **kapot-plaatje-icoon** (rode
+  driehoek). Dit zijn dezelfde velden als P1-6's al gedocumenteerde
+  `horecagelegenheid_current_widget.dart:377/500/747`
+  (titel/logo/content) — **maar dit weerlegt P1-6's aanname dat het om
+  incidentele ontbrekende data gaat**: het gebeurde bij *beide* geteste
+  gelegenheden, terwijl een ándere sectie op diezelfde pagina (de
+  "events op deze locatie"-carousel onderaan) voor "Hotel Den Helder"
+  wél gewoon echte, gelegenheid-specifieke data toonde. Een betere
+  Default-Value-tekst (P1-6's voorgestelde fix) verhelpt dus niets
+  hier — de onderliggende data komt al niet aan.
+- **`EvenementHorecagelegenheid`** (embedded op `EventCurrent`, bv. bij
+  evenement "Mythic Fest II", nid `214370`, alleen zichtbaar als het
+  evenement een `horecaid` heeft): toont **"HorecaNaam"** (letterlijke
+  fallback-tekst, niet ingevuld) i.p.v. een echte gelegenheidsnaam, plus
+  een forse layout-overflow. In de `flutter run`-log verschijnen hierbij
+  herhaaldelijk (in bursts van 3, telkens gelijktijdig met deze sectie):
+  ```
+  Another exception was thrown: RangeError (length): Invalid value: Valid value range is empty: 0
+  Another exception was thrown: A RenderFlex overflowed by 109 pixels on the bottom.
+  Another exception was thrown: Invalid argument(s): No host specified in URI Logo
+  ```
+  Geen volledige stack trace gevangen deze sessie (het "1x volledige
+  dump per proceslevensduur"-limiet, zie `CLAUDE.md`, werd al verbruikt
+  door Home's eigen overflow vóór deze pagina bereikt werd; een gerichte
+  herhaling met `--route "/eventCurrent?nid=214370&horecaid=<echte
+  id>"` ná een schone process-start zou de exacte regel moeten opleveren
+  — nid `214370` zonder `horecaid` reproduceert de crash niet, dus de
+  volgende poging heeft een evenement met een **wél ingevulde**
+  `horecaid` nodig, bv. via de widget-tree of een gerichte API-check
+  welk evenement een horecaid heeft).
+- **Nog niet hard bevestigd, wel plausibele kandidaat-oorzaken (verder
+  onderzoek nodig vóór een builder-fix zin heeft):**
+  1. `EstablishmentInfoCall`'s JSONPath-expressies
+     (`r'''$[:].nid'''`/`titel`/`content`/etc.,
+     `lib/backend/api_requests/api_calls.dart:925` e.v.) versus de
+     werkelijke vorm van de Drupal-JSON-respons — als de respons niet
+     een array-met-1-object is zoals verwacht, levert `getJsonField`
+     stilzwijgend `null` (geen crash, geen foutmelding) en valt alles
+     terug op de design-time placeholder.
+  2. De `nid` die de overzicht-kaart doorgeeft bij navigatie
+     (`horecagelegenheden_overzicht_page_data_type_widget.dart:397-403`
+     en de 5 vergelijkbare blokken verderop in hetzelfde bestand, regel
+     606/790/974/1158/1342) gebruikt
+     `getJsonField(item, r'''$.nid''').toString()` — als het onderliggende
+     veld `null` is, geeft Dart's `null.toString()` de **letterlijke
+     string `"null"`** terug (geen exceptie), die dan als een
+     "geldige" nid wordt doorgegeven aan `EstablishmentInfoCall`. Let
+     op: dit verklaart *niet zonder meer* waarom de events-carousel op
+     dezelfde pagina wél de juiste gelegenheid vond (die lijkt een
+     eigen/werkende nid-scoping te hebben) — dus mogelijk is dit niet
+     de (enige) oorzaak; vandaar "kandidaat", niet "bevestigd".
+  - **Aanbevolen volgende stap:** één gelegenheid opzoeken waarvan de
+    echte `nid` bekend is (bv. via Widget Inspector/`View Code` of een
+    directe Drupal-check) en `EstablishmentInfoCall`'s endpoint
+    (`https://uitgaanskrant.com/en/flutterdrup/views/flutterflowmobiel_establishment_info.json?display_id=services_1&nid=<echte-nid>`)
+    los curlen (met de Basic-Auth-header uit P0-5's bijvangst) om te
+    zien of de JSON-vorm klopt met wat `EstablishmentInfoCall`
+    verwacht — dat scheidt kandidaat 1 en 2 definitief. **P0** omdat
+    dit een kernpagina raakt (horecagelegenheidpagina) die voor
+    *iedere* bezochte gelegenheid vrijwel leeg oogt voor een
+    eindgebruiker.
 
 ## P1 — snel na livegang
 
@@ -252,7 +357,11 @@ gezien de omvang hieronder (~45 treffers); pak het file-voor-file op.
   (317/339 zijn **nieuw t.o.v. de 2026-08-04-audit**, waren toen nog
   niet aanwezig of gemist)
 - `horecagelegenheid_current_widget.dart:377/500/747` — title/logo/content
-  (**volledig nieuw gevonden, stond niet in de vorige audit**)
+  (**volledig nieuw gevonden, stond niet in de vorige audit**). **Zie
+  P0-7:** deze 3 velden bleken 2026-08-12 live op *elke* geteste
+  gelegenheid permanent op de placeholder te blijven staan (niet
+  incidenteel) — een betere Default-Value-tekst alleen lost dat niet
+  op, eerst P0-7's onderliggende data-probleem oplossen.
 - `event_current_widget.dart:327/418/442` — title/nid/date (327 en 442
   zijn **nieuw t.o.v. de 2026-08-04-audit**, alleen nid stond er al in)
 - `evenement_horecagelegenheid_widget.dart` — **grootste blok, ~30
@@ -477,13 +586,18 @@ CachedNetworkImage/P1-15-patroon. Bevestigd via verse export:
 guard. Uit deze lijst verwijderd.)*
 
 **P1-13 · Eigenaar: Bob (geblokkeerd op een bevestigd FlutterFlow-
-platformprobleem, geen Claude-taak meer totdat dat opgelost is).** Root
-cause + fix zijn bekend en juist toegepast in de builder (door zowel
-Claude als Bob, op zowel 1 als meerdere tabs), maar de wijziging
-bereikt **nooit** de export — zie de uitgebreide blocker-documentatie
-hieronder. Volgende stap is bij Bob: Issues-paneel checken, de
-alternatieve SingleChildScrollView-route proberen, of FlutterFlow-
-support contacteren. Op `HorecagelegenhedenOverzicht` → tab "Activiteiten" overflowt de
+platformprobleem, geen Claude-taak meer totdat dat opgelost is).**
+**Live herbevestigd 2026-08-12 (Claude, verse build, telefoonformaat
+emulator-5554):** nog steeds kapot, exact zoals hieronder beschreven —
+"BOTTOM OVERFLOWED BY 1529 PIXELS" op de Activiteiten-tab, zichtbaar
+al na de 2e rij kaartjes, geen scroll mogelijk voorbij dat punt. Geen
+voortgang t.o.v. 2026-08-10, geen nieuwe informatie deze sessie — puur
+een bevestiging dat de taak actueel blijft. Root cause + fix zijn bekend
+en juist toegepast in de builder (door zowel Claude als Bob, op zowel 1
+als meerdere tabs), maar de wijziging bereikt **nooit** de export — zie
+de uitgebreide blocker-documentatie hieronder. Volgende stap is bij
+Bob: Issues-paneel checken, de alternatieve SingleChildScrollView-route
+proberen, of FlutterFlow-support contacteren. Op `HorecagelegenhedenOverzicht` → tab "Activiteiten" overflowt de
 kaartjesgrid. **Root cause definitief bevestigd
 (2026-08-09, Claude, verse volledige stack trace + visuele bevestiging
 op emulator-5554):**
@@ -728,6 +842,49 @@ laatste twee) — bij het oppakken van deze taak even meenemen.**
   regel 178-179, `mainAxisSize: MainAxisSize.min`, geen Wrap/Expanded).
   Kleiner overflow (2.4px, minder zichtbaar dan Home's 113px) maar
   zelfde onderliggende bug — zelfde fix-aanpak (Wrap i.p.v. Row).
+- **Scope definitief bevestigd veel breder (2026-08-12, Claude,
+  code-audit + live herbevestiging van het Home-exemplaar op een verse
+  build): hetzelfde kale-`Row`-met-`List.generate`-zonder-Wrap-patroon
+  zit in minstens 8 andere, live bereikbare plekken** — dit was expliciet
+  de "nog niet gecheckt"-vraag die deze taak zelf al openliet. Overal
+  identiek: `Row(mainAxisSize: MainAxisSize.max, children:
+  List.generate(<lijst>.length, ...))` zonder `Wrap`/scroll/`Expanded`
+  per item.
+  - `event_current_widget.dart:501` — categorie-tags **op EventCurrent
+    zelf** (de evenement-detailpagina's eigen kop-tags, niet een
+    subcomponent).
+  - `evenement_horecagelegenheid_widget.dart:221` (categoriehoreca),
+    `:1388` (afhaalopties), `:1477` (afhaalbetaalopties), `:1539`
+    (bezorgtin) — 4 aparte instanties in **hetzelfde bestand** als
+    P1-15's knoppen-crash, embedded op `EventCurrent` en
+    `HorecagelegenheidCurrent`.
+  - `horecagelegenheid_current_widget.dart:710` — cryptocoins-Row op de
+    horecagelegenheidpagina zelf (Bezorgen-tab).
+  - `uitgaantabel_kaart_component_widget.dart:261` — gebruikt
+    rechtstreeks op zowel **Home** als **PUitgaanPage**
+    (`UitgaantabelKaartComponentWidget(...)` in beide widgetbestanden).
+  - `p_uitgaantabel_kaart_component_widget.dart:307` — gebruikt op
+    **PUitgaanPage**.
+  - (`kaart_tabel_uitgaan_comp_widget.dart:176`,
+    `kaart_tabel_uitgaan_s_comp_widget.dart:208`,
+    `kaart_slider_uitgaan_s_comp_widget.dart:246` hebben het patroon
+    ook, maar hun aanroeppad loopt uitsluitend via
+    `uitgaan_tabel_component`/`_small`/`slider_uitgaan_component_small_current`,
+    die op hun beurt nergens buiten `lib/kanweg/` geïnstantieerd worden
+    — **niet live bereikbaar**, dus geen prioriteit, hooguit
+    meenemen bij een eventuele latere opschoning/hergebruik.)
+  - `evenement_component_widget.dart:284` heeft het patroon ook, maar
+    `EvenementComponent` wordt alleen gebruikt door de orphan
+    `EventWidget`-route (zie P2-7) — pas relevant als die route ooit
+    weer aangesloten wordt.
+  - **Praktisch gevolg voor de fix-volgorde:** dit is geen
+    "1-2 rijen aanpassen"-taak meer maar een terugkerend
+    FlutterFlow-generatiepatroon over minstens 6 live bereikbare
+    plekken. Overweeg met Bob of dit github-issue-gewijs 1-voor-1
+    (zoals nu gepland) of als bulk-sessie aangepakt wordt — de
+    builder-stap is overal identiek (Wrap Widget → Wrap), dus als het
+    Wrap-Widget-menu-item straks wél lukt (zie blocker hieronder), is
+    herhaling op de overige 5 plekken puur mechanisch werk.
 - **Poging door Claude (2026-08-09), geblokkeerd — geen wijziging
   aangebracht.** De juiste `Row`-node (kind `tagCategorieComponent`,
   binnen `Container` → sibling van de image-`Stack`) was betrouwbaar
@@ -753,6 +910,115 @@ laatste twee) — bij het oppakken van deze taak even meenemen.**
   image-`Stack`) → `Row` (bevat `tagCategorieComponent` als enige kind)
   → rechtsklik → **Wrap Widget (Ctrl+B)** → kies **Wrap** i.p.v. Row.
 
+**P1-20 · Eigenaar: Onbepaald.** Home toont weer een werkende
+"Terug"-knop naast de hamburger — **regressie t.o.v. P2-9-bijvangst**
+(die verwijderde Home's eigen dedicated `IconButtonBack`, bevestigd
+2026-08-10), maar via een ander pad: `HomeWidget`'s AppBar
+(`lib/uitgaanspaginas/home/home_widget.dart:127-168`) toont in de
+`FlexibleSpaceBar` twee gestapelde lagen — `title:` met alleen Home's
+eigen hamburger, en `background:` met een instantie van de **gedeelde**
+`HeaderButtonsComponentWidget()` (dezelfde component die P0-3 punt 2 op
+`EventCurrent` hergebruikte voor de locatienaam-header). Die gedeelde
+component heeft zélf óók een hamburger + een `arrow_back_outlined`-knop
+met tooltip "Terug" (`lib/components/header_buttons_component_widget.dart:182-194`,
+`onPressed: () => context.pop()`) — op `EventCurrent` hoort die
+terug-knop er terecht bij (je kwam ergens vandaan), maar op **Home**
+(de root-pagina, niets om naar terug te gaan) is hij een dooie-op-zich
+knop die desondanks zichtbaar en tikbaar is. **Bevestigd live
+(2026-08-12, verse build):**
+1. Tikken op de knop zelf toont de tooltip "Terug" en doet verder niets
+   zichtbaars (`context.pop()` is hier een no-op, geen crash) — puur
+   verwarrend voor een gebruiker die net de app opent.
+2. **Belangrijker:** de tikgebieden van de hamburger (Home's eigen,
+   title-laag) en van deze Terug-knop (background-laag) liggen zo dicht
+   op elkaar dat een tap bedoeld voor de hamburger soms in plaats
+   daarvan de Terug-tooltip toont — en zodra die tooltip eenmaal
+   getoond is, **bleven 3 opeenvolgende taps op exact dezelfde
+   hamburger-positie alleen de tooltip opnieuw tonen** (drawer opende
+   niet), tot een tap elders op het scherm of een hardware-back de
+   tooltip resette. Dit kan het openen van het hoofdmenu (de enige
+   manier om provincie/gemeente/horeca te wisselen vanaf Home) voor een
+   gebruiker onbetrouwbaar maken.
+- **Voorgestelde fix (builder):** op Home's instantie van
+  `HeaderButtonsComponentWidget()` (in de `background:`-slot van de
+  FlexibleSpaceBar) de Terug-knop verbergen — bv. een
+  Visibility-conditie op een nieuwe/bestaande component-parameter
+  (`showBackButton: false` voor Home, `true` voor `EventCurrent` en
+  andere sub-pagina's die 'm al gebruiken), zodat de component
+  herbruikbaar blijft maar niet overal dezelfde knoppen toont.
+
+**P1-21 · Eigenaar: Onbepaald.** AdBanner op `PUitgaanPage`
+(`lib/uitgaanspaginas/p_uitgaan_page/p_uitgaan_page_widget.dart:200-207`)
+toont **letterlijke developer-instructietekst** aan echte gebruikers
+i.p.v. een advertentie of een net leeg vak. Dit is FlutterFlow's eigen
+`FlutterFlowAdBanner`-widget
+(`lib/flutter_flow/flutter_flow_ad_banner.dart`): zolang er geen
+geladen advertentie is, rendert hij een zwart vlak met de tekst "Ad
+Loading... If this takes a long time, you may have to check whether
+the ad is being covered from a parent widget. ... AdBanner will
+automatically match the size of the banner to the device screen." —
+bedoeld als build-time debughulp, niet als eindgebruikers-UI.
+**Bevestigd live (2026-08-12):** dit bleef **8+ seconden onveranderd**
+zichtbaar (geen doorontwikkeling naar een echte advertentie), en de
+`flutter run`-log toonde de reden:
+```
+BannerAd failedToLoad: LoadAdError(code: 0, domain: com.google.android.gms.ads, message: Internal error., ...)
+```
+Twee losse punten om op te pakken:
+1. **`showsTestAd: true`** staat nog aan (regel 203, gebruikt Google's
+   demo-ad-ID i.p.v. de wél al ingevulde echte
+   `androidAdUnitID`/`iOSAdUnitID` op regel 204-205) — vermoedelijk
+   bewust tijdens ontwikkeling, maar een expliciete "zet dit om vóór
+   livegang"-controlepunt waard, anders draait de productie-app nog op
+   Google's testadvertenties (geen omzet).
+2. **De fallback-UI zelf moet sowieso weg/anders**, los van
+   test-vs-productie: een gebruiker mag nooit deze debugtekst zien, ook
+   niet als een echte advertentie een keer traag laadt of faalt (bv.
+   geen advertentie-inventory voor deze gebruiker/regio). Voorstel:
+   `flutter_flow_ad_banner.dart`'s fallback-`Container` vervangen door
+   iets neutraals (leeg vlak met dezelfde hoogte, of gewoon
+   `SizedBox.shrink()`) i.p.v. de zwarte debug-tekst-box — dit is een
+   **custom/lokaal bestand** (onderdeel van de FlutterFlow-standaard
+   widgetlibrary), dus in tegenstelling tot pagina's/componenten wél
+   rechtstreeks in de code aan te passen zonder builder-UI (net als
+   `lib/custom_code/`, zie `CLAUDE.md`).
+- **Kanttekening bij P2-5** ("Ad-banners..., na livegang"): P2-5 gaat
+  er nog van uit dat advertenties een niet-gebouwd P2-idee zijn — in
+  werkelijkheid staat er dus al minstens 1 banner live in de code
+  (alleen nog kapot/debug). Check met Bob of P2-5's "waar wel/geen
+  ads"-regel (geen ads op locatie-kiezer/login/account) al is
+  toegepast op deze ene bestaande banner, en of er bewust voor
+  `PUitgaanPage` gekozen is als eerste plek.
+
+**P1-22 · Eigenaar: Onbepaald.** Emoji in Drupal-content worden `?`
+-tekens i.p.v. correct weergegeven — content-encoding-bug,
+projectbreed. **Bevestigd live (2026-08-12)** op de omschrijving van
+evenement "Mythic Fest II" (zowel op de Home-kaart als op de
+EventCurrent-detailpagina, dus niet render-specifiek): tekst als
+`??? ?????????  ?????? ????` en `?????-???? ???????` vóór/tussen
+overigens prima leesbare Nederlandse tekst — precies het patroon van
+emoji die als vervangingstekens worden weergegeven. **Root cause
+(code-niveau, redelijk zeker):** elke API-call in `api_calls.dart` (in
+ieder geval `EvenementCall`, `HomeTabelCall`, `EstablishmentInfoCall`,
+`EstablishmentsCall` — lijkt projectbreed dezelfde template) heeft
+`decodeUtf8: false`. In `api_manager.dart:211-214`
+(`ApiCallResponse.fromHttpResponse`) betekent dat: de responsebody
+wordt gelezen via `response.body` (Dart's `http`-package, die zonder
+expliciete `charset` in de `Content-Type`-header van de server
+terugvalt op **Latin-1**-decodering) i.p.v. expliciet
+`Utf8Decoder().convert(response.bodyBytes)`. Gewone Nederlandse
+diakrieten (é/ë/ï) vallen toevallig ook binnen Latin-1 en blijven dus
+goed — maar emoji (buiten Latin-1) worden zo onherstelbaar naar
+vervangingstekens gemapt. **Waarschijnlijk simpele, projectbrede fix:**
+`decodeUtf8: true` zetten op de API-calls (of, als dat via losse
+builder-toggles per call moet, een enkele globale plek zoeken in de
+FlutterFlow-projectinstellingen voor API-defaults) — controleer na de
+wijziging of de Drupal-respons zelf al `charset=utf-8` in
+`Content-Type` meestuurt (zo niet, is dat een aanvullende
+server-side-check waard, maar de `decodeUtf8: true`-fix in de app zou
+hoe dan ook al moeten helpen zolang de bytes zelf al geldige UTF-8
+zijn, wat aannemelijk is voor Drupal-JSON-export).
+
 **P1-9 · Eigenaar: Onbepaald.** Visuele polish (los, per pagina) —
 resterend na sessie 2026-08-06:
 1. **Nog niet opgepakt:** Event-pagina (typografie/contrast/spacing).