Преглед на файлове

Fix: sessie werd nooit opgeslagen na inloggen (bool/JSON-crash in Inloggen-knop)

Root cause: login_widget.dart:534 (`if (_model.resultDrupalLogin!)`)
behandelt het resultaat van custom action drupalLogin (een JSON-map)
alsof het een bool is -> crasht altijd met 'type _Map<String, dynamic>
is not a subtype of type bool', ongeacht de credentials. Daardoor
draaiden de FFAppState-sessie-assignments erna nooit, en ging elke
beveiligde pagina (favorieten, kanweg) zonder sessie-cookie de deur uit.

Fix (functioneel, in drupal_login.dart custom action): sla de sessie
(userSessionid/userSessionname/userToken/userName/userUid/userMail)
al direct in FFAppState op zodra de Drupal-login 200 teruggeeft, vóórdat
de crashende if-check in de knop bereikt wordt. Live bevestigd op
Waydroid-emulator (testaccount bobcity): kanweg/FavorietenAgenda
krijgen na inloggen nu status 200 + geldige Cookie/X-CSRF-Token-headers
i.p.v. de eerdere lege/anonieme 403.

Dit was ook de werkelijke oorzaak van de 'FavorietenAgenda 403-fout'
die eerder aan Cloudflare Bot Management werd toegeschreven - niets
met IP-reputatie/TLS-fingerprint te maken.

Resterend (cosmetisch, builder-only, zie TASKS.md P1-18): de knop zelf
crasht nog steeds stil (geen succes-/foutmelding) omdat de If/Then-
conditie na de custom-action-stap in de builder aangepast moet worden
- kon het Actions-paneel voor deze knop niet vinden in de builder-UI,
zie CLAUDE.md voor wat is geprobeerd.

CLAUDE.md: Custom Code-editor Ctrl+S-valkuil vastgelegd (Synced-badge
verschijnt al vóór de wijziging echt in de export-pipeline zit), plus
widget-tree klik-coördinaat-onbetrouwbaarheid en het niet-vinden van
het knop-Actions-paneel.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
bob преди 1 месец
родител
ревизия
d5077e2275
променени са 4 файла, в които са добавени 125 реда и са изтрити 20 реда
  1. 67 0
      CLAUDE.md
  2. 47 16
      TASKS.md
  3. 4 4
      ios/Runner.xcodeproj/project.pbxproj
  4. 7 0
      lib/custom_code/actions/drupal_login.dart

+ 67 - 0
CLAUDE.md

@@ -477,6 +477,73 @@ testwaarde (bv. Cookie-header) kan per ongeluk blijven staan i.p.v.
 "Include"-vinkje in Response & Test — staat die uit, dan wordt de
 letterlijke `[varname]`-tekst meegestuurd i.p.v. de testwaarde.
 
+**Custom Code-editor (Custom Functions/Widgets/Actions): tekst-editor,
+betrouwbaar te bewerken — maar wijziging verschijnt pas in een export
+ná een expliciete Ctrl+S.** In tegenstelling tot widget-canvas/
+rechterpaneel (coördinaat-onbetrouwbaar, zie hieronder) is dit een
+echte Monaco-editor: getypte code (incl. auto-closing brackets/quotes)
+komt gewoon correct aan, geen speciale precautions nodig. **Kritieke
+valkuil, 2026-08-09 bevestigd:** de header toont "Synced" al direct
+na typen, maar dat weerspiegelt **niet** dat de wijziging al naar de
+export-pipeline is doorgezet — een `flutterflow export-code` direct
+daarna (ook na een volledige herstart van `ff-run-fvm.sh`, dus geen
+lokale cache-issue) gaf 2x achter elkaar nog de **oude** bestandsinhoud
+terug. Pas ná een expliciete **Ctrl+S** in de editor (zichtbaar:
+kort "Syncing…" i.p.v. "Synced", + auto-format herschrijft de
+zojuist getypte regels) nam een verse export de wijziging over.
+**Vuistregel: na elke Custom Code-wijziging altijd Ctrl+S drukken**
+vóórdat je `ff-run-fvm.sh`/`export-code` draait, en bij twijfel eerst
+verifiëren met een losse
+`flutterflow export-code --project <id> --dest /tmp/check --token
+"$(cat ~/.ff_token)" --no-parent-folder --as-debug` + `grep` op de
+verwachte regel, i.p.v. blind op de "Synced"-badge te vertrouwen.
+- Bereikbaar via het `⌘+K`-commandpalet (zoek op de custom-action-naam,
+  bv. "drupalLogin") — betrouwbaarder dan door de linkerzijbalk
+  klikken (die leed in deze sessie aan hetzelfde klik-coördinaat-
+  probleem als de widget-tree, zie hieronder). **Let op:** klik het
+  zoekresultaat aan met de muis, druk geen Enter — een nog openstaand
+  rechtsklik-contextmenu elders op de pagina kan de Enter-toets
+  onderscheppen (2026-08-09 1x per ongeluk een widget gedupliceerd op
+  deze manier; met Ctrl+Z + Delete op de duplicaat hersteld, geen
+  blijvende schade). Sluit dus eerst met Escape elk open contextmenu
+  vóór je `⌘+K` gebruikt.
+
+**Widget Tree/canvas: klik-coördinaten zijn NIET betrouwbaar 1-op-1
+met wat een screenshot toont, en dit is geen vast te rekenen offset.**
+Los van de al bekende rechterpaneel-breedte-clipping (hierboven) bleek
+2026-08-09: een klik op een zichtbare tree-rij selecteerde herhaaldelijk
+een héél andere rij (soms 2, soms 3 rijen verderop, niet consistent
+in pixels of in aantal rijen). Werkende aanpak: **na een klik nooit
+blind vertrouwen** — verifieer met `Home` + `Shift+End` (selecteert de
+hele regel/rij zonder iets te wijzigen) of een read-only zoom op het
+rechterpaneel, en pas de klik-y-coördinaat handmatig aan op basis van
+wat je net *echt* selecteerde, vóór je verdergaat. Reload van de
+pagina (`navigate` naar dezelfde URL) hielp de eerstvolgende klik weer
+correct te laten landen, maar het patroon kwam later opnieuw terug —
+geen structurele fix gevonden, alleen de per-klik-verificatie hierboven.
+`double_click` op een widget (zowel canvas als tree) selecteerde
+herhaaldelijk de root-pagina i.p.v. in te zoomen — vermijd double-click
+voor selectie, gebruik single-click + verificatie.
+
+**Actions-paneel voor een Button-widget (onPressed/If-Then na een
+custom action) — niet gevonden in deze sessie, ondanks uitgebreid
+zoeken.** De 2 extra tab-iconen naast de standaard Widget Styling-tab
+bleken **Animations** en **Accessibility** te zijn — geen "Actions"-tab
+ertussen. Ook niet gevonden: via rechtsklik (canvas of tree, beide
+andere contextmenu's, geen "Edit Actions"-optie), via het
+"Search properties…"-veld (geen match op "action"/"tap"), via de losse
+tree-rij-iconen (leken niets te doen), via de globale "24"-badge
+rechtsboven (Action Blocks-teller, opent geen paneel bij klikken). Het
+`⌘+K`-commandpalet vindt wel "Custom Action: `<naam>`" maar dat
+springt naar de **Custom Code-editor van de actie zelf** (functie-body),
+niet naar de knop's eigen Actions-configuratie. **Nog niet uitgeprobeerd:**
+uiBuilder-canvasmodus met een expliciete hover (i.p.v. click) op de
+rand van de knop, of Bob zelf vragen waar dit paneel in zijn versie
+zit. Bij een volgende taak die een knop-actie/conditie moet wijzigen:
+eerst hier verder zoeken vóór blind te herhalen wat hierboven al niet
+werkte, en anders vroeg overdragen aan Bob i.p.v. tijd te verliezen
+(kostte deze sessie ~1,5 uur zonder resultaat).
+
 ## Domein/architectuurcontext
 
 - **Taal/locale volgt het toestel, niet hardcoded Nederlands** — zonder

+ 47 - 16
TASKS.md

@@ -89,18 +89,6 @@ tijd stoppen goed te doen.
   (P2-2 t/m P2-6, P2-8) — geen mechanisch patroon, dus geen goede
   Haiku-fit.
 
-## Status: actief bij Bob (geen Claude-actie nodig, ter info)
-
-- **FavorietenAgenda 403-fout** — **Eigenaar: Bob — bezig.** Bob
-  troubleshoot dit zelf. FlutterFlow-requests komen bij nginx binnen
-  met een lege Cookie-header; zijn eigen browser/curl (via dezelfde
-  Cloudflare-edge) sturen de sessie-cookie wél mee. Cloudflare Cache
-  Rule voor `SSESS*` staat al goed (bypass, eerste regel).
-  Werkhypothese: Cloudflare Bot Management behandelt FlutterFlow's
-  server-side traffic anders op basis van IP-reputatie/
-  TLS-fingerprint. Niet opnieuw diagnosticeren zonder navraag — check
-  eerst of Bob al verder is.
-
 ## P0 — blokkeert livegang
 
 **P0-6 · Eigenaar: Onbepaald (mechanisch: widgets verwijderen/verbergen
@@ -188,14 +176,56 @@ favorieten drawer-link + 3-tabblad-pagina, hartje op horeca-kaart +
 - Lege-lijst empty-state op de favorietenpagina (nu kale/lege
   Container als er nog geen favorieten zijn).
   `lib/favorieten/favorieten_widget.dart`.
-- Bevestigen dat favorieten écht syncen via Drupal bij inloggen —
-  hangt af van FavorietenAgenda-403 hierboven.
+- ~~Bevestigen dat favorieten écht syncen via Drupal bij inloggen~~ —
+  **root cause gevonden + gefixed (Claude, 2026-08-09), zie P1-18.**
+  De eerder aan Cloudflare Bot Management toegeschreven
+  "FavorietenAgenda 403-fout" (lege Cookie-header bij FlutterFlow-
+  requests) bleek gewoon het gevolg van de login-sessie die nooit
+  werd opgeslagen — niets met Cloudflare/IP-reputatie te maken. Live
+  bevestigd met testaccount `bobcity` op emulator: na de fix geeft
+  `flutterfavorietenagenda.json` **status 200 + geldige
+  `Cookie`/`X-CSRF-Token`-headers + echte data** i.p.v. de eerdere
+  lege/anonieme 403. Kan hiermee als afgerond beschouwd worden zodra
+  Bob dit ook zelf in de FavorietenAgenda-flow (niet alleen de
+  `kanweg`-testpagina) bevestigt.
 
 **P0-5 · Eigenaar: Bob.** Drupal: anonieme leestoegang onderzoeken
 voor browse-endpoints. Drupal-niveau, geen Claude-taak.
 
 ## P1 — snel na livegang
 
+**P1-18 · Eigenaar: Bob (1 conditie-edit in de builder — Claude vond
+het Actions-paneel voor deze knop niet, zie CLAUDE.md).** Login-knop
+(`login`-pagina, "Inloggen") crasht **altijd** stil na een druk erop —
+geen succes-/foutmelding, en (belangrijker) **de sessie werd nooit
+opgeslagen**, waardoor elke beveiligde pagina (favorieten, `kanweg`)
+zonder sessie-cookie draaide. Root cause (bevestigd via
+`flutter run`-log, 2026-08-09): `login_widget.dart:534` —
+`if (_model.resultDrupalLogin!) {` — behandelt het resultaat van de
+custom action `drupalLogin` (een JSON-map: `{success, sessid,
+session_name, token, uid, name, mail}`) alsof het een `bool` is. Dat
+crasht altijd met `type '_Map<String, dynamic>' is not a subtype of
+type 'bool'`, ongeacht of de credentials kloppen — dus ook de regels
+daarna (`FFAppState().userSessionid = ...`) draaiden nooit.
+**Functioneel al gefixed (Claude, Custom Code-editor):**
+`lib/custom_code/actions/drupal_login.dart` zet de sessievelden
+(`userSessionid`/`userSessionname`/`userToken`/`userName`/`userUid`/
+`userMail`) nu **zelf al in `FFAppState()`** vóórdat de crashende
+regel in de knop bereikt wordt — dat gebeurt dus altijd, ook al
+crasht de knop daarna nog steeds. Live bevestigd (emulator, testaccount
+`bobcity`): na inloggen + navigeren naar `kanweg` komt er nu een
+`Cookie`-header mee en status 200 i.p.v. de eerdere lege/403-request.
+**Resterend (cosmetisch, builder-only):** de If/Then-conditie ná de
+Custom Action-stap in de Inloggen-knop's Actions aanpassen van
+"resultDrupalLogin is true" naar een check op het JSON-veld
+`$.success` (zelfde recept als het bekende
+"Is Set and Not Empty tegen valueOrDefault"-patroon hieronder: bind
+tegen de rauwe `getJsonField($.success)`-expressie, operator "Is
+Set"/"== true"), zodat de succes-/foutmelding weer verschijnt. Claude
+kon het Actions-paneel voor deze knop niet vinden ondanks uitgebreid
+zoeken (widget-tree, canvas, rechtsklik-context-menu's, Cmd+K) — zie
+CLAUDE.md voor wat wel/niet geprobeerd is.
+
 **P1-1 · Eigenaar: Bob (mechanisch, ~10 sec per stuk) — audit
 compleet, wachtend op Bob.** Loading/foutafhandeling-patroon uitrollen
 naar overige lijst-/detailpagina's. Referentiepatroon bevestigd
@@ -691,5 +721,6 @@ gemeente-/provincienaam (favoriete plaats maken/markeren) — losgemaakt
 van P0-3 (2026-08-05, Bob: te veel voor de eerste release). Naam wordt
 inmiddels al getoond op de meeste pagina's via `HeaderButtonsComponent`
 (zie P0-3); dit punt is puur de hartje-tap-functionaliteit erbovenop.
-Hangt af van de `FavorietenAgenda`-403-fix (zie "Status: actief bij
-Bob" bovenaan dit bestand) — niet oppakken vóórdat die opgelost is.
+Hing af van de `FavorietenAgenda`-403-fout — die bleek onderdeel van
+de login-sessie-bug, root cause gevonden + functioneel gefixed
+(2026-08-09, zie P0-4/P1-18). Kan nu opgepakt worden.

+ 4 - 4
ios/Runner.xcodeproj/project.pbxproj

@@ -44,8 +44,8 @@
 		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
 		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
-		6436409027A31CD700820AF7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		6436409F27A31CDC00820AF7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		6436409C27A31CD800820AF7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		6436409427A31CD800820AF7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -225,8 +225,8 @@
 		6436409C27A31CD800820AF7 /* InfoPlist.strings */ = {
 			isa = PBXVariantGroup;
 			children = (
-				6436409027A31CD700820AF7 /* nl */,
-				6436409F27A31CDC00820AF7 /* en */,
+				6436409C27A31CD800820AF7 /* nl */,
+				6436409427A31CD800820AF7 /* en */,
 			);
 			name = InfoPlist.strings;
 			sourceTree = "<group>";

+ 7 - 0
lib/custom_code/actions/drupal_login.dart

@@ -31,6 +31,13 @@ Future<dynamic> drupalLogin(
 
     if (response.statusCode == 200) {
       final data = jsonDecode(response.body);
+      FFAppState().userSessionid = data['sessid']?.toString() ?? '';
+      FFAppState().userSessionname = data['session_name']?.toString() ?? '';
+      FFAppState().userToken = data['token']?.toString() ?? '';
+      FFAppState().userName = data['user']?['name']?.toString() ?? '';
+      FFAppState().userUid =
+          int.tryParse(data['user']?['uid']?.toString() ?? '') ?? 0;
+      FFAppState().userMail = data['user']?['mail']?.toString() ?? '';
 
       return {
         'success': true,