Skip to content

feat(site): the Zuiddrecht example site, installed and removed with one command - #1206

Merged
rubenvdlinde merged 36 commits into
developmentfrom
feat/zuiddrecht-demo-site
Oct 5, 2026
Merged

rubenvdlinde merged 36 commits into
developmentfrom
feat/zuiddrecht-demo-site

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

What this adds

The website of Zuiddrecht, a municipality that does not exist, as a site an administrator installs with one command and removes with one command. It replaces the hand-made VNG-styled portal we show in demonstrations, which nobody can install.

OpenSpec change: example-site-zuiddrecht.

  • The site declaration lib/Settings/sites/zuiddrecht.json: the portal record (theme zuiddrecht, header search, the button "Mijn Zuiddrecht", the footer with its button and contact column), the main menu and two footer menus, 33 pages and 4 public news items. Header, footer, home and the page "Afval scheiden en ophalen" follow the approved boards (Kop, Voet, Home, Contentpagina). The other 31 pages are short new copy, so no link is dead.
  • occ portaliq:example-site:install zuiddrecht writes what is missing and never changes what is there. After writing it reads the instance back: per type the number found, and per created object every declared key the stored object lost. Exit 0 complete, 1 nothing done, 2 something missing or lost. It does not trust the answer of the write, because OpenRegister echoes a key the schema drops.
  • occ portaliq:example-site:remove zuiddrecht deletes the objects the install recorded and nothing else. A portal that was there before, or that holds content of your own, stays.
  • The current menu item can sit in the line under the menu (the latest decision on the Kop board: a red line, and a blue 5px piece under the current item). Two optional theme tokens, --nldesign-website-nav-current-in-line and --nldesign-website-nav-current-color. Without them the item keeps its bar.
  • A designed site reads in the set's own font. The vendored sheet sets the family on body as a literal, so the menu, hero heading, task labels and link lists stayed in Roboto under a set that names Fira Sans (measured: 40 of 78 text runs on the home page). Only for a portal with the designed header.
  • Tables and link lists are readable on a set that names no role for them: room in a cell, a line between rows, room between links. Each rule reads the set's token first.
  • nlLinkList and nlButtonLink open pages of the site wherever it is served. Their links were plain paths, so on a portal reached through Nextcloud (?portal=), which is how every fresh install is reached, they left the site. Link list links also take the theme's link colour instead of the browser's blue.
  • The site names a set's grey emblem (--nldesign-emblem-grey-url), for a watermark without a tint.
  • Documentation: docs/Installation/example-site-zuiddrecht.md.

Depends on

Files of this change

lib/Settings/sites/zuiddrecht.json, lib/Service/ExampleSite/* (7 classes), lib/Command/ExampleSiteInstall.php, lib/Command/ExampleSiteRemove.php, appinfo/info.xml, css/site-theme.css (the blocks marked example-site-zuiddrecht), src/site/widgets/nlLinkList, nlButtonLink, nlActionGroup, the emblem-grey variant in PortalThemeResolver, PortalPageController and templates/site.php, package.json (the new check), docs/Installation/example-site-zuiddrecht.md, openspec/changes/example-site-zuiddrecht, and the tests below.

Verified

All of this ran on the branch after development was merged in (head defafc7d).

  • PHPUnit, new: ExampleSiteInstallerTest (against the shipped declaration and a store that drops unknown keys, refuses a page, ignores filters), ExampleSiteStoreTest, ExampleSiteCommandsTest: 24 tests green. 17 mutations tried in two rounds on the installer, remover, record and proof: five survived, four are caught now by added tests, one is equivalent (the guard for a portal row without an id).
  • node, new: tests/example-site.spec.mjs, in check:specs. It holds the declaration against the register's schemas (a key a schema does not declare is an error), the widgets the site renders and the props each takes, its own links, and the house style. Ten controls tried, each fails the right test. Rerun after the merge against a register from before feat(site): the header, footer, sign-in page and motif of the school designs #1202: it fails and names portal.headerSearch, portal.accountLabel and portal.footer.cta.
  • composer check:strict, full run: exit 1.
    • lint, phpcs (0 errors), psalm and phpstan clean.
    • PHPUnit: 46 errors, all "class not found" for Nextcloud and OpenRegister classes outside a server tree. The same suite on a clean clone of origin/development (ca591037) beside this one, same PHP, same vendor: 46 errors, and the list of failing tests is identical (compared line by line). None is a test of this change.
    • phpmd named three findings on this change's classes at line numbers of code that is no longer there (ExampleSiteCatalogue::find() complexity 13 at a method that now has two branches). The same command on the whole of lib/ with a cache of its own (a fresh HOME, so not the ~/.pdepend every clone on this machine shares) finds nothing, exit 0, for both rulesets. The three were served from the shared cache.
  • npm run lint 0 errors, stylelint 0, format 0, check:manifest 0, check:l10n-js 0, check:schema-l10n 0, check:reuse 0.
  • check:specs: each of its 113 checks run on its own, without a build in js/: 113 pass. check:ways-in-screens, red while this branch carried feat(site): the header, footer, sign-in page and motif of the school designs #1202 unmerged, passes now.
  • hydra gates (ConductionNL/.github main, base origin/development): 87 of 87 applicable gates ran, all passed. Gate-16, red before on feat(site): the header, footer, sign-in page and motif of the school designs #1202's files, is clean.
  • openspec validate example-site-zuiddrecht --strict: valid.
  • Not run: a production webpack build, and PHPUnit inside a Nextcloud with OpenRegister (the tree where the 46 classes resolve).

Seen in a browser, and how

Rendered in Chromium from this branch's own bundle (development build), this branch's CSS, thematiq #1097's files plus the six follow-up token lines, with the content API answered from the declaration through the real PortalShell projection. No instance was changed.

  • Home and "Afval scheiden en ophalen" at 1440 px and 390 px. No horizontal scroll at 390 px.
  • Every visible text pair on five pages computed from the rendered colours: lowest 5.64:1 (white on #3669A5 and the reverse), all pass 4.5:1.
  • Twelve tab stops on the home page: the skip link first, then search, the account button, the menu. Each shows the dotted outline with its white halo.
  • Links in a link list, a button link and the task tiles open the page without a page load.

Not seen: the install against a real OpenRegister, the site served by PHP from stored objects, the remove command on an instance, and the search page with OpenCatalogi. The coordinator's live check covers these.

Live check

  1. On an instance with openregister, thematiq (development, ideally with fix(inbox): a dossiq message shows its text, date, read state and attachments #1099) and this branch: occ maintenance:repair (register 0.66.0), then occ portaliq:example-site:install zuiddrecht. Expect four lines ending in 1, 3, 33, 4 found afterwards and exit 0.
  2. Open /index.php/apps/portaliq/site?portal=zuiddrecht: logo, search box, button "Mijn Zuiddrecht", seven menu items, the red line with the piece under "Home", the footer with the three bands.
  3. Click "Afval": the table, the side list, the breadcrumb. Click a link in "Meer over afval": the address keeps portal=zuiddrecht.
  4. Run the install again: every line says 0 created.
  5. occ portaliq:example-site:remove zuiddrecht: Portal: deleted, exit 0, and the address answers not found.

Copy that is not from the design files

Header, footer, home and "Afval scheiden en ophalen" carry the boards' text. These 31 pages exist so no link is dead, and their copy is new. Strike any you do not want: each is one entry in pages of the declaration, and the check then names the links that point at it.

  • Afvalbrengstation: /afval/afvalbrengstation
  • Container kapot of kwijt: /afval/container
  • Afvalstoffenheffing: /afval/afvalstoffenheffing
  • Wonen en leven: /wonen-en-leven
  • Paspoort en ID-kaart: /paspoort-en-id-kaart
  • Verhuizing doorgeven: /verhuizing-doorgeven
  • Melding openbare ruimte: /melding-openbare-ruimte
  • Afspraak maken: /afspraak-maken
  • Belastingen betalen: /belastingen
  • Parkeren: /parkeren
  • Ondernemen: /ondernemen
  • Bestuur en organisatie: /bestuur
  • Vergaderingen en stukken: /bestuur/vergaderingen
  • Raadsleden: /bestuur/raadsleden
  • Inspreken bij de raad: /bestuur/inspreken
  • Burgemeester en wethouders: /bestuur/college
  • Besluiten van het college: /bestuur/collegebesluiten
  • Coalitieakkoord: /bestuur/coalitieakkoord
  • Inkoop en aanbesteding: /bestuur/inkoop
  • Werken bij Zuiddrecht: /werken-bij-zuiddrecht
  • Klacht over de gemeente: /klacht
  • Contact en openingstijden: /contact
  • Alle onderwerpen van A tot Z: /onderwerpen
  • Toegankelijkheid: /toegankelijkheid
  • Privacy: /privacy
  • Cookies: /cookies
  • Kwetsbaarheid melden: /kwetsbaarheid-melden
  • Nieuws: /nieuws (no copy of its own: shows the news items)
  • Al het nieuws: /nieuwsoverzicht (no copy of its own: shows the news items)
  • Zoeken in Woo-publicaties: /zoeken (one line of copy; the search and detail blocks do the rest)
  • Publicatie: /publicatie (one line of copy; the search and detail blocks do the rest)

The four news items have the boards' titles and dates. Their body text is new, except the first item's opening line.

Left out of the design, and why

  • "Veel gezocht" under the hero search: the hero block has no place for a row of links.
  • The alert strip's link and its yellow ground: the banner block takes text only, and its colour is the theme's.
  • The news photo: the item has no photo, the list shows none.
  • The grey band behind "Bestuur en organisatie": a page has no coloured section block.
  • The postcode form on the afval page: no block looks up a waste calendar.
  • The task icons are the block's own 18 line icons, not the board's drawings.
  • The card button reads "Inloggen bij Mijn Zuiddrecht", not "Inloggen met DigiD": the portal has two ways in, and the button opens the choice.
  • The check marks on that card take the set's accent, red on the deep blue. They are decoration. A token for a mark on a dark card would fix it in thematiq.
  • Page headings keep the site's size (32px), smaller than the board's 44px.

🤖 Generated with Claude Code

… read through /api/content/news

newsItem 0.4.0 (register 0.59.0) gains public, portal and audienceLabel.
PublicNewsReader serves only published items staff put on this portal,
never one about single children, and only photos from the portal's own
published media library.
…d for the school home pages

nlQuickTasks, nlNewsList, nlNewsArticle and nlEventList load on demand.
nlSignIn gains a card display and is handed the portal's own ways in;
nlList draws numbered steps. OpenSpec change site-school-blocks.
…ch, the account button, the footer button and contact column, and the sign-in cards
…p, phone menu), designed footer, sign-in cards, motif and hero styling
…th its own name for screen readers (lane L3's shape)
…ts through logoFileFor, the register test knows the new keys
…demo site places

The register moves to 0.63.0 with portal 0.10.0 and newsItem 0.4.0, so the
schema keys of both merged branches reach an instance on upgrade.
…link list and button link open pages of the site wherever it is served
…laration is checked against the register, the widgets and its own links
…anded)

The register moves to 0.65.0 with portal 0.10.0: development is at 0.64.0, and
the portal keys of site-chrome-follows-the-design reach an instance only when
the version moves.
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/portaliq @ 56ac773

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ✅
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-specs ❌
check-manifest ✅
format ✅
check-l10n-js ✅
check-schema-l10n ❌
check-reuse ✅
composer ✅ ✅ 108/108
npm ✅ ✅ 984/984
app:check-code ⏭️
info.xml ✅
REUSE ✅
lockfile sync ✅
PHPUnit ✅
Newman ✅
Playwright ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development.
Hydra gates ❌

Quality workflow — 2026-10-05 17:53 UTC

Download the full PDF report from the workflow artifacts.

Development carries the portal keys now (register 0.66.0, portal 0.11.0), so this
branch takes its register as it is: the example site adds no schema key.
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/portaliq @ 9ea23fd

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ✅
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-specs ✅
check-manifest ✅
format ✅
check-l10n-js ✅
check-schema-l10n ✅
check-reuse ✅
composer ✅ ✅ 108/108
npm ✅ ✅ 984/984
app:check-code ⏭️
info.xml ✅
REUSE ✅
lockfile sync ✅
PHPUnit ✅
Newman ✅
Playwright ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development.
Hydra gates ✅

Quality workflow — 2026-10-05 18:29 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit 41adb1c into development Oct 5, 2026
46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant