Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
9157f17
fix(reporting): the KPI contradicted the error banner beside it (#1268)
rubenvdlinde Aug 27, 2026
cb909e6
fix(aggregations): the segment-P&L batch, verified against the rows (…
rubenvdlinde Aug 27, 2026
85b9d46
fix(l10n): translate 2,213 manifest strings into Dutch (#1274)
rubenvdlinde Aug 27, 2026
310eb9c
fix(aggregations): the consolidated trial balance, with a real debit/…
rubenvdlinde Aug 27, 2026
589ac7a
fix(aggregations): gate the BARE half of the field-reference check (#…
rubenvdlinde Aug 27, 2026
6dc211a
docs(repair): point the RetireSubsidieSchema hold at the issue that e…
rubenvdlinde Aug 27, 2026
74d199e
fix(deps): development cannot npm install (#1285)
rubenvdlinde Aug 27, 2026
381982a
fix(clean-env): point the vendored skill at a script that exists (#1277)
rubenvdlinde Aug 27, 2026
1fc10c1
perf(ci): one Code Quality run per commit, not two (#1294)
rubenvdlinde Aug 27, 2026
465c670
fix(walkthrough): give the getting-started tour a stop at Flows (#1292)
rubenvdlinde Aug 27, 2026
e0593c7
fix(schemas): exclusiveMinimum must be a number, not true
rubenvdlinde Aug 27, 2026
a7b3671
feat(demo-data): ship demo data for all 499 shillinq schemas (ADR-111)
rubenvdlinde Aug 27, 2026
e494ef4
feat(glline): declare fiscalYearId, and backfill it from the parent t…
rubenvdlinde Aug 27, 2026
4590af4
refactor(lib): collapse three single-class namespaces into Service/ (…
rubenvdlinde Aug 27, 2026
31d7332
fix(aggregations): translate the legacy DSL — batch 1 of the #1261 sw…
rubenvdlinde Aug 27, 2026
2a89656
fix(walkthrough): let the Flows stop actually reach people who alread…
rubenvdlinde Aug 27, 2026
2b36eab
feat(setup): offer the demo data as the first setup step (ADR-111 rul…
rubenvdlinde Aug 27, 2026
77ad6c9
chore(l10n): translate the three strings the Flows walkthrough stop s…
rubenvdlinde Aug 27, 2026
8e3c9f0
fix(aggregations): translate the expression-bearing operations maps —…
rubenvdlinde Aug 27, 2026
0c48c9e
chore: merge development into feat/demo-data-adr-111
rubenvdlinde Aug 27, 2026
030f676
fix(manifest): fit the ADR-111 demo-data step inside the boot-payload…
rubenvdlinde Aug 27, 2026
60d59ca
fix(tests): pass DemoDataService where the SetupController constructo…
rubenvdlinde Aug 27, 2026
2b546cf
fix(aggregations): reach the files a bulk rewrite could not — batch 3…
rubenvdlinde Aug 28, 2026
2ced115
fix(l10n): translate the demo-data step, and rebuild the browser cata…
rubenvdlinde Aug 28, 2026
0118955
fix(l10n): keep the manifest strings in nl.json only
rubenvdlinde Aug 28, 2026
847d91d
build(deps): take @conduction/nextcloud-vue 2.21.0 so the Flows stop …
Aug 28, 2026
71a884a
fix(aggregations): rename the last plain `operation` declarations to …
rubenvdlinde Aug 28, 2026
4312e0f
fix(demo-data): the mock no longer carries blocks that name PHP code
rubenvdlinde Aug 28, 2026
fab5b5b
fix(aggregations): numeric conditions, and infer the source from the …
rubenvdlinde Aug 28, 2026
f05155c
fix(demo-data): the mock carries objects, not a second copy of every …
rubenvdlinde Aug 28, 2026
70618c4
chore(deps): hydra-gates 1.10, so the E2E skip-discipline gate can ru…
rubenvdlinde Aug 28, 2026
486e26d
fix(ci): a push to development must reach a verdict here too (#1311)
rubenvdlinde Aug 28, 2026
74eccbc
Revert "fix(schemas): exclusiveMinimum must be a number, not true"
rubenvdlinde Aug 28, 2026
4be80ae
Merge pull request #1300 from ConductionNL/chore/walkthrough-flows-l10n
rubenvdlinde Aug 28, 2026
072a1a4
test(setup): cover the demo-data action, which nothing exercised
rubenvdlinde Aug 28, 2026
e865045
refactor(manifest): the flow pages are an index and a flow (#1302)
rubenvdlinde Aug 28, 2026
fdc0e52
fix(setup): open with welcome, then the demo-data offer (ADR-111 rule 4)
Aug 28, 2026
935e05c
Merge development: resolve the Dutch catalogue, keep welcome-first
Aug 28, 2026
1b4186c
fix(l10n): restore the demo-data translations a merge resolution dropped
rubenvdlinde Aug 28, 2026
d71e45e
test(demo-data): cover the unreadable-descriptor branch
rubenvdlinde Aug 28, 2026
72546d4
Merge pull request #1295 from ConductionNL/feat/demo-data-adr-111
rubenvdlinde Aug 28, 2026
5fa00e0
docs: add a local demo environment (shillinq-compose.yaml + setup pag…
rubenvdlinde Aug 28, 2026
38931fc
test(e2e): exercise the ADR-111 demo-data step against a running inst…
rubenvdlinde Aug 28, 2026
7ee6ac9
fix(e2e): stand the setup wizard down before it covers the shell (#1322)
rubenvdlinde Aug 28, 2026
c106ffd
fix(e2e): close the setup wizard by satisfying every step, not just t…
rubenvdlinde Aug 28, 2026
0d76773
fix(ci): ci-seed aborted on an unbound SERVER_DIR, taking E2E with it
rubenvdlinde Aug 28, 2026
c10cf6b
Merge pull request #1328 from ConductionNL/fix/ci-seed-unbound-server…
rubenvdlinde Aug 28, 2026
c9c99e6
fix(e2e): define SERVER_DIR, which ci-seed references but never set (…
rubenvdlinde Aug 28, 2026
7db15d8
fix(e2e): a real demo-data import needs more than the 60s default (#1…
rubenvdlinde Aug 28, 2026
ed3a93f
fix(validate-seeds): read both schema shapes, as the seed collector does
rubenvdlinde Aug 28, 2026
b29bbbe
Merge pull request #1334 from ConductionNL/fix/validate-seeds-reads-b…
rubenvdlinde Aug 29, 2026
7e4ee76
chore(deps): @conduction/nextcloud-vue 2.21.0 -> 2.22.1 (#1338)
rubenvdlinde Aug 29, 2026
abe3715
fix(l10n): drop nine locale bundles that ship another language's text…
rubenvdlinde Aug 29, 2026
5b8bfe6
fix(l10n): drop the three locale copies a byte comparison could not s…
rubenvdlinde Aug 29, 2026
ba788c7
fix(l10n): drop three locale bundles that ship another language's tex…
rubenvdlinde Aug 29, 2026
aec94c3
ci(docs): publish from development, and retire the old hostname (#1341)
rubenvdlinde Aug 29, 2026
b417420
chore(release): 0.2.2-unstable.20260829131116 (#1346)
github-actions[bot] Aug 29, 2026
2493c76
chore(deps): @conduction/nextcloud-vue 2.22.1 -> 2.24.1 (#1347)
rubenvdlinde Aug 29, 2026
88b87c5
chore(deps): @conduction/nextcloud-vue 2.24.1 -> 2.24.2 (#1349)
rubenvdlinde Aug 29, 2026
378ec12
build(deps): bump pinia from 3.0.4 to 4.0.3 (#1243)
dependabot[bot] Aug 30, 2026
0534dbe
feat(flows): give the flow-detail canvas its sidebar (#1336)
rubenvdlinde Aug 30, 2026
de145db
chore(sync): record beta's ancestry on development
rubenvdlinde Aug 30, 2026
df7ac14
chore(sync): carry beta back into development
rubenvdlinde Aug 30, 2026
679300f
Merge pull request #1352 from ConductionNL/sync/beta-to-development-2…
rubenvdlinde Aug 30, 2026
93bd565
Merge pull request #1353 from ConductionNL/sync/beta-ancestry-2026083…
rubenvdlinde Aug 30, 2026
f1fecdb
fix(build): make the frontend resolve pinia 4 (#1351)
rubenvdlinde Aug 30, 2026
efc90ff
chore(release): 0.2.3-unstable.20260829195247 (#1350)
github-actions[bot] Aug 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 68 additions & 16 deletions .claude/skills/clean-env/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ description: Reset the OpenRegister development environment (stop, remove volume

# Clean Environment

Run the `clean-env.sh` script to fully reset the OpenRegister development environment.
Reset the Conduction dev instance and bring it back up healthy.

This will:
1. Stop all containers from the OpenRegister docker-compose
2. Remove all containers and volumes (full data reset)
3. Start containers fresh
4. Wait for Nextcloud to become ready
5. Install core apps: openregister, opencatalogi, softwarecatalog, nldesign, mydash
> **This skill used to name a script that does not exist.** It said to run
> `bash .claude/scripts/clean-env.sh`; there is no such file in this repo or in
> any app checkout, and there never was one to find. Its documented app list was
> five entries long (`openregister opencatalogi softwarecatalog nldesign
> launchpad`) at a time when the fleet was twenty-one and three of those five
> names were app *directories* rather than app ids. Anyone following it got a
> "command not found" if they were lucky and a half-configured instance if they
> improvised past it. The real, maintained entry point is
> `.github/dev-up.sh` — it is the one place that knows about the mounts, the
> vendored PHP dependencies and the frontend bundles.

**Model check — only apply when this skill is run standalone. Skip this section entirely if this skill was called from within another skill — the calling skill is responsible for model selection.**

Expand All @@ -27,22 +31,70 @@ This will:

## Instructions

Run the clean-env script:
Work from the workspace root (the directory holding `.github/` and the app
checkouts as siblings).

### Restart and heal — the common case

Most "my environment is broken" reports need only this. It re-establishes
partial mounts, clears maintenance mode, runs pending migrations, installs any
missing `vendor/`, enables every mounted Conduction app and reports any app
whose frontend bundle would render blank:

```bash
bash .github/dev-up.sh
```

### Full reset — destructive

**This deletes the database and every volume.** Only run it when a full reset is
actually intended; `dev-up.sh` alone fixes most breakage.

```bash
bash .claude/scripts/clean-env.sh
docker compose -p openregister -f .github/docker-compose.yml down -v
bash .github/dev-up.sh
```

**Important:** This is a destructive operation — it removes all database data and volumes. Only run when a full reset is intended.
## Verifying

After the script completes, verify the environment:
1. Check that Nextcloud is accessible at http://nextcloud.local
2. Log in with admin/admin
3. Confirm apps are listed and enabled
`dev-up.sh` ends in a status block — read it rather than assuming success:

- `needsDbUpgrade: false` — an instance stuck at `true` serves a 503 the moment
anything trips maintenance mode.
- `apps visible: N/N` — a shortfall is named per app, and it says whether the
cause is an empty checkout (clone it) or a mount that did not attach.
- `apps enabled:` plus any `⚠` lines. **A `⚠ … need a frontend rebuild` line
means those apps are enabled and still render a blank page** — `occ` reports
them as perfectly healthy. Run the `npm ci && npm run build` command the
script prints for each one.

Then open http://localhost:8080 (admin/admin) and confirm the apps appear in the
app menu.

## If an app still fails to enable

`dev-up.sh` prints the actual `occ` error per app; act on that rather than
retrying. The two failures that recur:

- **`Class "…" not found`** — the app's `vendor/` is missing or half-installed.
`(cd <app-dir> && composer install --no-dev --ignore-platform-reqs)`. If
composer dies on `Could not delete …/vendor/…`, the tree contains root-owned
files from a container-side composer run; `dev-up.sh` heals that on its next
run.
- **`SKIP <app> — empty checkout`** — the directory is mounted but empty. Clone
the repo into it, or drop its mount from `.github/docker-compose.yml`.

To enable one by hand (note `-u www-data` — without it `occ` runs as root and
refuses):

If any app fails to enable, try running manually:
```bash
docker exec nextcloud php occ app-enable <appname>
docker exec -u www-data nextcloud php occ app:enable <app-id>
```

Use the app **id** (`integriq`, `filinq`, `dossiq`, `stackiq`, `keepiq`,
`larpinq`, `learniq`, `decidiq`, `buildiq`, `humaniq`), not the checkout
directory name (`openconnector`, `docudesk`, `procest`, …). The id is the `<id>`
in `appinfo/info.xml`; a wrong name is not an error you will notice, because
`occ app:enable` on an unknown app just does nothing useful.

> 💡 If you switched models to run this command, don't forget to switch back to your preferred model with `/model <name>` (e.g. `/model default` or `/model sonnet`).
111 changes: 66 additions & 45 deletions .claude/skills/clean-env/examples/expected-output.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,85 @@
<!-- Example output — clean-env skill for OpenRegister development environment -->
<!-- Example output — clean-env skill for the Conduction development environment -->

# Expected Output: clean-env

Captured from a real run on 2026-08-27, not written from memory. The previous
version of this file showed a script that does not exist writing "✓ All apps
installed" against five app names, at a URL (`http://nextcloud.local`) the
instance does not serve — an example nobody could ever have produced.

## Successful run

```
$ bash .claude/scripts/clean-env.sh

[clean-env] Stopping containers...
Stopping nextcloud ... done
Stopping nextcloud_db ... done
✓ Containers stopped
$ bash .github/dev-up.sh

[clean-env] Removing containers and volumes...
Removing nextcloud ... done
Removing nextcloud_db ... done
Removing volume nextcloud_nextcloud_data ... done
Removing volume nextcloud_db_data ... done
✓ Containers and volumes removed
==> Starting stack (project=openregister)
==> Waiting for the DB
==> Waiting for all 36 app mounts inside the container
only 34/36 app dirs visible
collectives: EMPTY CHECKOUT at openregister/custom_apps/collectives -- clone it or drop its mount; restarting cannot help
zaakafhandelapp: EMPTY CHECKOUT at zaakafhandelapp -- clone it or drop its mount; restarting cannot help
every missing dir is an empty checkout, not a mount failure -- not restarting
==> Ensuring un-busted assets are not cached for 6 months
ok
==> Ensuring custom_apps is writable by www-data
ok
==> Clearing maintenance mode
==> Reconciling pending app upgrades (only if needed)
no upgrade needed
==> Healing PHP dependencies (vendor/)
stackiq: no vendor/autoload.php -- installing
ok
==> Ensuring Conduction apps are enabled
enabling keepiq (disabled)
ok
enabling integriq (disabled)
ok
enabling stackiq (disabled)
ok
SKIP zaakafhandelapp -- empty checkout at ../zaakafhandelapp (nothing to enable)
==> Re-reconciling upgrades (enabling an app can register a migration)
no upgrade needed
==> Checking frontend bundles match the app id
ok
==> Done. Status:
- installed: true
- version: 34.0.0.12
- maintenance: false
- needsDbUpgrade: false
apps visible: 34/36
apps enabled: 71
UI: http://localhost:8080 (admin/admin)
```

[clean-env] Starting fresh containers...
Creating network "openregister_default" with the default driver
Creating volume "nextcloud_db_data" ... done
Creating volume "nextcloud_nextcloud_data" ... done
Creating nextcloud_db ... done
Creating nextcloud ... done
✓ Containers started
## What a problem looks like

[clean-env] Waiting for Nextcloud to become ready...
..........
✓ Nextcloud is ready at http://nextcloud.local
The script does not hide these; read to the end of the output.

[clean-env] Installing apps...
openregister installed and enabled.
opencatalogi installed and enabled.
softwarecatalog installed and enabled.
nldesign installed and enabled.
mydash installed and enabled.
✓ All apps installed
An app that is enabled and would still render a blank page — `occ` calls this
app perfectly healthy, so this section is the only thing that reports it:

[clean-env] Done! Environment is clean and ready.
```
==> Checking frontend bundles match the app id
integriq: js/integriq-main.js missing (found openconnector-main.js -- stale, pre-rename)
fix: (cd ../openconnector && npm ci && npm run build)
...
⚠ 5 app(s) need a frontend rebuild before their page renders
```

## Post-script verification
An app that refused to enable, with the reason rather than a shrug:

```
✅ Nextcloud accessible at http://nextcloud.local
✅ Logged in with admin/admin
✅ Apps enabled and active:
- openregister ✓
- opencatalogi ✓
- softwarecatalog ✓
- nldesign ✓
- mydash ✓
enabling keepiq (disabled)
FAILED: An unhandled exception has been thrown: Error: Class "Ramsey\Uuid\Uuid" not found in …/keepiq/lib/Repair/SeedSecretTypes.php:115
1 app(s) could not be enabled -- see the errors above
```

## If an app fails to enable
The stack failing to start at all — note that a **public** image answers
`denied: denied` when the local ghcr.io credential has expired, so the script
logs out and retries once before believing it:

```bash
# Re-enable manually:
docker exec nextcloud php occ app:enable openregister
docker exec nextcloud php occ app:enable opencatalogi
```
==> Starting stack (project=openregister)
Error response from daemon: Head "https://ghcr.io/v2/conductionnl/n8n-nextcloud/manifests/latest": denied: denied
ghcr.io denied a pull -- logging out (credentials may be stale) and retrying once
```
72 changes: 48 additions & 24 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,46 @@ name: Code Quality

on:
push:
# An ALLOW-LIST of branch prefixes is a gate with a hole in it, and the
# hole is SILENT: a branch matching nothing gets no CI at all, and its last
# visible status is whatever it inherited — indistinguishable, on every
# dashboard, from a branch that passed.
# DEFAULT BRANCHES ONLY. `pull_request` below carries every other branch.
#
# Two live examples, both found 2026-08-14: `perf/**` was uncovered in
# openconnector, where a merge carrying unresolved conflict markers and 84
# failing tests was pushed and nothing ran; and `feat/**` was uncovered in
# openregister — note the list said `feature/**`, so every branch anyone
# named `feat/...` had been running unchecked.
# This was an allow-list of branch prefixes, and that was a gate with a
# SILENT hole: a branch matching nothing got no CI at all, and its last
# visible status was whatever it inherited — indistinguishable, on every
# dashboard, from a branch that passed. Two live examples, both found
# 2026-08-14: `perf/**` was uncovered in openconnector, where a merge
# carrying unresolved conflict markers and 84 failing tests was pushed and
# nothing ran; and `feat/**` was uncovered in openregister, because the
# list said `feature/**`.
#
# Prefixes are added rather than replaced with `**` because this workflow is
# expensive (PHPUnit matrix, Newman, Playwright). The fast structural checks
# DO run on `**` — see merge-hygiene.yml, added in the same change.
# The comment that stood here said adding prefixes was not the durable fix,
# and that the durable fix was to let the pull_request trigger gate it.
# THIS IS THAT CHANGE.
#
# ⚠️ Adding prefixes is not the durable fix; the next invented one is
# uncovered again. The durable fix is branch protection requiring a PR into
# development, which the pull_request trigger below already gates correctly.
# What forced it now: a push to a branch with an open PR ran the SAME 34
# jobs TWICE on the same commit. `concurrency` cannot dedupe them — the
# group is suffixed by event name deliberately (.github#540: a
# default-branch push carries jobs a PR run does not, and a dispatch must
# not be cancellable by a standing release PR), so the two events sit in
# different lanes BY DESIGN and both run to completion. Measured fleet-wide
# 2026-08-25..27, 659 of 2,106 Code Quality runs were that duplicate — 31%
# of the fleet's most expensive workflow, re-deciding a commit another run
# was already deciding. The account ceiling is 60 concurrent jobs (Team
# plan); the fleet was measured at 53 running with 1,528 jobs queued behind
# them, the oldest run 7 hours old and not yet started.
#
# NO BRANCH LOSES ITS FLOOR. merge-hygiene.yml runs on `'**'` — every
# branch anyone pushes, no prefix list to forget — and it is the check
# `development` actually requires. That is the smoke alarm; this workflow
# is the fire brigade and belongs on the PR. Of 668 feature-branch push
# runs in that window, only NINE were on a branch with no PR run beside
# them.
#
# The default branches STAY: their push runs are not duplicates, they are
# the only carrier of Coverage Baseline Check, SBOM and Features Extract,
# none of which run on a pull_request event.
branches:
- main
- development
- feature/**
- feat/**
- bugfix/**
- hotfix/**
- perf/**
- refactor/**
- chore/**
- fix/**
pull_request:
branches: [main, master, development, beta]
workflow_dispatch:
Expand Down Expand Up @@ -109,7 +120,20 @@ concurrency:
# A branch name is not a unique lane when two event types can each produce a
# run for it, so the event is now always part of the key.
group: quality-${{ github.head_ref || github.ref_name }}${{ github.event_name != 'pull_request' && format('-{0}', github.event_name) || '' }}
cancel-in-progress: true

# PUSH RUNS ARE NOT CANCELLED — and this has to be said HERE, not only in the
# shared workflow. .github#597 set `cancel-in-progress` on quality.yml itself,
# but a caller's own concurrency cancels the whole run before the called
# workflow's setting can apply, so that fix reached only the apps that declare
# no concurrency of their own. Measured 2026-08-28 over push runs on
# `development` since #597: 0 of 11 cancelled where the caller was silent, 7 of
# 13 (54%) cancelled where the caller still said `true`.
#
# An integration branch needs a verdict per commit: the run being cancelled is
# the only thing that would have said whether what just landed is sound, and
# its replacement is cancelled too. `pull_request` keeps cancelling, where
# superseding really is correct.
cancel-in-progress: ${{ github.event_name != 'push' }}

# Permission CEILING for the called quality pipeline. GitHub statically
# validates the called workflow's declared job permissions against this
Expand Down
26 changes: 24 additions & 2 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
name: Documentation

# Publishes the docs site to the Cloudflare Worker that serves it.
#
# TRIGGERS ON `development`, NOT ON A `documentation` BRANCH. This file used to
# listen on a branch called `documentation`; nobody has pushed to one since
# 2026-05-25, so the site simply stopped being rebuilt while every docs change
# merged to development satisfied its review and published nothing.
on:
push:
branches: [documentation]
branches: [development]
pull_request:
branches: [documentation]
branches: [development]

jobs:
deploy:
uses: ConductionNL/.github/.github/workflows/documentation.yml@main
# A reusable workflow receives NO secrets by default. Without this block the
# callee's publish step finds CF_API_TOKEN empty, skips itself on its own
# `if:` guard, and the run finishes GREEN having changed nothing -- the
# failure that left the fleet's docs sites on May builds. The names are the
# same on both sides; the org secrets really are CF_API_TOKEN/CF_ACCOUNT_ID.
secrets:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
with:
cname: shillinq.conduction.nl
# EVERY host this worker answers on, in FULL: wrangler reconciles the
# worker's triggers against this list, so a host left out is REMOVED and
# goes dark.
docs-hosts: shillinq.conduction.nl
# PINNED. Deriving the name is how a deploy goes green and reaches
# nobody: wrangler creates the derived worker and publishes there while
# the custom domains keep routing to the real one.
worker-name: shillinq-docs
Loading
Loading