CLAUDE.md 47 KB

Uitgaanskrant — werkinstructies voor Claude

Werkdirectory

Werk uitsluitend binnen deze projectdirectory (/home/bob/Projects/ff-app/uitgaanskrant-1qhvtd). Niet daarbuiten zoeken of scannen — scope alle bestandsoperaties tot dit project.

Werkwijze binnen een sessie

  • Meld bij elke nieuwe stap kort vooraf wat je gaat doen, vóór je begint (staande voorkeur Bob, 2026-08-04).
  • Bob bespreekt elke taak in een nieuwe, aparte chat — geen eerdere conversatie om op terug te vallen. CLAUDE.md + TASKS.md zijn samen het volledige geheugen tussen sessies.
  • Groepeer opgepakte taken per sessie op FlutterFlow-paginagebied waar mogelijk (bv. twee taken op dezelfde pagina/component samen oppakken) — minder heen-en-weer-navigeren in de builder, minder tokens.
  • TASKS.md-status kan achterlopen op de echte code (Bob werkt gelijktijdig, en documentatie-updates lopen niet altijd synchroon met de export). Check een taak die er al even staat met git log --oneline -S"<kenmerkende string/tekst>" of een gerichte grep vóórdat je 'm oppakt — niet blind vertrouwen dat "open" betekent "nog niet gefixt". (Precedent: 2026-08-04 bleken 2 "open" P0-taken al op 2026-08-02 gefixt te zijn, git-bevestigd.)
  • Elke taak in TASKS.md heeft een stabiel ID (bv. P0-1) en een Eigenaar:-regelBob (sneller/simpeler voor hem zelf, meestal builder-UI met een bekend fragiele dialoog, zie hieronder), Claude (onbeklaimd, vrij op te pakken), of ... — bezig (iemand is er nu actief mee bezig). Vuistregel voor wie een nieuwe taak zou moeten doen: een kort, mechanisch herhaald patroon zonder geneste dialogen → Claude; ConditionalBuilder/JSON-Path-condities, List-typed function-argumenten, of iets dat eerder al vastliep → Bob.
  • ⚠️ Concurrency: Bob start elke taak in een nieuwe chat, dus er kunnen meerdere sessies tegelijk actief zijn. Check vóór je een taak oppakt of de Eigenaar-regel al "— bezig" zegt door iemand anders — zo ja, niet zelfstandig ook gaan bouwen aan hetzelfde bestand/component, vraag Bob eerst wie 'm afmaakt. Zet zelf "— bezig" zodra je serieus begint — dit geldt óók voor puur onderzoek/ reproductie (bv. een eigen flutter run-sessie starten om een stack trace te vangen), niet alleen voor builder-edits. (Precedent 2026-08-04: twee sessies pakten onafhankelijk dezelfde P0-taak op — Bob moest scheidsrechteren tussen twee stukken werk aan hetzelfde bestand. Tweede precedent, 2026-08-09: een sessie deed 20+ minuten actief P1-13-onderzoek — eigen flutter run-proces + een nieuwe bug gevonden (P1-19) — zonder ooit "— bezig" te zetten; een nieuwe sessie kwam er via git diff/proces-inspectie toevallig achter vlak vóórdat ze zelf hetzelfde pad zou inslaan. Geen schade, maar puur geluk — vandaar nu ook ff-session-check.sh, zie hieronder.)
  • Start elke sessie met /home/bob/Projects/ff-session-check.sh (géén argumenten nodig voor dit project) — bundelt in één keer git-status, welke devices/emulators draaien, welke flutter/ff-run-fvm/script-processen actief zijn (met leeftijd), en welke TASKS.md-taken al "— bezig" staan. Vervangt de losse handmatige git status/adb devices/ps aux-stappen hieronder — dat was voorheen makkelijk (deels) over te slaan, dit script niet. Een draaiend ff-run-fvm.sh/flutter run-proces alléén is géén betrouwbaar signaal dat er "nu" iemand actief mee bezig is — bevestigd 2026-08-07: meerdere van die processen bleken dagen oud (gestart Aug05/Aug06, nog steeds draaiend), puur omdat het interactieve hot-restart-loop-karakter ze nooit vanzelf afsluit. Het betrouwbaardere signaal voor "hier ligt nog niet-afgerond werk": een niet-gecommitte git status/git diff (vooral als TASKS.md/ CLAUDE.md zelf ook wijzigingen tonen t.o.v. de laatste commit) — dát is een aanwijzing dat een sessie iets heeft afgerond/uitgevoerd maar de afsluitroutine (commit+push, zie hieronder) nog niet heeft gedaan. Beide signalen samen (proces + ongecommitte diff) zijn het sterkste bewijs van live werk — het script hierboven toont ze gecombineerd. Zie zo'n situatie: bouw erop voort waar zinnig, maar commit niet over andermans nog-niet-afgeronde wijziging heen zonder navraag.

Sessiegeheugen — afsluitroutine

Aan het eind van elke sessie/taak:

  1. TASKS.md: een afgeronde taak wordt volledig verwijderd (niet gearchiveerd — onnodige context/kosten voor latere sessies). Elke resterende open taak moet zelfstandig te begrijpen zijn (concreet, met bestandspad) zonder de ontstaanschat gelezen te hebben.
  2. CLAUDE.md: alleen aanvullen met blijvend herbruikbare inzichten (conventie, architectuurkeuze, bekend valkuil-patroon) die een latere sessie anders opnieuw zou moeten uitzoeken. Geen sessieverslag/changelog. Ruim verouderde info op i.p.v. eronder te plakken — dit bestand moet klein en scanbaar blijven.
  3. Commit + push de gewijzigde .md-bestanden direct (geen FlutterFlow-export nodig voor pure documentatiewijzigingen).

Geen apart memory-systeem meer nodig voor projectfeiten — die staan allemaal hier en in TASKS.md, wat al elke sessie automatisch geladen wordt. (Auto-memory-bestanden zijn per 2026-08-04 opgeschoond omdat ze dit bestand 1-op-1 dupliceerden.)

FlutterFlow-workflow — belangrijk

Dit project wordt gebouwd via FlutterFlow (app.flutterflow.io). De FlutterFlow-cloudomgeving is de bron van waarheid, niet deze lokale code-export.

  • Bob kan geen code rechtstreeks bewerken in dit repo. Alle wijzigingen aan pagina's, componenten en modellen moeten via de FlutterFlow-website. Enige uitzondering: custom functions/widgets (lib/custom_code/) — ook die voert Bob in via de Custom Code-editor op de website, niet hier lokaal.
  • Gevolg: directe Edit/Write-wijzigingen aan gegenereerde bestanden worden bij de volgende export overschreven — niet duurzaam. Gebruik deze repo om te lezen/ontwerpen/verifiëren (flutter analyze), maar voer het eindresultaat uit via de builder (zelf via browser-automation, of als instructie aan Bob). Ga nooit uit van behoud van een lokale bestandswijziging.
  • Werk je rechtstreeks in de builder (Claude in Chrome): commit na elke afgeronde taak binnen FlutterFlow's eigen versiebeheer ("main"/"Synced" bovenin), met duidelijke omschrijving. Geen lokale git commit.
  • Gebruik mcp__claude-in-chrome__* (Bob's gedeelde Chrome), niet de in-app Browser pane.
  • Resize de browser niet zelf. Bob's eigen gedeelde vensters — meld en vraag i.p.v. zelf te resizen.
  • Bob werkt vaak gelijktijdig zelf in dezelfde builder-sessie — check eerst of hij iets claimde ("dat regel ik zelf") voordat je wijzigingen overschrijft.
  • Check bij een mislukte export/pull eerst het Issues-paneel (badge rechtsboven) voordat je een bug bij jezelf zoekt — een rode teller blokkeert elke export, ook niet-gerelateerde, en is vaak Bob's eigen work-in-progress.
  • De browser-automation naar de FlutterFlow-builder loopt via Bob's eigen, ingelogde Chrome-sessie op zijn machine — dus alleen betrouwbaar terwijl hij actief aanwezig is. Bevestigd 2026-08-09: terwijl Bob een uur weg was, hing een simpele navigate-aanroep naar een FlutterFlow-URL 2x achter elkaar 5 minuten vast (op andere MCP-calls in dezelfde browser, bv. tabs_context, geen probleem) — vermoedelijke oorzaak: een vergrendeld/inactief scherm maakt de extensie/CDP-brug onbetrouwbaar. Praktisch gevolg: builder-UI-werk is geen geschikte taak voor een sessie terwijl Bob niet achter zijn scherm zit (ook niet via /loop of een geplande taak) — Bash/ code-audit/emulator-werk (geen browserafhankelijkheid) juist wel.

Lokale git-repo + pull/push-workflow

Projectdirectory = eigen schone git-repo, origin ssh://gogs.digitalforce.tv:2222/Uitgaanskrant.com/flutterflow.git, branch master. Los van de grotere/rommelige repo hoger in de mappenstructuur (AndroidStudioProjects, Flutter-SDK e.d.) — commits en pushes horen hier.

Vaste workflow na elke afgeronde taak (staand akkoord, geen aparte bevestiging nodig): niet los flutterflow export-code, maar:

export PATH="/home/bob/fvm/bin:$HOME/.pub-cache/bin:$PATH" && /home/bob/Projects/ff-run-fvm.sh emulator-5554 uitgaanskrant-1qhvtd -s
  • De export PATH=... prefix is verplicht — Bash draait niet-interactief, ~/.bashrc wordt niet geladen. Zonder prefix faalt het script stil ("fvm: command not found" — geen harde error).
  • Interactief script (device-run + hot-restart-loop) → Bash met run_in_background: true. Volg tot minimaal "All done!" én idealiter een succesvolle app-launch (Launching lib/main.dart..., geen nieuwe EXCEPTION CAUGHT BY RENDERING LIBRARY).
  • Testdevices (vanaf 2026-08-09): twee lokale AVD's, geen fysieke toestellen meer. emulator-5554 (licht_avd, telefoon-formaat, laag RAM-profiel) en emulator-5556 (tablet_avd, tablet- schermverhouding) — beide starten automatisch bij Bob's desktop-login via systemd user-services (~/.config/systemd/user/android-emulator*.service). WayDroid en losse fysieke devices zijn niet meer in gebruik (WayDroid's adb shell screencap leed structureel aan PTY/CRLF-corruptie bij screenshots — vandaar de overstap). Check altijd eerst met adb devices welke van de twee daadwerkelijk draaien vóórdat je ff-run-fvm.sh of de android-mcp-tools gebruikt — draait geen van beide: navragen bij Bob i.p.v. blind op het eerste beschikbare device te draaien. De android-mcp-server-tools (mcp__android__*) accepteren een device_id-parameter per call, dus beide devices zijn los aan te sturen zonder config-wijziging — handig om ontwerp/layout op zowel telefoon- als tabletformaat te verifiëren (bv. relevant voor P1-11's responsive-grid-taak).
  • Een EXCEPTION CAUGHT BY RENDERING LIBRARY/crash tijdens de run is niet per se een regressie van je eigen wijziging — check eerst de stack trace op bestandsnaam. lib/kanweg/ is Bob's eigen scratch-testgebied (zie Opschonen hieronder) en kan legitiem crashen zonder dat dat iets met de huidige taak te maken heeft; de app kan daar staan door een eerdere hot-restart die Bob's laatst bezochte route onthield, niet per se doordat het de echte initialLocation is (check nav.dart).
  • Slechts één volledige EXCEPTION CAUGHT BY RENDERING LIBRARY-dump per proceslevensduur, ongeacht hoeveel verschillende widgets daarna overflowen. Flutter's dumpErrorToConsole toont de volledige stack trace + widget/bestand/regel alleen bij de allereerste exceptie sinds process- of hot-restart; elke volgende (ook een heel andere widget/pagina) wordt ingekort tot Another exception was thrown: <bericht> zonder bestandslocatie. Bevestigd 2026-08-09 (P1-13-onderzoek): de Home-pagina's al bekende overflow (PUitgaanSliderKaartComponent, P1-3) consumeerde de enige volledige dump nog vóórdat er genavigeerd kon worden naar de eigenlijk onderzochte pagina — alle latere overflows op die andere pagina bleven anoniem. Om een verse stack trace voor een specifieke, latere crash te pakken: eerst een hot-restart (R) sturen vlak vóór je die crash reproduceert, ván een schone/crash-vrije pagina uit — dat reset de teller. Een run_in_background-Bash-aanroep van ff-run-fvm.sh heeft stdin op /dev/null (niet-interactief), dus r/R is dan niet te versturen. Kale mkfifo alléén werkt niet (Flutter's keyboard-handler test op een echte TTY vóórdat hij raw keypresses verwerkt — een FIFO is er geen, dus de R komt nooit aan, ook al accepteert flutter run de pipe zonder foutmelding). Bevestigd werkend recept (2026-08-09): setsid op zowel de FIFO-writer als de flutter run-aanroep zelf, elk in een eigen run_in_background-Bash-call:

    mkfifo /pad/naar/fifo
    setsid bash -c "exec 9>'/pad/naar/fifo'; sleep 3600" < /dev/null > /dev/null 2>&1 &
    disown
    # aparte tool-call:
    setsid script -qc "fvm flutter run -d <device>" /pad/naar/logfile < /pad/naar/fifo > /dev/null 2>&1 &
    disown
    # later, weer een eigen call, om te restarten:
    printf 'R' > /pad/naar/fifo
    

    setsid geeft beide achtergrondprocessen een eigen sessie los van de Bash-call die ze startte, dus ze overleven gewoon over meerdere losse tool-calls heen. Flutter DevTools (de devtools-URL uit dezelfde run-log) is zelf ook een Flutter-Web-canvas-app zonder toegankelijke DOM — geen bruikbare omweg om alsnog bij de volledige historische foutenlijst te komen. Update 2026-08-09: het R+deep-link-race-probleem is opgelost — gebruik --route bij het starten in plaats van een hot-restart + losse deep-link. fvm flutter run -d <device> --route "/pad?param=waarde" zet Flutter's defaultRouteName al vóór de eerste frame, dus go_router opent direct die pagina — een tussenliggende Home-build (en dus Home's eigen overflow, die anders de enige volledige-dump- slot opsoupeert) vindt niet plaats. Geen FIFO/R/am start meer nodig wanneer de doelpagina zelf met een directe route+query-param bereikbaar is. Een hot-restart (R) blijft altijd terugvallen op de initialLocation/Home, en een deep-link-am start vlak daarna wordt door de net-herstarte app niet opnieuw verwerkt (adb toont dan "Activity not started, intent has been delivered to currently running top-most instance" terwijl de app toch op Home blijft) — dus die combinatie blijft de dump-slot-race verliezen. Het FIFO/R- recept hierboven blijft wel nodig voor pagina's die niet met een kale --route te bereiken zijn (bv. een crash die pas na meerdere gebruikersacties optreedt).

Daarna automatisch (of gebruik ff-commit.sh, zie hieronder):

  1. git status --short, dan git addniet blind -A. Alleen echte FlutterFlow/app-wijzigingen (lib/, android/, ios/, pubspec*, .gitignore). .claude/ blijft uitgesloten (sessiestate, geen app-code). Bob's eigen concurrente wijzigingen horen gewoon mee in dezelfde commit.
  2. git commit met duidelijke boodschap.
  3. git push (-u origin master als tracking nog niet staat).

Valkuil: flutterflow export-code overschrijft .gitignore bij elke export terug naar FlutterFlow's standaardversie. Voeg na elke export, vóór staging, deze regel weer toe als hij ontbreekt:

# Claude Code session state (not app code)
.claude/

(CLAUDE.md zelf overleeft een export altijd — check voor de zekerheid toch even.)

/home/bob/Projects/ff-commit.sh (2026-08-09) automatiseert bovenstaande 3 stappen + de .gitignore-valkuil-check in één keer:

/home/bob/Projects/ff-commit.sh "commit message"          # app-code modus (lib/android/ios/pubspec*/.gitignore)
/home/bob/Projects/ff-commit.sh --docs "commit message"   # alleen CLAUDE.md/TASKS.md

Herstelt automatisch de .claude/-gitignore-regel, staget alleen wat echt gewijzigd is binnen de relevante paden, toont wat wél/niet meegaat, en vraagt bevestiging vóór commit+push. Optioneel --dir <pad> voor een ander projectpad dan de default (ff-app/uitgaanskrant-1qhvtd).

Eerst research, dan bouwen

Vóór een niet-triviale taak (bugfix, nieuw patroon, integratie): kort online zoeken naar bestaande oplossingen i.p.v. zelf trial-and-error in de builder. Geldt niet voor mechanische herhaling van een patroon dat al bevestigd werkt.

FlutterFlow-builder: bekende problemen & patronen

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 effect te hebben op die specifieke sectie) — de bekende breedte-clipping (zie hieronder) geldt dus ook verticaal. Werkende workaround: het zoekveld bovenaan het paneel ("Search properties...") filtert op eigenschapsnaam (bv. "blur", "offset", "radius", "padding", "shadow") en toont dan alléén die eigenschap, ongeacht scrollpositie — vrijwel altijd binnen het zichtbare/klikbare gebied. Bij een samengestelde eigenschap met 2 velden naast elkaar (bv. Offset X/Y) kan het tweede veld nog steeds net buiten beeld vallen; een Tab-naar-volgend-veld-workaround is niet betrouwbaar gebleken (de waarde bleef soms op de oude staan zonder foutmelding, 2026-08-06 bevestigd op PUitgaanSliderKaartComponent's schaduw-offset). Voor sliders zonder zichtbaar numeriek veld (bv. "Uniform Radius/Padding" na het omzetten van per-hoek naar uniform): klikpositie op de track geeft alleen een grove benadering, geen exacte waarde — prima voor "ruwweg kleiner/groter", niet voor een precieze doelwaarde.

  • Na een edit altijd verifiëren met een screenshot van het gefilterde veld — een schijnbaar geslaagde Ctrl+A + typen + Return/Tab bleek meermaals niet vast te houden. Werkte betrouwbaarder: triple-click op het veld → Delete → typen (i.p.v. Ctrl+A → typen).
  • Zekerste verificatie: "View Code"-paneel, maar bereik dat via directe navigatie naar https://app.flutterflow.io/code/<project>?component=<Naam> (of ?page=<Naam>) i.p.v. te klikken op het </>-icoon rechtsboven — die iconenrij verschuift afhankelijk van app-state (een commit-icoon verschijnt/verdwijnt), waardoor een vast coördinaat soms een heel ander icoon raakt. Bevestigd 2026-08-06: 2x per ongeluk een "Create Commit"-dialoog geopend, 1x een "Make Project Public"-dialoog (met een Make Public-knop — nooit klikken), 1x de app-preview. Geen van alle bevestigd/doorgeklikt, maar wel tijdverlies — klik in die iconenrij rechtsboven nooit blind op een onthouden coördinaat, altijd eerst een screenshot ná de vorige actie. In de code-view zelf: gewoon muiswiel-scrollen werkt daar evenmin betrouwbaar, gebruik Ctrl+F (opent een echte browser-find-balk, werkt wel).
    • Update 2026-08-07: na directe navigatie naar de code-URL toont het middenpaneel soms alleen de kleine component-preview-thumbnail rechtsonder, geen code — klik op die thumbnail (niet op de "Widget"/"Model"-toggle erboven) om de code-editor daadwerkelijk te tonen; kost soms 2 pogingen na een page-reload. Eenmaal in de editor: Ctrl+F opent hier een Monaco-stijl in-editor zoekbalk (geen browser-native find), en die zoekbalk toonde bij mij geen bruikbare matchteller (mogelijk zelf ook geclipt) — voor het vinden van een specifieke regel werkte Ctrl+G ("Go to Line") betrouwbaarder: typ een regelnummer (desnoods een schatting op basis van de zichtbare structuur) + Enter, springt direct daarheen. De editor is read-only (typen geeft een "Cannot edit"-tooltip) — geen risico op per ongeluk wijzigen.

Geneste "Set Variable"-dialoog lijkt vast te zitten. Bij een conditie (ConditionalBuilder, Visibility → Conditional) op een niet-triviaal type (JSON Path, API-response-veld, List<DataType> function-argument) opent een tweede dialoog bovenop de eerste; Confirm/Cancel reageren soms niet zichtbaar. Twee oorzaken, in volgorde van proberen:

  1. Viewport-clipping (meest voorkomend) — knoppen renderen buiten het zichtbare canvas. Sleep de dialoog omhoog via het handvat bovenin naar een hogere y-positie; de knoppen worden dan zichtbaar en werken gewoon.
  2. Echt bevroren pagina (alle clicks doen niets) — de widget-wrap staat al server-side, de conditie-edit niet. Herlaad de pagina (navigate naar dezelfde URL); wrap blijft staan, conditie moet opnieuw.
  3. Kortere weg om dit te vermijden: operator "Is Set" i.p.v. "Not Equal To" + lege string — geen Second Value nodig, dus geen tweede dialoog.
  4. Loopt dit na 1-2 pogingen (incl. reload) nog vast: kost dan meer tijd dan Bob het zelf kan doen — meld concreet (component, exacte stappen) en vraag het aan hem.

Component Name kan per ongeluk overschreven worden. Vlak na paginanavigatie kan een klik bedoeld voor "Search properties..." op het Component Name-veld landen (focus/z-order race), en typen hernoemt dan stilletjes het component. Zelfde risico bij een widget-tree zoekactie die per ongeluk double-click-to-rename triggert i.p.v. navigeren — druk direct Escape om te herstellen. Mitigatie: na elke click-before-type eerst een screenshot om focus te bevestigen, zeker vlak na navigatie. Herstel: rechtsklik component in zoekresultaten → "Rename Component".

Rechterpaneel kan te breed zijn voor de viewport. Sommige controls (Expansion segmented control, Visibility → Conditional expression-builder, maar ook simpele checkboxen zoals "Show Empty List Widget" op een Carousel/ListView) renderen soms deels buiten beeld — geen resize_window-probleem (niet zelf resizen, zie boven). Bevestigd 2026-08-04: dit blijft optreden zelfs nadat Bob zijn eigen venster al vergroot had — de FlutterFlow-app zelf lijkt de extra breedte niet te gebruiken (real window 1970px, maar bruikbare schermafbeelding/klikbare ruimte bleef begrensd tot ~1176px; de JS-laag rapporteert wel de volle vensterbreedte, dus dit zit in hoe Flutter Web rendert/schaalt, niet in het venster zelf). Geen DOM/accessibility tree beschikbaar (canvas-rendering) — find en read_page werken hier niet, alleen coördinaat-gebaseerd klikken. Geprobeerd en zonder succes: direct klikken op meerdere x-posities, klikken + Space-toets, horizontaal scrollen. Na 1-2 bevestigde pogingen stoppen en aan Bob vragen — geef het exacte pad (component, tree-node, veldnaam) zodat hij het in seconden kan doen.

  • Specifiek bevestigd structureel (2026-08-05) voor de "Show Empty List Widget"-checkbox op een Carousel: dit is geen per-component toeval maar een systematische blokkade van Claude's browser-automation-viewport — opgetreden op vier verschillende componenten (HomeUitgaanSliderComponent, PUitgaanSliderComponent, EvenementComponent, horecagelegenheidCurrent, allemaal Carousel). Niet meer opnieuw proberen per component — deze checkbox specifiek is voor Claude via browser-automation niet bereikbaar, ongeacht welk component. Verzamel in plaats daarvan de volledige lijst van componenten die de fix nodig hebben en geef die in één keer aan Bob (elk 10 sec in zijn eigen browser, geen viewport-beperking daar).

Patroon: lege/ontbrekende afbeeldings-URL laat de app crashen. CachedNetworkImage gooit een synchrone ArgumentError bij het bouwen van de widget als imageUrl een lege string is — dit gebeurt vóórdat er ooit een netwerkverzoek is, dus errorWidget/"Show Error Image on Failure" vangt dit niet (dat vangt alleen échte laadfouten zoals 404's). Werkende fix:

  1. Rechtsklik het Image-widget → Wrap Widget (Ctrl+B)ConditionalBuilder.
  2. IF-conditie: Conditions → Single Condition → First Value = de exacte expressie waar de Image's Path-property al aan gebonden was → operator "Is Set".
  3. THEN-tak: de bestaande Image (blijft staan na de wrap).
  4. ELSE-tak: rechtsklik → Insert Widget → Icon → "image not supported" → eerste Material-resultaat.
  5. Simpeler alternatief indien van toepassing: de "Default Variable Value"-toggle op een "Set from Variable"-binding substitueert al bij zowel null als lege string (in-builder tooltip: "if the resulting value is null or empty") — géén ConditionalBuilder nodig. Werkt hier niet voor Image-widgets met Image Type: Network zolang er geen gehoste fallback-afbeeldings-URL bestaat in dit project. Komt die er ooit (bv. default-logo op FlutterFlow-CDN/Drupal-server): gebruik dan Default Variable Value + "Show Error Image on Failure" — sneller te bouwen dan ConditionalBuilder.

Patroon: "Is Set and Not Empty"-conditie tegen een Default-Value/valueOrDefault-gebonden veld is een no-op — en kan een crash verbergen. Bevestigd 2026-08-07 (evenement_horecagelegenheid_widget.dart, zie TASKS.md P1-15): gegenereerde code als if (valueOrDefault<String>(veld, 'placeholder') != null && valueOrDefault<String>(veld, 'placeholder') != '') is altijd waar, omdat valueOrDefault bij een lege/ontbrekende bron juist de placeholder-tekst teruggeeft (nooit null/''). Gevolg: een widget die eigenlijk verborgen zou moeten zijn bij ontbrekende data blijft zichtbaar mét de placeholder-tekst — en als die widget een onTap/actie heeft die de (placeholder-)waarde gebruikt (bv. launchURL(valueOrDefault(...)) op een social-media-/website-knop), crasht de app bij tikken i.p.v. gewoon niets te doen. Fix: bind de Visibility/If-conditie's First Value niet aan een veld waar al een Default Value op zit, maar rechtstreeks aan de rauwe API-response- expressie (dezelfde JSON Path als de widget's eigen Path-property, vóór een eventuele Default Value-substitutie) met operator "Is Set" — zelfde recept als de CachedNetworkImage-fix hierboven. Check dit patroon bij elke knop/link die een API-veld gebruikt, niet alleen bij de al bekende P1-6-lijst met lelijke placeholder-tekst — die twee problemen (lelijke tekst vs. crash-bij-tikken) hebben dezelfde bron maar zijn niet automatisch allebei opgelost met alleen een betere Default Value-tekst.

Custom-Function met meerdere argumenten in een Set-Variable-actie: tweede argument bevriest de pagina. Bij het configureren van een multi-argument custom function (bv. gemeenteNaamById(lijst, id)) als Set-Variable-waarde: het eerste argument instellen via de "Search variables..." → categorie-expand → item-klik-flow werkt betrouwbaar. Zodra je daarna probeert het tweede argument in te stellen (klik op de argument-dropdown-selector, bv. van "lijst" naar "id"), kan de hele pagina volledig bevriezen (alle clicks doen niets meer, geen enkele visuele terugkoppeling) — bevestigd reproduceerbaar 2026-08-05 op gemeenteNaamById, NIET opgetreden bij hetzelfde patroon op provincieNaamById een moment eerder (niet 100% deterministisch, maar bij deze functie 3x achter elkaar gereproduceerd). Reload lost dit niet volledig op zoals bij het bekende "echt bevroren pagina"-patroon hierboven: de Custom-Function-keuze zelf (bv. welke functie, welk App-State-veld het target is) overleeft een reload wél, maar het al ingestelde eerste argument (bv. lijst) gaat weer naar "UNSET" terug — dus geen gratis doorstart, elke reload kost een herhaling van stap 1.

  • Niet blijven proberen na 2-3 pogingen (elke poging = volledige page-reload + component heropenen + Actions-tab + veld heropenen, kost al snel 10+ tool-calls) — meld concreet aan Bob welke twee argumenten hij moet zetten en op welk veld, dat kost hem in zijn eigen browser seconden.
  • Voorbeeld hoe dat er dan uitziet (2026-08-05, SelectStateDropDownComponentDropDownGemeente → Actions → On Selected → Action 1 → Set Fields → gemeenteSelectNaam): de functie gemeenteNaamById staat al goed gekozen (herkenbaar aan rode "gemeenteN…" tekst i.p.v. "Unset" in de Set Fields-lijst), nog toe te voegen: argument lijst = App State gemeentelijst, argument id = App State gemeenteSelectId, dan Confirm.
  • Zelfde bevroren-Confirm-patroon ook bevestigd op een Text-widget's If/Then/Else-conditie (niet alleen Custom-Function-argumenten) — 2026-08-05 op EventCurrent's AppBar-Row, in totaal 5x bevroren bij het klikken op "Confirm" (soms al bij de binnenste Single-Condition-Confirm, soms pas bij de outer Confirm) ná het instellen van een Single Condition (Is Set and Not Empty). Precies dezelfde stappen lukten wél zonder freeze op HeaderButtonsComponent, én lukten wél voor het vergelijkbare Gemeente-Custom-Function- argumentenpunt na een computer-restart — dus dit is niet louter algemene omgevingsinstabiliteit die met een restart oplost. Een computer-restart tussen pogingen 2 en 3 loste dit specifieke geval niet op (2x nieuwe freeze ná restart, identiek patroon). Blijft onverklaard waarom dit specifieke widget/actie op dit specifieke component structureel vaker vastloopt dan elders — mogelijk iets aan de AppBar-Row-context van EventCurrent zelf. Na 5x: gestopt met proberen, definitief overgedragen aan Bob (zie TASKS.md P0-3). Vuistregel blijft: 1-2 pogingen (incl. 1 reload), dan overdragen met exacte stappen — niet blijven proberen.

Tooltip toevoegen aan een icon-only widget: rechtsklik → Wrap Widget (Ctrl+B) → 4e rij van de grid (kan geclipt lijken) → 1e icoon (spraakwolkje) = "Tooltip". Genereert een AlignedTooltip, geen losse styling nodig. Werkt niet op iconen embedded als suffixIcon van een TextFormField (bv. Login-pagina wis-/toon-wachtwoord-iconen — geen losse wrapbare tree-node).

Widget toevoegen: gebruik de kleine inline "Insert Widget", niet de grote centrale "Insert"-modal. Rechtsklik op een Widget Tree-rij → "Insert Widget" (of het kleine "+"-icoon naast een tree-node) opent een compacte dropdown die betrouwbaar werkt: klik op een widget-kaart voegt 'm meteen toe. De grote centrale Insert-modal (bv. via de "+"-knop bovenaan het linkerpaneel) opent wél, en widget-kaarten lijken klikbaar/highlighten bij hover, maar een klik registreert niet — geen insertie, dialoog blijft open, geen foutmelding. Bevestigd 2026-08-05 op EventCurrent (Button toevoegen na EvenementHorecagelegenheid): pas de inline-variant via rechtsklik werkte. Sluit aan bij een eerdere observatie (2026-08-04, op HorecagelegenheidCurrent): een widget toevoegen in een AppBar-Row faalde herhaaldelijk stil via beide insert-varianten, terwijl exact dezelfde inline-picker op een gewone body-Column wél meteen werkte — mogelijk is een AppBar-Row specifiek een moeilijkere insertie-plek, sowieso eerst de inline-variant op een Column proberen vóór de grote modal.

  • Update 2026-08-07: de compacte inline-dropdown is niet betrouwbaar per se buiten AppBar-Row zoals hierboven gesuggereerd — op HorecagelegenhedenOverzicht (een gewone Column, TabBar-node) opende rechtsklik → "Insert Widget" herhaaldelijk wél de grote, kapotte modal (klikken/dubbelklikken/zoeken op widgetnaam, niets registreerde — 5+ pogingen). Blijkbaar niet 100% voorspelbaar per context. Werkende omweg wanneer je alleen decoratie/styling nodig hebt (geen echt nieuw kind-widget), bevestigd op ditzelfde component: i.p.v. een nieuwe widget te inserten, de bestaande node (bv. TabBar, of een Column met tags) Wrap Widget (Ctrl+B) → Container — dat dialoogvenster werkt wel betrouwbaar (bevestigd meerdere keren deze sessie) — en geef die nieuwe Container dan een BoxShadow/Fill Color/Border Radius via de eigenschappen-zoekbalk. Voor een schaduw onder een widget (bv. TabBar-afscheiding): Box ShadowShadow Color (hex-veld, bv. 33000000) → apart zoeken op "offset y" (aparte property, niet samen met "offset" x/y in één filter) en "blur". Voor een simpele achtergrond-scrim (bv. tegen storende achtergrond-afbeelding): alleen Fill Color op de wrap-Container volstaat al, ook zonder eigen padding als de wrap toevallig al een bestaande Padding-widget omvat. Bij een écht nieuw structureel widget (geen bestaande node om te wrappen) blijft de Insert-modal het enige pad — dan na 1-2 pogingen stoppen en aan Bob overdragen, zoals altijd.

Set-Variable/parameter-waarde koppelen aan App State: klein icoontje naast het "Value"-label, niet de tekstinvoer zelf. Bij een actie-parameter (bv. Navigate To met page-parameters) toont het "Value"-veld standaard een tekstinvoer (voor een letterlijke waarde). Om aan een variabele (App State, Page Parameter, …) te binden: klik op het kleine icoontje vlak vóór/naast het woord "Value" (niet in het invoerveld zelf) — dat opent een "Set Variable"-dialoog met een zoekbalk en een "Source"-lijst (Page Parameters/App State/Global Properties/…) om uit te klappen en te doorzoeken. Dit icoontje is makkelijk te missen/verkeerd te klikken (kleiner dan de rest van het paneel) — bij twijfel zoom gebruiken op de regio rond "Value" om de exacte pixelpositie te bepalen vóór je klikt.

  • Binden aan een veld van een lijst-item (bv. een ListView/GridView itemBuilder-variabele als "evenementen item"), 2026-08-07 bevestigd: het item zelf selecteren in de Set Variable-dialoog is niet genoeg — je krijgt dan het hele JSON-object, niet een veld ervan. Klik het item, dan "Available Options" (dropdown, staat eerst op "No Further Changes") → "JSON Path" → typ het pad met een voorloop-$, bv. $.nid of $.horecagelegenheidid (exacte veldnamen uit de API-respons, zie lib/backend/api_requests/api_calls.dart). Werkt identiek aan de al bestaande getJsonField(item, r'''$.veld''')-code elders in dit project — dit is precies hetzelfde patroon, alleen via de builder-UI ingesteld i.p.v. handmatig in code.
  • Direct binden aan een bestaande Component Parameter (niet JSON Path) is minder betrouwbaar dan het lijkt — altijd verifiëren via View Code. Op een non-JSON-Path-binding (klik direct op een Component Parameter-naam in de Set Variable-lijst, geen "Available Options" nodig omdat het al de juiste String is) leek de builder-UI 2026-08-07 een keer de waarde correct te tonen (Value-veld toonde de parameternaam oranje) maar genereerde de export toch serializeParam('', ParamType.String) — een lege string i.p.v. de parameter-referentie. Reproduceerbaar herstel: Value-icoontje opnieuw aanklikken, dialoog opnieuw openen, dezelfde parameter opnieuw selecteren — de tweede keer sloeg het wél correct op. Vertrouw dus nooit alleen op het rechterpaneel na zo'n binding; controleer altijd even via View Code (zie hieronder) dat de gegenereerde code echt naar de variabele verwijst en niet naar een lege/letterlijke waarde.

API-call headers: check op hardcoded literals i.p.v. [varname] templates. Werkt een call via curl wél maar vanuit de app/Response & Test-panel niet: check het Headers-tabblad — een handmatig ingeplakte testwaarde (bv. Cookie-header) kan per ongeluk blijven staan i.p.v. [sessionname]=[sessionid]. Check ook het per-variabele "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.

  • Werkende widget-verwijder-recept (bevestigd 2026-08-09, 5x succesvol op Login-knoppen): de zwevende toolbar boven een geselecteerd canvas-widget (prullenbak-icoon) lijdt aan hetzelfde coördinaat-probleem en klikt daardoor vaak mis (geen zichtbare fout, gewoon geen effect). Betrouwbaarder: rechtsklik op de Widget Tree-rij (niet het canvas) → tekst-menu-item "Remove Widget" (met woorden, niet het icoon) aanklikken. Werkte 5x op rij zonder falen zodra eenmaal de juiste rij geselecteerd was (zie hieronder voor selectie). Een simpele Delete-toetsaanslag wordt door de Bash/computer-permissie-classifier geblokkeerd als destructieve actie — niet bruikbaar, gebruik het menu-item.
  • Selectie-kalibratietruc: bij twijfel over de klik-offset, klik eerst op een duidelijk identificeerbare rij (bv. de eerste) en vergelijk in het rechterpaneel welke rij echt geselecteerd werd. Het verschil (in pixels) tussen bedoelde en werkelijke rij is op dat moment constant voor de rest van diezelfde paneel-render — pas die vaste correctie toe op volgende kliks i.p.v. te blijven gokken. Geldt zowel voor links- als rechtsklik.
  • Tekst typen in het rechterpaneel (bv. Hint Text/vertaalvelden) is op Claude's viewport structureel niet mogelijk gebleken (2026-08-09, login-hintText-veld). Klik, triple-click, Ctrl+A+typen, losse key-events, zelfs opzettelijk buiten-viewport-coördinaten (in de aanname dat click-ruimte niet 1-op-1 met screenshot-ruimte is) — niets kwam aan (waarde bleef letterlijk ongewijzigd). Dit is erger dan de bekende checkbox-clipping: niet alleen "net buiten beeld", maar functioneel onbereikbaar. Bob's tip (2026-08-09): voor een Text-widget zit naast het "Text"-label een klein bolletje/ globe-icoontje dat de vertaling direct opent — sneller dan via App Settings → Languages, en waarschijnlijk ook betrouwbaarder bereikbaar in Bob's eigen (niet-geclipte) browser. Nog niet bevestigd of dat icoontje voor Claude wél bereikbaar is (waarschijnlijk ook geclipt, niet meer getest deze sessie) — bij een volgende soortgelijke taak eerst dat proberen vóór je het opgeeft.
  • Testen met een niet-Nederlandse systeemlocale: gebruik adb shell cmd locale set-app-locales <package> --locales nl-NL (per-app override, Android 13+/API 33+) i.p.v. het systeembrede settings put system system_locales + am broadcast -a android.intent.action.LOCALE_CHANGED — dat laatste faalt zonder root (Neither user ... nor current process has android.permission.CHANGE_CONFIGURATION) en werkte zelfs als root niet betrouwbaar zonder herstart. De per-app cmd locale-route werkte in één keer, direct zichtbaar na een am force-stop + relaunch, geen reboot nodig — dit is de snellere/betrouwbaardere manier om P1-17-achtige locale-afhankelijke bugs te reproduceren/verifiëren.

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).

"+ Add App State Variable"/"+ Add App Constant"-knop reageert niet op Claude's klikken (2026-08-09). Op zowel ?tab=appValues&appValuesTab=state als ...=constant (bereikbaar via ⌘+K → typ een bestaande App State-naam → Enter, betrouwbaarder dan de linker-navigatierail klikken — zie hieronder): een klik op de knop opent geen dialoog, voegt geen rij toe (geverifieerd via de paneel-eigen zoekbalk erna — 0 resultaten), en blind doortypen na de klik komt nergens terecht. 6+ pogingen (directe klik, exacte pixel-herpositionering op zowel tekst als "+"-icoon, klik+wachten 2s, klik+blind-typen) — geen resultaat, geen zichtbare foutmelding. Navigeren tussen "App State"/ "Constants" in de linkerrail en het zoekveld typen werkten in dezelfde sessie wél probleemloos, dus dit is geen algemene klik-doodheid van de pagina, specifiek deze twee "Add"-knoppen. Los probleem: mogelijk gerelateerd aan de bekende Confirm-freeze-patronen elders in dit bestand, maar hier verscheen zelfs geen gedeeltelijke dialoog om vast te lopen — niets gebeurde. Ook: de rij-✏️-edit-iconen op bestaande App State-velden reageerden even onbewogen. Nog niet geprobeerd: browser-zoom (blijkt via keyboard-shortcut geblokkeerd, "page zoom keyboard shortcuts are not supported" — alleen de zoom-tool voor screenshots, niet de pagina zelf); Bob's eigen browser (geen bekende clipping daar). Vuistregel voor volgende sessie: nieuwe App State-velden/Constants zijn voor Claude niet zelfstandig toe te voegen — na 1-2 pogingen overdragen aan Bob met exacte veldnaam+type-specificatie (kost hem seconden per veld).

Domein/architectuurcontext

  • Taal/locale volgt het toestel, niet hardcoded Nederlands — zonder opgeslagen voorkeur (FFLocalizations/_kLocaleStorageKey) valt MaterialApp.locale terug op de systeemtaal van het toestel; matcht die met 'en' (tweede taal in FFLocalizations.languages() = ['nl','en']), dan draait de app in het Engels. Er is vrijwel geen echte Engelse vertaling (zie TASKS.md P1-17, live bevestigd 2026-08-07: van 169 sleutels in lib/flutter_flow/internationalization.dart zijn er maar 2 waar nl/en daadwerkelijk verschillen, en één daarvan is een fout i.p.v. een vertaling). Test dus altijd met het testtoestel/de emulator op Nederlands (adb shell getprop ro.product.locale checken), anders lijkt de UI kapot terwijl het eigenlijk gewoon de ontbrekende Engelse vertaling is.

  • Drupal 7 Services sessie-auth: sessid + session_name (uit LoginCall's response) vormen samen de sessie-cookie: Cookie: <session_name>=<sessid>. token is een los CSRF-token, alleen nodig bij schrijf-requests (POST/PUT/DELETE), nooit bij GET.

  • Drupal page cache bootstrapt vóór de sessie — een ooit anoniem gecachete response (bv. een 403) kan session-bootstrap, hooks én custom-module-logging volledig overslaan. Bij twijfel: Drupal-cache legen en opnieuw testen vóór verder debuggen.

  • Views numeric filter: $view->filter['uid']->value moet array('value' => $uid) zijn, niet array($uid) — de foute vorm faalt stil (geen filter toegepast) i.p.v. een error te geven.

  • Provincie/gemeente blijft het basismodel voor content-scoping (bevestigd: mensen zoeken primair lokaal). Home is de landelijke standaard-startpagina zónder verplichte gemeente-keuze vooraf — dat vervangt het provincie/gemeente-model niet, het is een aanvullende ingang. De Home-prefixed componenten (HomeUitgaantabelKaartComponent e.d.) zijn een bewuste kopie van PUitgaanSliderComponent/ UitgaantabelKaartComponent + een eigen cityid-loze API-call — geen dode code, niet meenemen in opschoonacties.

  • Favorieten/login zijn P0. Backend-endpoint bestaat al; Drupal 7 views die de respons voeden hebben soms nog aanpassing nodig.

  • Fout-/leeg-afhandeling bij API-calls: het "geen enkele FutureBuilder checkt op meer dan !snapshot.hasData"-beeld klopte niet helemaal (gecorrigeerd 2026-08-04). ApiCallResponse vangt netwerkfouten zelf op (api_manager.dart, catch (e) => ApiCallResponse(null, {}, -1, ...)) — de Future voltooit dus altijd, geen oneindige spinner. Het eigenlijke risico was een synchrone crash: bij jsonBody: null gooit getJsonField(null, ...).toList() een NoSuchMethodError vóórdat de lijst-widget ooit gebouwd wordt. Bob heeft hiervoor op HorecagelegenhedenOverzicht een werkend patroon gebouwd (2026-08-04, rechtstreeks in de builder): bij lege/mislukte data toont elke tab nu een standaardplaatje i.p.v. te crashen. Exacte builder-stappen (welke widget/property) nog niet gedocumenteerd — bij het uitrollen naar andere pagina's (zie TASKS.md P1-1) eerst navragen/naspeuren i.p.v. blind het Carousel-"Empty List Widget"-patroon hierboven te kopiëren, want dat lost alleen itemCount: 0 op, niet per se de null-jsonBody-crash die hier de kern van het probleem was.

  • API-call cache: true werkt functioneel correctApiCallOptions (lib/backend/api_requests/api_manager.dart) extends Equatable met params/headers in de props-lijst, dus de in-memory _apiCache vergelijkt op echte parameterwaarden (deep equality), niet op object-referentie. Geen reference-equality-bug om je zorgen over te maken — cache: true is een veilige, lichte performance-fix voor calls met effectief statische data binnen een sessie (referentie- lijsten zoals provincies/gemeenten, categorieën). Lost wél alleen herhaalde identieke calls op (bv. bij een rebuild), niet een eerste gelijktijdige burst van meerdere verschillende calls (bv. een eager TabBarView met 6+ tabs die elk hun eigen data ophalen bij page-load, zie TASKS.md P1-10).

Samenwerken met Bob

  • Bob is de enige developer/eigenaar, werkt vaak zelf gelijktijdig in dezelfde builder-sessie. Neem niet aan dat elke wijziging van jou komt.
  • Prioriteit: "eerst een werkende app live, daarna features" — P0 weegt zwaar boven P1 en P2. Bob herprioriteert soms fors zelf (bv. login+favorieten van P2 naar P0) — volg dat exact.
  • Claimt Bob een taak terug ("dat regel ik zelf") — stop daar direct mee en pak iets anders onafhankelijks op.
  • Kost iets veel tijd door handmatige builder-acties (vastzittende dialogen, geclipte controls): na 1-2 serieuze pogingen stoppen en concreet aan Bob voorstellen dat hij het zelf doet (exacte stappen).
  • Rapporteer nieuw gevonden bugs (vooral op een pagina waar Bob net zelf op zit) direct en duidelijk, niet pas in een latere samenvatting.