Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

feat: scaffold the JSON manifest renderer pattern as the template default (template-manifest-v1)#27

Merged
rubenvdlinde merged 4 commits into
developmentfrom
feature/template-manifest-v1
May 10, 2026
Merged

feat: scaffold the JSON manifest renderer pattern as the template default (template-manifest-v1)#27
rubenvdlinde merged 4 commits into
developmentfrom
feature/template-manifest-v1

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Summary

Make nextcloud-app-template the canonical Tier-4 scaffolding for the JSON manifest renderer pattern. After this PR, every new Conduction Nextcloud app generated from this template starts with a working manifest-driven shell on first npm install && npm run build.

Implements hydra ADR-024 at the source — the template — rather than retrofitting per app:

"Every Conduction app SHOULD ship a src/manifest.json validated against the canonical schema. New apps MUST adopt at least Tier 1 from inception."

What ships

  • src/manifest.json — minimal opinionated 4-page manifest, one each of dashboard | index | detail | settings, with dependencies: ["openregister"], schema-validates against @conduction/nextcloud-vue@1.0.0-beta.13's 1.2.0 schema (zero errors).
  • src/main.js — Tier-4 mount-survivable bootstrap (decidesk's 50e4df7c + 866ff132): shallow-cloned CnPageRenderer / defaultPageTypes / customComponents to dodge Vue 2's _Ctor mutation against frozen barrel exports; routes built from manifest.pages[*]; mount on #content immediately, NOT inside loadTranslations.
  • src/App.vue<CnAppRoot> shell with manifest / customComponents / pageTypes / app-id / translate / permissions props; objectSidebarState provide channel; <CnObjectSidebar> in the #sidebar slot.
  • src/customComponents.js — empty-by-default registry contract with one example placeholder (CustomExample) so the registry's role is visible to first-time cloners. Manifest does NOT reference it by default.
  • src/views/CustomExample.vue — trivial example custom component documenting when to reach for type: "custom" (rarely).
  • tests/validate-manifest.js — Ajv-based schema validator copied from decidesk; npm run check:manifest runs it.
  • webpack.config.js@nextcloud/axios$ alias (decidesk pattern) so the lib's transitive axios import resolves to the app's installed copy.
  • package.json@conduction/nextcloud-vue ^0.1.0-beta.3 → ^1.0.0-beta.12; @nextcloud/router ^2.0.1 → ^3.1.0 (NC-vue 8.37 needs getBaseUrl); ajv + ajv-formats devDeps; check:manifest script.
  • README.md — manifest-first quickstart with a page-type table; tells cloners to edit src/manifest.json rather than writing per-page Vue files.
  • Deleted legacy shell: src/router/index.js, src/navigation/MainMenu.vue, src/views/Dashboard.vue, src/views/settings/.

Validation results

$ node tests/validate-manifest.js
[validate-manifest] Ajv validation: PASS (0 errors)

$ npx eslint src tests/validate-manifest.js
(zero errors, zero warnings)

$ npx webpack --config webpack.config.js --mode production
webpack 5.105.4 compiled with 4 warnings  (asset-size warnings only — same shape as decidesk)

OpenSpec change

openspec/changes/template-manifest-v1/ — proposal, design (with smoke-test recipe), tasks (all ticked), and 10 REQ-TMV1-* requirements.

Test plan

  • Reviewer: clone the branch, run npm install && npm run build && npm run check:manifest. Verify all three exit zero.
  • Reviewer: make dev-link && docker exec nextcloud php occ app:enable app-template, browse to /index.php/apps/app-template/. Expected: CnAppNav renders 3 left-side menu entries (Dashboard, Items, Documentation) + Settings in the footer; Dashboard renders the placeholder widget; Settings renders the version-info widget.
  • Reviewer: console MUST be free of "Cannot add property _Ctor", "[CnAppRoot] manifest is required", "[useAppManifest] schema validation failed".
  • Reviewer: confirm the deleted files (src/router/, src/navigation/MainMenu.vue, src/views/Dashboard.vue, src/views/settings/) have no remaining references in the codebase.

Out of scope

  • A make new-app NAME=... scaffolder (manual rename remains; left for a follow-up).
  • Removing the OpenRegister wiring from PHP backend (lib/Service, lib/Repair/InitializeSettings.php) — the template stays pre-wired for OR because most new Conduction apps use OR; opting out is a 4-line README delta.
  • Backend /api/manifest override endpoint (Tier 4 ships bundled-only per ADR-024 §4).
  • Runtime smoke inside a live NC instance — the template has no fleet schemas to point register-mapping at; smoke is delegated to the first downstream consumer.

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/).
@github-actions

github-actions Bot commented May 9, 2026

Copy link
Copy Markdown
Contributor

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

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

Coverage: 0% (0/3 statements)


Quality workflow — 2026-05-09 16:37 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde rubenvdlinde merged commit 3878110 into development May 10, 2026
49 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant