Bläddra i källkod

API-oppervlak dichtgezet (fase 1+2) en mijn_aanmeldingen-filters bewezen

Fase 2 op devbob en productie doorgevoerd: node/retrieve + relationships/files,
file/create + file/retrieve, taxonomy_term en taxonomy_vocabulary uit. Endpoint
flutterdrup gaat daarmee van 42 naar 22 methodes.

Het bewezen lek is weg: node/<nid>.json gaf anoniem 200 met 46 velden inclusief
'name' (de inlognaam van de auteur, dus user enumeration) en geeft nu 404.
Nagemeten dat ongepubliceerde nodes al 403 gaven en file/create anonieme POSTs
al weigerde, dus die twee waren minder urgent dan eerder ingeschat.

Regressiecheck op beide omgevingen: vijf views-endpoints 200, plaatsen /
plaatsen_bij_gemeente / horecacategorieen 200, POST user/login.json 401 op
onzin, en een afbeelding uit een view 200 image/jpeg — file/retrieve uitzetten
breekt dus geen afbeeldingen.

mijn_aanmeldingen.json: ?type= en ?komend= staan op productie en zijn met een
echte sessie bewezen, mét tegencontrole dat onbekende parameters stil genegeerd
worden. Drupal-kant van taak 110 is af.

G0.7 feature graphic klaar (variant B), in ~/uk-play-assets/feature-graphic/.
Pagina Event vastgelegd als doodlopend spoor: onbereikbaar in de app, maar
verwijderen/hernoemen/verplaatsen falen alle drie.

CLAUDE.md: drush-scripts moeten naar aegir1 (scp -P 959), bouw een stand-kop in
beheerscripts, en meet bij API-dichtzetten ook wat moet blijven werken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bob 1 dag sedan
förälder
incheckning
638837e2af
2 ändrade filer med 89 tillägg och 64 borttagningar
  1. 42 0
      CLAUDE.md
  2. 47 64
      TASKS.md

+ 42 - 0
CLAUDE.md

@@ -2301,6 +2301,16 @@ kind zijn eigen hoogte. Zat er geen pagination op, dan is de Replace zonder
 voorbereiding te doen en gaat `shrinkWrap` er vanzelf af (wat klopt zodra de
 ouder een begrensde hoogte geeft, bv. een `Expanded`).
 
+**⚠️ Een sleep in de Widget Tree landt alleen als de DOEL-rij vooraf GESELECTEERD
+is (2026-09-20, taak 110, ~12 mislukte pogingen vóór dit duidelijk was).** Klik
+eerst de doel-`Column` aan (rechterpaneel toont 'm), druk `Escape`, en sleep dán.
+Een sleep naar een niet-geselecteerde doelrij laat de bronrij gedimd achter en
+verandert niets — ook niet bij een tweede poging of na een herlaad. Een verse
+`zoom` van de boom vóór elke sleep blijft nodig, want de rijen schuiven.
+**Tussen twee `TabBar Page`s slepen kan bovendien niet rechtstreeks:** in twee
+hops via de buitenste `Column` (drop op de Column-rij → positie 0, dan die
+Column-rij deselecteren, doel-kolom selecteren en opnieuw slepen) werkt wel.
+
 **Een widget VERPLAATSEN lukt wél — sleep de rij in de Widget Tree, en
 een drop op een container-rij voegt hem er altijd als EERSTE kind in.**
 Bevestigd 2026-09-03 (P1-36, `HorecagelegenheidoverzichtKaart`): een
@@ -4909,6 +4919,38 @@ minder calls per scherm, niet in Views.
   kijk naar 404 vs 403** — 403 ("Toegang geweigerd voor gebruiker anonymous")
   betekent "route bestaat, sessie ontbreekt", 404 betekent "resource niet
   aangezet". Dat onderscheid scheelt zoeken in de verkeerde hoek.
+
+**⚠️ Een drush-script dat Claude schrijft moet eerst NAAR AEGIR1 — drush draait
+niet op Bob's desktop.** Kostte 2026-09-20 een hele ronde: het script stond in
+`/home/bob/Projects/`, Bob draaide op de server het gelijknamige oude script uit
+`~/tmp/`, en de uitvoer zág er goed uit (hij zette netjes 12 methodes uit) —
+alleen waren het de verkeerde. **Bouw daarom in elk beheerscript een
+"HUIDIGE STAND"-kop in die per doelwit `<-- FASE N` toont**, dan zie je in de
+droogdraai meteen of je het juiste script voor je hebt. Overzetten:
+```
+scp -P 959 <script> o1@aegir1.digitalforce.nl:~/tmp/
+drush @<alias> php-script ~/tmp/<script>        # droogdraai als default
+drush @<alias> php-script ~/tmp/<script> doen   # uitvoeren
+```
+Aliassen: `@uitgaanskrant.com` (productie) en `@devbob.uitgaanskrant.com`.
+
+**Meet bij het uitzetten van API-oppervlak ook wat er moet BLIJVEN werken — en
+meet dat op devbob vóór productie.** Alleen "geeft het nu 404?" is een halve
+check; de vraag is of de app nog draait. Vaste regressieset voor dit project:
+de vijf views-endpoints · `plaatsen` · `plaatsen_bij_gemeente` ·
+`horecacategorieen` · `POST user/login.json` met onzin-gegevens (moet **401**
+geven, niet 404) · en **een afbeeldings-URL uit een view**. Dat laatste nam
+2026-09-20 de enige reële twijfel weg bij `file/retrieve`: afbeeldingen lopen via
+directe `sites/.../files/`-URL's en staan volledig los van de Services
+`file`-resource, dus die uitzetten breekt niets.
+
+**Een 403 op een schrijf-resource is niet hetzelfde als een lek.** Bij het
+afwegen van wat er dicht moet: test elke resource ook echt anoniem in plaats van
+op zijn naam af te gaan. `file/create` klonk als open schrijftoegang maar weigerde
+anonieme POSTs (403), en `node/retrieve` respecteerde node access netjes
+(ongepubliceerde node → 403). Wat er wél lekte was subtieler: van een
+**gepubliceerde** node gaf `node/<nid>.json` 46 velden terug inclusief `name` —
+de inlognaam van de auteur, dus user enumeration op al je redacteuren.
   hierop wijst:** een endpoint/pad dat op de ene Drupal-omgeving prima
   werkt en op de andere een 404 geeft mét een compleet lege body en
   zonder de gebruikelijke custom response-headers (bij dit project

+ 47 - 64
TASKS.md

@@ -18,24 +18,26 @@ De **app-kant is vrijwel af.** Op 2026-09-19 zijn o.a. afgerond: de
 header-locatie-keten (Home toont *Heel Nederland*, provinciepagina de
 provincienaam), het adaptive icon, de loginpagina, het drawer-logo, Crashlytics,
 "Mijn aanmeldingen", de categoriedropdown op het horeca-overzicht, de
-horeca-agenda-entiteiten en de opruimronde. Wat rest is **livegang-werk**:
-Google Play, het API-oppervlak dichtzetten, en één doorloop die alleen Bob kan
-doen.
+horeca-agenda-entiteiten en de opruimronde. Op 2026-09-20 kwamen daar het **dichtgezette API-oppervlak** (42 → 22 methodes,
+het `name`-lek weg) en de **feature graphic** bij. Wat rest is **livegang-werk**:
+Google Play en één doorloop die alleen Bob kan doen.
 
 ## 👤 CLAUDE — OPEN
 
 | # | Taak | Kort |
 |---|---|---|
 | **G0.6** | Play-screenshots | ✅ Nieuwe set van 10 klaar (2026-09-19 avond). Alleen `tel-04-horeca.png` moet over zodra *Show Test Ads* uit staat |
-| **nameten** | Na het services-script op productie | `node/<nid>.json` moet 403/404 geven i.p.v. 200 met 46 velden |
 
-| **110** | `MijnProfiel` ombouwen naar 3 tabs | **Eigenaar: Claude — bezig (2026-09-20).** Tab 1 *Mijn evenementen* (komende horeca-evenementen + horecakaarten met knop "+ Evenement aanmaken"), tab 2 *Stadseditor* (komende activiteiten + gemeenten met knop "+ Activiteit aanmaken"), tab 3 *Account*. Opzet zoals `Favorieten`. Drupal-kant (Bob): `mijn_aanmeldingen.json` heeft `?type=` en `?komend=1` — ✅ op devbob geplaatst en getest 2026-09-20, **nog naar productie**. Hint-link onder de horecalijst → `https://uitgaanskrant.com/nl/support/mobieleapp` (Bob). Bijvangst: "Uitloggen" stond op `desktop: false` |
+| **110** | `MijnProfiel` ombouwen naar 3 tabs | **Eigenaar: Claude — bezig (2026-09-20).** Tab 1 *Mijn evenementen* (komende horeca-evenementen + horecakaarten met knop "+ Evenement aanmaken"), tab 2 *Stadseditor* (komende activiteiten + gemeenten met knop "+ Activiteit aanmaken"), tab 3 *Account*. Opzet zoals `Favorieten`. ✅ **Drupal-kant is AF**: `mijn_aanmeldingen.json?type=go_out_event|activity` en `?komend=1` staan op **productie** en zijn met een echte sessie bewezen (2026-09-20, `bobcity`), mét tegencontrole dat onbekende parameters stil genegeerd worden. Hertesten kan met `/home/bob/Projects/test-mijn-aanmeldingen.sh [prod]` (leest het wachtwoord zelf in). Hint-link onder de horecalijst → `https://uitgaanskrant.com/nl/support/mobieleapp` (Bob). Bijvangst: "Uitloggen" stond op `desktop: false` |
+
+| **112** | `Selectprovinciegemeente` / `SelectStateDropDownComponent` opknappen | **Eigenaar: Claude — bezig (2026-09-20).** (a) hartje-tekst → "Maak favoriet" / "Favoriet"; (b) mailtekst `24bdnkhi` weg; (c) favorietenlijst van `Wrap` → `Column` met echte rijen (speldje + naam + chevron, witte rij, scheidingslijn) onder de kop "of kies een favoriet"; (d) hartje-status synchroniseren met de serverlijst (`favorieteGemeenteIds` wordt nu nooit vanaf de server gevuld); (e) kop+lijst achter de ingelogd-conditie; (f) lege `drupalRequest('GET','','','','','')` uit de On-Component-Load-keten |
+
+| **113** | Filterbalk (zoek + datum + chips) ook op `PUitgaanPage` | **Eigenaar: Claude — bezig (2026-09-20).** `PUitgaanPage` bedient **provincie én gemeente** (10 drawer-ingangen: 5 categorieën × `provincieSelectId`/`gemeenteSelectId`) — één keer bouwen dekt beide. Drupal is al klaar: gemeten op productie dat `townid` samen met `datum_van`/`datum_tot`/`zoek` werkt op plaats- (28695), gemeente- (28694) én provincie-tid (28666), mét tegencontrole `onzinparam=123` → ongewijzigd. Nog te doen in de app: (1) `UitgaanstabelCall` 3 variabelen + query-parameters erbij; (2) `PUitgaantabelKaartComponent` 3 parameters (Required **uit**) + binden in de Backend Query; (3) filterbalk op de pagina. Onderzoeksstap loopt: werkt *Convert to Component* op het filterblok in `homeCopy`? |
 
 ## 👤 BOB — OPEN, in volgorde van wat de livegang blokkeert
 
 | # | Taak | Waarom nu |
 |---|---|---|
-| **🔒 API dichtzetten — FASE 2** | `node`, `file`, `taxonomy_term`, `taxonomy_vocabulary` | Fase 1 staat **op productie** en is nagemeten ✅. Fase 2 is een bewuste afweging — zie het blok |
 | **G** | Google Play-checklist G0–G4 | Volledige checklist hieronder |
 | **65** | De **ingelogde** doorloop | Kernfuncties zijn nooit op een release-build getest. Claude kan dit niet (geen wachtwoorden) |
 | **AdMob** | `Show Test Ads` uit | App Settings → AdMob. Wacht op de Google-registratie |
@@ -129,7 +131,15 @@ die twee niet meer los afwerken. Vink hier af.*
       `gemeenteSelectId`), terwijl Home *Heel Nederland* zegt. Voor een event in
       Steenwijk oogt dat wat vreemd; als je dat consequent wilt, is dat een aparte
       taak op de header-keten.
-- [ ] **G0.7 — Feature graphic 1024×500** laten maken (grafisch werk, Bob).
+- [x] **G0.7 — ✅ KLAAR (Claude 2026-09-20, variant B gekozen door Bob).**
+      📁 `~/uk-play-assets/feature-graphic/DEFINITIEF-feature-graphic-1024x500.png`
+      — 1024×500, RGB zonder alpha, 88 kB; voldoet aan de Play-eisen.
+      **B = het complete app-icoon links als afgeronde tegel op leisteen
+      (`#3E454C`), rechts de naam + tagline + oranje accentstreep.** Rood op
+      leisteen geeft het icoon contrast; de twee andere merkkleuren doen de rest.
+      Variant A (merkelement groot op merkrood) staat ernaast, niet gekozen.
+      `feature.py` staat erbij: tekst of kleur wijzigen is één regel + opnieuw
+      draaien. Rest nog: uploaden bij **G3.2**.
 
 #
 
@@ -274,65 +284,29 @@ taak 100 zette de padding op 40; opnieuw bekijken bij de volgende release-build)
   drawer én de data-deletion-URL voor Play) en `/nl/support/privacybeleid`.
 - **`devbob` staat niet meer in de levende app-code** (alleen in dode kopieën).
 
-## 🔒 API-oppervlak dichtzetten — FASE 1 AF OP PRODUCTIE (2026-09-20)
-
-**Bob draaide `services-dicht.php` op productie; Claude heeft nagemeten.**
-
-| moet dicht | productie |
-|---|---|
-| `user/1.json` · `geocoder.json` · `userestablishments.json` | **404** ✅ |
-| `POST system/connect.json` | **404** ✅ |
-
-| moet blijven werken | productie |
-|---|---|
-| `plaatsen` · `plaatsen_bij_gemeente` · `horecacategorieen` | **200** ✅ |
-| alle vijf views-endpoints | **200** ✅ |
-| `POST user/login.json` | **401** ✅ (bestaat, wijst af op onzin-inloggegevens) |
-
-12 methodes uitgezet, gelogd in watchdog.
-
-### ⚠️ Correctie: het alarm was overtrokken — er stond nooit schrijftoegang open
-
-De droogdraai gaf de **werkelijke** stand: **42 methodes**, niet "tientallen
-inclusief create/update/delete". Concreet stond er nooit aan:
-`node/create|update|delete` · `system/set_variable|del_variable` ·
-`taxonomy_term/create|update|delete` · `taxonomy_vocabulary/create|update|delete`.
-
-**Oorzaak van de misser:** Claude leidde die lijst af uit de geplakte HTML van het
-resourcescherm, waar **"Enabled" een kolomlabel is en geen status**. Bob wees daar
-al op bij `system`. Les: die pagina-tekst is onbruikbaar om vinkjes uit af te
-lezen — gebruik de droogdraai van het script of een live HTTP-test.
-Wat wél hard bewezen was en blijft staan: `node/<nid>.json` geeft anoniem **200**
-met 46 velden, inclusief `name` (de inlognaam van de auteur).
+## ✅ API-oppervlak dichtgezet — KLAAR (2026-09-20)
 
-### 🔵 FASE 2 — nog open, vier resources
-
-Staan nog uitgecommentarieerd in het script. Wat er nu nog aanstaat:
-
-| resource | methodes | oordeel |
-|---|---|---|
-| `node` | `operations/retrieve`, `relationships/files` | 🔴 **het bewezen lek** — `node/222338.json` geeft nog 200. De app gebruikt `node/*` nergens |
-| `file` | `operations/create`, `operations/retrieve` | ⚠️ `create` is **schrijftoegang** ("Create a file with base64 encoded data"). De app uploadt via `bestand_upload/upload` |
-| `taxonomy_term` | `operations/retrieve`, `actions/selectNodes` | alleen lezen |
-| `taxonomy_vocabulary` | `operations/retrieve`, `actions/retrieveByMachineName` | alleen lezen |
+**Fase 1 én 2 staan op productie en zijn nagemeten.** Van 42 naar **22**
+methodes op endpoint `flutterdrup`. Het bewezen lek is weg: `node/<nid>.json`
+gaf anoniem 200 met 46 velden inclusief `name` (de **inlognaam** van de auteur,
+dus user enumeration) en geeft nu 404.
 
-**Afweging:** de app roept geen van vieren aan (geverifieerd op de export). Het
-enige risico van uitzetten is een ánder script dat ze gebruikt — Feeds niet, die
-werkt via de interne Drupal-API. Bob koos ervoor de accesslog niet te
-controleren, dus dit is een bewuste afweging: `node/retrieve` en `file/create`
-zijn de twee die het meest de moeite waard zijn.
+**Dicht (404):** `node/retrieve` + `relationships/files` · `file/create` +
+`file/retrieve` · `taxonomy_term` · `taxonomy_vocabulary` · `user/retrieve|create|
+delete|logout|token|user_pass_reset|cancel|password_reset|resend_welcome_email` ·
+`system/connect` · `geocoder` · `userestablishments`.
 
-**Stand 2026-09-20 (nagemeten door Claude, anoniem, Dart-UA):** `node/222338.json`
-**200** met 46 velden waaronder `name = 'bob'` · `taxonomy_term/28695.json` **200** ·
-`file/1.json` 406. Fase 2 staat dus nog volledig open.
+**Blijft aan (22):** de app-resources (`plaatsen`, `plaatsen_bij_gemeente`,
+`horecacategorieen`, `views`, de favorieten-, aanmaak- en upload-acties,
+`mijn_*`, `categorieen`, `entreeopties`, `accountdelete`) plus `user/login` en
+`user/request_new_password`.
 
-📁 **Het script staat weer klaar: `/home/bob/Projects/services-dicht-fase2.php`**
-(het oude stond in een vluchtige sessie-scratchpad en was weg). Droogdraaien met
-`drush @<alias> php-script /home/bob/Projects/services-dicht-fase2.php`,
-uitvoeren met `... -- doen`. Doet zelf `services_endpoint_save()` +
-`menu_rebuild()` + `cache_clear_all()` + een `watchdog()`-regel.
+**Regressiecheck na afloop, devbob én productie:** alle vijf views-endpoints 200 ·
+`plaatsen`/`plaatsen_bij_gemeente`/`horecacategorieen` 200 · `POST user/login.json`
+401 op onzin · een afbeelding uit een view 200 `image/jpeg`.
 
-**Daarna nameten:** `node/222338.json` moet 403/404 geven in plaats van 200.
+📁 Script: `/home/bob/Projects/services-dicht-fase2.php` (droogdraai is de default,
+`doen` als argument voert uit). Bewaren voor als er ooit een resource bij komt.
 
 ### 📌 Views-resource: al beperkt, niets te doen
 
@@ -356,9 +330,18 @@ niet op de toegestane lijst", niet "display bestaat niet".
 
 - **Builder-opruimronde, laatste restanten.** Nog in de export: componenten
   `SliderUitgaanComponentSmallCurrent` en
-  `PUitgaantabelKaartComponentOrgineelMetKaartjeerin`, pagina `Event` (weigert
-  structureel élke wijziging met "Invalid Action" — na één poging laten staan) en
-  de custom function `dISABLEdatumVoorApi`. Moet in de **builder**, niet met
+  `PUitgaantabelKaartComponentOrgineelMetKaartjeerin` en de custom function
+  `dISABLEdatumVoorApi`.
+
+  ⚠️ **Pagina `Event`: laten staan, dit is een doodlopend spoor.** Bob bevestigde
+  2026-09-20 dat óók *hernoemen* afketst op "Invalid Action" — verwijderen,
+  verplaatsen en hernoemen falen dus alle drie, ook in zijn eigen browser.
+  **Nagemeten op de export (2026-09-20): de pagina is onbereikbaar.** De enige
+  verwijzingen zijn de twee die FlutterFlow automatisch voor élke pagina
+  genereert (`index.dart` en de route-registratie in `nav.dart`); er is nergens
+  een `goNamed`/`pushNamed` naartoe. Geen enkele gebruiker komt er dus, behalve
+  via een handmatige deep link. Kosten van laten staan: één dode route in
+  `nav.dart` en ~30 kB in de app. Niet opnieuw agenderen. Moet in de **builder**, niet met
   `git rm` — anders staat alles na de volgende export terug.
 
 - **P1-17 · laatste vertaling(en).** `1k52hayg` → `End date` en `22xoyrqe` →