Prechádzať zdrojové kódy

TASKS.md: nieuwe taak P2-15 (evenementen/stadsactiviteiten aanmaken, Drupal-API klaar+getest, FlutterFlow-bouwplan) + CLAUDE.md: node->language='nl' vereist bij programmatisch node_save() (Calendar-crash gefixt)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
bob 2 týždňov pred
rodič
commit
6be5de9cfe
2 zmenil súbory, kde vykonal 108 pridanie a 0 odobranie
  1. 25 0
      CLAUDE.md
  2. 83 0
      TASKS.md

+ 25 - 0
CLAUDE.md

@@ -1465,10 +1465,35 @@ exacte veldnaam+type-specificatie (kost hem seconden per veld).
   `LoginCall`'s response) vormen samen de sessie-cookie:
   `LoginCall`'s response) vormen samen de sessie-cookie:
   `Cookie: <session_name>=<sessid>`. `token` is een los CSRF-token,
   `Cookie: <session_name>=<sessid>`. `token` is een los CSRF-token,
   alleen nodig bij schrijf-requests (POST/PUT/DELETE), nooit bij GET.
   alleen nodig bij schrijf-requests (POST/PUT/DELETE), nooit bij GET.
+- **Handmatig curl-testen tegen Drupal Services: voeg altijd HTTP Basic
+  Auth toe (`curl -u <user>:<pass> ...`), zowel op devbob als productie.**
+  Bevestigd 2026-08-26: zonder deze `-u`-vlag krijg je geen JSON terug maar
+  een kale challenge-/foutpagina die op het eerste gezicht als een
+  Cloudflare-blokkade oogt (bevatte zelfs Cloudflare-JS-snippets) — bleek
+  in werkelijkheid een server-niveau HTTP Basic Auth-laag vóór Drupal,
+  losstaand van de gewone Drupal-sessie-login hierboven. Kostte een aantal
+  verwarrende rondes voordat dit duidelijk werd; voortaan gewoon altijd
+  meegeven. Credentials staan niet hier (git-bestand) maar in de lokale
+  Claude-projectmemory.
 - **Drupal page cache bootstrapt vóór de sessie** — een ooit anoniem
 - **Drupal page cache bootstrapt vóór de sessie** — een ooit anoniem
   gecachete response (bv. een 403) kan session-bootstrap, hooks én
   gecachete response (bv. een 403) kan session-bootstrap, hooks én
   custom-module-logging volledig overslaan. Bij twijfel: Drupal-cache
   custom-module-logging volledig overslaan. Bij twijfel: Drupal-cache
   legen en opnieuw testen vóór verder debuggen.
   legen en opnieuw testen vóór verder debuggen.
+- **Programmatisch een node aanmaken (`node_save()` buiten het
+  website-formulier om, bv. via een custom Services-actie): zet
+  `$node->language` op `'nl'`, niet op `LANGUAGE_NONE`.** Bevestigd
+  2026-08-26 (v2 evenementen/stadsactiviteiten-aanmaak, zie
+  `TASKS.md` P2-15): `LANGUAGE_NONE` leek logisch omdat veld-*waarden*
+  toch al onder `LANGUAGE_NONE`/`['und']` staan, maar het node-**taal**-
+  attribuut zelf hoort op deze i18n-bewuste site op `'nl'` te staan
+  (bestaande content staat op "Nederlands", nooit op "Taalonafhankelijk").
+  Met `LANGUAGE_NONE` crashte elke pagina die de nieuwe node toont/bewerkt
+  met `Attempt to assign property "calendar_date_link" on null in
+  calendar_plugin_row->pre_render()` — Date Views' `$view->date_info`-
+  opbouw bleek afhankelijk van de node-taal. Alle overige velden (datum,
+  adres, geo, stad) waren steeds al correct; dit was zuiver het
+  `language`-attribuut. Geldt generiek voor toekomstig programmatisch
+  `node_save()`-werk op deze site, niet uniek voor één endpoint.
 - **Views numeric filter**: `$view->filter['uid']->value` moet
 - **Views numeric filter**: `$view->filter['uid']->value` moet
   `array('value' => $uid)` zijn, niet `array($uid)` — de foute vorm
   `array('value' => $uid)` zijn, niet `array($uid)` — de foute vorm
   faalt stil (geen filter toegepast) i.p.v. een error te geven.
   faalt stil (geen filter toegepast) i.p.v. een error te geven.

+ 83 - 0
TASKS.md

@@ -2544,3 +2544,86 @@ overwegen bij een volgende theme-update:
    nodig, eerder een patroon om **naar de app te kopiëren** (zie
    nodig, eerder een patroon om **naar de app te kopiëren** (zie
    P2-11/P1-27: de app's hamburger is een klein rood knopje, minder
    P2-11/P1-27: de app's hamburger is een klein rood knopje, minder
    opvallend).
    opvallend).
+
+---
+
+**P2-15 · Eigenaar: Bob (builder), Claude regisseert/verifieert —
+zelfde live pair-fix-aanpak als eerder.** Evenementen/stadsactiviteiten
+aanmaken vanuit de app (horeca-eigenaren + elke gebruiker). **Drupal-kant
+volledig klaar en curl-getest op devbob (2026-08-26)** — dit is nu
+zuiver FlutterFlow-bouwwerk. Volledige achtergrond/velden/beslissingen
+staan in het Artifact "Redactierechten & Contentschema"
+(`https://claude.ai/code/artifact/becb0c6f-e43b-4392-9f84-7dbf44eda5b2`,
+sectie "FlutterFlow-vervolgspec") — open dat eerst, hieronder alleen de
+samenvatting + concrete eerste bouwstappen.
+
+**Endpoints (allemaal bevestigd werkend):** `evenementen/create`,
+`stadsactiviteiten/create`, `mijn_horecagelegenheden` (index),
+`mijn_stadsrechten` (index), `categorieen` (index),
+`bestand_upload/upload`. Basis-auth (`bob:serhii`, zie lokale
+Claude-memory) nodig voor handmatig curl-testen, niet vanuit de app
+zelf.
+
+**Look & feel — bevindingen uit de bestaande app-code (geen browser
+gebruikt, puur codeonderzoek):**
+- **`HorecagelegenheidoverzichtKaartWidget`**
+  (`lib/horecagelegenhedenoverzicht/horecagelegenheidoverzicht_kaart/`)
+  is al de kaart-widget die Favorieten Tab 2 gebruikt
+  (`favorieten_widget.dart:678`, in een `MasonryGridView.builder`) —
+  parameters (`nid`, `titel`, `adres`, `plaats`, `logo`, `categorie`)
+  matchen 1-op-1 met wat `mijn_horecagelegenheden` teruggeeft. **Gewoon
+  hergebruiken** voor de nieuwe "Mijn horecagelegenheden"-sectie, geen
+  nieuwe kaart-widget nodig.
+- **Geen bestaand upload-precedent in de app** (`grep` op
+  `ImagePicker`/media-upload buiten `custom_code/` gaf 0 treffers) —
+  de foto-upload-flow (image picker → bytes → base64 → nieuwe custom
+  action → `bestand_upload/upload` → fid) is de enige écht nieuwe
+  bouwsteen zonder bestaand patroon om te kopiëren. Grootste
+  onzekerheid in deze taak; begin hier apart mee testen vóór je de
+  hele formulier-pagina bouwt.
+- **Thema:** gewoon `FlutterFlowTheme.of(context)`-tokens overal
+  gebruiken (primary `#4B39EF`, secondary `#39D2C0`, tertiary
+  `#EE8B60`, font Inter/Inter Tight via Google Fonts) — geen eigen
+  palet nodig, sluit al aan bij de rest van de app.
+- **Waar leeft "mijn profiel"?** Er bestaat nu geen aparte
+  profiel-pagina — `FavorietenWidget` (`lib/favorieten/`) heeft een
+  4e tab "Gebruiker" (`favorieten_widget.dart:245`) met een simpele
+  verticale lijst `ListTile`-rijen (Uitloggen, Wachtwoord wijzigen,
+  Account verwijderen — zie regel 700-935, patroon: `InkWell` →
+  `Material` → `ListTile` met `trailing: Icon(Icons.arrow_forward_ios_rounded)`,
+  `tileColor: secondaryBackground`, `borderRadius: 8.0`). **Aanbeveling:
+  nieuwe secties "Mijn horecagelegenheden" en "Mijn redactierechten"
+  hier bovenaan toevoegen** (vóór Uitloggen) i.p.v. een hele nieuwe
+  pagina + nav-entry te bouwen — kleinste wijziging, blijft binnen de
+  al bestaande "Gebruiker"-tab die feitelijk al de profielpagina is.
+  **Open vraag voor Bob:** akkoord met deze plek, of toch een losse
+  pagina? (zijn oorspronkelijke formulering was "de user profile
+  pagina, los van de favoriete pagina" — kan ook betekenen dat hij een
+  ECHT aparte pagina wil, niet nog een tab op dezelfde `FavorietenWidget`.)
+
+**Concrete bouwvolgorde (1 stap per keer, zoals gebruikelijk):**
+1. Custom action `bestand_upload` bouwen (image picker → base64 →
+   POST) en LOS testen (upload 1 plaatje, bevestig een fid terugkomt)
+   vóór er iets anders bijkomt.
+2. Pagina "Stadsactiviteit aanmaken" (simpelste van de twee — geen
+   eigenaarschap-gate, geen horecagelegenheid-picker): velden per de
+   Stadsactiviteit-tabel in het Artifact, plaats-picker (bestaand
+   patroon, zie `SelectStateDropDownComponent`/`Selectprovinciegemeente`),
+   categorie-multiselect via `categorieen/index`. Na indienen: melding
+   "wordt beoordeeld", niet "geplaatst".
+3. Pagina "Evenement aanmaken": horecagelegenheid-picker gevuld via
+   `mijn_horecagelegenheden` (auto-select bij precies 1 resultaat),
+   verder zelfde velden-aanpak als stap 2.
+4. "Gebruiker"-tab (of nieuwe pagina, zie open vraag hierboven):
+   sectie "Mijn horecagelegenheden" (hergebruik
+   `HorecagelegenheidoverzichtKaartWidget`) + "Mijn redactierechten"
+   (`mijn_stadsrechten`, verberg de sectie helemaal als leeg), elk met
+   een knop die naar stap 2/3 navigeert met een page-parameter
+   (`plaats_tid` resp. `horecagelegenheid_nid`) vooringevuld.
+
+**Nog te testen (restpunten uit de curl-ronde, niet kritiek maar wel
+before-launch de moeite waard):** `mijn_stadsrechten` met een
+niet-triviale gebruiker; `evenementen/create` met een horecagelegenheid
+die NIET van de ingelogde user is (moet 403 geven); >5 `fotos_fids`
+(moet 400 geven); een ongeldige `categorie_tid` (moet 400 geven, geen
+kale crash).