Explorar el Código

B3/B5 afgemeld, P2-44 vervalt, Drupal-code taak 88A + Crashlytics-actie klaar

B3 geverifieerd op productie: helppagina heeft nu een sectie "Zelf een
evenement of activiteit aanmelden" met een link naar /nl/ondernemers#hoewerkthet.

B5 geverifieerd met verse export: alle 13 dode eenheden weg, dart analyze
0 errors, geen ambiguous_import.

P2-44 vervalt op Bob's besluit (er bestaan geen evenementen zonder datum).

Taak 88A: gekozen voor een custom Services-resource i.p.v. Views, omdat A1
ongepubliceerde nodes moet tonen, A2 rauwe tids/fids en een 403 nodig heeft,
en alle bestaande mijn_*-endpoints al custom resources zijn. Veldnamen uit
het inventarisatie-Artifact; A2's sleutels gecontroleerd tegen de twee
create-actions in de app.

G0.1 (D-U-N-S) afgevinkt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bob hace 11 horas
padre
commit
9b957fd453
Se han modificado 1 ficheros con 106 adiciones y 13 borrados
  1. 106 13
      TASKS.md

+ 106 - 13
TASKS.md

@@ -30,8 +30,8 @@ klopt sinds je 'm las.*
    `EvenementInfo` en de zaakpagina.
 4. **88 · "Mijn aanmeldingen" + kloonknop** — nieuw 2026-09-18, zie het blok
    hieronder. Deel A (Drupal) bij Bob, deel B (app) bij Claude.
-5. **P2-44 · datum-icoon zonder datum op `EventCurrent`** — ⚠️ niet gelukt via
-   browser-automation, ligt bij Bob; zie het blok verderop voor de valkuil.
+5. ~~**P2-44 · datum-icoon zonder datum op `EventCurrent`**~~ — **VERVALT**
+   (Bob 2026-09-19: er bestaan geen evenementen zonder datum).
 6. ~~**P2-45 · knop "Selecteer datum" naast de datumchips op Home**~~ — **AF**
    (Claude 2026-09-18, label door Bob 2026-09-19), export-geverifieerd. Nog open,
    allebei klein: **P2-45b** (annuleren van de kiezer zet het filter op vandaag)
@@ -87,7 +87,12 @@ direct onder deze lijst** (opgesteld 2026-09-19 op Bob's verzoek; vervangt en
 consolideert taak 63 a-i en punt 2 van "Bob's 7"). Dit is de langste wachtstap
 en staat los van alle code.
 
-**B3 · Helppagina: één link erbij (taak 87, deel 1). 2 minuten Drupal.**
+**B3 · ✅ AF 2026-09-19 (Bob), geverifieerd.** De helppagina heeft nu een hele
+sectie "Zelf een evenement of activiteit aanmelden" mét een link naar
+`https://uitgaanskrant.com/nl/ondernemers#hoewerkthet` (anker bestaat, pagina
+geeft anoniem 200). Oorspronkelijke opdracht hieronder bewaard.
+
+**B3 (origineel) · Helppagina: één link erbij (taak 87, deel 1).**
 Op `/nl/support/mobieleapp` staat de zin *"Horecagelegenheden toevoegen kan op
 dit moment alleen via de website."* — gemeten vanmiddag: **zonder link**. Maak
 van die zin een link naar `https://uitgaanskrant.com/nl/ondernemers` (anoniem 200,
@@ -96,18 +101,26 @@ Claude bouwt dezelfde verwijzing tegelijk in de app in (taak 87 deel 2), dus dan
 sluit het op elkaar aan. Daarna `cc all` + de Cloudflare-rule purgen.
 
 **B4 · Twee builder-dingetjes waar Claude aantoonbaar niet bij komt.**
-- **P2-44 · datum-icoon zonder datum op `EventCurrent`.** Zie het blok verderop
-  voor de valkuil: de Visibility-conditie moet via *Conditions → Single Condition
-  → Is Set*, **niet** door de API-respons rechtstreeks als bron te kiezen — die
-  tweede route genereert `if (getJsonField(...))` zonder null-check en crasht bij
-  runtime. Claude kreeg die Conditions-sectie niet opengeklikt.
+- **P2-44 · ❌ VERVALT — besluit Bob 2026-09-19: "er bestaan geen evenementen
+  zonder datum".** De guard is dus overbodig; het eenzame kalender-icoon kan in
+  de praktijk niet optreden. Niet opnieuw voorstellen.
 - **P2-45a · label van de datumknop op Home.** De binding naar de custom function
   `datumKnopLabel` vraagt een **Confirm** in de Set-Variable-dialoog, en die knop
   reageert niet op browser-automation (8 pogingen, Remove en Cancel werken wél).
   ⚠️ Een half gebonden functie-argument **blokkeert de export van het hele
   project** — dus als je dit oppakt, maak het in één keer af of klik *Remove*.
 
-**B5 · Opruimen — jij verwijdert, Claude nooit (staande regel).**
+**B5 · ✅ AF 2026-09-19 (Bob), geverifieerd.** Alle 13 dode eenheden verwijderd
+(`HeaderButtonsComponentCopy`, `HeaderCurrentCopy`, `DrawerComponentCopy`,
+`HomeCopy`, `HomeCopy2`, `KanwegHomeCopy`, `KanwegHeaderButtonsComponentCopy`,
+`HomeUitgaanSliderComponentCopy`, `HomeUitgaantabelKaartComponentCopy`,
+`KanweghorecagelegenheidCurrentCopy`, `FavorietenCopy`, `FavorietenCopy2`,
+`HorecagelegenheidEventTabelComponentCopy`, `KanwegHorecagelegenhedenOverzicht`).
+Verse export + `fvm dart analyze lib/` → **0 errors**, geen `ambiguous_import`.
+Alleen `lib/kanweg_test_upload` staat er nog (stond niet op de lijst; los te
+beoordelen). Oorspronkelijke opdracht hieronder bewaard.
+
+**B5 (origineel) · Opruimen — jij verwijdert, Claude nooit (staande regel).**
 `HeaderButtonsComponentCopy` mag weg (taak 89a: taak 89 is af en gecommit als
 `4c3f0aa`, deze kopie was het vangnet). En de twaalf dode eenheden van taak 70 /
 P2-7 — de actuele lijst staat in het livegang-blok verderop; `homeCopy2` staat
@@ -143,10 +156,10 @@ die twee niet meer los afwerken. Vink hier af.*
   de app uit Play. Dit is de meest gemaakte fout en kost weken.
 
 ### G0 · Nu doen, terwijl de verificatie loopt (buiten Play Console)
-- [ ] **G0.1 — D-U-N-S: check of Digital Force er al een heeft** vóór je een
-      nieuwe aanvraagt (dubbele nummers geven later een mismatch). Gratis bij
-      Dun & Bradstreet. Leg het nummer + de exact geregistreerde bedrijfsnaam en
-      het adres vast. 🔴 Langste wachtstap.
+- [x] **G0.1 — D-U-N-S: AL BINNEN** (Bob 2026-09-19: "die krijg je standaard in
+      Nederland, heb ik al gevonden"). De langste wachtstap valt dus weg.
+      ⚠️ Blijft staan: leg het nummer vast mét de **exact** daarop geregistreerde
+      bedrijfsnaam en adres — die moeten letterlijk matchen met G0.2.
 - [ ] **G0.2 — Payments-profiel gelijktrekken** met precies die naam/adres.
 - [ ] **G0.3 — Besluit upload-route** (was taak 63d, nog open): FlutterFlow-deploy
       (advies — dan hoeft er lokaal niets) óf lokaal. Lokaal betekent een keystore
@@ -391,6 +404,86 @@ export met een generieke 400 (zie `CLAUDE.md`) — loopt dat vast, dan is het ee
 Bob-stukje. (2) `stadsactiviteitAanmaken` heeft exact hetzelfde formulier­patroon;
 bouw eerst evenementen helemaal af en kopieer daarna pas, niet allebei tegelijk.
 
+### 🆕 88A · Drupal-code LIGT KLAAR (Claude 2026-09-19) · Eigenaar: Bob (plaatsen + testen)
+
+Bob's vraag: *"kun je hier een custom view voor custom module maken, of is het
+makkelijker met views?"* → **Custom resource, geen Views.** Vier redenen, in
+volgorde van gewicht:
+1. **A1 moet ongepubliceerde nodes tonen** — dat is de hele functie ("wacht op
+   goedkeuring"). Views filtert die standaard weg; je zou het Published-filter
+   moeten slopen én de permissie *view own unpublished content* moeten uitdelen.
+2. **A2 moet rauwe tids en fids geven.** Views levert principieel labels en
+   URL's — precies waarom `flutterflow_events.json` niet volstaat.
+3. **A2 heeft een 403 nodig** bij andermans node. Views kan geen statuscode geven.
+4. **Het bestaande patroon is al custom resource.** Alle `mijn_*`-endpoints staan
+   op `/nl/flutterdrup/<naam>.json`, niet onder `/flutterdrup/views/`.
+Bijkomend: Views-sleutelnamen komen uit het veld-*label* (bekende valkuil), en
+`field_date` staat in UTC — in een custom callback reken je dat in één regel om.
+
+**Geleverd (drie bestanden, naar Bob gestuurd):**
+- `custom.mijn_aanmeldingen.inc` — beide callbacks + helpers (284 regels).
+- `custom.module-WIJZIGINGEN-taak88.txt` — de twee regels die in `custom.module`
+  moeten, plus ⚠️ de resource aanvinken op
+  `/en/admin/structure/services/list/flutterdrup/resources` (anders kale 404).
+- `curl-testen-taak88.sh` — 8 tests incl. de foutpaden 401/403/404/400.
+
+**Veldnamen komen uit het inventarisatie-Artifact**, niet gegokt:
+`go_out_event` → `title_field`, `field_date`, `body`, `field_horecagelegeheid1`
+(let op de typo in de veldnaam zelf), `field_goo_entree`, `field_entrance`,
+`field_admission_notes`, `field_tickets`, `field_website2`, `field_logo4`,
+`field_picture2`, `field_category2`, `field_city_taxonomy_reference_`.
+`activity` → `title`, `field_date`, `body`, `field_act_state_municipality_tow`,
+`field_entrance_fee`, `field_admission_rules`, `field_website1`, `field_logo2`,
+`field_pictures`, `field_act_categorie`, `field_address1`, `field_act_organiser`,
+`field_act_contact`.
+
+**A2's sleutels zijn 1-op-1 gelijk aan wat de app al naar de create-endpoints
+stuurt** (gecontroleerd tegen `evenement_create.dart` en
+`stadsactiviteit_create.dart`): `horecagelegenheid_nid`, `titel`,
+`omschrijving`, `entree_tid`, `entree_prijs`, `toelichting_entree`,
+`tickets_url`, `website_url`, `categorie_tids`, `logo_fid`, `fotos_fids`.
+⚠️ Dit corrigeert de oorspronkelijke spec, die `entreeprijs` (zonder streepje)
+noemde. De kloonknop kan de waarden nu ongewijzigd doorgeven.
+
+**Fids hergebruiken (Bob's antwoord: mag) — waarschijnlijk GEEN extra werk.**
+Drupal's `file_field_insert()` roept bij `node_save()` zelf
+`file_usage_add($file, 'file', 'node', $nid)` aan, dus dezelfde fid op twee
+nodes geeft gewoon twee usage-rijen en het bestand blijft bestaan zolang één
+node het gebruikt. Voorwaarde: de create-resource vult het veld en doet een
+echte `node_save()` (dat doet hij). **Te verifiëren met één kloontest:** kloon
+een aanmelding met foto, verwijder het origineel, en controleer dat de foto op
+de kloon nog laadt. Alleen als dat misgaat is een expliciete `file_usage_add()`
+nodig.
+
+**De datumvelden komen bewust NIET mee in A2** — je kloont juist om hetzelfde
+op een nieuwe datum te zetten, en twee lege datumvelden zijn meteen de rem
+tegen per ongeluk dezelfde aanmelding twee keer publiceren.
+
+⚠️ **Niet edge-cachen.** Beide endpoints zijn per definitie user-specifiek en
+horen achter de `SESS`-cookie-voorwaarde te blijven, net als de andere
+`mijn_*`-endpoints.
+
+**Daarna is deel B (de app) aan Claude:** overzichtspagina `MijnAanmeldingen` +
+ingang op Favorieten tab 4, daarna pas de kloonknop.
+
+### 🆕 66 · Crashlytics-testactie LIGT KLAAR (Claude 2026-09-19) · Eigenaar: Bob (plaatsen + Firebase bekijken)
+
+`crashlytics_test.dart` — één custom action `crashlyticsTest(String? modus)`,
+argument mag **Unset** blijven (String mag dat; alleen een List-typed argument
+blokkeert de export). Drie standen: Unset → echte crash, `melding` → niet-fatale
+melding, `flutter` → via de `FlutterError.onError`-koppeling uit `main.dart`.
+
+**Gemeten gat in de huidige opzet:** `main.dart:44` zet alléén
+`FlutterError.onError`. Er is **geen** `PlatformDispatcher.instance.onError`,
+dus een fout in een async custom action buiten het framework wordt **niet**
+gerapporteerd. Zeg het als dat erbij moet — dat is één regel in `main.dart`,
+maar `main.dart` is gegenereerd, dus het moet via FlutterFlow's
+*Final Actions*/custom-code-hook, niet lokaal.
+
+**Verwachting bij het testen:** een echte crash wordt pas bij de **volgende
+start** van de app geüpload. Een `melding` gaat meteen weg en verschijnt onder
+*Non-fatals*. Reken op ~5 minuten tot het in het dashboard staat.
+
 ### 🆕 87 · Uitleggen waar je een horecagelegenheid aanmaakt — kan alleen via de website · Eigenaar: Bob (helppagina-link, = B3), Claude (app-kant — de sectieregel staat er al, alleen de klikbare link ontbreekt nog; zie taak 91)
 
 Bob 2026-09-17: *"we moeten nog ergens kwijt dat we uitleggen waar je een