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

feat(infra): typed initial-state contract#45

Merged
rubenvdlinde merged 1 commit into
developmentfrom
feature/impl-initial-state-contract
Apr 30, 2026
Merged

feat(infra): typed initial-state contract#45
rubenvdlinde merged 1 commit into
developmentfrom
feature/impl-initial-state-contract

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Summary

Implements initial-state-contract per REQ-INIT-001..REQ-INIT-005.

  • PHP: New OCA\MyDash\Service\InitialStateBuilder (Page enum + typed
    setters + apply() with required-key enforcement) + MissingInitialStateException.
    INITIAL_STATE_SCHEMA_VERSION = 1 stamped on every payload under
    _schemaVersion. Refactored PageController::index and
    MyDashAdmin::getForm to use the builder — every other call site to
    IInitialState::provideInitialState is forbidden by a PHPUnit grep lint.
  • JS: Mirrored typed reader src/utils/loadInitialState.js with per-page
    default tables, schema-version mismatch warning, and a getDeclaredKeys()
    helper. Refactored src/main.js and src/admin.js to load via the reader
    and provide() each key by identical name (REQ-INIT-004 / REQ-INIT-005 — no
    ref/reactive wrap, no rename at boundary).
  • Tests: 5 unit tests for the builder (per-page apply, missing-key throw,
    schema-version always present) + 1 lint test that scans lib/ for stray
    provideInitialState calls. All 110 tests pass.

This change is foundational for the upcoming runtime-shell capability.

Notes

  • Spec lives on origin/feature/replica-spec-proposals (PR Add 25 OpenSpec proposals for multi-tenant dashboard platform #42).
  • The matching JS-side Vitest grep (forbidding loadState(['\"]mydash outside
    the reader) is deferred pending PR chore(test): add Vitest infrastructure #43 (chore/add-vitest-setup) — the
    PHP test contains a TODO referencing the follow-up. A manual grep confirms
    no src/ file currently bypasses the reader.
  • tests/bootstrap.php now registers vendor/nextcloud/ocp PSR-4 as a fallback
    autoloader so OCP-interface mocks resolve when running outside the Nextcloud
    Docker container — no impact on in-container behaviour.

Quality gates

  • composer lint / phpcs / phpmd / psalm (touched files): clean
  • composer phpstan baseline failures unchanged in shape (OCP-stub discovery
    pre-existing on development; 725 → 765 — same root cause, no new defects)
  • composer test:all: 110 tests / 321 assertions OK (5 new builder tests +
    1 new lint test)
  • ESLint on touched JS: clean

Test plan

  • Builder rejects missing required keys for each Page (workspace + admin)
  • _schemaVersion is pushed on every apply()
  • loadInitialState('workspace') returns 10 keys with declared defaults
  • loadInitialState('admin') returns 4 keys with declared defaults
  • Schema-version mismatch logs a console warning (manual check after Vitest lands)
  • PHPUnit lint test fails when a controller adds a direct provideInitialState call

@rubenvdlinde rubenvdlinde added the ready-for-code-review Build complete — awaiting code reviewer label Apr 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/mydash @ 1775fc9

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

Quality workflow — 2026-04-30 11:43 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde rubenvdlinde force-pushed the feature/impl-initial-state-contract branch from 697469e to f650e25 Compare April 30, 2026 12:01
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/mydash @ 1b044ec

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

Quality workflow — 2026-04-30 12:03 UTC

Download the full PDF report from the workflow artifacts.

….005

Centralises every Nextcloud IInitialState::provideInitialState call behind a
typed PHP builder (InitialStateBuilder + Page enum + MissingInitialStateException)
and mirrors it on the JS side with a typed loadInitialState(page) reader that
fills defaults and warns on schema-version mismatch.

- lib/Service/InitialStateBuilder.php: typed setters per page key, REQUIRED_KEYS
  map keyed by Page::WORKSPACE / Page::ADMIN, apply() validates and pushes every
  key plus _schemaVersion (INITIAL_STATE_SCHEMA_VERSION = 1).
- lib/Exception/MissingInitialStateException.php: thrown by apply() with page
  + missing-key context.
- lib/Controller/PageController.php and lib/Settings/MyDashAdmin.php: refactored
  to construct the builder and call apply() — the only sanctioned call sites.
- src/utils/loadInitialState.js: per-page key/default tables mirroring the spec
  Data Model exactly; emits a console.warn on _schemaVersion mismatch.
- src/main.js and src/admin.js: load via the reader and provide() each key by
  identical name (no renaming at the boundary, no ref/reactive wrapping).
- tests/Unit/Service/InitialStateBuilderTest.php: per-page apply pushes every
  key + schema version, missing required key throws, schema-version always
  pushed (5 tests / 28 assertions).
- tests/Unit/Service/InitialStateContractLintTest.php: PHP grep that fails when
  any file under lib/ outside InitialStateBuilder.php calls
  provideInitialState() directly.
- tests/bootstrap.php: register vendor/nextcloud/ocp PSR-4 autoload as fallback
  when running outside the Nextcloud container so OCP-interface mocks resolve.

PR #42 owns the spec text on origin/feature/replica-spec-proposals.

The matching JS-side Vitest scan (loadState\(['"]mydash) is deferred pending
PR #43 (chore/add-vitest-setup); a TODO comment in
InitialStateContractLintTest references the follow-up.
@rubenvdlinde rubenvdlinde force-pushed the feature/impl-initial-state-contract branch from ac3d46b to cac8fb3 Compare April 30, 2026 12:05
@rubenvdlinde rubenvdlinde merged commit 1da56c2 into development Apr 30, 2026
29 of 32 checks passed
@rubenvdlinde rubenvdlinde deleted the feature/impl-initial-state-contract branch April 30, 2026 12:05
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/mydash @ 3062d3b

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

Quality workflow — 2026-04-30 12:07 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde added a commit that referenced this pull request Apr 30, 2026
* feat(admin-settings): runtime gating on personal-dashboard creation per REQ-ASET-003 + 015

Implements REQ-ASET-003 (modified) runtime gating: when allow_user_dashboards flag
is OFF, POST /api/dashboards returns HTTP 403 with {status:'error',
error:'personal_dashboards_disabled', message:<translated>}.

- New PersonalDashboardsDisabledException (HTTP 403, stable error code)
- DashboardService::assertPersonalDashboardsAllowed() reads setting with default=false
- DashboardApiController::create() calls assert before permission checks; catches
  exception and returns exact spec envelope; read/update/delete untouched
- i18n: English + Dutch strings in all four l10n files (json + js)
- PHPUnit: 7 tests covering envelope shape, readability/editability with flag off,
  no-mutation guarantee, default-blocks-creation, defence-in-depth
- REQ-ASET-015 initial-state mirror already done in PR #45 (InitialStateBuilder);
  skip per spec instruction
- Fork-side wiring deferred to fork-current-as-personal PR
- Pre-existing: fixed 13 phpcbf-auto-fixable blank-line errors in DashboardApiController

* chore: update SBOM

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
rubenvdlinde added a commit that referenced this pull request May 3, 2026
….005 (#45)

Centralises every Nextcloud IInitialState::provideInitialState call behind a
typed PHP builder (InitialStateBuilder + Page enum + MissingInitialStateException)
and mirrors it on the JS side with a typed loadInitialState(page) reader that
fills defaults and warns on schema-version mismatch.

- lib/Service/InitialStateBuilder.php: typed setters per page key, REQUIRED_KEYS
  map keyed by Page::WORKSPACE / Page::ADMIN, apply() validates and pushes every
  key plus _schemaVersion (INITIAL_STATE_SCHEMA_VERSION = 1).
- lib/Exception/MissingInitialStateException.php: thrown by apply() with page
  + missing-key context.
- lib/Controller/PageController.php and lib/Settings/MyDashAdmin.php: refactored
  to construct the builder and call apply() — the only sanctioned call sites.
- src/utils/loadInitialState.js: per-page key/default tables mirroring the spec
  Data Model exactly; emits a console.warn on _schemaVersion mismatch.
- src/main.js and src/admin.js: load via the reader and provide() each key by
  identical name (no renaming at the boundary, no ref/reactive wrapping).
- tests/Unit/Service/InitialStateBuilderTest.php: per-page apply pushes every
  key + schema version, missing required key throws, schema-version always
  pushed (5 tests / 28 assertions).
- tests/Unit/Service/InitialStateContractLintTest.php: PHP grep that fails when
  any file under lib/ outside InitialStateBuilder.php calls
  provideInitialState() directly.
- tests/bootstrap.php: register vendor/nextcloud/ocp PSR-4 autoload as fallback
  when running outside the Nextcloud container so OCP-interface mocks resolve.

PR #42 owns the spec text on origin/feature/replica-spec-proposals.

The matching JS-side Vitest scan (loadState\(['"]mydash) is deferred pending
PR #43 (chore/add-vitest-setup); a TODO comment in
InitialStateContractLintTest references the follow-up.
rubenvdlinde added a commit that referenced this pull request May 3, 2026
* feat(admin-settings): runtime gating on personal-dashboard creation per REQ-ASET-003 + 015

Implements REQ-ASET-003 (modified) runtime gating: when allow_user_dashboards flag
is OFF, POST /api/dashboards returns HTTP 403 with {status:'error',
error:'personal_dashboards_disabled', message:<translated>}.

- New PersonalDashboardsDisabledException (HTTP 403, stable error code)
- DashboardService::assertPersonalDashboardsAllowed() reads setting with default=false
- DashboardApiController::create() calls assert before permission checks; catches
  exception and returns exact spec envelope; read/update/delete untouched
- i18n: English + Dutch strings in all four l10n files (json + js)
- PHPUnit: 7 tests covering envelope shape, readability/editability with flag off,
  no-mutation guarantee, default-blocks-creation, defence-in-depth
- REQ-ASET-015 initial-state mirror already done in PR #45 (InitialStateBuilder);
  skip per spec instruction
- Fork-side wiring deferred to fork-current-as-personal PR
- Pre-existing: fixed 13 phpcbf-auto-fixable blank-line errors in DashboardApiController

* chore: update SBOM

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

ready-for-code-review Build complete — awaiting code reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant