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

feat(admin-templates): primary-group routing resolver#49

Merged
rubenvdlinde merged 2 commits into
developmentfrom
feature/impl-group-routing
Apr 30, 2026
Merged

feat(admin-templates): primary-group routing resolver#49
rubenvdlinde merged 2 commits into
developmentfrom
feature/impl-group-routing

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Summary

Implements REQ-TMPL-012 (primary-group resolution algorithm) and REQ-TMPL-013 (single routing authority) from the group-routing change proposal.

  • New pure function AdminTemplateService::resolvePrimaryGroup(string $userId): string — walks the admin-configured group_order setting and returns the first matching Nextcloud group ID, or the literal sentinel Dashboard::DEFAULT_GROUP_ID ('default') when no match exists.
  • Internal pure helper pickFirstMatch(array $orderedGroups, array $userGroups): ?string exposed as static for direct intersection-logic unit tests.
  • Tolerates stale (deleted) group IDs in group_order and unknown user IDs without throwing — cleanup is the admin UI's responsibility.

Builds on

Single-source-of-truth contract

This is the single routing authority for primary-group resolution. Every workspace-rendering and dashboard-resolution code path (REQ-DASH-013, REQ-DASH-018, …) MUST consult this resolver instead of inlining the algorithm. Parallel implementations are forbidden by REQ-TMPL-013.

Out of scope

Refactoring existing call sites in PageController::index and DashboardService::getVisibleDashboards to consume resolvePrimaryGroup is intentionally deferred to follow-up PRs (incremental work, one consumer per PR). This PR provides the resolver and locks its contract.

Test plan

  • ./vendor/bin/phpunit — 186/186 tests pass (17 new tests in AdminTemplateServiceTest)
  • composer phpcs (PHPCS strict) — clean on lib/
  • composer phpmd — clean
  • Psalm + PHPStan — same 3 pre-existing baseline errors (Ramsey\Uuid stub gap + IUser::getLanguage), no new errors introduced
  • Hydra gates — failures all in pre-existing files (PermissionService, ConditionalService, AdminController); none in AdminTemplateService.php
  • Table-driven cover of every REQ-TMPL-012 scenario: priority-order match, no overlap, empty group_order, configured-but-not-member, deleted/stale group, unknown user
  • Read-only contract pinned via mock expects(never()) on every write surface

Spec source

openspec/changes/group-routing/{proposal,tasks,specs/admin-templates/spec}.md on branch feature/replica-spec-proposals.

Pure read-only `AdminTemplateService::resolvePrimaryGroup(string $userId): string`
that walks the admin-configured `group_order` setting (PR #44) and returns the
first matching Nextcloud group, or the literal sentinel
`Dashboard::DEFAULT_GROUP_ID` ('default') when no match exists. Single source of
truth for downstream resolvers (REQ-DASH-013, REQ-DASH-018, etc.) — workspace
rendering and dashboard resolution code paths MUST consume this method instead
of inlining the algorithm.

Tolerates stale (deleted) group IDs in `group_order` and unknown user IDs
without throwing, per REQ-TMPL-012 final scenarios.

Includes table-driven PHPUnit coverage of every REQ-TMPL-012 scenario:
priority-order match, no overlap, empty group_order, configured-but-not-member,
deleted/stale entries, unknown user. Also pins the literal 'default' sentinel
and asserts the resolver performs zero writes (read-only contract).

Internal helper `pickFirstMatch(array, array): ?string` is exposed as a static
pure function for direct unit tests of the intersection logic.

Out of scope (per change proposal): refactoring existing PageController /
DashboardService call sites to consume the resolver — that's incremental work
for a follow-up PR. This PR provides the resolver and locks its contract.
@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 @ c25d67b

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

Download the full PDF report from the workflow artifacts.

@rubenvdlinde rubenvdlinde merged commit ffede45 into development Apr 30, 2026
4 checks passed
@rubenvdlinde rubenvdlinde deleted the feature/impl-group-routing branch April 30, 2026 12:34
rubenvdlinde added a commit that referenced this pull request May 3, 2026
* feat(admin-templates): primary-group resolver per REQ-TMPL-012..013

Pure read-only `AdminTemplateService::resolvePrimaryGroup(string $userId): string`
that walks the admin-configured `group_order` setting (PR #44) and returns the
first matching Nextcloud group, or the literal sentinel
`Dashboard::DEFAULT_GROUP_ID` ('default') when no match exists. Single source of
truth for downstream resolvers (REQ-DASH-013, REQ-DASH-018, etc.) — workspace
rendering and dashboard resolution code paths MUST consume this method instead
of inlining the algorithm.

Tolerates stale (deleted) group IDs in `group_order` and unknown user IDs
without throwing, per REQ-TMPL-012 final scenarios.

Includes table-driven PHPUnit coverage of every REQ-TMPL-012 scenario:
priority-order match, no overlap, empty group_order, configured-but-not-member,
deleted/stale entries, unknown user. Also pins the literal 'default' sentinel
and asserts the resolver performs zero writes (read-only contract).

Internal helper `pickFirstMatch(array, array): ?string` is exposed as a static
pure function for direct unit tests of the intersection logic.

Out of scope (per change proposal): refactoring existing PageController /
DashboardService call sites to consume the resolver — that's incremental work
for a follow-up PR. This PR provides the resolver and locks its contract.

* 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