Skip to content

Release: merge development into beta - #18

Open
github-actions[bot] wants to merge 202 commits into
betafrom
development
Open

Release: merge development into beta#18
github-actions[bot] wants to merge 202 commits into
betafrom
development

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Automated PR to sync development changes to beta for beta release.

Merging this PR will trigger the beta release workflow.

Reminder: Add a major, minor, or patch label to this PR to control the version bump. Default is patch.

WilcoLouwerse and others added 7 commits March 24, 2026 15:02
Release: promote beta to stable — initial CI pipeline and app scaffold
…uctors

Issues caught by every code review on apps built from this template:
- <licence>agpl</licence> → <licence>eupl</licence>
- OC.requestToken → getRequestToken() from @nextcloud/auth
- Added SPDX-License-Identifier: EUPL-1.2 to all PHP/JS/Vue files
- Constructor properties: private → private readonly
The app store only recognises agpl/apache/mit — not eupl.
Source files use SPDX EUPL-1.2 headers (the actual licence).
info.xml uses agpl for store compatibility only.
…uth dep

Fixes from planix: correct .phphunit → .phpunit typo, remove duplicate
glob patterns, and add @nextcloud/auth for getCurrentUser() support.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 321c395

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 100/100
npm ✅ 215/215
PHPUnit ⏭️
Newman ⏭️
Playwright ⏭️

Quality workflow — 2026-04-16 15:18 UTC

Download the full PDF report from the workflow artifacts.

WilcoLouwerse and others added 22 commits April 16, 2026 18:31
Replace the individual conduction symlink inside openspec/schemas/ with
a single symlink at openspec/schemas pointing to hydra schemas directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…asset only) (#24)

The central Quality workflow (ConductionNL/.github#34) now publishes SBOMs
exclusively as release assets — see SECURITY.md "Software Bill of Materials".

This PR cleans up the per-app remnants:
- delete .github/workflows/sbom.yml (the central job replaces it)
- delete the checked-in sbom.cdx.json (release asset is the source of truth)
- gitignore SBOM files so future generations don't accidentally land in repo

Stable URL for clients:
  https://github.com/ConductionNL/nextcloud-app-template/releases/latest/download/sbom.cdx.json

Co-authored-by: SBOM Cleanup <ops@conduction.nl>
Path-based codeowner mapping per the OR-abstraction-audit follow-up
(2026-05-03). PRs that touch each domain auto-request review from
the matching owners; first-to-approve unblocks per the org ruleset.
Wires the ConductionNL bundling pattern from ADR-004 (Build / bundling)
into the template so apps cloned from this repo get a working dashboard
widget out of the box and never trip the appName/devtool/duplicate-framework
pitfalls that landed across opencatalogi/pipelinq/procest/docudesk.

What is added:

- webpack.config.js: optimization.splitChunks with stable-filename shared
  chunks for Vue + @nextcloud/vue + pinia + icons + @conduction/nextcloud-vue.
  Each entry-point keeps only entry-specific code; shared chunks load once.
- lib/Dashboard/ExampleWidget.php: minimal IWidget. load() attaches shared
  chunks BEFORE the per-widget bundle (vendor → nc-vue → widget). Comments
  explain why and reference ADR-004.
- src/exampleWidget.js: webpack entry that registers the Vue renderer via
  OCA.Dashboard.register. Hard-coded id matches Widget::getId() from PHP.
- src/views/widgets/ExampleWidget.vue: minimal NcDashboardWidget that fetches
  /api/items via @nextcloud/axios with try/catch + graceful empty state.
- AppInfo/Application.php: registerDashboardWidget(ExampleWidget::class).
- README: 'Adding a dashboard widget' how-to listing the 5 registration
  points and pointing at ADR-004 for the full rationale.

Apps that don't need a dashboard widget delete:
  - lib/Dashboard/ + src/exampleWidget.js + src/views/widgets/
  - the registerDashboardWidget(...) line in Application.php
  - the exampleWidget entry in webpack.config.js

The splitChunks block is harmless with only main + adminSettings entries
(produces small shared chunks that two entries reuse) and starts paying off
the moment a widget is added.
Spec the canonical Tier-4 scaffolding for the JSON manifest renderer
pattern in nextcloud-app-template. Codifies hydra ADR-024's "new apps
MUST adopt the manifest from inception" requirement at the source —
the template — rather than retrofitting per app.

Includes proposal, design, tasks, and 10 REQ-TMV1-* requirements
covering manifest contents, bootstrap pattern, registry contract,
webpack alias, dependency floor, and the manifest-first README
quickstart.
Add the canonical template manifest with 4 example pages (one each of
type dashboard / index / detail / settings) and 4 menu entries.
Declares openregister as the default dependency. Settings page
demonstrates the version-info rich-section widget.

Add src/customComponents.js as the empty-by-default registry contract
with a single example placeholder (CustomExample) so the registry's
role is visible to first-time cloners. The manifest does NOT
reference CustomExample by default — it only ships as documentation.

Add tests/validate-manifest.js (copied from decidesk's reference) for
Ajv-based schema validation. Wired up via npm run check:manifest.

Trim l10n/en.json to a clean baseline aligned with the new manifest
strings; add an empty l10n/en_US.json placeholder.
Adopt decidesk's mount-survivable bootstrap pattern (commits 50e4df7c
+ 866ff132) as the template default:

main.js:
  - Import bundledManifest from './manifest.json' and customComponents
    from './customComponents.js'.
  - Build vue-router routes from manifest.pages[*].{id,route} via a
    routesFromManifest() helper that uses a shallow-cloned
    CnPageRenderer ({ ...CnPageRenderer }) — required because Vue 2's
    Vue.extend() mutates the component options object with a _Ctor
    cache, which throws against the lib's frozen barrel exports.
  - Pass shallow-cloned defaultPageTypes and customComponents to
    App.vue as props.
  - Mount on #content immediately, NOT inside loadTranslations'
    callback (NC dev installs commonly 404 the /l10n/<locale>.json
    route, which would silently kill boot). Translation load is
    fire-and-forget; strings fall back to English on miss.

App.vue:
  - Mount <CnAppRoot> with manifest + customComponents + pageTypes
    props, app-id, translateForApp closure, and permissions array.
  - Provide an objectSidebarState reactive channel via provide() and
    mount <CnObjectSidebar> in the #sidebar slot — the standard
    pattern for CnDetailPage → host-rendered sidebar.

settings.js + AdminRoot.vue:
  - Keep the Nextcloud admin app-settings webpack entry-point (a
    distinct surface from the manifest's type:'settings' SPA page).
    Replace the deleted views/settings/AdminRoot.vue with a minimal
    placeholder NcSettingsSection that documents the divergence.

Delete the legacy shell:
  - src/router/index.js (routes built from manifest at boot).
  - src/navigation/MainMenu.vue (CnAppNav replaces it).
  - src/views/Dashboard.vue (manifest type:'dashboard' replaces it).
  - src/views/settings/ (manifest type:'settings' replaces it).
…README

package.json:
  - @conduction/nextcloud-vue ^0.1.0-beta.3 → ^1.0.0-beta.12 (the
    published lib version with the Vue.extend frozen-component fix).
  - @nextcloud/router ^2.0.1 → ^3.1.0 — required by @nextcloud/vue
    8.37+ (NcDashboardWidget / NcAvatar import getBaseUrl, missing
    from router 2.x).
  - Add ajv ^8.17.1 + ajv-formats ^3.0.1 devDependencies for the
    manifest validator.
  - Add scripts.check:manifest → node tests/validate-manifest.js
    (satisfies the fleet adoption spec's build-time validation gate).

webpack.config.js:
  - Add @nextcloud/axios$ alias to force the lib's transitive axios
    import to resolve to the app's installed copy (decidesk pattern,
    commit ed34703c). Without the $ exact-match suffix webpack walks
    up to the lib's own node_modules and loads a second axios
    instance, breaking shared interceptors / CSRF tokens.

eslint.config.js:
  - Override no-console / n/no-process-exit / n/shebang for the
    tests/validate-manifest.js Node CLI script.

README.md:
  - Lead with manifest-first messaging in the intro paragraph and
    in the OpenRegister callout.
  - Add an "Adding a page (manifest-first)" section that documents
    the page-type table and tells cloners to edit src/manifest.json
    rather than writing per-page Vue files. Custom Vue components
    are only required for type:"custom" pages.
  - Add a "Renaming the app" section listing the files where the
    app id appears (the manifest itself does NOT carry the id).
  - Update the directory-structure diagram to reflect the new
    layout (manifest.json, customComponents.js, no router/, no
    navigation/).
feat: scaffold the JSON manifest renderer pattern as the template default (template-manifest-v1)
…copy with placeholders

The SCSS webpack rule was added to webpack.config.js in a prior PR
(commit 209224e "chore: bump nextcloud-vue + router, add axios alias"),
but the actual sass + sass-loader packages were never added to
devDependencies. Result: running 'npm run build' on a fresh clone of
the development branch produces a 'Module parse failed: Unexpected
token' error whenever nextcloud-vue components ship <style lang=scss>
blocks.

Fix:
- package.json devDependencies: add sass ^1.99.0, sass-loader ^16.0.8
  (matching the versions already in opencatalogi + decidesk)
- package-lock.json regenerated via 'npm install --package-lock-only'

Separately, appinfo/info.xml currently ships marketing copy for the
template itself (Nextcloud App Template, A template for creating new
Nextcloud apps, plus a 13-line feature-list description). This copy
survives '/app-create' scaffolding because the placeholder substitution
phase only rewrites identifier-shaped tokens (app-template ->
{APP_ID}, AppTemplate -> {APP_NAMESPACE}). Result: every newly
scaffolded app ships with the template's own description until a human
remembers to rewrite it.

Fix:
- appinfo/info.xml: replace summary + description content with
  {APP_NAME}, {APP_SUMMARY}, {APP_DESCRIPTION} placeholders so the
  /app-create skill can auto-substitute them from openspec/app-config.json
  during scaffolding.

Companion PR in ConductionNL/market-intelligence updates the
.claude/skills/app-create placeholder-replacement-guide.md so the new
placeholders get processed automatically.
…-placeholders

fix: add sass + sass-loader to devDeps + use placeholders for info.xml marketing copy
… deps

PR #28 (merge 4601d2c) shipped a package-lock.json that was missing 11
transitive dependencies of pinia (devtools-kit, devtools-shared, mitt,
perfect-debounce, speakingurl, superjson, copy-anything, is-what,
rfdc, plus a nested @nextcloud/dialogs > pinia entry).

Result: `npm ci` failed on every CI quality job, taking down 5
checks at once (Security npm, License npm, ESLint, Stylelint, SBOM).

Fix: regenerate the lockfile with `npm install` (no package.json
changes). Verified locally:
- `npm ci` now succeeds
- `npm run lint` passes
- `npm run stylelint` passes
- `npm audit --audit-level=high` reports 0 high/critical (25 low/moderate)
chore: regenerate package-lock.json to fix quality CI failures
…hecks (#32)

Adds a Spec Validation workflow + three checks that catch the class of bug
seen in scholiq Wave 2 *before* it reaches development:

- tests/validate-json-strict.js — strict JSON parse of src/manifest.json +
  lib/Settings/*_register.json; FAILS on duplicate keys (git merges JSON
  line-by-line; two adds at the same key but different file positions produce
  no textual conflict, just a doc with a dup key, and json_decode keeps the
  last → silent schema/page loss) and on `appendOnly` nested inside an
  x-openregister block (OpenRegister's Schema::hydrate only reads a top-level
  appendOnly, so a nested one is silently dropped).
- tests/validate-register.js — structural checks on the register seed: every
  schema has slug/type/required/properties; slug uniqueness; lifecycle
  `requires:` references a PHP class that exists under lib/ (catches scholiq's
  missing CoursePublishGuard); a 'schema looks clobbered / is a stub' heuristic
  (≤3 props + no x-openregister-*). Optional deep check against OR's
  configurations/validate endpoint when OR_BASE_URL + OR_BASIC_AUTH are set.
- package.json: check:register, check:json-strict, check:specs scripts.
- .github/workflows/spec-validation.yml: runs `npm run check:specs` on every
  push/PR. Add 'Spec Validation / validate' to the branch-protection ruleset's
  required checks to make it block merges.
- README: documents the new checks and why they matter.

Every app scaffolded from this template inherits the gate.
* feat: adopt the Features & Roadmap menu

Ships the in-product Features & Roadmap page wired into the manifest so apps
scaffolded from this template inherit the Settings-section "Features & roadmap"
entry (powered by OpenRegister's github-issue-proxy, UI from
@conduction/nextcloud-vue). Mirrors the per-app adoptions (procest/decidesk/
pipelinq/scholiq/openbuilt).

- src/views/FeaturesRoadmap.vue — thin wrapper around CnFeaturesAndRoadmapView;
  the `repo` fallback is `ConductionNL/nextcloud-app-template` — cloners change
  it (or provide it via IInitialState `<appId>::features_roadmap_*`)
- customComponents.js — register it as the `FeaturesRoadmap` custom component
- manifest.json — add the `FeaturesRoadmap` custom page (route /features-roadmap)
  + a `FeaturesRoadmapMenu` entry in the settings section
- bump @conduction/nextcloud-vue ^1.0.0-beta.12 → ^1.0.0-beta.35; pin
  @nextcloud/axios ~2.5.2 (+ overrides) — 2.6.0 ships a broken `exports` field
  that breaks @nextcloud/vue under webpack (cf. ConductionNL/openregister#1489)

Refs: ConductionNL/hydra#251

* chore: refresh package-lock.json for the @conduction/nextcloud-vue ^1.0.0-beta.35 bump
…ate (#31)

Wires the AI Chat Companion MCP-tool pattern (hydra ADR-034/035) into the
template so new Conduction apps get it by default.

- lib/Mcp/ExampleToolProvider.php — heavily-commented copy-me provider with
  two trivial example tools: app-template.ping and app-template.describeApp
- lib/AppInfo/Application.php — registers the provider under the alias
  OCA\OpenRegister\Mcp\IMcpToolProvider::{appId}
- tests/Stubs/Mcp/IMcpToolProvider.php — stub interface until openregister
  PR #1466 ships the real one; wired via composer autoload-dev + bootstraps
- tests/Unit/Mcp/ExampleToolProviderTest.php — contract test (7 cases)
- README: new "AI Chat Companion / MCP tools" section
- psalm.xml: allow the OCA\OpenRegister\Mcp\IMcpToolProvider cross-app ref

Widget mount: the template already mounts CnAppRoot from
@conduction/nextcloud-vue (^1.0.0-beta.12), which renders the companion FAB
once nextcloud-vue beta.31 (CnAiCompanion) is published — no bump needed.
…ings) (#34)

- Change SettingsMenu entry to action: "user-settings" / icon: "Cog"; drop route + section.
  CnAppNav invokes cnOpenUserSettings inject (CnAppRoot) which opens NcAppSettingsDialog.
  The Settings type:'settings' page stays for direct-URL /settings access.
- App.vue: import NcAppSettingsSection; add #user-settings slot to CnAppRoot
  with a placeholder NcAppSettingsSection — replace with real settings content
  when scaffolding a new app.
- README: one-line note in the manifest/menu section documenting the pattern.
- Upgrade @conduction/nextcloud-vue from beta.30 → beta.35 (schema 1.5.0) to
  support action: "user-settings" — package.json already declared ^1.0.0-beta.35;
  node_modules was behind.
- validate-manifest PASS (0 Ajv errors, schema 1.5.0); lint 0 errors; build succeeds.
Keeps the app template on the current lib — CnIndexPage store-backed
self-fetch (nc-vue #223) + columns[].formatter / .widget / .aggregate +
pages[].config.filter (#219/#221/#222) — so scaffolded apps start at the
right version.
chore(deps): bump @conduction/nextcloud-vue to ^1.0.0-beta.40
…fold (#36)

Every new Conduction app currently inherits only a documentation.yml
deploy-workflow stub with no Docusaurus site behind it. This adds the
default so a scaffolded app is born docs-ready:

- docs/ on @conduction/docusaurus-preset 2.6.1 — createConfig/BRAND_THEME,
  brand <DetailHero>/<WidgetShelf> landing page, intro.md, custom.css,
  sidebars.js, package-lock.json, static/CNAME (app-template.conduction.nl),
  static/img/logo.svg.
- journeydoc scaffold (hydra ADR-030) — tutorials/{_category_,user/,admin/}
  with two stock stories (user "open the app for the first time" → Dashboard,
  admin "manage settings" → Admin Settings), tests/e2e/docs-screenshots.spec.ts
  capture suite, and playwright.config.ts with chromium + docs-capture projects.
- .github/workflows/documentation.yml — deploy from `development` to
  app-template.conduction.nl (was: `documentation` branch / app-template.app).
- .gitignore — docs/ build artefacts, docs/i18n/nl/, playwright outputs.
- README.md — Screenshots section now points at the journeydoc workflow,
  directory-structure block lists docs/ + tests/e2e/ + playwright.config.ts,
  and a Documentation section describes the docs-site build + deploy.

Build verified locally (`npm ci --legacy-peer-deps && npm run build`).
…Vue-mount failure) (#37)

webpack.config.js uses splitChunks with `enforce: true` cacheGroups that
emit two shared chunks (`<appId>-shared-vendor`,
`<appId>-shared-nc-vue`). The main and adminSettings entry bundles wrap
their Vue mount in `__webpack_require__.O(0, [shared chunks], …)`, which
only fires once every listed chunk has registered itself on
`self.webpackChunk<appId>`. With only the entry script in
`addScript()`, the shared chunks never load, the mount callback never
fires, and the app silently renders nothing.

Mirrors the canonical fix in zaakafhandelapp#206. ExampleWidget.php
already loaded the shared chunks correctly; this brings the page and
admin-settings templates into line.

Because this is the scaffold template, every newly-generated app
inherits the fix.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 61e8a30

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 720/720
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-23 22:19 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 2 commits August 24, 2026 17:58
GitHub is the only host for this org; Codeberg was a mirror and was retired
on 2026-08-04, so every codeberg.org link in this repo is dead.

Conversions applied (13 files):
- Repo/org: codeberg.org/Conduction/<slug> -> github.com/ConductionNL/<slug>
  (openregister, hydra, nextcloud-vue, nextcloud-app-template).
- Path shapes: /src/branch/<B>/<FILE> -> /blob/<B>/<FILE>, /src/branch/<B>/<DIR>
  -> /tree/<B>/<DIR>, /raw/branch/<B>/<p> -> /raw/<B>/<p>.
- Badges: the Gitea release badge became the shields GitHub release badge and
  the ci.codeberg.org status badge became the GitHub Actions badge for
  .github/workflows/code-quality.yml (confirmed the workflow file exists).
- Docusaurus navbar label 'Codeberg' -> 'GitHub'; editUrl -> /edit/development/docs/.

Two judgement calls, recorded deliberately:
- Issue/PR numbers are NOT mapped across hosts. The openregister PR #1466 link
  in README.md lost its URL and kept the fact as plain text; GitHub serves
  /pulls/<N> as the PR list page with HTTP 200, so a host swap would have
  pointed at the wrong page while passing any status check.
- docs/canonical-files.md pointed at adr-033-root-config-consolidation.md, which
  exists on neither host: hydra renumbered it to adr-039 (identical slug, title
  "ADR-039: Root Configuration Consolidation", verified via the GitHub API).
  The link now points at adr-039 rather than swapping one dead URL for another.

Left untouched on purpose:
- .forgejo/workflows/* `runs-on: codeberg-medium` — CI runner labels, not links.
- .github/workflows/l10n-parity.yml — historical note that Codeberg was retired.

All introduced URLs were spot-checked (HTTP 200); private hydra targets were
confirmed via `gh api`. Changed JSON/JS/YAML re-parsed clean.
hydra-gates v1.9.0 -> v1.9.0
nc-vue      2.11.1 -> 2.15.0

Lock-only: both packages are already declared with caret ranges that
permit these versions, so nothing about what this app ACCEPTS changes
- only what it currently resolves to. Opened by the weekly fleet
shared-dependency bump, because a lock nobody re-resolves is a pin
nobody chose.

Merging is gated by this repository's own suite, deliberately: taking
hydra-gates v1.8.1 added patchObject() to a published interface, which
is a load-time fatal for any concrete double that implements it without
the method. CI is the only thing that can tell a safe bump from that.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ d89c8bb

Check PHP Vue Security License Tests
lint ⏭️
phpcs ⏭️
phpmd ⏭️
psalm ⏭️
phpstan ⏭️
phpmetrics ⏭️
eslint ⏭️
stylelint ⏭️
build ⏭️
composer ⏭️ ⏭️
npm ⏭️ ⏭️
app:check-code ⏭️
info.xml ⏭️
REUSE ⏭️
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-24 16:10 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 67085cd

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-24 17:11 UTC

Download the full PDF report from the workflow artifacts.

This repository's only issue forms lived under `.forgejo/issue_template/`.
GitHub is the fleet's only host, so those forms are invisible to everyone
filing an issue here.

Two approved fleet changes make this urgent:

1. `.forgejo/` is being removed fleet-wide. Without this port that removal
   would delete the only issue forms this repo has, leaving contributors
   with a blank issue box.
2. The shared library's `DEFAULT_FORGE` moves from `codeberg` to `github`.
   The in-product "Request a feature" deep-link then targets a GitHub Issue
   Form named exactly `feature-request.yml`. If that file is absent GitHub
   silently drops every pre-filled field instead of erroring, so the app
   context (app, page, surface, object, spec-ref) would be lost without a
   single visible failure.

Copies all four templates to `.github/ISSUE_TEMPLATE/`, keeping the
filenames identical. `.forgejo/` is deliberately left untouched; its removal
is a separate later change.

Conversion is lossless: Forgejo's issue-template schema is derived from
GitHub's, and every construct used here (markdown/input/textarea/dropdown
blocks, `render: shell`, `validations.required`, `labels`, `assignees`,
`title`) is valid GitHub issue-form syntax. Nothing was dropped or reworded.
The top-level `type: "Feature"` in feature-request.yml was verified against
the ConductionNL org issue types, where "Feature" exists and is enabled.

No `config.yml` was added: `.forgejo/issue_template/` has no equivalent.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 55d1083

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-24 19:13 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde and others added 2 commits August 24, 2026 22:08
…es (#133)

axe-core sat in `dependencies`, declaring an accessibility *testing*
library as an application runtime dependency.

Measured: nothing under src/ imports axe-core, and the built bundle never
contained it (webpack only emits what the import graph reaches). What put
it in every app manifest is a bogus peerDependency on
`axe-core: ^4.10.0` declared by @conduction/nextcloud-vue, which does not
import it either. Real accessibility scanning uses @axe-core/playwright,
and the hydra WCAG gate injects axe from cdnjs — neither needs this entry.

Not a bundle-size fix; the bundle is unchanged. It stops a test dependency
being declared as production surface (SBOM, `npm ci --omit=dev`, advisory
triage). devDependencies still satisfy nc-vue's peer.

Verified: npm ci + production build both exit 0.
The caller overrode `hydra-gates-ref: v1.3.0`. The shared workflow already
defaults that input to `main`, and this repo consumes `quality.yml` at
`@main`, so dropping the override makes the workflow and the gates package
move together.

This is the scaffold template, so the pin was not just this repo's problem:
every app generated from it inherited the same frozen ref. Now they inherit
its absence instead.

A pin is a silent expiry date. 22 repos sat on v1.0.1 and 16 gates were dead
fleet-wide while every one of them reported PASS (ConductionNL/.github#159).
Then a default flipped on `.github` main reached those same old runners and
turned them red on gates they had no subject matter for (.github#173). Both
failure shapes come from the same split: shared workflow at @main, package
pinned per caller.

The pin-justifying comment is replaced with a short note that also states the
template consequence. `enable-hydra-gates: true` and the deliberate absence
of `enable-axe` are unchanged.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 9350089

Check PHP Vue Security License Tests
lint ⏭️
phpcs ⏭️
phpmd ⏭️
psalm ⏭️
phpstan ⏭️
phpmetrics ⏭️
eslint ⏭️
stylelint ⏭️
build ⏭️
composer ⏭️ ⏭️
npm ⏭️ ⏭️
app:check-code ⏭️
info.xml ⏭️
REUSE ⏭️
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-24 20:10 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 0faaf63

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-24 21:20 UTC

Download the full PDF report from the workflow artifacts.

GitHub is the only host this organisation publishes to. No local checkout has
a Codeberg git remote, so nothing is pushed there and no workflow under
.forgejo/ has ever run for this repository.

Issue templates: the 4 templates under `.forgejo/issue_template/` were
already ported to `.github/ISSUE_TEMPLATE/` and were verified present there
before deletion (including `feature-request.yml`, which the in-product
"Request a feature" deep-link targets by that exact filename).

This repository had no `.forgejo` release workflow. Its release path,
`.github/workflows/release-beta.yml, release-stable.yml`, is untouched.

.github/workflows/ is untouched — that is the live CI. Any CODEBERG_TOKEN
reference lived only inside the deleted files and goes with them.

Removes 9 file(s) under .forgejo/.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 49bb00a

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-24 22:19 UTC

Download the full PDF report from the workflow artifacts.

…#168)

.gitignore has listed sbom.cdx.json since line 102, but the file was already
tracked when the rule landed, and gitignore does not apply to tracked files.
So the template shipped a committed SBOM that the same repo declares should
never be committed, and every app scaffolded from it inherited the file.

The SBOM is generated per run by the shared quality workflow, published as
the sbom-<app> artifact and attached to stable releases. A committed copy is
stale the moment a lockfile moves. This one dated from the template's own
scaffold and had not been regenerated since.

Refs ConductionNL/.github#572, ConductionNL/hydra#617
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 7f5cca4

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-24 23:14 UTC

Download the full PDF report from the workflow artifacts.

… cnFetchJson (#179)

* fix(store): drop the hand-rolled object store; route settings through cnFetchJson

The template shipped TWO object stores. `src/store/store.js` already created
the canonical one with `createObjectStore` from @conduction/nextcloud-vue,
while `src/store/modules/object.js` defined a second `useObjectStore` as a
hand-rolled `defineStore('object')` doing raw `fetch()` with a hand-set
`requesttoken`.

Nothing imported the second one — but every app scaffolded from this template
inherited it, which is why ADR-071 finds app-local `store/modules/object.js`
variants in six apps and parallel generic stores in two more. The template was
the source that kept re-seeding the pattern ADR-071 Decisions 1 and 2 delete.

Changes:

- Delete src/store/modules/object.js (dead, and the anti-pattern's seed).
- settings.js now uses cnFetchJson instead of raw fetch + getRequestToken
  (ADR-071 Decision 1). URLs still go through generateUrl, because cnFetch's
  own prefixUrl only adds /index.php and does not know the instance webroot —
  handing it an already-generated URL is a no-op there, so this keeps the
  correct URL AND the library's blessed headers.
- settings.js gains an `error` state. Both actions previously returned null on
  failure, and null was also the legitimate "nothing yet" value, so a settings
  endpoint returning 500 was indistinguishable from a fresh install. Failures
  are now logged AND observable; the actions still resolve rather than throw,
  so a broken endpoint cannot stop the SPA mounting.
- Bump @conduction/nextcloud-vue ^2.3.0 -> ^2.16.0. REQUIRED, not cosmetic:
  cnFetch/cnFetchJson first shipped in v2.11.0, and the installed tree was on
  2.2.0, so the import would not have resolved. ^2.16.0 matches openregister
  and decidesk; the lock resolves 2.17.0.

The spec is corrected in the same commit, because it was wrong in two ways:

- It REQUIRED the deleted module by path, and pinned `configure()` /
  `registerObjectType()` / `fetchObjects()` — an API the dead module had and
  the library store does not. The spec described the module nothing imported
  while the code used the other one.
- Its "degrade gracefully" clause REQUIRED failures to resolve to a safe
  empty/null value and said nothing about surfacing them, writing the
  unobservable-failure pattern into a normative requirement. It now requires
  the safe value AND a recorded error.

Verified: npm run build compiles (webpack 5.109.2, 2 pre-existing warnings).

Refs ADR-071 Decisions 1-2, ADR-026, ADR-100 Decision 5.

* test(store): pin the settings store's failure behaviour; fix two jsdoc warnings

gate-47 (security-change-has-tests) flagged the previous commit: it changed
CSRF/transport handling with no test co-change. It was right to.

tests/settings-store.spec.js covers both halves of the fix, because either one
alone is the bug:

  * resolving to null WITHOUT recording      -> the original silent failure
  * recording but THROWING out of the action -> a broken endpoint blocks boot

Arm 4 is the one that would have caught the original defect. It asserts that
'the backend had nothing' and 'the backend failed' are DISTINGUISHABLE, rather
than merely that failure returns null — a test asserting only '=== null' passes
against the broken version unchanged.

VERIFIED AGAINST THE OLD BEHAVIOUR, not just the new one: re-running this exact
spec against a reconstructed silent-failure store fails 4 of 6 arms, with arm 4
reporting 'indistinguishable'. A test that only passes on the fixed code cannot
be shown to detect the defect it was written for.

Wired into check:specs alongside the sibling node specs, so it runs in CI
rather than only by hand.

Also fixes the two eslint warnings the previous commit introduced (the repo
runs --max-warnings 0): a jsdoc block opening with text on the /** line, and a
getter missing its @PARAM.

The spec harness reimplements the action bodies rather than importing pinia,
matching registry.spec.js / manifest-v2.spec.js which run under bare node. That
limit is stated in the file: it pins the CONTRACT, not the module wiring, and
the wiring is covered by the build plus the e2e app-shell spec.

* style(test): prettier formatting and function-declaration form

The repo runs `prettier --check` over **/*.js and eslint with --max-warnings 0,
and the new spec satisfied neither. Formatting applied with prettier --write;
the two top-level arrow consts (`bad`, `rejecting`) become function
declarations, which is what antfu/top-level-function requires.

No behaviour change — the spec still passes all six arms, and still fails four
of them against a reconstructed silent-failure store, which is the property
that makes it worth having.
@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ d01447f

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-26 11:35 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ 5b05c62

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-27 19:42 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor Author

Quality Report — ConductionNL/nextcloud-app-template @ d1c4106

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-30 10:26 UTC

Download the full PDF report from the workflow artifacts.

…#186)

* fix(l10n): the template shipped 38 catalogues the browser never reads

Nextcloud loads a locale catalogue in two formats and neither substitutes for
the other. l10n/<locale>.json is read server-side by PHP $l->t().
l10n/<locale>.js is an OC.L10N.register() call and is the only one the browser
ever sees. This repo had 38 .json files and zero .js, so every translation in
it was inert in the frontend, and every app scaffolded from this template
started that way too.

That is the shape of the defect a user reported on dossiq: an account set to
Dutch still reading English. Working fleet apps ship both halves (openregister
37/38, opencatalogi 37/38, dossiq 38/39, petstore 38/38). This repo and
thematiq shipped 0.

Also closes gate-102 (manifest-l10n-coverage), which failed on development with
9 manifest strings having no nl.json key. They are the example-app menu labels,
widget titles and empty state: Examples, Example, Open examples, In progress,
Closed, Recent examples, No examples yet, Close example, Features & roadmap.

The generator is petstore's scripts/build-l10n-js.js adopted unchanged rather
than reimplemented, with the l10n:build and check:l10n-js scripts that keep the
two halves from drifting again. Apps carrying check:l10n-js have measured zero
drift; apps without it had accumulated 142 to 1,090 unreachable entries.

Verified: all 9 strings reach l10n/nl.js with their Dutch values and the
register call names the right app id (apptemplate); nl.js holds 49 keys; the
manifest now has 0 user-visible strings missing from nl.json; check:l10n-js
exits 0; all 38 generated files pass node --check and none is empty.

* fix(l10n): exempt the generated catalogues from prettier

The 38 l10n/*.js files this branch adds are emitted by
scripts/build-l10n-js.js with the Nextcloud l10n tooling's own four-space
shape, so prettier wants to rewrite all 38 and `npm run l10n:build` wants to
rewrite them back. Without the ignore the format check fails forever and the
two tools fight over the same files.

dossiq already carries this exact entry for the same reason; this matches it.

Verified load-bearing rather than assumed: with the entry removed `npm run
format` reports "Code style issues found in 38 files" and exits 1; with it
restored the check passes and exits 0.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
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.

5 participants