Skip to content

feat: rename the app id from softwarecatalog to stackiq - #708

Open
rubenvdlinde wants to merge 11 commits into
developmentfrom
feat/rename-softwarecatalog-to-stackiq
Open

feat: rename the app id from softwarecatalog to stackiq#708
rubenvdlinde wants to merge 11 commits into
developmentfrom
feat/rename-softwarecatalog-to-stackiq

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Renames the app id softwarecatalog -> stackiq, with the data migration that makes it safe.

Why the migration is the point

Nextcloud namespaces oc_appconfig and oc_preferences by app id, and there is no in-place app-id upgrade. After the rename every stored row is unreachable — and because every reader supplies a default, nothing errors. Settings just revert, silently. MigrateAppConfigKeys and MigrateUserPreferences run first in both <install> and <post-migration>; MigrateBackgroundJobClasses deregisters jobs orphaned by the namespace move.

Fixed on the way through

lib/Service/StackiqService.php had already been renamed on disk but still declared class SoftwareCatalogueService, and the Service\SoftwareCatalogue sub-namespace still pointed at a directory now called Service/Stackiq. Both are corrected, so the class, the namespace and the path finally agree.

Postman: the path array was rewritten alongside the raw URL. Postman builds the request from the array, so rewriting only raw would leave the collection quietly hitting a different URL than the diff shows.

FROZEN — and what renaming each would have done

Frozen Consequence
softwarecatalog.conduction.nl Verified live (HTTP 200); stackiq.conduction.nl returns 000. The manifest documentationUrl and footer href would point at nothing.
softwarecatalogus The Dutch VNG catalogue — an external system's name, not this app's id. Covers the GEMMA fixture XMLs and lib/Settings/softwarecatalogus_register.json.
x-openregister.app in the register descriptor OpenRegister attributes the register by this field and may match on it. Renaming risks a duplicate register or an orphaned one. Reported rather than guessed — worth a second opinion.
openspec/changes/archive/** History. Rewriting it breaks every @spec path pointing into it.
openspec/coverage-report.* A dated audit snapshot. Rewriting its observations to say something it never observed is falsification.
LEGACY_APP_ID in both Migrate* steps, and the old namespace inside MigrateBackgroundJobClasses These name what the steps read from. "Correcting" them breaks the migration in the one direction nothing would notice.
codeberg.org/Conduction/SoftwareCatalog URLs A different host and org, stale independently of this rename.

Register slugs are voorzieningen and vng-gemma — neither contains the app id, so neither moved.

Local verification

phpcs 0 errors · psalm clean · eslint 0 errors · 120/120 jest. PHPUnit cannot run outside a Nextcloud container here (Class "OC_App" not found in the bootstrap) — CI's matrix is the check that matters for it.

Conduction Release Bot and others added 7 commits August 22, 2026 18:23
…ob classes across the app-id rename

Nextcloud namespaces oc_appconfig and oc_preferences by app id and has no
in-place app-id upgrade, so every stored row becomes unreachable when the id
moves. Every reader supplies a default, so nothing errors -- settings just
revert. oc_jobs has the same shape one level down: it stores the job CLASS
NAME, so the namespace rename orphans all four job rows.

Three IRepairSteps, registered FIRST in both <install> and <post-migration>.
<install> matters because an app-id rename presents to Nextcloud as a FIRST
install of stackiq, and installAppLastSteps() guards <post-migration> with
$previousVersion !== '' -- so <install> is the only hook that fires on the
very upgrade these steps exist for. FIRST matters because InitializeSettings
writes config itself; running it first would make every key look already
present and strand the operator's value in the old namespace.

Exhaustive enumeration (getKeys / callForSeenUsers + getUserKeys, never
getUsersForUserValue which matches on a VALUE and so migrates nothing over an
open value set). Reserved keys enabled/installed_version/types are skipped --
copying 'enabled' as STRING makes the next app:enable fail permanently with
AppConfigTypeConflictException. Idempotent, non-destructive, and every read
AND write inside the try so a throw cannot abort the install.

28 unit tests covering all three.
…d dev scripts

Also repoints this app's own badges and clone URL from the retired
codeberg.org host to github.com/ConductionNL/stackiq, and replaces the
softwarecatalog.app doc link (DNS: no record) with the live
softwarecatalog.conduction.nl. The .conduction.nl host itself stays --
stackiq.conduction.nl does not resolve.
Completes the sweep: PHP namespace OCA\SoftwareCatalog -> OCA\Stackiq (the
sub-namespace Service\SoftwareCatalogue -> Service\Stackiq, and the class
SoftwareCatalogueService -> StackiqService, which had been left disagreeing with
its already-renamed file), /apps/softwarecatalog -> /apps/stackiq routes across
code, tests, postman collections, docs and cursor rules.

Postman: the path ARRAY was rewritten alongside the raw URL. Postman builds the
request from the array, so rewriting only raw would leave the collection hitting
a different URL than the diff shows.

FROZEN, each because renaming would fail silently rather than loudly:
  - softwarecatalog.conduction.nl (HTTP 200; stackiq.conduction.nl is 000) --
    the manifest documentationUrl and footer href would point at nothing.
  - softwarecatalogus -- the Dutch VNG catalogue, an external system's name,
    not this app's id. Includes the GEMMA fixture XMLs and the register file.
  - x-openregister.app in the register descriptor: OpenRegister attributes the
    register by this field and may match on it; renaming risks a duplicate or
    an orphan. Reported rather than guessed.
  - openspec/changes/archive/** -- history; rewriting breaks @SPEC paths.
  - openspec/coverage-report.* -- a dated audit snapshot. Rewriting its
    observations to say something it never observed is falsification.
  - LEGACY_APP_ID in the two Migrate* repair steps, and the old namespace in
    MigrateBackgroundJobClasses -- these name what the steps read FROM.
  - codeberg.org URLs -- a different host and org, stale independently.

Register slugs are voorzieningen and vng-gemma; neither contains the app id, so
neither moved.

Local: phpcs 0 errors, psalm clean, eslint 0 errors, 120/120 jest.
The register descriptor attributes the register to an owning app through
x-openregister.app. It was left on the old app id when the id moved, so the
descriptor claimed ownership by an app that no longer answers to that name.

Safe to move now: these instances are development-only, so there is no live
register whose attribution could be split.

The register SLUG is deliberately NOT touched here — that is the key objects
are stored against, and it is a separate decision from attribution. Other
apps' ids appearing in the same file (e.g. opencatalogi) are cross-app
references and stay as they are.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ b1c9f4b

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

Quality workflow — 2026-08-22 17:41 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ f75af66

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

Quality workflow — 2026-08-22 18:01 UTC

Download the full PDF report from the workflow artifacts.

…rfaced

The scripted sweep was fast but blunt. Five distinct failures, each a case of
a name moving without the thing that answers to it.

1. TEST CONSTANTS INVERTED THE MIGRATION. The sweep rewrote the tests'
   LEGACY constant from 'softwarecatalog' to 'stackiq', so they asserted that
   the migration reads from the namespace it writes TO -- a migration that
   does nothing, with a green bar. Both now bind to the step's own
   LEGACY_APP_ID constant, so they cannot drift again.

2. 50 DANGLING @SPEC REFERENCES. The sweep rewrote citation PATHS to
   openspec/specs/stackiq-* while the directories are still
   softwarecatalog-*. Capability ids are frozen -- gate-46 dereferences them
   and archived changes cannot move -- so the citations are reverted, not the
   directories. gate-46 now resolves every anchor.

3. l10n KEYS ARE THE ENGLISH SOURCE STRING, so renaming a user-visible string
   renames its key. Two keys drifted out of en.json. Repointed, with the Dutch
   VALUES carried across (Softwarecatalogus -> Stackiq only where it is the
   product name, never where it means the VNG catalogue).
   The .js artifacts were stale too: the l10n check reads JSON, but Nextcloud
   SERVES the .js, so nl.js/en_US.js would have kept the old keys and Dutch
   users would have silently fallen back to English past a green check.

4. phpstan: callForSeenUsers() expects Closure(IUser): (bool|null); a void
   closure does not satisfy it. The IJobList::has()/remove() class-string
   errors are unsatisfiable BY DESIGN -- this step exists to deregister jobs
   whose class no longer exists -- so they carry a scoped ignore with that
   reason, not a baseline entry.

5. gate-16 and prettier: four changed methods tagged with the requirement
   they implement; 50 files reflowed because 'stackiq' is shorter than
   'softwarecatalog' (measured 50 against 2 on development).

Local: phpcs 0 errors, phpstan clean, phpmd 0, eslint 0, 120/120 jest,
l10n OK, prettier clean, gate-16 0, gate-46 0.
Both CI failures had the same root cause, and it is a subtle one.

eslint-suppressions.json and phpmd.baseline.xml are keyed BY FILE PATH. The
sweep repointed those keys to the new filenames, but the rename of two source
files was a COPY, not a move -- so the old files stayed on disk, now with no
suppression entry pointing at them, and their long-standing findings resurfaced
as new errors. Neither file was reachable any more:

  - src/store/plugins/softwarecatalogPlugin.js -- superseded by stackiqPlugin.js,
    which orClient.js and store/modules/object.js already import.
  - src/views/settings/SoftwareCatalogSettings.vue -- superseded by
    StackiqSettings.vue, which registry.js already imports. The registry KEY
    stays SoftwareCatalogSettingsPage: that is a manifest identifier, not a
    filename.

Deleting them is the fix; repointing the suppressions back would have kept dead
code alive and silenced.

Also removed a genuine new else in MigrateAppConfigKeys::run() (guard plus
continue), rather than adding it to phpmd.baseline.xml -- a baseline records
debt already inherited, and same-day code does not belong in it.

Local: phpcs 0, phpmd 0, phpstan OK, eslint 0 errors, 120/120 jest, l10n OK,
prettier 0, gate-16 0.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ 72fb368

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

Quality workflow — 2026-08-23 07:29 UTC

Download the full PDF report from the workflow artifacts.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ 23d30d9

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

Quality workflow — 2026-08-23 07:47 UTC

Download the full PDF report from the workflow artifacts.

The earlier bulk pass built its file list with a case-SENSITIVE grep for
'softwarecatalog'. Every file whose only occurrences were 'SoftwareCatalog' or
'SoftwareCatalogue' -- the PHP namespace and class-name spellings -- was
therefore never in the list, and never rewritten. CI found them as 32 errors:
Class "OCA\SoftwareCatalog\EventListener\SoftwareCatalogEventListener" not
found, because composer's psr-4 now maps only OCA\Stackiq\.

Renamed the missed files and directories with git mv, and removed four stale
DUPLICATES the earlier rename had left behind by copying rather than moving --
tests/Unit/EventListener/SoftwareCatalogEventListener{,Decomposition}Test.php
and tests/Unit/Service/SoftwareCatalogueService{Decomposition,OrganisationMapper}Test.php.
Each had a live counterpart under the new name; the old copies still declared
the old namespace, so they could only ever fail.

lib/Settings/softwarecatalogus_register.json stays: softwarecatalogus is the
Dutch VNG catalogue, not this app, and the file is loaded by an explicit path.

Local: phpcs 0, phpstan OK, phpmd 0, eslint 0, 120/120 jest, l10n OK,
prettier 0, gate-16 0, gate-46 0.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ 6784d17

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

Quality workflow — 2026-08-23 08:18 UTC

Download the full PDF report from the workflow artifacts.

An earlier flatten of tests/Unit/Service/SoftwareCatalogue left BOTH
tests/Unit/Service/Stackiq/ and tests/Unit/Service/Stackiq/Stackiq/ tracked,
with byte-identical files. PHP fataled on the second copy:

  Cannot declare class OCA\Stackiq\Tests\Unit\Service\Stackiq\
  ContactPersonHandlerDecompositionTest, because the name is already in use

which aborted the whole PHPUnit run (exit 255) rather than failing a test.

Local: phpcs 0, phpstan OK, gate-16 0.
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.

1 participant