Просмотр исходного кода

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 месяц назад
Родитель
Сommit
28b1213aa3
2 измененных файлов с 329 добавлено и 14 удалено
  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
    pre-verifiëren (is hij nog steeds nodig, of intussen al door iemand
    anders/een eerdere sessie opgelost?) — scheelt een aparte
    anders/een eerdere sessie opgelost?) — scheelt een aparte
    heen-en-weer ronde.
    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
 6. Bob geeft na afronding van een cluster ook een eigen commit in
    FlutterFlow's interne versiebeheer ("main"/"Synced" bovenin) — los
    FlutterFlow's interne versiebeheer ("main"/"Synced" bovenin) — los
    vangnet naast Claude's export-verificatie.
    vangnet naast Claude's export-verificatie.
@@ -352,6 +358,49 @@ dat al bevestigd werkt.
 
 
 ## FlutterFlow-builder: bekende problemen & patronen
 ## 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
 **Rechterpaneel-clipping: gebruik de "Search properties..."-zoekbalk
 i.p.v. scrollen.** Het rechterpaneel (Widget Tree → property-editor)
 i.p.v. scrollen.** Het rechterpaneel (Widget Tree → property-editor)
 scrollt via browser-automation vaak niet (muiswiel-events lijken geen
 scrollt via browser-automation vaak niet (muiswiel-events lijken geen

+ 280 - 14
TASKS.md

@@ -1,11 +1,34 @@
 # Uitgaanskrant — takenlijst
 # 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
 builder-edits zelf, Claude gaf per punt de exacte stappen en
 verifieerde daarna elke edit met een verse `flutterflow export-code`
 verifieerde daarna elke edit met een verse `flutterflow export-code`
 + grep (niet op de builder-UI zelf vertrouwd). **9 taken écht afgerond
 + 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.
   `kanweg`-testpagina) bevestigt.
 
 
 **P0-5 · Eigenaar: Bob.** Drupal: anonieme leestoegang onderzoeken
 **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
 ## 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
   (317/339 zijn **nieuw t.o.v. de 2026-08-04-audit**, waren toen nog
   niet aanwezig of gemist)
   niet aanwezig of gemist)
 - `horecagelegenheid_current_widget.dart:377/500/747` — title/logo/content
 - `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
 - `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)
   zijn **nieuw t.o.v. de 2026-08-04-audit**, alleen nid stond er al in)
 - `evenement_horecagelegenheid_widget.dart` — **grootste blok, ~30
 - `evenement_horecagelegenheid_widget.dart` — **grootste blok, ~30
@@ -477,13 +586,18 @@ CachedNetworkImage/P1-15-patroon. Bevestigd via verse export:
 guard. Uit deze lijst verwijderd.)*
 guard. Uit deze lijst verwijderd.)*
 
 
 **P1-13 · Eigenaar: Bob (geblokkeerd op een bevestigd FlutterFlow-
 **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
 kaartjesgrid. **Root cause definitief bevestigd
 (2026-08-09, Claude, verse volledige stack trace + visuele bevestiging
 (2026-08-09, Claude, verse volledige stack trace + visuele bevestiging
 op emulator-5554):**
 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).
   regel 178-179, `mainAxisSize: MainAxisSize.min`, geen Wrap/Expanded).
   Kleiner overflow (2.4px, minder zichtbaar dan Home's 113px) maar
   Kleiner overflow (2.4px, minder zichtbaar dan Home's 113px) maar
   zelfde onderliggende bug — zelfde fix-aanpak (Wrap i.p.v. Row).
   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
 - **Poging door Claude (2026-08-09), geblokkeerd — geen wijziging
   aangebracht.** De juiste `Row`-node (kind `tagCategorieComponent`,
   aangebracht.** De juiste `Row`-node (kind `tagCategorieComponent`,
   binnen `Container` → sibling van de image-`Stack`) was betrouwbaar
   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)
   image-`Stack`) → `Row` (bevat `tagCategorieComponent` als enige kind)
   → rechtsklik → **Wrap Widget (Ctrl+B)** → kies **Wrap** i.p.v. Row.
   → 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) —
 **P1-9 · Eigenaar: Onbepaald.** Visuele polish (los, per pagina) —
 resterend na sessie 2026-08-06:
 resterend na sessie 2026-08-06:
 1. **Nog niet opgepakt:** Event-pagina (typografie/contrast/spacing).
 1. **Nog niet opgepakt:** Event-pagina (typografie/contrast/spacing).