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

feat(dashboards): per-group default dashboard#52

Merged
rubenvdlinde merged 1 commit into
developmentfrom
feature/impl-default-dashboard-flag
Apr 30, 2026
Merged

feat(dashboards): per-group default dashboard#52
rubenvdlinde merged 1 commit into
developmentfrom
feature/impl-default-dashboard-flag

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Summary

Implements REQ-DASH-015..017 from spec change default-dashboard-flag: a single canonical default per group_shared dashboard group, flipped via a dedicated transactional endpoint, with create/update paths hardened against isDefault mutation.

  • New endpoint POST /api/dashboards/group/{groupId}/default (admin-only, body {"uuid": "..."}).
  • DashboardService::setGroupDefault() runs the SET-target + CLEAR-others writes inside a single IDBConnection::beginTransaction() / commit() / rollBack() block. Cross-group uuids return 404 with the existing default preserved.
  • createGroupShared() always inserts with isDefault = 0; updateGroupShared() strips isDefault from the patch — the only mutation path for the flag is the dedicated endpoint.
  • Reuses the existing isDefault SMALLINT column from the admin-templates change — no schema migration required.

Spec sources

Transactional invariant

The service writes in this order: setGroupDefaultUuid first → if 0 rows affected, throw DoesNotExistException and roll back so the previous default in any other group is untouched. Only when the target write succeeds does clearGroupDefaults run, then commit(). Concurrent admin clicks on different uuids in the same group can only end with a single isDefault = 1 row.

Test plan

  • composer phpcs passes (clean).
  • composer phpmd passes (clean — fixed MissingImport for InvalidArgumentException).
  • composer test:all — 183 tests / 480 assertions pass (was 169 before; +14 new tests).
  • composer check:strict reports ALL CHECKS PASSED.
  • Hydra reviewer + security reviewer (added ready-for-code-review label only per feedback_hydra-reset-sequential.md).

Notes

  • Tests use a small tests/Stubs/DoctrineStubs.php to allow PHPUnit to mock IDBConnection outside the Docker container — no-op inside the container, where the real Doctrine classes are loaded by lib/base.php.
  • Pre-existing Psalm error in UserAttributeResolver and PHPStan error in ImageMimeValidator are unrelated to this change and predate development HEAD; not touched per the strict "modify only files needed for this implementation" rule.
  • Frontend tasks (5.x), Playwright tests (7.x), OpenAPI/Postman regeneration (8.3), and i18n keys (8.4) from tasks.md are deferred — backend contract is complete and unblocks them as a follow-up.

@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 @ 95dfdbb

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:29 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde force-pushed the feature/impl-default-dashboard-flag branch from 000a613 to 217c15c Compare April 30, 2026 12:35
Add a transactional single-default-per-group invariant for
`group_shared` dashboards by reusing the existing `isDefault SMALLINT`
column (no schema migration required).

Changes
- `DashboardMapper::clearGroupDefaults()` and `setGroupDefaultUuid()`:
  the two halves of the transactional flip.
- `DashboardService::setGroupDefault()`: admin-only, wraps both writes
  in a single `IDBConnection::beginTransaction()` / `commit()` /
  `rollBack()` block. Order is SET-target first so the 0-row count
  triggers a 404 with the previous default preserved.
- `DashboardService::createGroupShared()`: explicitly forces
  `isDefault = 0` on insert (REQ-DASH-016 — defense-in-depth against
  payload smuggling).
- `DashboardService::updateGroupShared()`: drops `isDefault` from the
  patch before applying (REQ-DASH-017 — PUT can never flip the flag).
- `DashboardApiController::setGroupDefault()` mapped to
  `POST /api/dashboards/group/{groupId}/default`. Admin guard is in
  the body (matches existing `updateGroup`/`deleteGroup` pattern).

Tests
- 7 service tests cover the transactional invariant (commit on
  happy path, rollBack on cross-group 404, rollBack on mid-flip
  exception), the non-admin guard, and the create/update field
  hardening.
- 6 controller tests cover the route surface — non-admin 403,
  anonymous 401, missing-uuid 400, happy path 200, cross-group 404,
  and reflection-level checks that `createGroup`/`updateGroup`
  signatures do not expose `isDefault` as a parameter.
- `tests/Stubs/DoctrineStubs.php` defines minimal Doctrine DBAL
  placeholder classes so PHPUnit's automatic mock generator can
  introspect `IDBConnection` outside the Nextcloud container; no-op
  inside the container.

Spec source: PR #42 (`feature/replica-spec-proposals`,
`openspec/changes/default-dashboard-flag/`). Builds on PR #47
(`multi-scope-dashboards`, already in `development`).
@rubenvdlinde
rubenvdlinde force-pushed the feature/impl-default-dashboard-flag branch from 217c15c to 34ae9bb Compare April 30, 2026 12:36
@rubenvdlinde
rubenvdlinde merged commit 68e2721 into development Apr 30, 2026
31 of 32 checks passed
@rubenvdlinde
rubenvdlinde deleted the feature/impl-default-dashboard-flag branch April 30, 2026 12:36
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/mydash @ 205be00

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

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

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/mydash @ b296d8f

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:39 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde added a commit that referenced this pull request May 1, 2026
Lockfile-only update via `npm audit fix` (no --force, no
package.json changes, no major bumps). Resolves every high-severity
npm vulnerability flagged on the development branch:

- fast-xml-parser CVE chain (incl. Dependabot alerts #52, #70):
  4.5.4 → 4.5.6 (entity-expansion bypass + comment/CDATA injection)
- lodash prototype pollution
- node-forge prototype pollution
- path-to-regexp ReDoS
- picomatch ReDoS

As a side effect npm chose @conduction/nextcloud-vue 0.1.0-beta.15
(was beta.3), picking up the 12 intervening upstream releases
including all the recent CnAppNav/CnAppRoot work. The Nc* re-export
issue blocking eslint is unaffected — that lands when nextcloud-vue
PR #102 ships and a new beta is published.

Remaining: 12 moderate + 32 low. All require major-version bumps
(@nextcloud/webpack-vue-config v7, vue-loader v17, @vue/test-utils v2
which is Vue-3-only and would break the app, etc.) — out of scope
for an audit-fix sweep, deserve dedicated PRs with build/test
verification.

Verified locally:
- `npm run build` succeeds (35 webpack warnings, same baseline as dev)
- `npm run lint` no new errors (the 32 Nc* `import/named` errors are
  pre-existing, fixed by nextcloud-vue PR #102)
- `npm audit` reports 0 high-severity vulnerabilities (was 6)
rubenvdlinde added a commit that referenced this pull request May 1, 2026
#81)

Lockfile-only update via `npm audit fix` (no --force, no
package.json changes, no major bumps). Resolves every high-severity
npm vulnerability flagged on the development branch:

- fast-xml-parser CVE chain (incl. Dependabot alerts #52, #70):
  4.5.4 → 4.5.6 (entity-expansion bypass + comment/CDATA injection)
- lodash prototype pollution
- node-forge prototype pollution
- path-to-regexp ReDoS
- picomatch ReDoS

As a side effect npm chose @conduction/nextcloud-vue 0.1.0-beta.15
(was beta.3), picking up the 12 intervening upstream releases
including all the recent CnAppNav/CnAppRoot work. The Nc* re-export
issue blocking eslint is unaffected — that lands when nextcloud-vue
PR #102 ships and a new beta is published.

Remaining: 12 moderate + 32 low. All require major-version bumps
(@nextcloud/webpack-vue-config v7, vue-loader v17, @vue/test-utils v2
which is Vue-3-only and would break the app, etc.) — out of scope
for an audit-fix sweep, deserve dedicated PRs with build/test
verification.

Verified locally:
- `npm run build` succeeds (35 webpack warnings, same baseline as dev)
- `npm run lint` no new errors (the 32 Nc* `import/named` errors are
  pre-existing, fixed by nextcloud-vue PR #102)
- `npm audit` reports 0 high-severity vulnerabilities (was 6)
rubenvdlinde added a commit that referenced this pull request May 3, 2026
#52)

Add a transactional single-default-per-group invariant for
`group_shared` dashboards by reusing the existing `isDefault SMALLINT`
column (no schema migration required).

Changes
- `DashboardMapper::clearGroupDefaults()` and `setGroupDefaultUuid()`:
  the two halves of the transactional flip.
- `DashboardService::setGroupDefault()`: admin-only, wraps both writes
  in a single `IDBConnection::beginTransaction()` / `commit()` /
  `rollBack()` block. Order is SET-target first so the 0-row count
  triggers a 404 with the previous default preserved.
- `DashboardService::createGroupShared()`: explicitly forces
  `isDefault = 0` on insert (REQ-DASH-016 — defense-in-depth against
  payload smuggling).
- `DashboardService::updateGroupShared()`: drops `isDefault` from the
  patch before applying (REQ-DASH-017 — PUT can never flip the flag).
- `DashboardApiController::setGroupDefault()` mapped to
  `POST /api/dashboards/group/{groupId}/default`. Admin guard is in
  the body (matches existing `updateGroup`/`deleteGroup` pattern).

Tests
- 7 service tests cover the transactional invariant (commit on
  happy path, rollBack on cross-group 404, rollBack on mid-flip
  exception), the non-admin guard, and the create/update field
  hardening.
- 6 controller tests cover the route surface — non-admin 403,
  anonymous 401, missing-uuid 400, happy path 200, cross-group 404,
  and reflection-level checks that `createGroup`/`updateGroup`
  signatures do not expose `isDefault` as a parameter.
- `tests/Stubs/DoctrineStubs.php` defines minimal Doctrine DBAL
  placeholder classes so PHPUnit's automatic mock generator can
  introspect `IDBConnection` outside the Nextcloud container; no-op
  inside the container.

Spec source: PR #42 (`feature/replica-spec-proposals`,
`openspec/changes/default-dashboard-flag/`). Builds on PR #47
(`multi-scope-dashboards`, already in `development`).
rubenvdlinde added a commit that referenced this pull request May 3, 2026
#81)

Lockfile-only update via `npm audit fix` (no --force, no
package.json changes, no major bumps). Resolves every high-severity
npm vulnerability flagged on the development branch:

- fast-xml-parser CVE chain (incl. Dependabot alerts #52, #70):
  4.5.4 → 4.5.6 (entity-expansion bypass + comment/CDATA injection)
- lodash prototype pollution
- node-forge prototype pollution
- path-to-regexp ReDoS
- picomatch ReDoS

As a side effect npm chose @conduction/nextcloud-vue 0.1.0-beta.15
(was beta.3), picking up the 12 intervening upstream releases
including all the recent CnAppNav/CnAppRoot work. The Nc* re-export
issue blocking eslint is unaffected — that lands when nextcloud-vue
PR #102 ships and a new beta is published.

Remaining: 12 moderate + 32 low. All require major-version bumps
(@nextcloud/webpack-vue-config v7, vue-loader v17, @vue/test-utils v2
which is Vue-3-only and would break the app, etc.) — out of scope
for an audit-fix sweep, deserve dedicated PRs with build/test
verification.

Verified locally:
- `npm run build` succeeds (35 webpack warnings, same baseline as dev)
- `npm run lint` no new errors (the 32 Nc* `import/named` errors are
  pre-existing, fixed by nextcloud-vue PR #102)
- `npm audit` reports 0 high-severity vulnerabilities (was 6)
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