From 584f0ed15fc69f0240d4ceedd0bd41d6d7416ff5 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Sat, 12 Sep 2026 20:29:10 +0000
Subject: [PATCH 01/45] chore(release): 0.2.3-unstable.20260912202721
---
appinfo/info.xml | 2 +-
openapi.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 15874ec6c..c296c0ece 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -50,7 +50,7 @@ Vrij en open source onder de EUPL-licentie.
**Ondersteuning:** Voor ondersteuning, neem contact op via support@conduction.nl. Voor een Service Level Agreement (SLA), neem contact op via sales@conduction.nl.
]]>
- 0.2.2-unstable.20260910105110
+ 0.2.3-unstable.20260912202721
EUPL-1.2
Conduction
Stackiq
diff --git a/openapi.json b/openapi.json
index 264274cdb..9746b7596 100644
--- a/openapi.json
+++ b/openapi.json
@@ -2,7 +2,7 @@
"openapi": "3.0.3",
"info": {
"title": "stackiq",
- "version": "0.2.2-unstable.20260910105110",
+ "version": "0.2.3-unstable.20260912202721",
"description": "Stackiq",
"license": {
"name": "agpl"
From a8a66d05551a97b1a440659f5ecf5dd57ca7123c Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Mon, 14 Sep 2026 22:28:43 +0200
Subject: [PATCH 02/45] feat(integrations): show stackiq's connections through
integriq's registry (#1032)
* feat(connections): declare email, federation and the end-of-life feed for integriq
* feat(connections): refresh and report email, federation and the end-of-life feed to integriq
* feat(connections): an Integrations page over integriq's connection registry
* test(connections): an e2e spec for the Integrations page, with integriq in CI
* test(connections): named arguments, and stubs that wait for OCP
* refactor(connections): keep the event senders private
---
.github/workflows/code-quality.yml | 9 +-
l10n/en.js | 15 +-
l10n/en.json | 15 +-
l10n/nl.js | 15 +-
l10n/nl.json | 15 +-
lib/AppInfo/Application.php | 11 +-
lib/Controller/SettingsController.php | 13 +
lib/Service/ConnectionReportService.php | 501 ++++++++++++++++++
lib/Service/EolSyncService.php | 31 +-
lib/Service/Federation/FederationService.php | 35 +-
lib/Settings/connections.json | 37 ++
.../adopt-connection-registry/.openspec.yaml | 2 +
.../adopt-connection-registry/design.md | 96 ++++
.../adopt-connection-registry/proposal.md | 45 ++
.../specs/admin-integrations/spec.md | 95 ++++
.../adopt-connection-registry/tasks.md | 34 ++
phpstan.neon | 4 +
psalm.xml | 6 +
src/App.vue | 11 +
src/customComponents.js | 12 +
src/icons.js | 2 +
src/manifest.d/connection-registry.json | 87 +++
src/services/connectionRegistry.js | 99 ++++
.../settings/sections/EmailConfiguration.vue | 1 +
.../settings/sections/EolSyncSettings.vue | 1 +
.../settings/sections/FederationSettings.vue | 1 +
.../Event/ConnectionRefreshRequestedEvent.php | 46 ++
.../Event/ConnectionStatusReportedEvent.php | 52 ++
...SettingsControllerConnectionReportTest.php | 165 ++++++
.../Service/ConnectionReportCallersTest.php | 303 +++++++++++
.../Service/ConnectionReportServiceTest.php | 489 +++++++++++++++++
.../Settings/ConnectionsDeclarationTest.php | 355 +++++++++++++
tests/bootstrap-unit.php | 15 +
tests/bootstrap.php | 19 +
tests/e2e/workflows/integrations-page.spec.ts | 154 ++++++
tests/vitest/connectionRegistry.spec.js | 165 ++++++
36 files changed, 2945 insertions(+), 11 deletions(-)
create mode 100644 lib/Service/ConnectionReportService.php
create mode 100644 lib/Settings/connections.json
create mode 100644 openspec/changes/adopt-connection-registry/.openspec.yaml
create mode 100644 openspec/changes/adopt-connection-registry/design.md
create mode 100644 openspec/changes/adopt-connection-registry/proposal.md
create mode 100644 openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md
create mode 100644 openspec/changes/adopt-connection-registry/tasks.md
create mode 100644 src/manifest.d/connection-registry.json
create mode 100644 src/services/connectionRegistry.js
create mode 100644 tests/Stubs/Integriq/Event/ConnectionRefreshRequestedEvent.php
create mode 100644 tests/Stubs/Integriq/Event/ConnectionStatusReportedEvent.php
create mode 100644 tests/Unit/Controller/SettingsControllerConnectionReportTest.php
create mode 100644 tests/Unit/Service/ConnectionReportCallersTest.php
create mode 100644 tests/Unit/Service/ConnectionReportServiceTest.php
create mode 100644 tests/Unit/Settings/ConnectionsDeclarationTest.php
create mode 100644 tests/e2e/workflows/integrations-page.spec.ts
create mode 100644 tests/vitest/connectionRegistry.spec.js
diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml
index 026f5a693..213bafb1f 100644
--- a/.github/workflows/code-quality.yml
+++ b/.github/workflows/code-quality.yml
@@ -158,7 +158,14 @@ jobs:
# object API directly (tests/e2e/workflows/_fixtures.ts), so testing
# against `main` measures a different backend than the one this app is
# written for. Pinned to `development` to match.
- additional-apps: '[{"repo":"ConductionNL/openregister","app":"openregister","ref":"development"}]'
+ #
+ # integriq is here because the Integrations page reads integriq's
+ # `app_connection` rows (adopt-connection-registry). Without it the page
+ # shows the missing-dependency screen and
+ # `tests/e2e/workflows/integrations-page.spec.ts` fails on every run.
+ # `app` is `integriq`, verified in its appinfo/info.xml on `development`
+ # on 2026-09-14.
+ additional-apps: '[{"repo":"ConductionNL/openregister","app":"openregister","ref":"development"},{"repo":"ConductionNL/integriq","app":"integriq","ref":"development"}]'
# Newman disabled: tests/magic-mapper-import.postman_collection.json was
# written against a dev env with URL rewriting + a fixed disk layout — it
# hits bare paths like `/configurations` and uploads files from
diff --git a/l10n/en.js b/l10n/en.js
index 08b68094d..47b812dcd 100644
--- a/l10n/en.js
+++ b/l10n/en.js
@@ -704,7 +704,20 @@ OC.L10N.register(
"xmlns": "xmlns",
"xsi": "xsi",
"Pre-filled with the names the Integriq endoflife-date-source change provisions. Change them if your instance uses different names, no code change required.": "Pre-filled with the names the Integriq endoflife-date-source change provisions. Change them if your instance uses different names, no code change required.",
- "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?": "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?"
+ "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?": "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?",
+ "Integrations": "Integrations",
+ "Status message": "Status message",
+ "Last checked": "Last checked",
+ "All connections": "All connections",
+ "Add integration": "Add integration",
+ "Open settings": "Open settings",
+ "Configured": "Configured",
+ "Limited": "Limited",
+ "Not configured": "Not configured",
+ "Simulated": "Simulated",
+ "Not available": "Not available",
+ "Error": "Error",
+ "Settings": "Settings"
},
"nplurals=2; plural=(n != 1);"
)
diff --git a/l10n/en.json b/l10n/en.json
index 81aaa9c63..8c8626820 100644
--- a/l10n/en.json
+++ b/l10n/en.json
@@ -703,6 +703,19 @@
"xmlns": "xmlns",
"xsi": "xsi",
"Pre-filled with the names the Integriq endoflife-date-source change provisions. Change them if your instance uses different names, no code change required.": "Pre-filled with the names the Integriq endoflife-date-source change provisions. Change them if your instance uses different names, no code change required.",
- "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?": "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?"
+ "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?": "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?",
+ "Integrations": "Integrations",
+ "Status message": "Status message",
+ "Last checked": "Last checked",
+ "All connections": "All connections",
+ "Add integration": "Add integration",
+ "Open settings": "Open settings",
+ "Configured": "Configured",
+ "Limited": "Limited",
+ "Not configured": "Not configured",
+ "Simulated": "Simulated",
+ "Not available": "Not available",
+ "Error": "Error",
+ "Settings": "Settings"
}
}
diff --git a/l10n/nl.js b/l10n/nl.js
index 6c52495c3..cd3abea30 100644
--- a/l10n/nl.js
+++ b/l10n/nl.js
@@ -777,7 +777,20 @@ OC.L10N.register(
"xmlns": "xmlns",
"xsi": "xsi",
"Pre-filled with the names the Integriq endoflife-date-source change provisions. Change them if your instance uses different names, no code change required.": "Vooraf ingevuld met de namen die de Integriq-wijziging endoflife-date-source aanmaakt. Wijzig ze als uw omgeving andere namen gebruikt, geen codewijziging nodig.",
- "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?": "het geconfigureerde register of schema kon niet worden gevonden. Is de Integriq-wijziging endoflife-date-source geïnstalleerd?"
+ "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?": "het geconfigureerde register of schema kon niet worden gevonden. Is de Integriq-wijziging endoflife-date-source geïnstalleerd?",
+ "Integrations": "Koppelingen",
+ "Status message": "Statusbericht",
+ "Last checked": "Laatst gecontroleerd",
+ "All connections": "Alle verbindingen",
+ "Add integration": "Integratie toevoegen",
+ "Open settings": "Instellingen openen",
+ "Configured": "Ingericht",
+ "Limited": "Beperkt",
+ "Not configured": "Niet geconfigureerd",
+ "Simulated": "Gesimuleerd",
+ "Not available": "Niet beschikbaar",
+ "Error": "Fout",
+ "Settings": "Instellingen"
},
"nplurals=2; plural=(n != 1);"
)
diff --git a/l10n/nl.json b/l10n/nl.json
index 0848195e0..74b03d236 100644
--- a/l10n/nl.json
+++ b/l10n/nl.json
@@ -776,6 +776,19 @@
"xmlns": "xmlns",
"xsi": "xsi",
"Pre-filled with the names the Integriq endoflife-date-source change provisions. Change them if your instance uses different names, no code change required.": "Vooraf ingevuld met de namen die de Integriq-wijziging endoflife-date-source aanmaakt. Wijzig ze als uw omgeving andere namen gebruikt, geen codewijziging nodig.",
- "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?": "het geconfigureerde register of schema kon niet worden gevonden. Is de Integriq-wijziging endoflife-date-source geïnstalleerd?"
+ "the configured register or schema could not be found. Is the Integriq endoflife-date-source change installed?": "het geconfigureerde register of schema kon niet worden gevonden. Is de Integriq-wijziging endoflife-date-source geïnstalleerd?",
+ "Integrations": "Koppelingen",
+ "Status message": "Statusbericht",
+ "Last checked": "Laatst gecontroleerd",
+ "All connections": "Alle verbindingen",
+ "Add integration": "Integratie toevoegen",
+ "Open settings": "Instellingen openen",
+ "Configured": "Ingericht",
+ "Limited": "Beperkt",
+ "Not configured": "Niet geconfigureerd",
+ "Simulated": "Gesimuleerd",
+ "Not available": "Niet beschikbaar",
+ "Error": "Fout",
+ "Settings": "Instellingen"
}
}
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 672b1cdec..175c58296 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -39,6 +39,7 @@
use OCA\Stackiq\Service\ArchiMateExportService;
use OCA\Stackiq\Service\ArchiMateImportService;
use OCA\Stackiq\Service\ArchiMateService;
+use OCA\Stackiq\Service\ConnectionReportService;
use OCA\Stackiq\Service\ContactpersoonService;
use OCA\Stackiq\Service\ContractApprovalService;
use OCA\Stackiq\Service\ContractStatusService;
@@ -674,7 +675,11 @@ function ($container) {
config: $container->get(FederationConfig::class),
merger: $container->get(FederationMerger::class),
settingsService: $container->get(SettingsService::class),
- logger: $container->get(LoggerInterface::class)
+ logger: $container->get(LoggerInterface::class),
+ // The integriq connection report (adopt-connection-registry). Passed by
+ // name: this factory is hand-built, so the constructor default of null
+ // would otherwise switch every federation report off without a sound.
+ connectionReports: $container->get(ConnectionReportService::class)
);
}
);
@@ -706,7 +711,9 @@ function ($container) {
settingsService: $container->get(SettingsService::class),
matcher: $container->get(EolMatcherService::class),
timeFactory: $container->get('OCP\AppFramework\Utility\ITimeFactory'),
- logger: $container->get(LoggerInterface::class)
+ logger: $container->get(LoggerInterface::class),
+ // Same reason as the FederationService factory above.
+ connectionReports: $container->get(ConnectionReportService::class)
);
}
);
diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php
index 2064ade21..7225595ed 100644
--- a/lib/Controller/SettingsController.php
+++ b/lib/Controller/SettingsController.php
@@ -27,6 +27,7 @@
use OCA\OpenRegister\Contract\ObjectServiceInterface;
use OCA\OpenRegister\Service\ConfigurationService;
use OCA\Stackiq\Service\ArchiMateService;
+use OCA\Stackiq\Service\ConnectionReportService;
use OCA\Stackiq\Service\EolSyncService;
use OCA\Stackiq\Service\OrganizationSyncService;
use OCA\Stackiq\Service\ProgressTracker;
@@ -84,8 +85,11 @@ class SettingsController extends Controller {
* @param ProgressTracker $progressTracker The progress tracking service.
* @param EolSyncService $eolSyncService The EOL feed sync orchestration service.
* @param LoggerInterface $logger The logger instance.
+ * @param ConnectionReportService|null $connectionReports Asks integriq to look again after an email settings save.
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function __construct(
$appName,
@@ -101,6 +105,7 @@ public function __construct(
private readonly ProgressTracker $progressTracker,
private readonly EolSyncService $eolSyncService,
private readonly LoggerInterface $logger,
+ private readonly ?ConnectionReportService $connectionReports = null,
) {
parent::__construct(appName: $appName, request: $request);
@@ -431,9 +436,14 @@ private function updateUserGroupSettings(array $data, array &$result): ?JSONResp
* @param array $data The raw request params.
* @param array $result The result accumulator (passed by reference).
*
+ * After the write it asks integriq to resolve the email connection again
+ * (adopt-connection-registry). That never throws, does nothing without
+ * integriq, and never changes the response.
+ *
* @return void
*
* @spec openspec/changes/method-decomposition/tasks.md#task-3
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
private function applyEmailSettingsUpdate(array $data, array &$result): void {
if (isset($data['emailSettings']) === false) {
@@ -441,6 +451,7 @@ private function applyEmailSettingsUpdate(array $data, array &$result): void {
}
$result['emailSettings'] = $this->settingsService->updateEmailSettings($data['emailSettings']);
+ $this->connectionReports?->emailSettingsSaved();
}//end applyEmailSettingsUpdate()
@@ -2025,6 +2036,7 @@ public function getEmailSettings(): JSONResponse {
*
* @return JSONResponse Update result
* @spec openspec/specs/settings-admin-controller/spec.md
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function updateEmailSettings(): JSONResponse {
$currentUser = $this->userSession->getUser();
@@ -2041,6 +2053,7 @@ public function updateEmailSettings(): JSONResponse {
$emailSettings = $data['emailSettings'] ?? $data;
$updatedSettings = $this->settingsService->updateEmailSettings($emailSettings);
+ $this->connectionReports?->emailSettingsSaved();
return new JSONResponse(
[
diff --git a/lib/Service/ConnectionReportService.php b/lib/Service/ConnectionReportService.php
new file mode 100644
index 000000000..646c48e8e
--- /dev/null
+++ b/lib/Service/ConnectionReportService.php
@@ -0,0 +1,501 @@
+
+ * @copyright 2026 Conduction B.V.
+ * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * @link https://conduction.nl
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ *
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
+ * SPDX-License-Identifier: EUPL-1.2
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Stackiq\Service;
+
+use OCA\Stackiq\AppInfo\Application;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventDispatcher;
+use Psr\Log\LoggerInterface;
+use Throwable;
+
+/**
+ * Sends connection refresh requests and reports to integriq.
+ *
+ * A save refreshes before it reports. Under hydra#674 a refresh retires the
+ * observations older than itself, so a report sent before the refresh would
+ * be retired by it. A pull or a sync run reports without a refresh: it
+ * changes no settings.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+class ConnectionReportService {
+
+ /**
+ * Integriq's report event (ADR-041). Named by string so stackiq stays
+ * installable without integriq: the class is only there when integriq is.
+ *
+ * @var string
+ */
+ public const STATUS_EVENT = 'OCA\Integriq\Event\ConnectionStatusReportedEvent';
+
+ /**
+ * Integriq's refresh event. Same reason for the string as above.
+ *
+ * @var string
+ */
+ public const REFRESH_EVENT = 'OCA\Integriq\Event\ConnectionRefreshRequestedEvent';
+
+ /**
+ * The email connection key in lib/Settings/connections.json.
+ *
+ * @var string
+ */
+ public const KEY_EMAIL = 'email';
+
+ /**
+ * The catalog federation connection key in lib/Settings/connections.json.
+ *
+ * @var string
+ */
+ public const KEY_FEDERATION = 'federation';
+
+ /**
+ * The end-of-life feed connection key in lib/Settings/connections.json.
+ *
+ * @var string
+ */
+ public const KEY_EOL = 'eol-feed';
+
+ /**
+ * The longest failure reason a message carries.
+ *
+ * @var int
+ */
+ public const REASON_LIMIT = 160;
+
+ /**
+ * What each EOL sync degrade reason means for the row, as status and message.
+ *
+ * The reasons are the ones EolSyncService::degrade() records.
+ *
+ * @var array
+ */
+ public const EOL_REASONS = [
+ 'disabled' => [
+ 'unconfigured',
+ 'End-of-life sync is switched off. Switch it on in the End-of-life feed sync section.',
+ ],
+ 'openregister-not-installed' => [
+ 'unavailable',
+ 'The end-of-life sync needs OpenRegister, and it is not installed.',
+ ],
+ 'object-service-unavailable' => [
+ 'error',
+ 'OpenRegister did not answer the last end-of-life sync.',
+ ],
+ 'module-schema-not-configured' => [
+ 'unconfigured',
+ 'Stackiq has no module or module version schema configured, so the sync has nothing to stamp.',
+ ],
+ 'eol-register-or-schema-not-found' => [
+ 'unconfigured',
+ 'The end-of-life register or schemas are missing. Install the endoflife.date source in integriq, '
+ . 'or fix the names in the End-of-life feed sync section.',
+ ],
+ ];
+
+ /**
+ * Constructor.
+ *
+ * @param IEventDispatcher $eventDispatcher Sends the integriq events (ADR-041).
+ * @param SymfonyEmailService $emailService Tells whether the saved email settings are complete.
+ * @param LoggerInterface $logger Records what could not be sent.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function __construct(
+ private readonly IEventDispatcher $eventDispatcher,
+ private readonly SymfonyEmailService $emailService,
+ private readonly LoggerInterface $logger,
+ ) {
+ }//end __construct()
+
+ /**
+ * After an email settings save: refresh, then report what the saved settings say.
+ *
+ * The `null` transport is left to integriq's rule 3, which outranks any
+ * report. Never throws, and does nothing without integriq.
+ *
+ * @return bool True when the report was sent.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function emailSettingsSaved(): bool {
+ if ($this->refresh(key: self::KEY_EMAIL) === false) {
+ return false;
+ }
+
+ try {
+ [$status, $message] = $this->describeEmail(
+ configStatus: $this->emailService->isEmailSystemConfigured(),
+ transportLabels: $this->emailService->getAvailableTransports()
+ );
+ } catch (Throwable $e) {
+ $this->logger->warning(
+ 'Stackiq: could not read the email settings for a connection report',
+ ['key' => self::KEY_EMAIL, 'exception' => $e->getMessage()]
+ );
+ return false;
+ }
+
+ return $this->report(key: self::KEY_EMAIL, status: $status, message: $message);
+ }//end emailSettingsSaved()
+
+ /**
+ * What the email configuration status says about the connection.
+ *
+ * @param array $configStatus The result of SymfonyEmailService::isEmailSystemConfigured().
+ * @param array $transportLabels Transport type to its label.
+ *
+ * @return array{0: string, 1: string} The status and the message.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function describeEmail(array $configStatus, array $transportLabels): array {
+ if (array_key_exists('transportType', $configStatus) === false) {
+ // SymfonyEmailService answers without a transport only when email is off.
+ return ['unconfigured', 'Email is switched off, so stackiq sends no mail.'];
+ }
+
+ $transport = (string) $configStatus['transportType'];
+ $label = ($transportLabels[$transport] ?? $transport);
+
+ if (($configStatus['hasCredentials'] ?? false) !== true) {
+ return ['unconfigured', 'Email is on, and the ' . $label . ' transport misses a setting it needs.'];
+ }
+
+ if (($configStatus['hasTemplates'] ?? false) !== true) {
+ return ['unconfigured', 'Email is on, and a required mail template is empty.'];
+ }
+
+ return ['configured', 'Email is on and the ' . $label . ' transport settings are filled. No test mail was sent.'];
+ }//end describeEmail()
+
+ /**
+ * After a peer was added or removed: refresh, then report a state that blocks federation.
+ *
+ * A ready federation gets no report: only a pull can tell whether the peers
+ * answer, so the row reads the declared "Not checked yet" until then.
+ *
+ * @param array $status The result of FederationService::getStatus().
+ *
+ * @return bool True when a report was sent.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function federationPeersChanged(array $status): bool {
+ if ($this->refresh(key: self::KEY_FEDERATION) === false) {
+ return false;
+ }
+
+ $blocked = $this->federationBlocker(
+ available: ($status['available'] ?? false) === true,
+ enabled: ($status['enabled'] ?? false) === true,
+ peerCount: count((array) ($status['peers'] ?? []))
+ );
+ if ($blocked === null) {
+ return false;
+ }
+
+ return $this->report(key: self::KEY_FEDERATION, status: $blocked[0], message: $blocked[1]);
+ }//end federationPeersChanged()
+
+ /**
+ * After a federation pull: report what the peers answered.
+ *
+ * @param array $pull The result of FederationService::pullAllPeers().
+ *
+ * @return bool True when a report was sent.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function federationPulled(array $pull): bool {
+ [$status, $message] = $this->describePull(pull: $pull);
+
+ return $this->report(key: self::KEY_FEDERATION, status: $status, message: $message);
+ }//end federationPulled()
+
+ /**
+ * What a federation pull says about the connection.
+ *
+ * @param array $pull The result of FederationService::pullAllPeers().
+ *
+ * @return array{0: string, 1: string} The status and the message.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function describePull(array $pull): array {
+ $reason = (string) ($pull['reason'] ?? '');
+ if (($pull['ok'] ?? false) !== true) {
+ $blocked = $this->federationBlocker(
+ available: $reason !== 'OpenCatalogi unavailable',
+ enabled: $reason !== 'federation disabled',
+ peerCount: 1
+ );
+
+ return ($blocked ?? ['error', 'The last federation pull failed: ' . $this->shorten(text: $reason)]);
+ }
+
+ $peers = array_values((array) ($pull['peers'] ?? []));
+ if ($peers === []) {
+ return ['unconfigured', 'Federation is on, and no peer catalog is added yet.'];
+ }
+
+ $failed = array_values(
+ array_filter($peers, static fn (mixed $peer): bool => is_array($peer) === true && ($peer['ok'] ?? false) !== true)
+ );
+ if ($failed === [] && count($peers) === 1) {
+ return ['configured', 'The peer catalog answered the last pull.'];
+ }
+
+ if ($failed === []) {
+ return ['configured', 'All ' . count($peers) . ' peer catalogs answered the last pull.'];
+ }
+
+ $first = $this->peerHost(url: (string) ($failed[0]['peer'] ?? ''))
+ . ' did not: ' . $this->shorten(text: (string) ($failed[0]['reason'] ?? ''));
+ if (count($failed) === count($peers)) {
+ return ['error', 'No peer catalog answered the last pull. ' . $first];
+ }
+
+ $answered = (count($peers) - count($failed));
+
+ return ['limited', $answered . ' of ' . count($peers) . ' peer catalogs answered the last pull. ' . $first];
+ }//end describePull()
+
+ /**
+ * After an EOL sync settings save: refresh, then report a switched-off sync.
+ *
+ * @param array $config The configuration as saved.
+ *
+ * @return bool True when a report was sent.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function eolSyncConfigSaved(array $config): bool {
+ if ($this->refresh(key: self::KEY_EOL) === false) {
+ return false;
+ }
+
+ if (($config['enabled'] ?? false) === true) {
+ return false;
+ }
+
+ [$status, $message] = self::EOL_REASONS['disabled'];
+
+ return $this->report(key: self::KEY_EOL, status: $status, message: $message);
+ }//end eolSyncConfigSaved()
+
+ /**
+ * After an EOL sync run: report the outcome the run recorded.
+ *
+ * @param array $runStatus The status EolSyncService::run() recorded.
+ *
+ * @return bool True when a report was sent.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function eolSyncRan(array $runStatus): bool {
+ [$status, $message] = $this->describeEolRun(runStatus: $runStatus);
+
+ return $this->report(key: self::KEY_EOL, status: $status, message: $message);
+ }//end eolSyncRan()
+
+ /**
+ * What an EOL sync run says about the connection.
+ *
+ * @param array $runStatus The status EolSyncService::run() recorded.
+ *
+ * @return array{0: string, 1: string} The status and the message.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ public function describeEolRun(array $runStatus): array {
+ if (($runStatus['available'] ?? false) === true) {
+ return [
+ 'configured',
+ 'The last sync stamped ' . (int) ($runStatus['matched'] ?? 0) . ' module versions and skipped '
+ . (int) ($runStatus['skipped'] ?? 0) . '.',
+ ];
+ }
+
+ $reason = (string) ($runStatus['reason'] ?? '');
+
+ return (self::EOL_REASONS[$reason] ?? ['error', 'The last end-of-life sync stopped: ' . $this->shorten(text: $reason)]);
+ }//end describeEolRun()
+
+ /**
+ * Ask integriq to resolve one connection again.
+ *
+ * @param string $key The connection key.
+ *
+ * @return bool True when the event was dispatched.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ private function refresh(string $key): bool {
+ $eventClass = $this->resolveEventClass(eventClass: self::REFRESH_EVENT);
+ if ($eventClass === null) {
+ return false;
+ }
+
+ return $this->send(
+ key: $key,
+ build: static fn (): object => new $eventClass(app: Application::APP_ID, key: $key)
+ );
+ }//end refresh()
+
+ /**
+ * Report one status for one connection.
+ *
+ * @param string $key The connection key.
+ * @param string $status One of the six registry statuses.
+ * @param string $message What stackiq observed.
+ *
+ * @return bool True when the event was dispatched.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ private function report(string $key, string $status, string $message): bool {
+ $eventClass = $this->resolveEventClass(eventClass: self::STATUS_EVENT);
+ if ($eventClass === null) {
+ return false;
+ }
+
+ return $this->send(
+ key: $key,
+ build: static fn (): object => new $eventClass(app: Application::APP_ID, key: $key, status: $status, message: $message)
+ );
+ }//end report()
+
+ /**
+ * The event class to instantiate, or null when integriq does not ship it.
+ *
+ * @param string $eventClass The fully qualified class name, without a leading backslash.
+ *
+ * @return string|null The class name to instantiate, or null when absent.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ protected function resolveEventClass(string $eventClass): ?string {
+ $qualified = '\\' . $eventClass;
+ if (class_exists($qualified) === false) {
+ return null;
+ }
+
+ return $qualified;
+ }//end resolveEventClass()
+
+ /**
+ * The state that keeps federation from pulling at all, or null when none does.
+ *
+ * @param bool $available Whether OpenCatalogi is installed.
+ * @param bool $enabled Whether federation_enabled is on.
+ * @param int $peerCount How many peers are configured.
+ *
+ * @return array{0: string, 1: string}|null The status and the message, or null.
+ */
+ private function federationBlocker(bool $available, bool $enabled, int $peerCount): ?array {
+ if ($available === false) {
+ return ['unavailable', 'Federation needs the OpenCatalogi app, and it is not installed.'];
+ }
+
+ if ($enabled === false) {
+ return [
+ 'unconfigured',
+ 'Federation is switched off. Run occ config:app:set stackiq federation_enabled --value=true --type=boolean.',
+ ];
+ }
+
+ if ($peerCount === 0) {
+ return ['unconfigured', 'Federation is on, and no peer catalog is added yet.'];
+ }
+
+ return null;
+ }//end federationBlocker()
+
+ /**
+ * The host of a peer URL, so a message never carries its path, query or credentials.
+ *
+ * @param string $url The peer URL.
+ *
+ * @return string The host, or "A peer" when the URL has none.
+ */
+ private function peerHost(string $url): string {
+ $host = parse_url($url, PHP_URL_HOST);
+ if (is_string($host) === false || $host === '') {
+ return 'A peer';
+ }
+
+ return $host;
+ }//end peerHost()
+
+ /**
+ * A reason cut to REASON_LIMIT characters.
+ *
+ * @param string $text The reason.
+ *
+ * @return string The reason, cut and trimmed.
+ */
+ private function shorten(string $text): string {
+ $text = trim($text);
+ if (mb_strlen($text) <= self::REASON_LIMIT) {
+ return $text;
+ }
+
+ return rtrim(mb_substr($text, 0, self::REASON_LIMIT)) . '...';
+ }//end shorten()
+
+ /**
+ * Build and dispatch one event, swallowing anything a listener throws.
+ *
+ * @param string $key The connection the event is about, for the log.
+ * @param callable(): object $build Builds the event.
+ *
+ * @return bool True when the event was dispatched without an exception.
+ */
+ private function send(string $key, callable $build): bool {
+ try {
+ $event = $build();
+ if (($event instanceof Event) === false) {
+ return false;
+ }
+
+ $this->eventDispatcher->dispatchTyped($event);
+ return true;
+ } catch (Throwable $e) {
+ $this->logger->warning(
+ 'Stackiq: could not send a connection event to integriq',
+ ['key' => $key, 'exception' => $e->getMessage()]
+ );
+ return false;
+ }
+ }//end send()
+}//end class
diff --git a/lib/Service/EolSyncService.php b/lib/Service/EolSyncService.php
index 7a138f9bb..8864d4fb2 100644
--- a/lib/Service/EolSyncService.php
+++ b/lib/Service/EolSyncService.php
@@ -57,12 +57,16 @@ class EolSyncService {
* @param EolMatcherService $matcher The pure matching/stamping logic.
* @param ITimeFactory $timeFactory The time factory (sync-run timestamp).
* @param LoggerInterface $logger The logger.
+ * @param ConnectionReportService|null $connectionReports Tells integriq what a save or a run met.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function __construct(
private readonly SettingsService $settingsService,
private readonly EolMatcherService $matcher,
private readonly ITimeFactory $timeFactory,
private readonly LoggerInterface $logger,
+ private readonly ?ConnectionReportService $connectionReports = null,
) {
}//end __construct()
@@ -82,12 +86,19 @@ public function getConfig(): array {
*
* @param array $data The submitted configuration fields.
*
+ * The save asks integriq to resolve the end-of-life feed connection again
+ * (adopt-connection-registry).
+ *
* @return array The persisted configuration result.
*
* @spec openspec/specs/eol-feed-integration/spec.md#requirement-products-are-mapped-to-endoflife-date-via-per-module-config
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function updateConfig(array $data): array {
- return $this->settingsService->updateEolSyncConfig($data);
+ $result = $this->settingsService->updateEolSyncConfig($data);
+ $this->connectionReports?->eolSyncConfigSaved(config: (array) ($result['config'] ?? []));
+
+ return $result;
}//end updateConfig()
/**
@@ -226,7 +237,7 @@ public function run(): array {
'skipped' => $totalSkipped,
'lastRunAt' => $fetchedAt,
];
- $this->settingsService->setEolSyncStatus($status);
+ $this->recordStatus(status: $status);
return $status;
}//end run()
@@ -476,8 +487,22 @@ private function degrade(string $reason): array {
'skipped' => 0,
'lastRunAt' => $this->timeFactory->getDateTime()->format(\DateTimeInterface::ATOM),
];
- $this->settingsService->setEolSyncStatus($status);
+ $this->recordStatus(status: $status);
return $status;
}//end degrade()
+
+ /**
+ * Record a run's status, and tell integriq what the run met.
+ *
+ * @param array{available: bool, reason: string|null, matched: int, skipped: int, lastRunAt: string|null} $status The run status.
+ *
+ * @return void
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
+ */
+ private function recordStatus(array $status): void {
+ $this->settingsService->setEolSyncStatus($status);
+ $this->connectionReports?->eolSyncRan(runStatus: $status);
+ }//end recordStatus()
}//end class
diff --git a/lib/Service/Federation/FederationService.php b/lib/Service/Federation/FederationService.php
index 2bd60c109..3bb5174b7 100644
--- a/lib/Service/Federation/FederationService.php
+++ b/lib/Service/Federation/FederationService.php
@@ -27,6 +27,7 @@
namespace OCA\Stackiq\Service\Federation;
+use OCA\Stackiq\Service\ConnectionReportService;
use OCA\Stackiq\Service\SettingsService;
use OCP\App\IAppManager;
use Psr\Container\ContainerInterface;
@@ -63,6 +64,9 @@ class FederationService {
* @param FederationMerger $merger The merge/staleness reconciler.
* @param SettingsService|null $settingsService Resolves the mirror register/schema (lazy/optional).
* @param LoggerInterface $logger Logger.
+ * @param ConnectionReportService|null $connectionReports Tells integriq what a peer change or a pull met.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function __construct(
private readonly ContainerInterface $container,
@@ -71,6 +75,7 @@ public function __construct(
private readonly FederationMerger $merger,
private readonly ?SettingsService $settingsService,
private readonly LoggerInterface $logger,
+ private readonly ?ConnectionReportService $connectionReports = null,
) {
}//end __construct()
@@ -141,9 +146,13 @@ public function getStatus(): array {
*
* @param string $peerUrl The peer base URL.
*
+ * A new peer asks integriq to resolve the federation connection again
+ * (adopt-connection-registry).
+ *
* @return array{ok:bool, reason:string} Result for the settings UI.
*
* @spec openspec/specs/federated-catalog-sync/spec.md
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function addPeer(string $peerUrl): array {
$peerUrl = trim($peerUrl);
@@ -162,6 +171,7 @@ public function addPeer(string $peerUrl): array {
$peers[] = $peerUrl;
$this->config->setPeers(array_values($peers));
+ $this->connectionReports?->federationPeersChanged(status: $this->getStatus());
return ['ok' => true, 'reason' => 'peer added'];
}//end addPeer()
@@ -170,9 +180,13 @@ public function addPeer(string $peerUrl): array {
*
* @param string $peerUrl The peer base URL.
*
+ * A removed peer asks integriq to resolve the federation connection again
+ * (adopt-connection-registry).
+ *
* @return array{ok:bool, reason:string} Result for the settings UI.
*
* @spec openspec/specs/federated-catalog-sync/spec.md
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function removePeer(string $peerUrl): array {
$peerUrl = trim($peerUrl);
@@ -184,6 +198,7 @@ public function removePeer(string $peerUrl): array {
$this->config->setPeers($filtered);
$this->config->setPeerFailures($peerUrl, 0);
+ $this->connectionReports?->federationPeersChanged(status: $this->getStatus());
return ['ok' => true, 'reason' => 'peer removed'];
}//end removePeer()
@@ -278,11 +293,29 @@ public function discoverPeers(): array {
* independently so one unreachable peer cannot block the rest. Returns a
* per-peer result summary for logging / the admin UI.
*
+ * Tells integriq what the pull met, from the Pull now button and from
+ * FederationSyncJob alike (adopt-connection-registry).
+ *
* @return array{ok:bool, reason:string, peers:array>}
*
* @spec openspec/specs/federated-catalog-sync/spec.md
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function pullAllPeers(): array {
+ $result = $this->pullEveryPeer();
+ $this->connectionReports?->federationPulled(pull: $result);
+
+ return $result;
+ }//end pullAllPeers()
+
+ /**
+ * Pull every subscribed peer, one at a time.
+ *
+ * @return array{ok:bool, reason:string, peers:array>}
+ *
+ * @spec openspec/specs/federated-catalog-sync/spec.md
+ */
+ private function pullEveryPeer(): array {
if ($this->config->isEnabled() === false) {
return ['ok' => false, 'reason' => 'federation disabled', 'peers' => []];
}
@@ -297,7 +330,7 @@ public function pullAllPeers(): array {
}
return ['ok' => true, 'reason' => 'ok', 'peers' => $results];
- }//end pullAllPeers()
+ }//end pullEveryPeer()
/**
* Pull one peer's published catalog and reconcile it into local mirrors.
diff --git a/lib/Settings/connections.json b/lib/Settings/connections.json
new file mode 100644
index 000000000..e2fcb8591
--- /dev/null
+++ b/lib/Settings/connections.json
@@ -0,0 +1,37 @@
+{
+ "app": "stackiq",
+ "connections": [
+ {
+ "key": "email",
+ "title": "Email",
+ "description": "Sends registration, activation and account mails to organisations and their users.",
+ "order": 10,
+ "settingsUrl": "/settings/admin/stackiq#section-email",
+ "adapter": {
+ "configKey": "email_transport_type",
+ "simulatedValues": ["null"],
+ "simulatedMessage": "The null transport is selected, so no mail leaves stackiq. Pick a real transport in the Email configuration section."
+ },
+ "unconfiguredMessage": "Not checked yet. Save the Email configuration section, and stackiq checks the settings."
+ },
+ {
+ "key": "federation",
+ "title": "Catalog federation",
+ "description": "Announces this catalog to directory.opencatalogi.nl and pulls published entries from peer catalogs, through OpenCatalogi.",
+ "order": 20,
+ "settingsUrl": "/settings/admin/stackiq#section-federation",
+ "reportedOnly": true,
+ "unconfiguredMessage": "Not checked yet. Choose Pull now in the Catalog federation section to check the peers."
+ },
+ {
+ "key": "eol-feed",
+ "title": "End-of-life feed",
+ "description": "Reads product cycles from endoflife.date through integriq, and stamps end-of-support dates on module versions.",
+ "order": 30,
+ "settingsUrl": "/settings/admin/stackiq#section-eol-sync",
+ "reportedOnly": true,
+ "sourceTemplate": "endoflife-date",
+ "unconfiguredMessage": "Not checked yet. Choose Sync now in the End-of-life feed sync section."
+ }
+ ]
+}
diff --git a/openspec/changes/adopt-connection-registry/.openspec.yaml b/openspec/changes/adopt-connection-registry/.openspec.yaml
new file mode 100644
index 000000000..a40cb63c1
--- /dev/null
+++ b/openspec/changes/adopt-connection-registry/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-14
diff --git a/openspec/changes/adopt-connection-registry/design.md b/openspec/changes/adopt-connection-registry/design.md
new file mode 100644
index 000000000..24231e76d
--- /dev/null
+++ b/openspec/changes/adopt-connection-registry/design.md
@@ -0,0 +1,96 @@
+# Design: adopt-connection-registry
+
+The contract is hydra `openspec/changes/connection-registry/design.md` (hydra#667, amended in hydra#673, with hydra#674 pending). This file records how stackiq meets it and where it fits loosely.
+
+## D1. Which connections are declared
+
+Each candidate was checked against the code on `development`.
+
+| Key | Declared as | Why |
+|---|---|---|
+| `email` | `adapter.configKey: email_transport_type`, `simulatedValues: ["null"]` | `SymfonyEmailService::createTransport()` builds `null://null` for `null`. |
+| `federation` | `reportedOnly: true` | `FederationService` needs OpenCatalogi installed and the boolean key `federation_enabled`. Neither is readable as a filled string. |
+| `eol-feed` | `reportedOnly: true`, `sourceTemplate: endoflife-date` | `EolSyncService::run()` reads integriq's `eol_product` and `eol_cycle` through OpenRegister. Integriq seeds the `endoflife-date` source. |
+
+**Why an empty transport is not simulated.** Stackiq reads a key that was never set with the default `smtp`. A key set to an empty or unknown value reaches the `default` branch of `createTransport()`, which builds an SMTP transport with a warning. An empty value sends real mail, so the contract default `[""]` would be a false Simulated. The file lists `null` only.
+
+**Why email has no `requiredConfig`.** Which keys a transport needs depends on the transport: a host for SMTP, an API key for SendGrid, nothing for sendmail. And `email_enabled` stores `false` as a filled string. No fixed key list can say "the settings are complete", so stackiq reports it (D2).
+
+**Why federation and eol-feed are reported only.** `federation_enabled` is typed boolean, and integriq's reader answers `typed` for it, which is a filled value. `eol_sync_config` is a JSON blob that is filled after any save, with `enabled` true or false. Rule 5 would read both as configured.
+
+**Anchors.** The admin section is `stackiq` (`StackiqAdmin::getSection()`), so each link is `/settings/admin/stackiq#section-…`. The three section components put the id on their `AlwaysVisibleSection`, whose root `NcSettingsSection` inherits it.
+
+## D2. What stackiq reports, and when
+
+`lib/Service/ConnectionReportService.php` sends both events. It names the classes by string behind `class_exists` (ADR-041) and never throws.
+
+Every save sends the refresh first and the report second. Under hydra#674 the refresh retires older observations, so a report sent before it would be retired by it.
+
+**Email, on an email settings save** (`POST /api/settings/email`, or `PUT` and `POST /api/settings` with `emailSettings`). Stackiq reads `SymfonyEmailService::isEmailSystemConfigured()`.
+
+| Stackiq sees | Status | Message |
+|---|---|---|
+| Email switched off | `unconfigured` | "Email is switched off, so stackiq sends no mail." |
+| The transport misses what it needs | `unconfigured` | "Email is on, and the SMTP Server transport misses a setting it needs." |
+| A required template is empty | `unconfigured` | "Email is on, and a required mail template is empty." |
+| Everything filled | `configured` | "Email is on and the SMTP Server transport settings are filled. No test mail was sent." |
+
+The `null` transport still reads Simulated: rule 3 sits above every report.
+
+**Federation, on a peer add or remove.** Stackiq reads `FederationService::getStatus()`.
+
+| Stackiq sees | Status | Message |
+|---|---|---|
+| OpenCatalogi not installed | `unavailable` | "Federation needs the OpenCatalogi app, and it is not installed." |
+| `federation_enabled` off | `unconfigured` | names the `occ` command |
+| No peers | `unconfigured` | "Federation is on, and no peer catalog is added yet." |
+| Ready | nothing | the refresh alone, so the row reads the declared "Not checked yet" |
+
+**Federation, after a pull** (Pull now, or `FederationSyncJob`). The same three blocking states come from the pull's `reason`. Otherwise:
+
+| Peers that answered | Status |
+|---|---|
+| all | `configured` |
+| some | `limited`, naming the first host that failed |
+| none | `error`, naming the first host that failed |
+
+A message names a peer by host only, never by its full URL, and cuts a failure reason at 160 characters.
+
+**End-of-life feed, on an EOL sync settings save.** A refresh, and `unconfigured` when `enabled` is off. Otherwise the row reads "Not checked yet" until the next run.
+
+**End-of-life feed, after a run** (Sync now, or `EolSyncJob`). `EolSyncService::run()` already records a status. The report maps its `reason`:
+
+| Reason | Status |
+|---|---|
+| none, the run completed | `configured`, with the matched and skipped counts |
+| `disabled` | `unconfigured` |
+| `openregister-not-installed` | `unavailable` |
+| `object-service-unavailable` | `error` |
+| `module-schema-not-configured` | `unconfigured` |
+| `eol-register-or-schema-not-found` | `unconfigured`, naming integriq's endoflife.date source |
+| anything else | `error`, naming the reason |
+
+**Why this is cheap.** A save and a button are admin actions. `FederationSyncJob` runs once per `federation_sync_interval` (3600 s by default), and `EolSyncJob` once per `intervalSeconds`, never below 300 s. No page request sends an event (ADR-076).
+
+**Wiring.** `FederationService`, `FederationSyncJob`'s service and `EolSyncService` are built by hand in `Application::register()`. Those factories pass the report service by name. `SettingsController` is autowired, so it takes the service as an optional last argument.
+
+## D3. The page
+
+- `src/manifest.d/connection-registry.json`: an `index` page `Integrations` at `/settings/integrations`, `requiresApp` integriq, `permission: admin`, `showAdd: false`, and the columns connection, status, status message, last checked and settings.
+- Its menu entry `IntegrationsMenu` sits in the settings gear with `query: {app: stackiq}`, `permission: admin` and `visibleIf.appInstalled: integriq`.
+- `src/services/connectionRegistry.js` holds the two formatters and `openIntegriqConnections`.
+- `App.vue` passes the formatters through CnAppRoot's `formatters` prop. It passed none before this change. `src/customComponents.js` carries the handler, because CnIndexPage resolves a header action's handler against `customComponents`.
+
+**Formatters.** The installed `@conduction/nextcloud-vue` 2.39.0 ships no `connectionStatus` built-in, so stackiq carries a local copy with all six labels, `limited` included.
+
+## D4. Contract misfits
+
+- **A boolean app-config key.** `federation_enabled` is typed boolean. Integriq's reader answers `typed` for a type conflict, which counts as filled, so a `requiredConfig` on it would read Configured while federation is off. The contract has no way to say "filled and true". `reportedOnly` works around it.
+- **A flag inside a blob.** `eol_sync_config` holds `{"enabled": false, …}`. `adapter.jsonPath` reads inside a blob, but only rule 3 uses it, and "switched off" is not "simulated". A `requiredConfig` with a JSON path would fit this row.
+- **Completeness that depends on the adapter.** Email needs different keys per transport. `requiredConfig` is one fixed list.
+- **Gate 116's vendored schema is behind integriq.** `hydra-gates/scripts/schemas/connections.schema.json` on `.github` `main` has no `jsonPath`, `simulatedValues` or `reportedOnly`, so gate 116 warns on every file that uses the hydra#673 fields. The file validates against integriq's own schema on `development`.
+
+## Risks
+
+- **Same-second ordering.** Stackiq sends the refresh before the report. If integriq stamps `refreshedAt` later than the report's `at` within one request, the report is retired. Hydra#674 compares with "not older than", so an equal stamp counts.
+- **A federation row can lag a failing peer.** Between pulls the row keeps the last outcome. `FederationSyncJob` bounds that to one sync interval.
diff --git a/openspec/changes/adopt-connection-registry/proposal.md b/openspec/changes/adopt-connection-registry/proposal.md
new file mode 100644
index 000000000..b43e66e1a
--- /dev/null
+++ b/openspec/changes/adopt-connection-registry/proposal.md
@@ -0,0 +1,45 @@
+---
+kind: code
+---
+
+# Proposal: adopt-connection-registry
+
+## Why
+
+Stackiq talks to three outside systems, and an admin can only tell whether they work by reading three settings sections and a log.
+
+- **Email.** Mail goes out through Symfony Mailer. `email_transport_type` picks smtp, sendmail, native, null, sendgrid, mailgun, postmark, ses or mailjet. On `null`, every mail is dropped without a sound.
+- **Catalog federation.** OpenCatalogi announces this catalog to directory.opencatalogi.nl and pulls entries from peer catalogs. It needs OpenCatalogi installed and `federation_enabled` on, and a peer can fail for hours before anyone notices.
+- **End-of-life feed.** Integriq ingests endoflife.date, and stackiq matches the cycles to module versions. A missing register or a switched-off sync shows only inside its own section.
+
+Hydra change `connection-registry` (hydra#667, amended in hydra#673 and hydra#674) gives every app one page of its connections, backed by integriq.
+
+## What changes
+
+- New `lib/Settings/connections.json` with three connections: `email`, `federation` and `eol-feed`.
+- `email` names `email_transport_type` as its adapter key, and only `null` reads Simulated. An empty value is not simulated: stackiq falls back to SMTP.
+- `federation` and `eol-feed` are `reportedOnly`. Only stackiq can see OpenCatalogi, `federation_enabled` (a boolean key) and the sync outcome.
+- `eol-feed` offers integriq's `endoflife-date` source as its template.
+- The three settings sections get stable ids: `section-email`, `section-federation` and `section-eol-sync`.
+- An email settings save, a peer add or remove, and an EOL sync settings save send `ConnectionRefreshRequestedEvent` for that connection, then report what stackiq can see.
+- A federation pull and an EOL sync run report their outcome. Both run on a schedule or on the admin's button, never on a page request.
+- An Integrations page under the settings gear, over integriq's `app_connection` schema, preset to `app=stackiq`, admin only, and only shown when integriq is installed.
+- Add integration opens `/apps/integriq/connections?app=stackiq&link=1`.
+- Local `connectionStatus` and `connectionSettingsLabel` formatters with all six statuses, and the strings in English and Dutch.
+
+## Depends on
+
+- hydra `openspec/changes/connection-registry`, design D2, D4, D6, D8, D9 and D12, and hydra#674 (a refresh retires older observations).
+- integriq on `development`: the `app_connection` schema, the declaration sync, both events, the Connections overview and the `endoflife-date` source.
+
+Without integriq the menu entry is hidden, a deep link shows the missing-dependency screen, and nothing is sent.
+
+## Out of scope
+
+- The stackiq register schema `connection` (softwarecatalogus). It describes a catalogue item and is unrelated to integriq's `app_connection`.
+- The email test buttons. The store posts `testEmail` and `settings`, and the controller reads `email` and `emailSettings`, so neither test reaches a real send today. A report from them would describe unsaved settings.
+- The directory announce. Its result is logged, and the row speaks for the pull.
+
+## Rollback
+
+Revert the change. Stackiq writes no rows of its own. Integriq removes the rows without a linked source on its next sync.
diff --git a/openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md b/openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md
new file mode 100644
index 000000000..7aae69757
--- /dev/null
+++ b/openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md
@@ -0,0 +1,95 @@
+# admin-integrations Specification Delta
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- [adopt-connection-registry](../../)
+
+## Purpose
+
+Admins see stackiq's outside connections on one page, with a status stackiq can back.
+
+## ADDED Requirements
+
+### Requirement: REQ-STACKIQ-CONN-001 Stackiq declares its outside connections in one static file
+
+Stackiq SHALL declare `email`, `federation` and `eol-feed` in `lib/Settings/connections.json` in the shape of hydra connection-registry design D2 (hydra REQ-CONN-001). The `email` entry SHALL name `email_transport_type` as its adapter key with `simulatedValues` holding `null` and not the empty string, because an empty transport sends mail through SMTP. The `federation` and `eol-feed` entries SHALL be `reportedOnly`. The `eol-feed` entry SHALL offer integriq's `endoflife-date` source template. Every `settingsUrl` SHALL point at a section id that exists in the admin settings page.
+
+#### Scenario: The declaration names this app and passes integriq's schema
+@e2e exclude A static file with no browser surface; tests/Unit/Settings/ConnectionsDeclarationTest.php checks the shape, the app id, unique keys and the anchors.
+
+- **GIVEN** `lib/Settings/connections.json`
+- **WHEN** it is validated against integriq's `connections.schema.json`
+- **THEN** it SHALL validate
+- **AND** its `app` SHALL equal the id in `appinfo/info.xml`
+- **AND** every key SHALL be unique
+- **AND** every `#section-…` anchor SHALL be an id in a settings section component
+
+#### Scenario: The null transport reads simulated, and an empty one does not
+@e2e tests/e2e/workflows/integrations-page.spec.ts
+
+- **GIVEN** integriq has synced stackiq's declaration
+- **WHEN** `email_transport_type` holds `null`
+- **THEN** the Email row SHALL read Simulated with the declared message
+- **AND** when `email_transport_type` is empty or `smtp`, rule 3 SHALL NOT apply
+
+### Requirement: REQ-STACKIQ-CONN-002 A save asks integriq to look again, and a run reports what it met
+
+When a save writes the settings of a declared connection, stackiq SHALL send `ConnectionRefreshRequestedEvent` with app `stackiq` and that key, and SHALL send it before any report for that key (hydra REQ-CONN-004, hydra#674). An email settings save SHALL then report what `SymfonyEmailService::isEmailSystemConfigured()` sees. A peer add or remove SHALL report OpenCatalogi missing as `unavailable`, and federation off or without peers as `unconfigured`. A federation pull SHALL report every peer answering as `configured`, some as `limited` and none as `error`. An EOL sync run SHALL report its recorded outcome. A message SHALL name a peer by host only. Both events SHALL be named by string and sent only when the class exists. Neither SHALL change the response of the request, job or run that sent it. No page request SHALL send an event.
+
+#### Scenario: Saving email settings refreshes, then reports
+@e2e exclude The event is not observable from a browser; tests/Unit/Service/ConnectionReportServiceTest.php and tests/Unit/Controller/SettingsControllerConnectionReportTest.php assert the order and the unchanged response.
+
+- **GIVEN** integriq is installed
+- **WHEN** an admin saves the email settings with email switched off
+- **THEN** stackiq SHALL send a refresh for `email`
+- **AND** then a report `unconfigured` saying email is switched off
+
+#### Scenario: A pull where some peers fail reads limited
+@e2e exclude A pull needs OpenCatalogi and reachable peers, which the CI instance does not have; tests/Unit/Service/ConnectionReportServiceTest.php drives the outcomes.
+
+- **GIVEN** federation is on with two peers
+- **WHEN** a pull reaches one peer and not the other
+- **THEN** stackiq SHALL report `federation` as `limited`
+- **AND** the message SHALL name the failing peer's host and not its path
+
+#### Scenario: An EOL run without integriq's register reads not configured
+@e2e exclude The run's outcome depends on integriq's register on the instance; tests/Unit/Service/ConnectionReportServiceTest.php asserts the report per reason, and tests/Unit/Service/ConnectionReportCallersTest.php that a run hands it over.
+
+- **GIVEN** EOL sync is switched on
+- **WHEN** a run cannot find the `eol_product` or `eol_cycle` schema
+- **THEN** stackiq SHALL report `eol-feed` as `unconfigured` with a message naming integriq's endoflife.date source
+
+#### Scenario: Without integriq nothing is sent
+@e2e exclude The CI instance installs integriq; tests/Unit/Service/ConnectionReportServiceTest.php asserts nothing is sent or logged when the class is absent.
+
+- **GIVEN** integriq is not installed
+- **WHEN** an admin saves email settings, or a pull or a sync runs
+- **THEN** no event SHALL be sent and nothing SHALL be logged
+- **AND** the save, pull or run SHALL answer as it did before this change
+
+### Requirement: REQ-STACKIQ-CONN-003 An admin reads the connections on an Integrations page
+
+Stackiq SHALL render an `index` page at `/settings/integrations` over `integriq/app_connection`, reached from the settings gear and preset to `app` equal to `stackiq` through its menu entry's `query` (hydra REQ-CONN-006). The page and its menu entry SHALL be admin only. The page SHALL require Integriq, and the menu entry SHALL only render when integriq is installed. The status column SHALL name all six statuses, `limited` included. The page SHALL NOT offer a generic Add button. Its Add integration action SHALL open `/apps/integriq/connections?app=stackiq&link=1`.
+
+#### Scenario: The page lists only the rows of stackiq
+@e2e tests/e2e/workflows/integrations-page.spec.ts
+
+- **GIVEN** stackiq and integriq are installed and integriq has synced the declaration
+- **WHEN** an admin opens the Integrations page
+- **THEN** the page SHALL list the three declared connections
+- **AND** every listed row SHALL have `app` equal to `stackiq`
+
+#### Scenario: Add integration goes to integriq
+@e2e tests/e2e/workflows/integrations-page.spec.ts
+
+- **GIVEN** the Integrations page
+- **WHEN** the admin chooses Add integration
+- **THEN** the browser SHALL open integriq's Connections overview with `app=stackiq` and `link=1`
+
+#### Scenario: A connection that works in part reads Limited
+@e2e exclude Only a federation pull with a failing peer produces limited; tests/vitest/connectionRegistry.spec.js asserts the label in English and Dutch.
+
+- **GIVEN** a row whose status is `limited`
+- **WHEN** the page renders it
+- **THEN** the cell SHALL read Limited, or Beperkt on a Dutch instance
diff --git a/openspec/changes/adopt-connection-registry/tasks.md b/openspec/changes/adopt-connection-registry/tasks.md
new file mode 100644
index 000000000..c524a3beb
--- /dev/null
+++ b/openspec/changes/adopt-connection-registry/tasks.md
@@ -0,0 +1,34 @@
+# adopt-connection-registry tasks
+
+## 1. Declare
+
+- [x] 1.1 Write `lib/Settings/connections.json` with `email`, `federation` and `eol-feed`.
+- [x] 1.2 Give the Email, Catalog federation and End-of-life feed sync sections the ids the file links to.
+- [x] 1.3 Guard the file in `tests/Unit/Settings/ConnectionsDeclarationTest.php`.
+
+## 2. Page
+
+- [x] 2.1 Add `src/manifest.d/connection-registry.json` with the page and its settings-gear menu entry.
+- [x] 2.2 Add `src/services/connectionRegistry.js` with the two formatters and the Add integration handler.
+- [x] 2.3 Wire the formatters in `src/App.vue` and the handler in `src/customComponents.js`; register `PowerPlugOutline` in `src/icons.js`.
+- [x] 2.4 Add the strings to `l10n/en` and `l10n/nl`.
+- [x] 2.5 Cover it in `tests/vitest/connectionRegistry.spec.js`.
+
+## 3. Reports and refresh
+
+- [x] 3.1 Add `lib/Service/ConnectionReportService.php`.
+- [x] 3.2 Refresh and report from the two email settings save paths in `SettingsController`.
+- [x] 3.3 Refresh and report from `FederationService` peer changes and pulls.
+- [x] 3.4 Refresh and report from `EolSyncService` config saves and runs.
+- [x] 3.5 Pass the service in the `Application` factories.
+- [x] 3.6 Add the integriq event stubs for PHPUnit, psalm and phpstan.
+- [x] 3.7 Cover it in `ConnectionReportServiceTest`, `ConnectionReportCallersTest` and `SettingsControllerConnectionReportTest`.
+
+## 4. End to end
+
+- [x] 4.1 Write `tests/e2e/workflows/integrations-page.spec.ts`.
+- [x] 4.2 Install integriq in the CI `additional-apps`.
+
+## 5. After integriq ships
+
+- [ ] 5.1 Run the e2e spec against an instance with both apps, then archive this change.
diff --git a/phpstan.neon b/phpstan.neon
index 804b28f31..f339f36a9 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -26,6 +26,10 @@ parameters:
# spellings are in the field, and without this one the analyser proves
# the newer half of the inbound guard dead.
- tests/analysis-stubs/decidiq-events.stub.php
+ # Integriq's connection-registry events (adopt-connection-registry).
+ # ConnectionReportService names them by string behind class_exists.
+ - tests/Stubs/Integriq/Event/ConnectionStatusReportedEvent.php
+ - tests/Stubs/Integriq/Event/ConnectionRefreshRequestedEvent.php
ignoreErrors:
# OrganizationSyncService's `if ($contactObject !== null)` at the top of
diff --git a/psalm.xml b/psalm.xml
index bd3c1db1f..176feef4d 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -45,6 +45,12 @@
stub already existed for PHPUnit mock generation and mirrors the real
signature in openregister/lib/Service/RegisterResolverService.php. -->
+
+
+
diff --git a/src/App.vue b/src/App.vue
index 1987ef141..c05275f09 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -22,6 +22,7 @@
:customComponents="customComponents"
:registry="registry"
:pageTypes="pageTypes"
+ :formatters="formatters"
appId="stackiq"
:translate="translateForApp"
:permissions="permissions"
@@ -75,6 +76,7 @@ import OrganisationSwitcher from './components/organisations/OrganisationSwitche
import Dialogs from './dialogs/Dialogs.vue'
import Modals from './modals/Modals.vue'
import { setActiveOrganisationUuid } from './composables/orClient.js'
+import { createConnectionFormatters } from './services/connectionRegistry.js'
import { settingsStore } from './store/store.js'
export default {
@@ -148,6 +150,15 @@ export default {
data() {
return {
+ /**
+ * Named cell formatters merged over CnAppRoot's built-ins.
+ * `connectionStatus` and `connectionSettingsLabel` render the
+ * Integrations page (adopt-connection-registry); nextcloud-vue
+ * 2.39.0 ships neither as a built-in. Before this change the app
+ * passed no formatters at all.
+ */
+ formatters: createConnectionFormatters((source) => ncT('stackiq', source)),
+
objectSidebarState: reactive({
active: false,
open: true,
diff --git a/src/customComponents.js b/src/customComponents.js
index dac0c48d3..e48c278b7 100644
--- a/src/customComponents.js
+++ b/src/customComponents.js
@@ -17,6 +17,7 @@
// - openspec/changes/stackiq-manifest-v1/design.md
// - @conduction/nextcloud-vue → docs/migrating-to-manifest.md
+import { generateUrl } from '@nextcloud/router'
import OrganisatieCard from './components/cards/OrganisatieCard.vue'
import ContractApprovalPanel from './components/contracts/ContractApprovalPanel.vue'
import OrganisationMergePanel from './components/organisations/OrganisationMergePanel.vue'
@@ -31,8 +32,19 @@ import LifecycleRoadmapView from './views/LifecycleRoadmapView.vue'
import PortfolioReportView from './views/organisaties/PortfolioReport.vue'
import StackiqSettingsPage from './views/settings/StackiqSettings.vue'
import SuitesIndexView from './views/suites/SuitesIndexView.vue'
+import { createConnectionHandlers } from './services/connectionRegistry.js'
export default {
+ // Header-action handler: the Integrations page's Add integration
+ // (adopt-connection-registry). A FUNCTION, because it leaves the app for
+ // integriq's Connections overview and a header action's `navigate` only
+ // pushes a route inside this app. CnIndexPage resolves a handler name
+ // against this map.
+ ...createConnectionHandlers({
+ generateUrl,
+ assign: (url) => window.location.assign(url),
+ }),
+
// OrganisatieCard — the bespoke card (inline contactpersoon toggle) used as
// the `cardComponent` of the now-decomposed Organisaties type='index' page
// (Phase 8). CnIndexPage's cardComponent config closed the prior lib gap.
diff --git a/src/icons.js b/src/icons.js
index f13e72b28..be09aea7a 100644
--- a/src/icons.js
+++ b/src/icons.js
@@ -53,6 +53,7 @@ import OfficeBuildingOutline from 'vue-material-design-icons/OfficeBuildingOutli
import Package from 'vue-material-design-icons/Package.vue'
import PackageVariant from 'vue-material-design-icons/PackageVariant.vue'
import PackageVariantClosed from 'vue-material-design-icons/PackageVariantClosed.vue'
+import PowerPlugOutline from 'vue-material-design-icons/PowerPlugOutline.vue'
import PuzzleOutline from 'vue-material-design-icons/PuzzleOutline.vue'
import ShieldAlert from 'vue-material-design-icons/ShieldAlert.vue'
import ShieldAlertOutline from 'vue-material-design-icons/ShieldAlertOutline.vue'
@@ -111,6 +112,7 @@ export default {
Package,
PackageVariant,
PackageVariantClosed,
+ PowerPlugOutline,
PuzzleOutline,
ShieldAlert,
ShieldAlertOutline,
diff --git a/src/manifest.d/connection-registry.json b/src/manifest.d/connection-registry.json
new file mode 100644
index 000000000..1b2f5e283
--- /dev/null
+++ b/src/manifest.d/connection-registry.json
@@ -0,0 +1,87 @@
+{
+ "$schema": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest-v2.schema.json",
+ "_note": "adopt-connection-registry (hydra connection-registry D8, hydra#667, hydra#673 and hydra#674). The rows are integriq's `app_connection` objects, synced from lib/Settings/connections.json; integriq works out each status. The app=stackiq preset is the menu entry's `query` (ADR-097 decision 5), which the index page merges into the fetch as a bare filter key. `showAdd` is false because a row nothing declared has nothing to check (D9). Add integration leaves for integriq's overview through the openIntegriqConnections handler in src/customComponents.js, because a header action's `navigate` only pushes a route inside this app. This page lists integriq's `app_connection`, never stackiq's own softwarecatalogus `connection` schema.",
+ "menu": [
+ {
+ "id": "IntegrationsMenu",
+ "label": "Integrations",
+ "icon": "PowerPlugOutline",
+ "route": "Integrations",
+ "query": {
+ "app": "stackiq"
+ },
+ "section": "settings",
+ "order": 98,
+ "permission": "admin",
+ "visibleIf": {
+ "appInstalled": "integriq"
+ }
+ }
+ ],
+ "pages": [
+ {
+ "id": "Integrations",
+ "route": "/settings/integrations",
+ "type": "index",
+ "title": "Integrations",
+ "permission": "admin",
+ "requiresApp": {
+ "id": "integriq",
+ "name": "Integriq"
+ },
+ "config": {
+ "register": "integriq",
+ "schema": "app_connection",
+ "showViewAction": false,
+ "showAdd": false,
+ "headerActions": [
+ {
+ "id": "add-integration",
+ "label": "Add integration",
+ "icon": "PowerPlugOutline",
+ "handler": "openIntegriqConnections"
+ }
+ ],
+ "defaultSort": {
+ "field": "order",
+ "direction": "asc"
+ },
+ "columns": [
+ {
+ "key": "title",
+ "label": "Connection"
+ },
+ {
+ "key": "status",
+ "label": "Status",
+ "formatter": "connectionStatus"
+ },
+ {
+ "key": "statusMessage",
+ "label": "Status message",
+ "sortable": false
+ },
+ {
+ "key": "checkedAt",
+ "label": "Last checked"
+ },
+ {
+ "key": "settingsUrl",
+ "label": "Settings",
+ "sortable": false,
+ "formatter": "connectionSettingsLabel",
+ "widget": "link",
+ "widgetProps": {
+ "href": "{settingsUrl}"
+ }
+ }
+ ],
+ "folderSidebar": {
+ "source": "field",
+ "field": "status",
+ "allLabel": "All connections"
+ }
+ }
+ }
+ ]
+}
diff --git a/src/services/connectionRegistry.js b/src/services/connectionRegistry.js
new file mode 100644
index 000000000..6a881ba7e
--- /dev/null
+++ b/src/services/connectionRegistry.js
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: EUPL-1.2
+// Copyright (C) 2026 Conduction B.V.
+
+/**
+ * The Integrations page's two formatters and its Add integration handler.
+ *
+ * The rows on that page are integriq's `app_connection` objects (hydra change
+ * connection-registry, design D8). The installed @conduction/nextcloud-vue
+ * 2.39.0 ships neither formatter, so stackiq carries this copy until a
+ * release with the built-ins is pinned. The names are the contract's, so the
+ * copies across the fleet stay interchangeable.
+ *
+ * Pure: the translator, the URL builder and the navigation are passed in, so
+ * the module runs under vitest's node environment with nothing mocked.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
+ */
+
+/**
+ * Where Add integration lands: integriq's Connections overview, preset to this
+ * app and opening the link-a-source dialog (hydra connection-registry D9).
+ */
+export const INTEGRIQ_CONNECTIONS_PATH = '/apps/integriq/connections?app=stackiq&link=1'
+
+/**
+ * The English label for each of the six registry statuses (design D3).
+ *
+ * `limited` came with hydra#673: the connection works in part.
+ */
+export const CONNECTION_STATUS_LABELS = Object.freeze({
+ configured: 'Configured',
+ limited: 'Limited',
+ unconfigured: 'Not configured',
+ simulated: 'Simulated',
+ unavailable: 'Not available',
+ error: 'Error',
+})
+
+/**
+ * Build the two connection formatters around a translator.
+ *
+ * @param {function(string): string} translate Translates an English source string for this app.
+ * @return {{connectionStatus: function(unknown): string, connectionSettingsLabel: function(unknown): string}} The formatters, keyed by their manifest names.
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
+ */
+export function createConnectionFormatters(translate) {
+ return {
+ /**
+ * The label for a status. An unknown value renders itself, because a
+ * status the app cannot name is still a status the admin should see.
+ *
+ * @param {unknown} value The row's `status`.
+ * @return {string} The label, the raw value, or '' when missing.
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
+ */
+ connectionStatus(value) {
+ const source = typeof value === 'string' && Object.hasOwn(CONNECTION_STATUS_LABELS, value)
+ ? CONNECTION_STATUS_LABELS[value]
+ : null
+ return source ? translate(source) : String(value ?? '')
+ },
+
+ /**
+ * The Open settings link text, or '' when the row has nowhere to send a
+ * reader. An empty text makes the link cell fall through to plain text.
+ *
+ * @param {unknown} value The row's `settingsUrl`.
+ * @return {string} The link text, or ''.
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
+ */
+ connectionSettingsLabel(value) {
+ return typeof value === 'string' && value.length > 0 ? translate('Open settings') : ''
+ },
+ }
+}
+
+/**
+ * Build the Add integration header-action handler.
+ *
+ * A FUNCTION handler because a header action's `navigate` keyword only pushes
+ * a route inside this app's router, which cannot leave the app.
+ *
+ * @param {{generateUrl: function(string): string, assign: function(string): void}} deps Builds the instance URL and navigates to it.
+ * @return {{openIntegriqConnections: function(): void}} The handler, keyed by its manifest name.
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
+ */
+export function createConnectionHandlers({ generateUrl, assign }) {
+ return {
+ /**
+ * Open integriq's Connections overview on the link-a-source dialog.
+ *
+ * @return {void}
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
+ */
+ openIntegriqConnections() {
+ assign(generateUrl(INTEGRIQ_CONNECTIONS_PATH))
+ },
+ }
+}
diff --git a/src/views/settings/sections/EmailConfiguration.vue b/src/views/settings/sections/EmailConfiguration.vue
index 61e255b9e..4ac71bb1a 100644
--- a/src/views/settings/sections/EmailConfiguration.vue
+++ b/src/views/settings/sections/EmailConfiguration.vue
@@ -18,6 +18,7 @@
+ */
+ private function sentSummary(): array {
+ return array_map(
+ static function (Event $event): string {
+ if ($event instanceof ConnectionStatusReportedEvent) {
+ return 'report:' . $event->key . ':' . $event->status;
+ }
+
+ if ($event instanceof ConnectionRefreshRequestedEvent) {
+ return 'refresh:' . $event->key;
+ }
+
+ return get_class($event);
+ },
+ $this->sent
+ );
+ }//end sentSummary()
+
+ /**
+ * An email save refreshes first and reports second, as stackiq, for the email key.
+ *
+ * Under hydra#674 a refresh retires every older observation, so the other
+ * order would have integriq throw the report away.
+ *
+ * @return void
+ */
+ public function testAnEmailSaveRefreshesBeforeItReports(): void {
+ $this->emailService->method('isEmailSystemConfigured')->willReturn(
+ ['configured' => false, 'reason' => 'Email notifications are disabled', 'hasCredentials' => false, 'hasTemplates' => false]
+ );
+
+ $this->assertTrue(condition: $this->service()->emailSettingsSaved());
+
+ $this->assertSame(expected: ['refresh:email', 'report:email:unconfigured'], actual: $this->sentSummary());
+ $this->assertSame(expected: 'stackiq', actual: $this->sent[0]->app);
+ $this->assertSame(expected: 'stackiq', actual: $this->sent[1]->app);
+ $this->assertSame(expected: 'Email is switched off, so stackiq sends no mail.', actual: $this->sent[1]->message);
+ }//end testAnEmailSaveRefreshesBeforeItReports()
+
+ /**
+ * Each email configuration state maps to the status the design names.
+ *
+ * @return void
+ */
+ public function testEachEmailStateMapsToTheDesignedStatus(): void {
+ $service = $this->service();
+
+ $this->assertSame(
+ expected: ['unconfigured', 'Email is on, and the SendGrid transport misses a setting it needs.'],
+ actual: $service->describeEmail(
+ configStatus: ['configured' => false, 'hasCredentials' => false, 'hasTemplates' => true, 'transportType' => 'sendgrid'],
+ transportLabels: self::TRANSPORTS
+ )
+ );
+ $this->assertSame(
+ expected: ['unconfigured', 'Email is on, and a required mail template is empty.'],
+ actual: $service->describeEmail(
+ configStatus: ['configured' => false, 'hasCredentials' => true, 'hasTemplates' => false, 'transportType' => 'smtp'],
+ transportLabels: self::TRANSPORTS
+ )
+ );
+ $this->assertSame(
+ expected: ['configured', 'Email is on and the SMTP Server transport settings are filled. No test mail was sent.'],
+ actual: $service->describeEmail(
+ configStatus: ['configured' => true, 'hasCredentials' => true, 'hasTemplates' => true, 'transportType' => 'smtp'],
+ transportLabels: self::TRANSPORTS
+ )
+ );
+ }//end testEachEmailStateMapsToTheDesignedStatus()
+
+ /**
+ * An email service that throws still refreshes, reports nothing, and never escapes.
+ *
+ * @return void
+ */
+ public function testAFailingEmailReadNeverEscapes(): void {
+ $this->emailService->method('isEmailSystemConfigured')->willThrowException(new RuntimeException('config broken'));
+ $this->logger->expects($this->once())->method('warning')
+ ->with($this->stringContains(string: 'could not read the email settings'), $this->arrayHasKey(key: 'exception'));
+
+ $this->assertFalse(condition: $this->service()->emailSettingsSaved());
+ $this->assertSame(expected: ['refresh:email'], actual: $this->sentSummary());
+ }//end testAFailingEmailReadNeverEscapes()
+
+ /**
+ * A peer change refreshes, and reports only a state that blocks federation.
+ *
+ * @return void
+ */
+ public function testAPeerChangeReportsOnlyABlockingState(): void {
+ $service = $this->service();
+
+ $service->federationPeersChanged(status: ['available' => false, 'enabled' => true, 'peers' => [['url' => 'https://a.example']]]);
+ $service->federationPeersChanged(status: ['available' => true, 'enabled' => false, 'peers' => [['url' => 'https://a.example']]]);
+ $service->federationPeersChanged(status: ['available' => true, 'enabled' => true, 'peers' => []]);
+ $this->assertFalse(
+ condition: $service->federationPeersChanged(status: ['available' => true, 'enabled' => true, 'peers' => [['url' => 'https://a.example']]])
+ );
+
+ $this->assertSame(
+ expected: [
+ 'refresh:federation',
+ 'report:federation:unavailable',
+ 'refresh:federation',
+ 'report:federation:unconfigured',
+ 'refresh:federation',
+ 'report:federation:unconfigured',
+ 'refresh:federation',
+ ],
+ actual: $this->sentSummary()
+ );
+ $this->assertStringContainsString(needle: 'OpenCatalogi', haystack: $this->sent[1]->message);
+ $this->assertStringContainsString(needle: 'federation_enabled', haystack: $this->sent[3]->message);
+ $this->assertStringContainsString(needle: 'no peer catalog', haystack: $this->sent[5]->message);
+ }//end testAPeerChangeReportsOnlyABlockingState()
+
+ /**
+ * A pull where every peer answered reads configured, and a pull that was blocked says why.
+ *
+ * @return void
+ */
+ public function testAPullMapsItsOutcome(): void {
+ $service = $this->service();
+ $ok = ['ok' => true, 'reason' => 'pulled'];
+
+ $this->assertSame(
+ expected: ['configured', 'All 2 peer catalogs answered the last pull.'],
+ actual: $service->describePull(pull: ['ok' => true, 'peers' => [['peer' => 'https://a.example'] + $ok, ['peer' => 'https://b.example'] + $ok]])
+ );
+ $this->assertSame(
+ expected: ['configured', 'The peer catalog answered the last pull.'],
+ actual: $service->describePull(pull: ['ok' => true, 'peers' => [['peer' => 'https://a.example'] + $ok]])
+ );
+ $this->assertSame(expected: 'unconfigured', actual: $service->describePull(pull: ['ok' => true, 'peers' => []])[0]);
+ $this->assertSame(expected: 'unconfigured', actual: $service->describePull(pull: ['ok' => false, 'reason' => 'federation disabled'])[0]);
+ $this->assertSame(expected: 'unavailable', actual: $service->describePull(pull: ['ok' => false, 'reason' => 'OpenCatalogi unavailable'])[0]);
+ $this->assertSame(
+ expected: ['error', 'The last federation pull failed: something else'],
+ actual: $service->describePull(pull: ['ok' => false, 'reason' => 'something else'])
+ );
+ }//end testAPullMapsItsOutcome()
+
+ /**
+ * A pull where some peers fail reads limited, and where all fail reads error.
+ *
+ * Neither may borrow configured: a failing peer is exactly what the row is for.
+ *
+ * @return void
+ */
+ public function testAPullWithFailingPeersIsNeverConfigured(): void {
+ $service = $this->service();
+ $good = ['peer' => 'https://good.example/catalog', 'ok' => true, 'reason' => 'pulled'];
+ $bad = ['peer' => 'https://bad.example/catalog', 'ok' => false, 'reason' => 'Connection refused'];
+
+ $this->assertSame(
+ expected: ['limited', '1 of 2 peer catalogs answered the last pull. bad.example did not: Connection refused'],
+ actual: $service->describePull(pull: ['ok' => true, 'peers' => [$good, $bad]])
+ );
+ $this->assertSame(
+ expected: ['error', 'No peer catalog answered the last pull. bad.example did not: Connection refused'],
+ actual: $service->describePull(pull: ['ok' => true, 'peers' => [$bad]])
+ );
+ }//end testAPullWithFailingPeersIsNeverConfigured()
+
+ /**
+ * A message names a peer by host, never by path, query or credentials, and cuts a long reason.
+ *
+ * Every admin reads the row, and a peer URL can carry a token.
+ *
+ * @return void
+ */
+ public function testAPullMessageCarriesOnlyTheHostAndAShortReason(): void {
+ $peer = [
+ 'peer' => 'https://user:s3cret@peer.gemeente.example/api/catalog?token=abc',
+ 'ok' => false,
+ 'reason' => str_repeat('x', 400),
+ ];
+
+ $message = $this->service()->describePull(pull: ['ok' => true, 'peers' => [$peer]])[1];
+
+ $this->assertStringContainsString(needle: 'peer.gemeente.example did not', haystack: $message);
+ foreach (['s3cret', 'user', 'token', 'abc', '/api'] as $leak) {
+ $this->assertStringNotContainsString(needle: $leak, haystack: $message);
+ }
+
+ $this->assertStringContainsString(needle: str_repeat('x', ConnectionReportService::REASON_LIMIT) . '...', haystack: $message);
+ $this->assertStringNotContainsString(needle: str_repeat('x', ConnectionReportService::REASON_LIMIT + 1), haystack: $message);
+ }//end testAPullMessageCarriesOnlyTheHostAndAShortReason()
+
+ /**
+ * A pull reports without a refresh: it changes no settings.
+ *
+ * @return void
+ */
+ public function testAPullReportsWithoutARefresh(): void {
+ $this->assertTrue(condition: $this->service()->federationPulled(pull: ['ok' => false, 'reason' => 'federation disabled']));
+ $this->assertSame(expected: ['report:federation:unconfigured'], actual: $this->sentSummary());
+ }//end testAPullReportsWithoutARefresh()
+
+ /**
+ * An EOL settings save refreshes, and reports only a switched-off sync.
+ *
+ * @return void
+ */
+ public function testAnEolSaveReportsOnlyASwitchedOffSync(): void {
+ $service = $this->service();
+
+ $this->assertTrue(condition: $service->eolSyncConfigSaved(config: ['enabled' => false]));
+ $this->assertFalse(condition: $service->eolSyncConfigSaved(config: ['enabled' => true]));
+
+ $this->assertSame(expected: ['refresh:eol-feed', 'report:eol-feed:unconfigured', 'refresh:eol-feed'], actual: $this->sentSummary());
+ }//end testAnEolSaveReportsOnlyASwitchedOffSync()
+
+ /**
+ * Every reason EolSyncService records maps to a status, and an unknown one reads error.
+ *
+ * @return void
+ */
+ public function testEachEolRunOutcomeMapsToTheDesignedStatus(): void {
+ $service = $this->service();
+ $expected = [
+ 'disabled' => 'unconfigured',
+ 'openregister-not-installed' => 'unavailable',
+ 'object-service-unavailable' => 'error',
+ 'module-schema-not-configured' => 'unconfigured',
+ 'eol-register-or-schema-not-found' => 'unconfigured',
+ ];
+
+ foreach ($expected as $reason => $status) {
+ $this->assertSame(
+ expected: $status,
+ actual: $service->describeEolRun(runStatus: ['available' => false, 'reason' => $reason])[0],
+ message: $reason
+ );
+ }
+
+ $this->assertStringContainsString(
+ needle: 'endoflife.date source in integriq',
+ haystack: $service->describeEolRun(runStatus: ['available' => false, 'reason' => 'eol-register-or-schema-not-found'])[1]
+ );
+ $this->assertSame(
+ expected: ['configured', 'The last sync stamped 4 module versions and skipped 2.'],
+ actual: $service->describeEolRun(runStatus: ['available' => true, 'reason' => null, 'matched' => 4, 'skipped' => 2])
+ );
+ $this->assertSame(
+ expected: ['error', 'The last end-of-life sync stopped: something-new'],
+ actual: $service->describeEolRun(runStatus: ['available' => false, 'reason' => 'something-new'])
+ );
+ }//end testEachEolRunOutcomeMapsToTheDesignedStatus()
+
+ /**
+ * The EOL reasons the report knows are exactly the ones EolSyncService records.
+ *
+ * A reason added to the service and not here would read as a bare error.
+ *
+ * @return void
+ */
+ public function testTheEolReasonsAreTheOnesTheSyncRecords(): void {
+ $source = (string) file_get_contents(dirname(__DIR__, 3) . '/lib/Service/EolSyncService.php');
+ preg_match_all('/degrade\(reason: \'([a-z-]+)\'\)/', $source, $matches);
+
+ $recorded = array_values(array_unique($matches[1]));
+ sort($recorded);
+ $known = array_keys(ConnectionReportService::EOL_REASONS);
+ sort($known);
+
+ $this->assertNotSame(expected: [], actual: $recorded);
+ $this->assertSame(expected: $recorded, actual: $known);
+ }//end testTheEolReasonsAreTheOnesTheSyncRecords()
+
+ /**
+ * Without integriq nothing is sent and nothing is logged.
+ *
+ * @return void
+ */
+ public function testWithoutIntegriqNothingIsSentOrLogged(): void {
+ $this->dispatcher->expects($this->never())->method('dispatchTyped');
+ $this->logger->expects($this->never())->method('warning');
+ $this->emailService->expects($this->never())->method('isEmailSystemConfigured');
+
+ $service = $this->serviceWithoutIntegriq();
+
+ $this->assertFalse(condition: $service->emailSettingsSaved());
+ $this->assertFalse(condition: $service->federationPeersChanged(status: ['available' => false]));
+ $this->assertFalse(condition: $service->federationPulled(pull: ['ok' => false, 'reason' => 'federation disabled']));
+ $this->assertFalse(condition: $service->eolSyncConfigSaved(config: ['enabled' => false]));
+ $this->assertFalse(condition: $service->eolSyncRan(runStatus: ['available' => false, 'reason' => 'disabled']));
+ }//end testWithoutIntegriqNothingIsSentOrLogged()
+
+ /**
+ * The class lookup answers null for a class nobody ships, and the class for a stub.
+ *
+ * This is the real guard, not the test double above.
+ *
+ * @return void
+ */
+ public function testTheLookupAnswersNullForAnAbsentClass(): void {
+ $method = new ReflectionMethod(ConnectionReportService::class, 'resolveEventClass');
+ $service = $this->service();
+
+ $this->assertNull(actual: $method->invoke($service, 'OCA\\Nobody\\Event\\ShipsThisEvent'));
+ $this->assertSame(
+ expected: '\\' . ConnectionReportService::STATUS_EVENT,
+ actual: $method->invoke($service, ConnectionReportService::STATUS_EVENT)
+ );
+ }//end testTheLookupAnswersNullForAnAbsentClass()
+
+ /**
+ * The event names are the ones integriq ships.
+ *
+ * A string class name is exactly the reference that rots into a silent
+ * no-op after a rename, so it is compared to the stubs' real names.
+ *
+ * @return void
+ */
+ public function testTheEventNamesAreTheContractNames(): void {
+ $this->assertSame(expected: ConnectionStatusReportedEvent::class, actual: ConnectionReportService::STATUS_EVENT);
+ $this->assertSame(expected: ConnectionRefreshRequestedEvent::class, actual: ConnectionReportService::REFRESH_EVENT);
+ }//end testTheEventNamesAreTheContractNames()
+
+ /**
+ * A listener that throws never escapes into the save, pull or run.
+ *
+ * @return void
+ */
+ public function testAThrowingListenerNeverEscapes(): void {
+ $dispatcher = $this->createMock(originalClassName: IEventDispatcher::class);
+ $dispatcher->method('dispatchTyped')->willThrowException(new RuntimeException('registry down'));
+ $this->logger->expects($this->exactly(count: 2))->method('warning')
+ ->with($this->stringContains(string: 'could not send'), $this->arrayHasKey(key: 'key'));
+
+ $service = new ConnectionReportService(eventDispatcher: $dispatcher, emailService: $this->emailService, logger: $this->logger);
+
+ $this->assertFalse(condition: $service->eolSyncRan(runStatus: ['available' => false, 'reason' => 'disabled']));
+ $this->assertFalse(condition: $service->eolSyncConfigSaved(config: ['enabled' => true]));
+ }//end testAThrowingListenerNeverEscapes()
+}//end class
diff --git a/tests/Unit/Settings/ConnectionsDeclarationTest.php b/tests/Unit/Settings/ConnectionsDeclarationTest.php
new file mode 100644
index 000000000..e532de97d
--- /dev/null
+++ b/tests/Unit/Settings/ConnectionsDeclarationTest.php
@@ -0,0 +1,355 @@
+
+ * @copyright 2026 Conduction B.V.
+ * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * @link https://conduction.nl
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-001-stackiq-declares-its-outside-connections-in-one-static-file
+ *
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
+ * SPDX-License-Identifier: EUPL-1.2
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Stackiq\Tests\Unit\Settings;
+
+use OCA\Stackiq\Service\ConnectionReportService;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Guards lib/Settings/connections.json against design D2 of connection-registry.
+ *
+ * The rules mirror integriq's `lib/Settings/connections.schema.json` on
+ * `development` field for field, including the hydra#673 amendments
+ * (`adapter.jsonPath`, `adapter.simulatedValues`, `reportedOnly`). That schema
+ * is not a dependency of this repo, so the rules are restated here. The file
+ * was also validated against the schema itself, fetched from integriq
+ * `development` with `gh api`, when this test was written.
+ *
+ * @coversNothing
+ */
+class ConnectionsDeclarationTest extends TestCase {
+
+ /**
+ * The fields the schema allows on one connection, with their JSON type.
+ *
+ * @var array
+ */
+ private const FIELD_TYPES = [
+ 'key' => 'string',
+ 'title' => 'string',
+ 'description' => 'string',
+ 'order' => 'integer',
+ 'settingsUrl' => 'string',
+ 'requiredConfig' => 'array',
+ 'adapter' => 'array',
+ 'reportedOnly' => 'boolean',
+ 'available' => 'boolean',
+ 'unavailableMessage' => 'string',
+ 'unconfiguredMessage' => 'string',
+ 'sourceTemplate' => 'string',
+ ];
+
+ /**
+ * The fields the schema allows inside `adapter`, with their JSON type.
+ *
+ * @var array
+ */
+ private const ADAPTER_FIELD_TYPES = [
+ 'configKey' => 'string',
+ 'jsonPath' => 'string',
+ 'simulatedValues' => 'array',
+ 'simulatedMessage' => 'string',
+ ];
+
+ /**
+ * The three connections, in page order.
+ *
+ * @var array
+ */
+ private const KEYS = ['email', 'federation', 'eol-feed'];
+
+ /**
+ * The repository root.
+ *
+ * @return string
+ */
+ private function root(): string {
+ return dirname(__DIR__, 3);
+ }//end root()
+
+ /**
+ * The raw declaration file.
+ *
+ * @return string
+ */
+ private function raw(): string {
+ $raw = file_get_contents($this->root() . '/lib/Settings/connections.json');
+ $this->assertIsString(actual: $raw, message: 'lib/Settings/connections.json must exist');
+
+ return $raw;
+ }//end raw()
+
+ /**
+ * The decoded declaration.
+ *
+ * @return array
+ */
+ private function declaration(): array {
+ $decoded = json_decode($this->raw(), true, 512, JSON_THROW_ON_ERROR);
+ $this->assertIsArray(actual: $decoded);
+
+ return $decoded;
+ }//end declaration()
+
+ /**
+ * The declared connections, keyed by connection key.
+ *
+ * @return array>
+ */
+ private function connectionsByKey(): array {
+ $byKey = [];
+ foreach ($this->declaration()['connections'] as $connection) {
+ $byKey[(string) $connection['key']] = $connection;
+ }
+
+ return $byKey;
+ }//end connectionsByKey()
+
+ /**
+ * The file names the app it ships in, and nothing else at the top level.
+ *
+ * Integriq refuses a file whose `app` differs from the app it was read from.
+ *
+ * @return void
+ */
+ public function testTheFileNamesThisApp(): void {
+ $declaration = $this->declaration();
+ $infoXml = simplexml_load_file($this->root() . '/appinfo/info.xml');
+
+ $this->assertNotFalse(condition: $infoXml);
+ $this->assertSame(expected: (string) $infoXml->id, actual: $declaration['app']);
+ $this->assertSame(expected: 'stackiq', actual: $declaration['app']);
+ $this->assertSame(expected: ['app', 'connections'], actual: array_keys($declaration));
+ }//end testTheFileNamesThisApp()
+
+ /**
+ * Every key is unique, well formed, and the one the report service sends.
+ *
+ * A row is keyed by app and key. A report for a key the file does not
+ * declare is refused by integriq with only a warning in its log.
+ *
+ * @return void
+ */
+ public function testTheKeysAreUniqueAndTheReportedOnes(): void {
+ $keys = array_column($this->declaration()['connections'], 'key');
+
+ $this->assertSame(expected: array_values(array_unique($keys)), actual: $keys);
+ $this->assertSame(expected: self::KEYS, actual: $keys);
+ $this->assertSame(
+ expected: self::KEYS,
+ actual: [ConnectionReportService::KEY_EMAIL, ConnectionReportService::KEY_FEDERATION, ConnectionReportService::KEY_EOL]
+ );
+ }//end testTheKeysAreUniqueAndTheReportedOnes()
+
+ /**
+ * Every entry uses only schema fields with the schema's types, and a rising order.
+ *
+ * @return void
+ */
+ public function testEveryEntryHasTheShapeIntegriqValidates(): void {
+ $previousOrder = 0;
+ foreach ($this->declaration()['connections'] as $connection) {
+ $key = (string) $connection['key'];
+
+ $this->assertSame(
+ expected: [],
+ actual: array_diff(array_keys($connection), array_keys(self::FIELD_TYPES)),
+ message: $key . ' carries a field the schema does not allow'
+ );
+ foreach ($connection as $field => $value) {
+ $this->assertSame(expected: self::FIELD_TYPES[$field], actual: $this->jsonType(value: $value), message: $key . '.' . $field);
+ }
+
+ foreach (($connection['adapter'] ?? []) as $field => $value) {
+ $this->assertArrayHasKey(key: $field, array: self::ADAPTER_FIELD_TYPES, message: $key . '.adapter.' . $field . ' is not a schema field');
+ $this->assertSame(expected: self::ADAPTER_FIELD_TYPES[$field], actual: $this->jsonType(value: $value), message: $key . '.adapter.' . $field);
+ }
+
+ $this->assertMatchesRegularExpression(pattern: '/^[a-z0-9]+(-[a-z0-9]+)*$/', string: $key);
+ $this->assertNotSame(expected: '', actual: trim((string) ($connection['title'] ?? '')), message: $key . ' has no title');
+ $this->assertStringStartsWith(prefix: '/', string: (string) ($connection['settingsUrl'] ?? '/'), message: $key);
+ $this->assertGreaterThan(expected: $previousOrder, actual: $connection['order'], message: $key . ' breaks the page order');
+ $previousOrder = $connection['order'];
+ }
+ }//end testEveryEntryHasTheShapeIntegriqValidates()
+
+ /**
+ * No text a reader sees carries an em-dash or a Title Case title (voice rule 8).
+ *
+ * @return void
+ */
+ public function testNoTextBreaksTheVoiceRules(): void {
+ $this->assertStringNotContainsString(needle: "\u{2014}", haystack: $this->raw());
+ $this->assertStringNotContainsString(needle: '--', haystack: $this->raw());
+
+ foreach ($this->declaration()['connections'] as $connection) {
+ $words = explode(' ', (string) $connection['title']);
+ foreach (array_slice($words, 1) as $word) {
+ $this->assertSame(expected: mb_strtolower($word), actual: $word, message: $connection['key'] . ' title is not sentence case');
+ }
+ }
+ }//end testNoTextBreaksTheVoiceRules()
+
+ /**
+ * Every settings link points at the stackiq admin section, at an id a section component defines.
+ *
+ * The admin section is `stackiq` (StackiqAdmin::getSection()). An anchor
+ * that no element carries opens the settings page at the top.
+ *
+ * @return void
+ */
+ public function testEverySettingsLinkPointsAtASectionThatExists(): void {
+ $sections = '';
+ foreach (glob($this->root() . '/src/views/settings/sections/*.vue') as $file) {
+ $sections .= (string) file_get_contents($file);
+ }
+
+ $admin = (string) file_get_contents($this->root() . '/lib/Settings/StackiqAdmin.php');
+ $this->assertStringContainsString(needle: "\$sectionName = 'stackiq';", haystack: $admin);
+
+ foreach ($this->declaration()['connections'] as $connection) {
+ $url = (string) ($connection['settingsUrl'] ?? '');
+ $this->assertMatchesRegularExpression(
+ pattern: '~^/settings/admin/stackiq#section-[a-z0-9-]+$~',
+ string: $url,
+ message: $connection['key'] . ' links somewhere other than a stackiq admin section'
+ );
+
+ $anchor = substr($url, (strpos($url, '#') + 1));
+ $this->assertSame(
+ expected: 1,
+ actual: substr_count($sections, 'id="' . $anchor . '"'),
+ message: $connection['key'] . ' links to #' . $anchor . ', and no section component carries that id once'
+ );
+ }
+ }//end testEverySettingsLinkPointsAtASectionThatExists()
+
+ /**
+ * The null transport reads simulated, and an empty or real transport does not.
+ *
+ * This applies the declared values the way integriq's ConnectionConfigReader
+ * does: trimmed, case-insensitive, against `simulatedValues`, which default
+ * to one empty string when absent. An empty `email_transport_type` sends
+ * mail through SMTP (SymfonyEmailService::createTransport()), so reading it
+ * as simulated would be a false Simulated.
+ *
+ * @return void
+ */
+ public function testOnlyTheNullTransportReadsSimulated(): void {
+ $adapter = $this->connectionsByKey()['email']['adapter'];
+
+ $this->assertSame(expected: 'email_transport_type', actual: $adapter['configKey']);
+ $this->assertArrayNotHasKey(key: 'jsonPath', array: $adapter);
+ $this->assertTrue(condition: $this->readsSimulated(adapter: $adapter, value: 'null'));
+ $this->assertTrue(condition: $this->readsSimulated(adapter: $adapter, value: ' NULL '));
+ foreach (['', 'smtp', 'sendmail', 'native', 'sendgrid', 'mailgun', 'postmark', 'ses', 'mailjet'] as $real) {
+ $this->assertFalse(condition: $this->readsSimulated(adapter: $adapter, value: $real), message: '"' . $real . '" must not read simulated');
+ }
+
+ $emailService = (string) file_get_contents($this->root() . '/lib/Service/SymfonyEmailService.php');
+ $this->assertStringContainsString(needle: "'null' => 'Null (No Emails)'", haystack: $emailService);
+ $this->assertMatchesRegularExpression(pattern: "/case 'null':\s+return Transport::fromDsn\('null:\/\/null'\);/", string: $emailService);
+ $this->assertMatchesRegularExpression(pattern: '/default:.*?return \$this->createSmtpTransport/s', string: $emailService);
+ }//end testOnlyTheNullTransportReadsSimulated()
+
+ /**
+ * Federation and the end-of-life feed are reported only, and neither guesses from settings.
+ *
+ * `federation_enabled` is a boolean key, which integriq's reader counts as
+ * filled whatever it holds, and `eol_sync_config` is filled after any save.
+ *
+ * @return void
+ */
+ public function testFederationAndTheFeedAreReportedOnly(): void {
+ $byKey = $this->connectionsByKey();
+
+ foreach (['federation', 'eol-feed'] as $key) {
+ $this->assertTrue(condition: $byKey[$key]['reportedOnly'], message: $key);
+ $this->assertArrayNotHasKey(key: 'requiredConfig', array: $byKey[$key], message: $key);
+ $this->assertArrayNotHasKey(key: 'adapter', array: $byKey[$key], message: $key);
+ $this->assertStringStartsWith(prefix: 'Not checked yet.', string: $byKey[$key]['unconfiguredMessage'], message: $key);
+ }
+
+ $this->assertArrayNotHasKey(key: 'reportedOnly', array: $byKey['email']);
+ $this->assertArrayNotHasKey(key: 'requiredConfig', array: $byKey['email']);
+ }//end testFederationAndTheFeedAreReportedOnly()
+
+ /**
+ * The end-of-life feed offers integriq's endoflife.date source.
+ *
+ * The slug is the one integriq seeds in
+ * `lib/Settings/register.d/endoflife-date-source.json`, and the defaults
+ * stackiq reads the feed from are integriq's register and schemas.
+ *
+ * @return void
+ */
+ public function testTheFeedOffersTheEndoflifeDateSource(): void {
+ $this->assertSame(expected: 'endoflife-date', actual: $this->connectionsByKey()['eol-feed']['sourceTemplate']);
+
+ $settings = (string) file_get_contents($this->root() . '/lib/Service/SettingsService.php');
+ $this->assertStringContainsString(needle: "EOL_DEFAULT_REGISTER = 'integriq'", haystack: $settings);
+ }//end testTheFeedOffersTheEndoflifeDateSource()
+
+ /**
+ * Whether integriq's rule 3 reads a value as simulated for this adapter.
+ *
+ * @param array $adapter The declared adapter block.
+ * @param string $value The app-config value.
+ *
+ * @return bool
+ */
+ private function readsSimulated(array $adapter, string $value): bool {
+ $values = ($adapter['simulatedValues'] ?? ['']);
+ $needle = mb_strtolower(trim($value));
+ foreach ($values as $candidate) {
+ if (mb_strtolower(trim((string) $candidate)) === $needle) {
+ return true;
+ }
+ }
+
+ return false;
+ }//end readsSimulated()
+
+ /**
+ * The JSON type name of a decoded value.
+ *
+ * @param mixed $value The decoded value.
+ *
+ * @return string
+ */
+ private function jsonType(mixed $value): string {
+ return match (true) {
+ is_bool($value) => 'boolean',
+ is_int($value) => 'integer',
+ is_string($value) => 'string',
+ is_array($value) => 'array',
+ default => get_debug_type($value),
+ };
+ }//end jsonType()
+}//end class
diff --git a/tests/bootstrap-unit.php b/tests/bootstrap-unit.php
index 79ba57ce8..97084ee81 100644
--- a/tests/bootstrap-unit.php
+++ b/tests/bootstrap-unit.php
@@ -73,3 +73,18 @@
break;
}//end foreach
});
+
+// Integriq's connection-registry events (adopt-connection-registry).
+// ConnectionReportService sends them by string class name behind class_exists
+// (ADR-041), so stackiq stays installable without integriq. The stubs mirror
+// hydra connection-registry design D6 and integriq's own classes, and load only
+// when the real classes are absent. They sit two directories deep on purpose:
+// the tests/Stubs glob in tests/bootstrap.php loads one level and would shadow
+// a real integriq before Nextcloud boots.
+foreach (['ConnectionStatusReportedEvent', 'ConnectionRefreshRequestedEvent'] as $integriqStubEvent) {
+ if (class_exists('\\OCA\\Integriq\\Event\\' . $integriqStubEvent) === false) {
+ require_once __DIR__ . '/Stubs/Integriq/Event/' . $integriqStubEvent . '.php';
+ }
+}
+
+unset($integriqStubEvent);
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 7abea96c4..09bd3bc33 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -170,3 +170,22 @@ function stackiq_nc_root_is_installed(string $ncRoot): bool
unset($stackiqNcRoot);
}
+
+// Integriq's connection-registry events (adopt-connection-registry).
+// ConnectionReportService sends them by string class name behind class_exists
+// (ADR-041), so stackiq stays installable without integriq. The stubs mirror
+// hydra connection-registry design D6 and integriq's own classes, and load only
+// when the real classes are absent. They sit two directories deep on purpose:
+// the tests/Stubs glob in tests/bootstrap.php loads one level and would shadow
+// a real integriq before Nextcloud boots.
+// Without a booted Nextcloud or OCP on the autoload path the stubs' parent
+// class is missing, so they are skipped rather than fatal.
+foreach (['ConnectionStatusReportedEvent', 'ConnectionRefreshRequestedEvent'] as $integriqStubEvent) {
+ if (class_exists('\\OCP\\EventDispatcher\\Event') === true
+ && class_exists('\\OCA\\Integriq\\Event\\' . $integriqStubEvent) === false
+ ) {
+ require_once __DIR__ . '/Stubs/Integriq/Event/' . $integriqStubEvent . '.php';
+ }
+}
+
+unset($integriqStubEvent);
diff --git a/tests/e2e/workflows/integrations-page.spec.ts b/tests/e2e/workflows/integrations-page.spec.ts
new file mode 100644
index 000000000..3a2765be0
--- /dev/null
+++ b/tests/e2e/workflows/integrations-page.spec.ts
@@ -0,0 +1,154 @@
+/*
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
+ * SPDX-License-Identifier: EUPL-1.2
+ *
+ * The Integrations page over integriq's connection registry
+ * (adopt-connection-registry, hydra connection-registry D8 and D9).
+ *
+ * WHERE THE ROWS COME FROM. The rows are integriq's `app_connection` objects,
+ * synced from stackiq's `lib/Settings/connections.json`, with `app` equal to
+ * `stackiq`. Stackiq writes no row: a settings save asks integriq to resolve
+ * again, a pull or a sync run reports what it met, and integriq decides the
+ * status. So this spec needs integriq installed and synced, and reads the rows
+ * from `/apps/openregister/api/objects/integriq/app_connection?app=stackiq`.
+ *
+ * `app` is a BARE filter key. The objects endpoint reads `filter[app]` as a
+ * filter on nothing and answers the empty set without an error.
+ *
+ * NOT THE CATALOGUE'S `connection` SCHEMA. Stackiq's own register has a schema
+ * with the slug `connection`. Every read here names integriq's register and
+ * `app_connection` explicitly.
+ *
+ * WHAT A RED HERE USUALLY MEANS. An empty list in the first test means
+ * integriq has not synced the declaration, or refused it whole.
+ *
+ * Locale: nothing forces the E2E language, so statuses are read from the API
+ * and rows are found by their declared titles, which are not translated.
+ *
+ * @e2e openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#the-page-lists-only-the-rows-of-stackiq
+ * @e2e openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#add-integration-goes-to-integriq
+ * @e2e openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#the-null-transport-reads-simulated-and-an-empty-one-does-not
+ */
+import type { APIRequestContext, Page } from '@playwright/test'
+
+import { expect, test } from '@playwright/test'
+import { APP_PATH } from '../base-url.ts'
+
+/** Integriq's objects endpoint for stackiq's connection rows. */
+const CONNECTIONS_API = '/index.php/apps/openregister/api/objects/integriq/app_connection?app=stackiq&_limit=50'
+
+/** Stackiq's email settings endpoint, admin only. */
+const EMAIL_SETTINGS_API = `${APP_PATH}/api/settings/email`
+
+/** The declared keys and titles, in declared order. */
+const DECLARED = [
+ { key: 'email', title: 'Email' },
+ { key: 'federation', title: 'Catalog federation' },
+ { key: 'eol-feed', title: 'End-of-life feed' },
+]
+
+/** Headers for the JSON API calls. */
+const JSON_HEADERS = { 'OCS-APIRequest': 'true', Accept: 'application/json' }
+
+/**
+ * Stackiq's connection rows, keyed by connection key.
+ *
+ * @param request An admin request context.
+ * @return The rows by key.
+ */
+async function rowsByKey(request: APIRequestContext): Promise>> {
+ const res = await request.get(CONNECTIONS_API, { headers: JSON_HEADERS })
+ expect(res.ok(), `list integriq/app_connection -> ${res.status()}`).toBeTruthy()
+ const body = await res.json()
+ const byKey: Record> = {}
+ for (const row of (body.results ?? []) as Record[]) {
+ // A row from another app here means the bare filter was dropped.
+ expect(String(row.app), 'a connection row from another app').toBe('stackiq')
+ byKey[String(row.key)] = row
+ }
+ return byKey
+}
+
+/**
+ * Open the Integrations page the way its menu entry does, with the preset.
+ *
+ * @param page The Playwright page.
+ */
+async function openIntegrations(page: Page): Promise {
+ await page.goto(`${APP_PATH}/settings/integrations?app=stackiq`, { timeout: 60_000 })
+ await expect(page.locator('.cn-index-page')).toBeVisible({ timeout: 30_000 })
+}
+
+test.describe('Integrations over the connection registry', () => {
+ test('lists the three declared connections, all of them stackiq\'s', async ({ page }) => {
+ const byKey = await rowsByKey(page.request)
+ expect(Object.keys(byKey).sort()).toEqual(DECLARED.map((d) => d.key).sort())
+
+ // Every row links to a section of stackiq's own admin page.
+ for (const { key } of DECLARED) {
+ expect(String(byKey[key]?.settingsUrl ?? ''), key).toMatch(/^\/settings\/admin\/stackiq#section-/)
+ }
+
+ await openIntegrations(page)
+ for (const { title } of DECLARED) {
+ await expect(page.getByRole('row', { name: new RegExp(`^${title}\\b`, 'i') })).toHaveCount(1)
+ }
+ })
+
+ test('reads Simulated once the null transport is saved, and not before', async ({ page }) => {
+ const before = await page.request.get(EMAIL_SETTINGS_API, { headers: JSON_HEADERS })
+ expect(before.ok(), `email settings read -> ${before.status()}`).toBeTruthy()
+ const previous = String((await before.json())?.emailSettings?.transportType ?? 'smtp')
+ test.skip(previous === 'null', 'This instance already runs the null transport, so there is no change to observe.')
+
+ /**
+ * The email row's status, read without asserting: a throw inside
+ * `expect.poll` ends the poll instead of retrying it.
+ *
+ * @return The status, or '' when the row is missing.
+ */
+ const emailStatus = async (): Promise => {
+ const list = await page.request.get(CONNECTIONS_API, { headers: JSON_HEADERS })
+ const rows = list.ok() ? ((await list.json()).results ?? []) : []
+ const row = rows.find((r: Record) => r.key === 'email' && r.app === 'stackiq')
+ return String(row?.status ?? '')
+ }
+
+ expect(await emailStatus()).not.toBe('simulated')
+
+ try {
+ // The save sends ConnectionRefreshRequestedEvent, and integriq's rule 3
+ // reads `null` from email_transport_type.
+ const res = await page.request.post(EMAIL_SETTINGS_API, {
+ headers: JSON_HEADERS,
+ data: { emailSettings: { transportType: 'null' } },
+ })
+ expect(res.ok(), `email settings save -> ${res.status()}`).toBeTruthy()
+
+ await expect.poll(emailStatus, { timeout: 15_000 }).toBe('simulated')
+ } finally {
+ // Put the VALUE back. The restore is a save too, so it refreshes the row again.
+ await page.request.post(EMAIL_SETTINGS_API, {
+ headers: JSON_HEADERS,
+ data: { emailSettings: { transportType: previous } },
+ })
+ }
+
+ await expect.poll(emailStatus, { timeout: 15_000 }).not.toBe('simulated')
+ })
+
+ test('sends Add integration to integriq instead of offering a form', async ({ page }) => {
+ await openIntegrations(page)
+
+ // No generic Add button: a row nothing declared has nothing to check.
+ await expect(page.locator('[data-testid="cn-cta-primary"]')).toHaveCount(0)
+
+ // The action lives in the overflow menu. English and Dutch are the two
+ // catalogues this change ships, and nothing forces the E2E locale.
+ await page.locator('[data-testid="cn-actions"] button').first().click()
+ await Promise.all([
+ page.waitForURL(/\/apps\/integriq\/connections\?app=stackiq&link=1$/, { timeout: 30_000 }),
+ page.getByRole('menuitem', { name: /Add integration|Integratie toevoegen/i }).click(),
+ ])
+ })
+})
diff --git a/tests/vitest/connectionRegistry.spec.js b/tests/vitest/connectionRegistry.spec.js
new file mode 100644
index 000000000..e6db90e12
--- /dev/null
+++ b/tests/vitest/connectionRegistry.spec.js
@@ -0,0 +1,165 @@
+/**
+ * SPDX-License-Identifier: EUPL-1.2
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
+ *
+ * The Integrations page over integriq's connection registry
+ * (adopt-connection-registry, hydra connection-registry D8 and D9).
+ *
+ * The page is declared in JSON and resolves two formatters, one handler and
+ * one icon by NAME. A misspelled name renders a raw enum, no glyph, or an Add
+ * integration that does nothing, and none of them logs a thing. So this spec
+ * reads the real fragment and checks every name against what has to answer it.
+ *
+ * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
+ */
+
+import * as fs from 'fs'
+import * as path from 'path'
+import { describe, expect, it } from 'vitest'
+import {
+ CONNECTION_STATUS_LABELS,
+ createConnectionFormatters,
+ createConnectionHandlers,
+ INTEGRIQ_CONNECTIONS_PATH,
+} from '../../src/services/connectionRegistry.js'
+
+const ROOT = path.resolve(__dirname, '../..')
+const read = (...parts) => fs.readFileSync(path.join(ROOT, ...parts), 'utf8')
+const fragment = JSON.parse(read('src', 'manifest.d', 'connection-registry.json'))
+const page = fragment.pages.find((p) => p.id === 'Integrations')
+const menu = fragment.menu.find((m) => m.id === 'IntegrationsMenu')
+
+/** A translator that marks what it translated, so a missing call shows. */
+const translate = (source) => `t:${source}`
+
+describe('connection formatters', () => {
+ const formatters = createConnectionFormatters(translate)
+
+ it('labels all six statuses, limited included', () => {
+ expect(Object.keys(CONNECTION_STATUS_LABELS).sort()).toEqual(
+ ['configured', 'error', 'limited', 'simulated', 'unavailable', 'unconfigured'],
+ )
+ expect(formatters.connectionStatus('configured')).toBe('t:Configured')
+ expect(formatters.connectionStatus('limited')).toBe('t:Limited')
+ expect(formatters.connectionStatus('unconfigured')).toBe('t:Not configured')
+ expect(formatters.connectionStatus('simulated')).toBe('t:Simulated')
+ expect(formatters.connectionStatus('unavailable')).toBe('t:Not available')
+ expect(formatters.connectionStatus('error')).toBe('t:Error')
+ })
+
+ // A connection that works in part is neither working nor broken, so it must
+ // not borrow either label.
+ it('keeps limited apart from configured, not available and error', () => {
+ const limited = formatters.connectionStatus('limited')
+ expect(limited).not.toBe(formatters.connectionStatus('configured'))
+ expect(limited).not.toBe(formatters.connectionStatus('unavailable'))
+ expect(limited).not.toBe(formatters.connectionStatus('error'))
+ })
+
+ it('renders an unknown status as itself and a missing one as empty', () => {
+ expect(formatters.connectionStatus('degraded')).toBe('degraded')
+ expect(formatters.connectionStatus('toString')).toBe('toString')
+ expect(formatters.connectionStatus(null)).toBe('')
+ expect(formatters.connectionStatus(undefined)).toBe('')
+ })
+
+ it('offers Open settings only when the row has a settings link', () => {
+ expect(formatters.connectionSettingsLabel('/settings/admin/stackiq')).toBe('t:Open settings')
+ expect(formatters.connectionSettingsLabel('')).toBe('')
+ expect(formatters.connectionSettingsLabel(undefined)).toBe('')
+ expect(formatters.connectionSettingsLabel(null)).toBe('')
+ })
+
+ it('ships an English and a Dutch catalogue entry for every label the page shows', () => {
+ const en = JSON.parse(read('l10n', 'en.json')).translations
+ const nl = JSON.parse(read('l10n', 'nl.json')).translations
+ const labels = [
+ ...Object.values(CONNECTION_STATUS_LABELS),
+ 'Open settings',
+ page.title,
+ menu.label,
+ page.config.folderSidebar.allLabel,
+ ...page.config.headerActions.map((a) => a.label),
+ ...page.config.columns.map((c) => c.label),
+ ]
+ for (const label of labels) {
+ expect(en[label], `en: ${label}`).toBe(label)
+ expect(nl[label], `nl: ${label}`).toBeTruthy()
+ }
+ expect(nl.Limited).toBe('Beperkt')
+ // The browser reads the .js catalogue, never the .json one.
+ expect(read('l10n', 'nl.js')).toContain('"Limited": "Beperkt"')
+ })
+})
+
+describe('Add integration handler', () => {
+ it('opens integriq on the link dialog, preset to stackiq', () => {
+ const opened = []
+ const handlers = createConnectionHandlers({
+ generateUrl: (p) => `/index.php${p}`,
+ assign: (url) => opened.push(url),
+ })
+
+ handlers.openIntegriqConnections()
+
+ expect(INTEGRIQ_CONNECTIONS_PATH).toBe('/apps/integriq/connections?app=stackiq&link=1')
+ expect(opened).toEqual(['/index.php/apps/integriq/connections?app=stackiq&link=1'])
+ })
+})
+
+describe('the Integrations page declaration', () => {
+ it('lists integriq app_connection rows, admin only, and requires integriq', () => {
+ expect(page.type).toBe('index')
+ expect(page.route).toBe('/settings/integrations')
+ expect(page.permission).toBe('admin')
+ expect(page.requiresApp).toEqual({ id: 'integriq', name: 'Integriq' })
+ expect(page.config.register).toBe('integriq')
+ expect(page.config.schema).toBe('app_connection')
+ expect(page.config.defaultSort).toEqual({ field: 'order', direction: 'asc' })
+ })
+
+ // A row nothing declared has nothing to check (connection-registry D9).
+ it('offers no generic Add button', () => {
+ expect(page.config.showAdd).toBe(false)
+ })
+
+ // THE PRESET. integriq's schema holds every app's rows. Without the query
+ // the page lists them all as though they were this app's.
+ it('scopes the rows to stackiq through the menu preset, in the gear', () => {
+ expect(menu.route).toBe(page.id)
+ expect(menu.query).toEqual({ app: 'stackiq' })
+ expect(menu.section).toBe('settings')
+ expect(menu.permission).toBe('admin')
+ expect(menu.visibleIf).toEqual({ appInstalled: 'integriq' })
+ })
+
+ it('names only formatters and handlers that exist, and wires both into the app', () => {
+ const formatters = createConnectionFormatters(translate)
+ const handlers = createConnectionHandlers({ generateUrl: (p) => p, assign: () => {} })
+
+ for (const column of page.config.columns.filter((c) => c.formatter)) {
+ expect(typeof formatters[column.formatter], column.formatter).toBe('function')
+ }
+ for (const action of page.config.headerActions) {
+ expect(typeof handlers[action.handler], action.handler).toBe('function')
+ }
+
+ expect(read('src', 'App.vue')).toContain(':formatters="formatters"')
+ expect(read('src', 'App.vue')).toContain('formatters: createConnectionFormatters(')
+ expect(read('src', 'customComponents.js')).toMatch(/^\t\.\.\.createConnectionHandlers\(\{$/m)
+ })
+
+ it('names an icon src/icons.js registers', () => {
+ const icons = read('src', 'icons.js')
+ for (const icon of [menu.icon, ...page.config.headerActions.map((a) => a.icon)]) {
+ expect(icons).toContain(`\n\t${icon},`)
+ }
+ })
+
+ it('keeps its id and route apart from every page the base manifest declares', () => {
+ const base = JSON.parse(read('src', 'manifest.json'))
+ expect(base.pages.map((p) => p.id)).not.toContain(page.id)
+ expect(base.pages.map((p) => p.route)).not.toContain(page.route)
+ expect(base.menu.map((m) => m.id)).not.toContain(menu.id)
+ })
+})
From 7828663e3ced4449699b138194621dc0a09e3301 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Wed, 16 Sep 2026 09:19:53 +0200
Subject: [PATCH 03/45] fix(tests): format the connection-registry files and
read info.xml as bytes (#1049)
Prettier 3.9.6 over the four files the connection-registry wave merged unformatted, so `npm run format` passes again. ConnectionsDeclarationTest now reads appinfo/info.xml as bytes: Nextcloud's lib/base.php installs an external entity loader that returns null, so simplexml_load_file() returns false in every CI cell.
Verified locally: npm run format exit 0, npm run lint 0 errors, composer check:strict ALL CHECKS PASSED, phpunit --filter ConnectionsDeclarationTest green.
---
src/App.vue | 4 +-
src/services/connectionRegistry.js | 15 +++--
.../Settings/ConnectionsDeclarationTest.php | 6 +-
tests/e2e/workflows/integrations-page.spec.ts | 63 ++++++++++++++-----
tests/vitest/connectionRegistry.spec.js | 45 +++++++++----
5 files changed, 100 insertions(+), 33 deletions(-)
diff --git a/src/App.vue b/src/App.vue
index c05275f09..83e9381f7 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -157,7 +157,9 @@ export default {
* 2.39.0 ships neither as a built-in. Before this change the app
* passed no formatters at all.
*/
- formatters: createConnectionFormatters((source) => ncT('stackiq', source)),
+ formatters: createConnectionFormatters((source) =>
+ ncT('stackiq', source),
+ ),
objectSidebarState: reactive({
active: false,
diff --git a/src/services/connectionRegistry.js b/src/services/connectionRegistry.js
index 6a881ba7e..081d40bf5 100644
--- a/src/services/connectionRegistry.js
+++ b/src/services/connectionRegistry.js
@@ -20,7 +20,8 @@
* Where Add integration lands: integriq's Connections overview, preset to this
* app and opening the link-a-source dialog (hydra connection-registry D9).
*/
-export const INTEGRIQ_CONNECTIONS_PATH = '/apps/integriq/connections?app=stackiq&link=1'
+export const INTEGRIQ_CONNECTIONS_PATH =
+ '/apps/integriq/connections?app=stackiq&link=1'
/**
* The English label for each of the six registry statuses (design D3).
@@ -54,9 +55,11 @@ export function createConnectionFormatters(translate) {
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
*/
connectionStatus(value) {
- const source = typeof value === 'string' && Object.hasOwn(CONNECTION_STATUS_LABELS, value)
- ? CONNECTION_STATUS_LABELS[value]
- : null
+ const source =
+ typeof value === 'string'
+ && Object.hasOwn(CONNECTION_STATUS_LABELS, value)
+ ? CONNECTION_STATUS_LABELS[value]
+ : null
return source ? translate(source) : String(value ?? '')
},
@@ -69,7 +72,9 @@ export function createConnectionFormatters(translate) {
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
*/
connectionSettingsLabel(value) {
- return typeof value === 'string' && value.length > 0 ? translate('Open settings') : ''
+ return typeof value === 'string' && value.length > 0
+ ? translate('Open settings')
+ : ''
},
}
}
diff --git a/tests/Unit/Settings/ConnectionsDeclarationTest.php b/tests/Unit/Settings/ConnectionsDeclarationTest.php
index e532de97d..9b82677b9 100644
--- a/tests/Unit/Settings/ConnectionsDeclarationTest.php
+++ b/tests/Unit/Settings/ConnectionsDeclarationTest.php
@@ -140,7 +140,11 @@ private function connectionsByKey(): array {
*/
public function testTheFileNamesThisApp(): void {
$declaration = $this->declaration();
- $infoXml = simplexml_load_file($this->root() . '/appinfo/info.xml');
+ // Read the bytes, not the path. Nextcloud's lib/base.php installs an external
+ // entity loader that returns null, and libxml routes the primary document
+ // through it too, so simplexml_load_file() returns false for a valid file in CI.
+ $infoRaw = (string) file_get_contents($this->root() . '/appinfo/info.xml');
+ $infoXml = simplexml_load_string($infoRaw);
$this->assertNotFalse(condition: $infoXml);
$this->assertSame(expected: (string) $infoXml->id, actual: $declaration['app']);
diff --git a/tests/e2e/workflows/integrations-page.spec.ts b/tests/e2e/workflows/integrations-page.spec.ts
index 3a2765be0..95b4053cf 100644
--- a/tests/e2e/workflows/integrations-page.spec.ts
+++ b/tests/e2e/workflows/integrations-page.spec.ts
@@ -35,7 +35,8 @@ import { expect, test } from '@playwright/test'
import { APP_PATH } from '../base-url.ts'
/** Integriq's objects endpoint for stackiq's connection rows. */
-const CONNECTIONS_API = '/index.php/apps/openregister/api/objects/integriq/app_connection?app=stackiq&_limit=50'
+const CONNECTIONS_API =
+ '/index.php/apps/openregister/api/objects/integriq/app_connection?app=stackiq&_limit=50'
/** Stackiq's email settings endpoint, admin only. */
const EMAIL_SETTINGS_API = `${APP_PATH}/api/settings/email`
@@ -56,7 +57,9 @@ const JSON_HEADERS = { 'OCS-APIRequest': 'true', Accept: 'application/json' }
* @param request An admin request context.
* @return The rows by key.
*/
-async function rowsByKey(request: APIRequestContext): Promise>> {
+async function rowsByKey(
+ request: APIRequestContext,
+): Promise>> {
const res = await request.get(CONNECTIONS_API, { headers: JSON_HEADERS })
expect(res.ok(), `list integriq/app_connection -> ${res.status()}`).toBeTruthy()
const body = await res.json()
@@ -75,31 +78,48 @@ async function rowsByKey(request: APIRequestContext): Promise {
- await page.goto(`${APP_PATH}/settings/integrations?app=stackiq`, { timeout: 60_000 })
+ await page.goto(`${APP_PATH}/settings/integrations?app=stackiq`, {
+ timeout: 60_000,
+ })
await expect(page.locator('.cn-index-page')).toBeVisible({ timeout: 30_000 })
}
test.describe('Integrations over the connection registry', () => {
- test('lists the three declared connections, all of them stackiq\'s', async ({ page }) => {
+ test("lists the three declared connections, all of them stackiq's", async ({
+ page,
+ }) => {
const byKey = await rowsByKey(page.request)
expect(Object.keys(byKey).sort()).toEqual(DECLARED.map((d) => d.key).sort())
// Every row links to a section of stackiq's own admin page.
for (const { key } of DECLARED) {
- expect(String(byKey[key]?.settingsUrl ?? ''), key).toMatch(/^\/settings\/admin\/stackiq#section-/)
+ expect(String(byKey[key]?.settingsUrl ?? ''), key).toMatch(
+ /^\/settings\/admin\/stackiq#section-/,
+ )
}
await openIntegrations(page)
for (const { title } of DECLARED) {
- await expect(page.getByRole('row', { name: new RegExp(`^${title}\\b`, 'i') })).toHaveCount(1)
+ await expect(
+ page.getByRole('row', { name: new RegExp(`^${title}\\b`, 'i') }),
+ ).toHaveCount(1)
}
})
- test('reads Simulated once the null transport is saved, and not before', async ({ page }) => {
- const before = await page.request.get(EMAIL_SETTINGS_API, { headers: JSON_HEADERS })
+ test('reads Simulated once the null transport is saved, and not before', async ({
+ page,
+ }) => {
+ const before = await page.request.get(EMAIL_SETTINGS_API, {
+ headers: JSON_HEADERS,
+ })
expect(before.ok(), `email settings read -> ${before.status()}`).toBeTruthy()
- const previous = String((await before.json())?.emailSettings?.transportType ?? 'smtp')
- test.skip(previous === 'null', 'This instance already runs the null transport, so there is no change to observe.')
+ const previous = String(
+ (await before.json())?.emailSettings?.transportType ?? 'smtp',
+ )
+ test.skip(
+ previous === 'null',
+ 'This instance already runs the null transport, so there is no change to observe.',
+ )
/**
* The email row's status, read without asserting: a throw inside
@@ -108,9 +128,14 @@ test.describe('Integrations over the connection registry', () => {
* @return The status, or '' when the row is missing.
*/
const emailStatus = async (): Promise => {
- const list = await page.request.get(CONNECTIONS_API, { headers: JSON_HEADERS })
+ const list = await page.request.get(CONNECTIONS_API, {
+ headers: JSON_HEADERS,
+ })
const rows = list.ok() ? ((await list.json()).results ?? []) : []
- const row = rows.find((r: Record) => r.key === 'email' && r.app === 'stackiq')
+ const row = rows.find(
+ (r: Record) =>
+ r.key === 'email' && r.app === 'stackiq',
+ )
return String(row?.status ?? '')
}
@@ -137,7 +162,9 @@ test.describe('Integrations over the connection registry', () => {
await expect.poll(emailStatus, { timeout: 15_000 }).not.toBe('simulated')
})
- test('sends Add integration to integriq instead of offering a form', async ({ page }) => {
+ test('sends Add integration to integriq instead of offering a form', async ({
+ page,
+ }) => {
await openIntegrations(page)
// No generic Add button: a row nothing declared has nothing to check.
@@ -147,8 +174,14 @@ test.describe('Integrations over the connection registry', () => {
// catalogues this change ships, and nothing forces the E2E locale.
await page.locator('[data-testid="cn-actions"] button').first().click()
await Promise.all([
- page.waitForURL(/\/apps\/integriq\/connections\?app=stackiq&link=1$/, { timeout: 30_000 }),
- page.getByRole('menuitem', { name: /Add integration|Integratie toevoegen/i }).click(),
+ page.waitForURL(/\/apps\/integriq\/connections\?app=stackiq&link=1$/, {
+ timeout: 30_000,
+ }),
+ page
+ .getByRole('menuitem', {
+ name: /Add integration|Integratie toevoegen/i,
+ })
+ .click(),
])
})
})
diff --git a/tests/vitest/connectionRegistry.spec.js b/tests/vitest/connectionRegistry.spec.js
index e6db90e12..8853490a3 100644
--- a/tests/vitest/connectionRegistry.spec.js
+++ b/tests/vitest/connectionRegistry.spec.js
@@ -36,9 +36,14 @@ describe('connection formatters', () => {
const formatters = createConnectionFormatters(translate)
it('labels all six statuses, limited included', () => {
- expect(Object.keys(CONNECTION_STATUS_LABELS).sort()).toEqual(
- ['configured', 'error', 'limited', 'simulated', 'unavailable', 'unconfigured'],
- )
+ expect(Object.keys(CONNECTION_STATUS_LABELS).sort()).toEqual([
+ 'configured',
+ 'error',
+ 'limited',
+ 'simulated',
+ 'unavailable',
+ 'unconfigured',
+ ])
expect(formatters.connectionStatus('configured')).toBe('t:Configured')
expect(formatters.connectionStatus('limited')).toBe('t:Limited')
expect(formatters.connectionStatus('unconfigured')).toBe('t:Not configured')
@@ -64,7 +69,9 @@ describe('connection formatters', () => {
})
it('offers Open settings only when the row has a settings link', () => {
- expect(formatters.connectionSettingsLabel('/settings/admin/stackiq')).toBe('t:Open settings')
+ expect(formatters.connectionSettingsLabel('/settings/admin/stackiq')).toBe(
+ 't:Open settings',
+ )
expect(formatters.connectionSettingsLabel('')).toBe('')
expect(formatters.connectionSettingsLabel(undefined)).toBe('')
expect(formatters.connectionSettingsLabel(null)).toBe('')
@@ -102,8 +109,12 @@ describe('Add integration handler', () => {
handlers.openIntegriqConnections()
- expect(INTEGRIQ_CONNECTIONS_PATH).toBe('/apps/integriq/connections?app=stackiq&link=1')
- expect(opened).toEqual(['/index.php/apps/integriq/connections?app=stackiq&link=1'])
+ expect(INTEGRIQ_CONNECTIONS_PATH).toBe(
+ '/apps/integriq/connections?app=stackiq&link=1',
+ )
+ expect(opened).toEqual([
+ '/index.php/apps/integriq/connections?app=stackiq&link=1',
+ ])
})
})
@@ -135,23 +146,35 @@ describe('the Integrations page declaration', () => {
it('names only formatters and handlers that exist, and wires both into the app', () => {
const formatters = createConnectionFormatters(translate)
- const handlers = createConnectionHandlers({ generateUrl: (p) => p, assign: () => {} })
+ const handlers = createConnectionHandlers({
+ generateUrl: (p) => p,
+ assign: () => {},
+ })
for (const column of page.config.columns.filter((c) => c.formatter)) {
- expect(typeof formatters[column.formatter], column.formatter).toBe('function')
+ expect(typeof formatters[column.formatter], column.formatter).toBe(
+ 'function',
+ )
}
for (const action of page.config.headerActions) {
expect(typeof handlers[action.handler], action.handler).toBe('function')
}
expect(read('src', 'App.vue')).toContain(':formatters="formatters"')
- expect(read('src', 'App.vue')).toContain('formatters: createConnectionFormatters(')
- expect(read('src', 'customComponents.js')).toMatch(/^\t\.\.\.createConnectionHandlers\(\{$/m)
+ expect(read('src', 'App.vue')).toContain(
+ 'formatters: createConnectionFormatters(',
+ )
+ expect(read('src', 'customComponents.js')).toMatch(
+ /^\t\.\.\.createConnectionHandlers\(\{$/m,
+ )
})
it('names an icon src/icons.js registers', () => {
const icons = read('src', 'icons.js')
- for (const icon of [menu.icon, ...page.config.headerActions.map((a) => a.icon)]) {
+ for (const icon of [
+ menu.icon,
+ ...page.config.headerActions.map((a) => a.icon),
+ ]) {
expect(icons).toContain(`\n\t${icon},`)
}
})
From 60142ceca56e19962ec1ca0a8ef0e35888f28cde Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Wed, 16 Sep 2026 11:51:10 +0200
Subject: [PATCH 04/45] fix(tests): initialise connectionReports on the
reflection-built controller (#1051)
The test builds SettingsController with newInstanceWithoutConstructor(), so the promoted ?ConnectionReportService $connectionReports = null never received its null and PHP threw on the read in all six cells. Verified with the standalone unit config: 11 tests pass, and the unchanged file reproduces CI's exact error.
---
.../Controller/SettingsControllerCanonicalWriteTest.php | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tests/Unit/Controller/SettingsControllerCanonicalWriteTest.php b/tests/Unit/Controller/SettingsControllerCanonicalWriteTest.php
index 177af5d6e..99c08838f 100644
--- a/tests/Unit/Controller/SettingsControllerCanonicalWriteTest.php
+++ b/tests/Unit/Controller/SettingsControllerCanonicalWriteTest.php
@@ -159,6 +159,12 @@ private function makeController(array $params, SettingsService $settingsService)
'request' => $request,
'settingsService' => $settingsService,
'logger' => $this->createMock(LoggerInterface::class),
+ // A promoted `?ConnectionReportService $connectionReports = null`
+ // gets its null from the constructor, which
+ // newInstanceWithoutConstructor() never runs. Left unset, the
+ // readonly property stays uninitialised and `?->` does not save
+ // it: PHP throws on the read before the null-safe check.
+ 'connectionReports' => null,
] as $name => $value
) {
$prop = $reflection->getProperty($name);
From 45f4d2a074faaa1afaae446a2c4be778ccf95852 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Wed, 16 Sep 2026 11:59:41 +0200
Subject: [PATCH 05/45] fix(schemas): drop a stray licence key so the module
schema imports again (#1054)
The module schema's licence property carried a stray "licence": "License" beside its real title. openregister's vocabulary check rejected the whole schema at import while answering 200, so CI seeding failed. openregister's own validator now reports 20 schemas, 0 rejected, for both register files (it reproduced the CI rejection before the fix). Gates pass.
---
lib/Settings/softwarecatalogus_register.json | 1 -
lib/Settings/stackiq_mock_register.json | 1 -
2 files changed, 2 deletions(-)
diff --git a/lib/Settings/softwarecatalogus_register.json b/lib/Settings/softwarecatalogus_register.json
index 7eb803a5a..a39f04273 100644
--- a/lib/Settings/softwarecatalogus_register.json
+++ b/lib/Settings/softwarecatalogus_register.json
@@ -6987,7 +6987,6 @@
"BSD License (Berkeley Software Distribution)",
"European Union Public Licence (EUPL), version 1.2"
],
- "licence": "License",
"title": "License"
},
"referenceComponents": {
diff --git a/lib/Settings/stackiq_mock_register.json b/lib/Settings/stackiq_mock_register.json
index 392c5ac03..ce12ee702 100644
--- a/lib/Settings/stackiq_mock_register.json
+++ b/lib/Settings/stackiq_mock_register.json
@@ -3388,7 +3388,6 @@
"BSD License (Berkeley Software Distribution)",
"European Union Public Licence (EUPL), version 1.2"
],
- "licence": "License",
"title": "License"
},
"referenceComponents": {
From f66ddcf91d4283406ec53ff4d71e770e369b016a Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Wed, 16 Sep 2026 12:00:08 +0200
Subject: [PATCH 06/45] feat(connections): federation and EOL sync read
Switched off, and the formatters come from nextcloud-vue 3.2.0 (#1053)
* feat(connections): switched-off federation and a switched-off EOL sync read disabled through their switches
federation declares switch on federation_enabled, and eol-feed on enabled
inside eol_sync_config (hydra connection-registry D4 rule 2b, D12 items
6, 7 and 9). A peer change, a pull, a sync save and a sync run no longer
report unconfigured when the feature is off: the save still refreshes,
and integriq resolves disabled itself.
* test(connections): a switched-off federation with no peers reports nothing
The earlier case had a peer, so dropping the switch guard left the
outcome the same and the test green. With no peers the guard is the only
thing between the switch and a no-peer-catalog report.
* chore(deps): @conduction/nextcloud-vue 2.39.0 -> 3.2.0, and the connection formatters come from the library
3.2.0 ships connectionStatus, with disabled read as Switched off, and
connectionSettingsLabel as built-ins (nextcloud-vue#1173, #1175). The
local copy in src/services/connectionRegistry.js and App.vue's formatters
prop are gone; the handler stays. The spec now checks the manifest's
formatter names against the installed library's built-in map. The range
was ^2.37.0 with 2.39.0 locked; against development only the library and
the hoisted @nextcloud/files (3.12.2 -> 4.0.0) move at the top level.
* test(connections): declare the built-in formatter reader with the function keyword
antfu/top-level-function refuses a top-level arrow function.
* test(connections): import the built-in formatters and call them, instead of reading the module source
---
lib/Service/ConnectionReportService.php | 104 ++++++++-----
lib/Service/EolSyncService.php | 2 +-
lib/Settings/connections.json | 9 ++
.../adopt-connection-registry/design.md | 16 +-
.../adopt-connection-registry/proposal.md | 4 +-
.../specs/admin-integrations/spec.md | 16 +-
.../adopt-connection-registry/tasks.md | 9 +-
package-lock.json | 141 +++++-------------
package.json | 2 +-
src/App.vue | 13 --
src/services/connectionRegistry.js | 67 +--------
.../Service/ConnectionReportCallersTest.php | 6 +-
.../Service/ConnectionReportServiceTest.php | 50 ++++---
.../Settings/ConnectionsDeclarationTest.php | 61 +++++++-
tests/vitest/connectionRegistry.spec.js | 126 ++++++++--------
15 files changed, 294 insertions(+), 332 deletions(-)
diff --git a/lib/Service/ConnectionReportService.php b/lib/Service/ConnectionReportService.php
index 646c48e8e..dc598f4ed 100644
--- a/lib/Service/ConnectionReportService.php
+++ b/lib/Service/ConnectionReportService.php
@@ -83,6 +83,26 @@ class ConnectionReportService {
*/
public const KEY_EOL = 'eol-feed';
+ /**
+ * The pull reason FederationService records for switched-off federation, which is never reported.
+ *
+ * The `federation` switch in lib/Settings/connections.json reads
+ * `federation_enabled`, so integriq shows `disabled` without a report
+ * (hydra connection-registry D4 rule 2b).
+ *
+ * @var string
+ */
+ public const PULL_REASON_SWITCHED_OFF = 'federation disabled';
+
+ /**
+ * The EOL sync degrade reason for a switched-off sync, which is never reported.
+ *
+ * The `eol-feed` switch reads `enabled` inside `eol_sync_config` itself.
+ *
+ * @var string
+ */
+ public const EOL_REASON_SWITCHED_OFF = 'disabled';
+
/**
* The longest failure reason a message carries.
*
@@ -93,15 +113,13 @@ class ConnectionReportService {
/**
* What each EOL sync degrade reason means for the row, as status and message.
*
- * The reasons are the ones EolSyncService::degrade() records.
+ * The reasons are the ones EolSyncService::degrade() records, apart from
+ * `disabled`: the `eol-feed` switch in lib/Settings/connections.json reads
+ * a switched-off sync itself, so that reason reports nothing.
*
* @var array
*/
public const EOL_REASONS = [
- 'disabled' => [
- 'unconfigured',
- 'End-of-life sync is switched off. Switch it on in the End-of-life feed sync section.',
- ],
'openregister-not-installed' => [
'unavailable',
'The end-of-life sync needs OpenRegister, and it is not installed.',
@@ -203,6 +221,9 @@ public function describeEmail(array $configStatus, array $transportLabels): arra
*
* A ready federation gets no report: only a pull can tell whether the peers
* answer, so the row reads the declared "Not checked yet" until then.
+ * Switched-off federation gets none either: the `federation` switch in
+ * lib/Settings/connections.json reads `federation_enabled` itself, and
+ * integriq shows `disabled`.
*
* @param array $status The result of FederationService::getStatus().
*
@@ -215,9 +236,13 @@ public function federationPeersChanged(array $status): bool {
return false;
}
+ $available = ($status['available'] ?? false) === true;
+ if ($available === true && ($status['enabled'] ?? false) !== true) {
+ return false;
+ }
+
$blocked = $this->federationBlocker(
- available: ($status['available'] ?? false) === true,
- enabled: ($status['enabled'] ?? false) === true,
+ available: $available,
peerCount: count((array) ($status['peers'] ?? []))
);
if ($blocked === null) {
@@ -237,7 +262,12 @@ public function federationPeersChanged(array $status): bool {
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function federationPulled(array $pull): bool {
- [$status, $message] = $this->describePull(pull: $pull);
+ $described = $this->describePull(pull: $pull);
+ if ($described === null) {
+ return false;
+ }
+
+ [$status, $message] = $described;
return $this->report(key: self::KEY_FEDERATION, status: $status, message: $message);
}//end federationPulled()
@@ -247,16 +277,19 @@ public function federationPulled(array $pull): bool {
*
* @param array $pull The result of FederationService::pullAllPeers().
*
- * @return array{0: string, 1: string} The status and the message.
+ * @return array{0: string, 1: string}|null The status and the message, or null when federation is switched off.
*
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
- public function describePull(array $pull): array {
+ public function describePull(array $pull): ?array {
$reason = (string) ($pull['reason'] ?? '');
if (($pull['ok'] ?? false) !== true) {
+ if ($reason === self::PULL_REASON_SWITCHED_OFF) {
+ return null;
+ }
+
$blocked = $this->federationBlocker(
available: $reason !== 'OpenCatalogi unavailable',
- enabled: $reason !== 'federation disabled',
peerCount: 1
);
@@ -291,26 +324,18 @@ public function describePull(array $pull): array {
}//end describePull()
/**
- * After an EOL sync settings save: refresh, then report a switched-off sync.
+ * After an EOL sync settings save: refresh, and send no report.
*
- * @param array $config The configuration as saved.
+ * The save may have switched the sync on or off, and the `eol-feed` switch
+ * in lib/Settings/connections.json reads `enabled` inside
+ * `eol_sync_config` itself. A run reports what the sync met.
*
- * @return bool True when a report was sent.
+ * @return bool True when the refresh was sent.
*
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
- public function eolSyncConfigSaved(array $config): bool {
- if ($this->refresh(key: self::KEY_EOL) === false) {
- return false;
- }
-
- if (($config['enabled'] ?? false) === true) {
- return false;
- }
-
- [$status, $message] = self::EOL_REASONS['disabled'];
-
- return $this->report(key: self::KEY_EOL, status: $status, message: $message);
+ public function eolSyncConfigSaved(): bool {
+ return $this->refresh(key: self::KEY_EOL);
}//end eolSyncConfigSaved()
/**
@@ -323,7 +348,12 @@ public function eolSyncConfigSaved(array $config): bool {
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
public function eolSyncRan(array $runStatus): bool {
- [$status, $message] = $this->describeEolRun(runStatus: $runStatus);
+ $described = $this->describeEolRun(runStatus: $runStatus);
+ if ($described === null) {
+ return false;
+ }
+
+ [$status, $message] = $described;
return $this->report(key: self::KEY_EOL, status: $status, message: $message);
}//end eolSyncRan()
@@ -333,11 +363,11 @@ public function eolSyncRan(array $runStatus): bool {
*
* @param array $runStatus The status EolSyncService::run() recorded.
*
- * @return array{0: string, 1: string} The status and the message.
+ * @return array{0: string, 1: string}|null The status and the message, or null when the sync is switched off.
*
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-002-a-save-asks-integriq-to-look-again-and-a-run-reports-what-it-met
*/
- public function describeEolRun(array $runStatus): array {
+ public function describeEolRun(array $runStatus): ?array {
if (($runStatus['available'] ?? false) === true) {
return [
'configured',
@@ -347,6 +377,9 @@ public function describeEolRun(array $runStatus): array {
}
$reason = (string) ($runStatus['reason'] ?? '');
+ if ($reason === self::EOL_REASON_SWITCHED_OFF) {
+ return null;
+ }
return (self::EOL_REASONS[$reason] ?? ['error', 'The last end-of-life sync stopped: ' . $this->shorten(text: $reason)]);
}//end describeEolRun()
@@ -416,24 +449,19 @@ protected function resolveEventClass(string $eventClass): ?string {
/**
* The state that keeps federation from pulling at all, or null when none does.
*
+ * Switched-off federation is not a blocker here: the callers leave it to the
+ * row's switch, which integriq reads itself.
+ *
* @param bool $available Whether OpenCatalogi is installed.
- * @param bool $enabled Whether federation_enabled is on.
* @param int $peerCount How many peers are configured.
*
* @return array{0: string, 1: string}|null The status and the message, or null.
*/
- private function federationBlocker(bool $available, bool $enabled, int $peerCount): ?array {
+ private function federationBlocker(bool $available, int $peerCount): ?array {
if ($available === false) {
return ['unavailable', 'Federation needs the OpenCatalogi app, and it is not installed.'];
}
- if ($enabled === false) {
- return [
- 'unconfigured',
- 'Federation is switched off. Run occ config:app:set stackiq federation_enabled --value=true --type=boolean.',
- ];
- }
-
if ($peerCount === 0) {
return ['unconfigured', 'Federation is on, and no peer catalog is added yet.'];
}
diff --git a/lib/Service/EolSyncService.php b/lib/Service/EolSyncService.php
index 8864d4fb2..86be572b3 100644
--- a/lib/Service/EolSyncService.php
+++ b/lib/Service/EolSyncService.php
@@ -96,7 +96,7 @@ public function getConfig(): array {
*/
public function updateConfig(array $data): array {
$result = $this->settingsService->updateEolSyncConfig($data);
- $this->connectionReports?->eolSyncConfigSaved(config: (array) ($result['config'] ?? []));
+ $this->connectionReports?->eolSyncConfigSaved();
return $result;
}//end updateConfig()
diff --git a/lib/Settings/connections.json b/lib/Settings/connections.json
index e2fcb8591..2e8c10bd2 100644
--- a/lib/Settings/connections.json
+++ b/lib/Settings/connections.json
@@ -21,6 +21,10 @@
"order": 20,
"settingsUrl": "/settings/admin/stackiq#section-federation",
"reportedOnly": true,
+ "switch": {
+ "configKey": "federation_enabled"
+ },
+ "disabledMessage": "Federation is switched off. Set the federation_enabled app setting to true with occ to switch it on.",
"unconfiguredMessage": "Not checked yet. Choose Pull now in the Catalog federation section to check the peers."
},
{
@@ -30,6 +34,11 @@
"order": 30,
"settingsUrl": "/settings/admin/stackiq#section-eol-sync",
"reportedOnly": true,
+ "switch": {
+ "configKey": "eol_sync_config",
+ "jsonPath": "enabled"
+ },
+ "disabledMessage": "End-of-life sync is switched off. Switch it on in the End-of-life feed sync section.",
"sourceTemplate": "endoflife-date",
"unconfiguredMessage": "Not checked yet. Choose Sync now in the End-of-life feed sync section."
}
diff --git a/openspec/changes/adopt-connection-registry/design.md b/openspec/changes/adopt-connection-registry/design.md
index 24231e76d..be0bc86f9 100644
--- a/openspec/changes/adopt-connection-registry/design.md
+++ b/openspec/changes/adopt-connection-registry/design.md
@@ -42,7 +42,7 @@ The `null` transport still reads Simulated: rule 3 sits above every report.
| Stackiq sees | Status | Message |
|---|---|---|
| OpenCatalogi not installed | `unavailable` | "Federation needs the OpenCatalogi app, and it is not installed." |
-| `federation_enabled` off | `unconfigured` | names the `occ` command |
+| `federation_enabled` off | nothing: the refresh alone, and the switch makes integriq read `disabled` with the declared message | |
| No peers | `unconfigured` | "Federation is on, and no peer catalog is added yet." |
| Ready | nothing | the refresh alone, so the row reads the declared "Not checked yet" |
@@ -56,14 +56,14 @@ The `null` transport still reads Simulated: rule 3 sits above every report.
A message names a peer by host only, never by its full URL, and cuts a failure reason at 160 characters.
-**End-of-life feed, on an EOL sync settings save.** A refresh, and `unconfigured` when `enabled` is off. Otherwise the row reads "Not checked yet" until the next run.
+**End-of-life feed, on an EOL sync settings save.** A refresh and no report. When `enabled` is off the switch makes integriq read `disabled`. Otherwise the row reads "Not checked yet" until the next run.
**End-of-life feed, after a run** (Sync now, or `EolSyncJob`). `EolSyncService::run()` already records a status. The report maps its `reason`:
| Reason | Status |
|---|---|
| none, the run completed | `configured`, with the matched and skipped counts |
-| `disabled` | `unconfigured` |
+| `disabled` | nothing, the switch says it |
| `openregister-not-installed` | `unavailable` |
| `object-service-unavailable` | `error` |
| `module-schema-not-configured` | `unconfigured` |
@@ -78,15 +78,15 @@ A message names a peer by host only, never by its full URL, and cuts a failure r
- `src/manifest.d/connection-registry.json`: an `index` page `Integrations` at `/settings/integrations`, `requiresApp` integriq, `permission: admin`, `showAdd: false`, and the columns connection, status, status message, last checked and settings.
- Its menu entry `IntegrationsMenu` sits in the settings gear with `query: {app: stackiq}`, `permission: admin` and `visibleIf.appInstalled: integriq`.
-- `src/services/connectionRegistry.js` holds the two formatters and `openIntegriqConnections`.
-- `App.vue` passes the formatters through CnAppRoot's `formatters` prop. It passed none before this change. `src/customComponents.js` carries the handler, because CnIndexPage resolves a header action's handler against `customComponents`.
+- `src/services/connectionRegistry.js` holds `openIntegriqConnections`.
+- `App.vue` passes no `formatters`: CnAppRoot supplies the two built-ins. `src/customComponents.js` carries the handler, because CnIndexPage resolves a header action's handler against `customComponents`.
-**Formatters.** The installed `@conduction/nextcloud-vue` 2.39.0 ships no `connectionStatus` built-in, so stackiq carries a local copy with all six labels, `limited` included.
+**Formatters.** `@conduction/nextcloud-vue` 3.2.0 ships `connectionStatus` and `connectionSettingsLabel` as built-ins, `disabled` included (nextcloud-vue#1173). Stackiq carried a local copy while it resolved 2.39.0, and dropped it on moving to 3.2.0.
## D4. Contract misfits
-- **A boolean app-config key.** `federation_enabled` is typed boolean. Integriq's reader answers `typed` for a type conflict, which counts as filled, so a `requiredConfig` on it would read Configured while federation is off. The contract has no way to say "filled and true". `reportedOnly` works around it.
-- **A flag inside a blob.** `eol_sync_config` holds `{"enabled": false, …}`. `adapter.jsonPath` reads inside a blob, but only rule 3 uses it, and "switched off" is not "simulated". A `requiredConfig` with a JSON path would fit this row.
+- **A boolean app-config key.** `federation_enabled` is typed boolean, and a stored `false` counted as filled. Resolved by hydra#676 (`false` reads empty) and hydra#677: the row declares `switch: {"configKey": "federation_enabled"}` and reads `disabled` while it is off.
+- **A flag inside a blob.** `eol_sync_config` holds `{"enabled": false, …}`. Resolved by hydra#677: the row declares `switch: {"configKey": "eol_sync_config", "jsonPath": "enabled"}`. An unset blob has no `enabled` and reads off, which matches `SettingsService::getEolSyncConfig()`'s default.
- **Completeness that depends on the adapter.** Email needs different keys per transport. `requiredConfig` is one fixed list.
- **Gate 116's vendored schema is behind integriq.** `hydra-gates/scripts/schemas/connections.schema.json` on `.github` `main` has no `jsonPath`, `simulatedValues` or `reportedOnly`, so gate 116 warns on every file that uses the hydra#673 fields. The file validates against integriq's own schema on `development`.
diff --git a/openspec/changes/adopt-connection-registry/proposal.md b/openspec/changes/adopt-connection-registry/proposal.md
index b43e66e1a..d2d3f8e36 100644
--- a/openspec/changes/adopt-connection-registry/proposal.md
+++ b/openspec/changes/adopt-connection-registry/proposal.md
@@ -18,14 +18,14 @@ Hydra change `connection-registry` (hydra#667, amended in hydra#673 and hydra#67
- New `lib/Settings/connections.json` with three connections: `email`, `federation` and `eol-feed`.
- `email` names `email_transport_type` as its adapter key, and only `null` reads Simulated. An empty value is not simulated: stackiq falls back to SMTP.
-- `federation` and `eol-feed` are `reportedOnly`. Only stackiq can see OpenCatalogi, `federation_enabled` (a boolean key) and the sync outcome.
+- `federation` and `eol-feed` are `reportedOnly`. Only stackiq can see OpenCatalogi, the peers and the sync outcome. Each declares its on/off setting as a `switch` (hydra#677): `federation_enabled`, and `enabled` inside `eol_sync_config`, so a switched-off feature reads Switched off.
- `eol-feed` offers integriq's `endoflife-date` source as its template.
- The three settings sections get stable ids: `section-email`, `section-federation` and `section-eol-sync`.
- An email settings save, a peer add or remove, and an EOL sync settings save send `ConnectionRefreshRequestedEvent` for that connection, then report what stackiq can see.
- A federation pull and an EOL sync run report their outcome. Both run on a schedule or on the admin's button, never on a page request.
- An Integrations page under the settings gear, over integriq's `app_connection` schema, preset to `app=stackiq`, admin only, and only shown when integriq is installed.
- Add integration opens `/apps/integriq/connections?app=stackiq&link=1`.
-- Local `connectionStatus` and `connectionSettingsLabel` formatters with all six statuses, and the strings in English and Dutch.
+- The `connectionStatus` and `connectionSettingsLabel` formatters come from `@conduction/nextcloud-vue` 3.2.0, which labels all seven statuses. The page strings are in English and Dutch.
## Depends on
diff --git a/openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md b/openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md
index 7aae69757..2d3c4ab48 100644
--- a/openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md
+++ b/openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md
@@ -13,7 +13,7 @@ Admins see stackiq's outside connections on one page, with a status stackiq can
### Requirement: REQ-STACKIQ-CONN-001 Stackiq declares its outside connections in one static file
-Stackiq SHALL declare `email`, `federation` and `eol-feed` in `lib/Settings/connections.json` in the shape of hydra connection-registry design D2 (hydra REQ-CONN-001). The `email` entry SHALL name `email_transport_type` as its adapter key with `simulatedValues` holding `null` and not the empty string, because an empty transport sends mail through SMTP. The `federation` and `eol-feed` entries SHALL be `reportedOnly`. The `eol-feed` entry SHALL offer integriq's `endoflife-date` source template. Every `settingsUrl` SHALL point at a section id that exists in the admin settings page.
+Stackiq SHALL declare `email`, `federation` and `eol-feed` in `lib/Settings/connections.json` in the shape of hydra connection-registry design D2 (hydra REQ-CONN-001). The `email` entry SHALL name `email_transport_type` as its adapter key with `simulatedValues` holding `null` and not the empty string, because an empty transport sends mail through SMTP. The `federation` and `eol-feed` entries SHALL be `reportedOnly`. The `federation` entry SHALL declare `federation_enabled` as its `switch`, and the `eol-feed` entry SHALL declare `enabled` inside `eol_sync_config` as its `switch`, so a switched-off feature reads `disabled` (hydra connection-registry D12 items 6, 7 and 9). The `eol-feed` entry SHALL offer integriq's `endoflife-date` source template. Every `settingsUrl` SHALL point at a section id that exists in the admin settings page.
#### Scenario: The declaration names this app and passes integriq's schema
@e2e exclude A static file with no browser surface; tests/Unit/Settings/ConnectionsDeclarationTest.php checks the shape, the app id, unique keys and the anchors.
@@ -25,6 +25,14 @@ Stackiq SHALL declare `email`, `federation` and `eol-feed` in `lib/Settings/conn
- **AND** every key SHALL be unique
- **AND** every `#section-…` anchor SHALL be an id in a settings section component
+#### Scenario: Switched-off federation and a switched-off sync read disabled
+@e2e exclude The rule lives in integriq's resolver; tests/Unit/Settings/ConnectionsDeclarationTest.php asserts both switches and that the code reads the same keys with an off default.
+
+- **GIVEN** integriq has synced stackiq's declaration
+- **WHEN** `federation_enabled` holds `false`, or `eol_sync_config` holds `{"enabled": false}`
+- **THEN** integriq's rule 2b SHALL resolve that row as `disabled`
+- **AND** stackiq SHALL send no report that says the feature is off
+
#### Scenario: The null transport reads simulated, and an empty one does not
@e2e tests/e2e/workflows/integrations-page.spec.ts
@@ -35,7 +43,7 @@ Stackiq SHALL declare `email`, `federation` and `eol-feed` in `lib/Settings/conn
### Requirement: REQ-STACKIQ-CONN-002 A save asks integriq to look again, and a run reports what it met
-When a save writes the settings of a declared connection, stackiq SHALL send `ConnectionRefreshRequestedEvent` with app `stackiq` and that key, and SHALL send it before any report for that key (hydra REQ-CONN-004, hydra#674). An email settings save SHALL then report what `SymfonyEmailService::isEmailSystemConfigured()` sees. A peer add or remove SHALL report OpenCatalogi missing as `unavailable`, and federation off or without peers as `unconfigured`. A federation pull SHALL report every peer answering as `configured`, some as `limited` and none as `error`. An EOL sync run SHALL report its recorded outcome. A message SHALL name a peer by host only. Both events SHALL be named by string and sent only when the class exists. Neither SHALL change the response of the request, job or run that sent it. No page request SHALL send an event.
+When a save writes the settings of a declared connection, stackiq SHALL send `ConnectionRefreshRequestedEvent` with app `stackiq` and that key, and SHALL send it before any report for that key (hydra REQ-CONN-004, hydra#674). An email settings save SHALL then report what `SymfonyEmailService::isEmailSystemConfigured()` sees. A peer add or remove SHALL report OpenCatalogi missing as `unavailable`, and federation without peers as `unconfigured`. Switched-off federation and a switched-off EOL sync SHALL send the refresh and no report, from a save, a pull or a run, because the row's switch says it. A federation pull SHALL report every peer answering as `configured`, some as `limited` and none as `error`. An EOL sync run SHALL report its recorded outcome. A message SHALL name a peer by host only. Both events SHALL be named by string and sent only when the class exists. Neither SHALL change the response of the request, job or run that sent it. No page request SHALL send an event.
#### Scenario: Saving email settings refreshes, then reports
@e2e exclude The event is not observable from a browser; tests/Unit/Service/ConnectionReportServiceTest.php and tests/Unit/Controller/SettingsControllerConnectionReportTest.php assert the order and the unchanged response.
@@ -70,7 +78,7 @@ When a save writes the settings of a declared connection, stackiq SHALL send `Co
### Requirement: REQ-STACKIQ-CONN-003 An admin reads the connections on an Integrations page
-Stackiq SHALL render an `index` page at `/settings/integrations` over `integriq/app_connection`, reached from the settings gear and preset to `app` equal to `stackiq` through its menu entry's `query` (hydra REQ-CONN-006). The page and its menu entry SHALL be admin only. The page SHALL require Integriq, and the menu entry SHALL only render when integriq is installed. The status column SHALL name all six statuses, `limited` included. The page SHALL NOT offer a generic Add button. Its Add integration action SHALL open `/apps/integriq/connections?app=stackiq&link=1`.
+Stackiq SHALL render an `index` page at `/settings/integrations` over `integriq/app_connection`, reached from the settings gear and preset to `app` equal to `stackiq` through its menu entry's `query` (hydra REQ-CONN-006). The page and its menu entry SHALL be admin only. The page SHALL require Integriq, and the menu entry SHALL only render when integriq is installed. The status column SHALL name all seven statuses, `limited` and `disabled` included, through the `connectionStatus` formatter `@conduction/nextcloud-vue` ships. The page SHALL NOT offer a generic Add button. Its Add integration action SHALL open `/apps/integriq/connections?app=stackiq&link=1`.
#### Scenario: The page lists only the rows of stackiq
@e2e tests/e2e/workflows/integrations-page.spec.ts
@@ -88,7 +96,7 @@ Stackiq SHALL render an `index` page at `/settings/integrations` over `integriq/
- **THEN** the browser SHALL open integriq's Connections overview with `app=stackiq` and `link=1`
#### Scenario: A connection that works in part reads Limited
-@e2e exclude Only a federation pull with a failing peer produces limited; tests/vitest/connectionRegistry.spec.js asserts the label in English and Dutch.
+@e2e exclude Only a federation pull with a failing peer produces limited; tests/vitest/connectionRegistry.spec.js asserts the status column uses the library's built-in connectionStatus, whose labels nextcloud-vue's tests/utils/builtInFormatters.spec.js (formatConnectionStatus) asserts, with Beperkt in the library's l10n/nl.json.
- **GIVEN** a row whose status is `limited`
- **WHEN** the page renders it
diff --git a/openspec/changes/adopt-connection-registry/tasks.md b/openspec/changes/adopt-connection-registry/tasks.md
index c524a3beb..bbac546b4 100644
--- a/openspec/changes/adopt-connection-registry/tasks.md
+++ b/openspec/changes/adopt-connection-registry/tasks.md
@@ -29,6 +29,11 @@
- [x] 4.1 Write `tests/e2e/workflows/integrations-page.spec.ts`.
- [x] 4.2 Install integriq in the CI `additional-apps`.
-## 5. After integriq ships
+## 5. Switch and built-in formatters (hydra#677)
-- [ ] 5.1 Run the e2e spec against an instance with both apps, then archive this change.
+- [x] 5.1 Declare `switch` on `federation` and `eol-feed`, and stop reporting `unconfigured` for a switched-off feature.
+- [x] 5.2 Move `@conduction/nextcloud-vue` to the release with the built-in connection formatters and delete the local copy.
+
+## 6. After integriq ships
+
+- [ ] 6.1 Run the e2e spec against an instance with both apps, then archive this change.
diff --git a/package-lock.json b/package-lock.json
index 9dce10ec0..f60e53540 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,7 @@
"dependencies": {
"@babel/core": "^7.22.9",
"@codemirror/lang-json": "^6.0.0",
- "@conduction/nextcloud-vue": "^2.37.0",
+ "@conduction/nextcloud-vue": "^3.2.0",
"@nextcloud/auth": "^2.6.0",
"@nextcloud/axios": "^2.5.0",
"@nextcloud/capabilities": "^1.2.1",
@@ -2202,9 +2202,9 @@
}
},
"node_modules/@conduction/nextcloud-vue": {
- "version": "2.39.0",
- "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.39.0.tgz",
- "integrity": "sha512-LmiQwc2VizxNfdzrVXF/A2NwItjIBg5DGi2EbvkMZwA8wXAgSaDWO2uant5TU+AHXotK5Csfqe0OXSe/b5qJqA==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-3.2.0.tgz",
+ "integrity": "sha512-jRKOE/xpLnsk9L8i2G6loifDJpRC+ORCsnfkpySDwAT3MRTriKDRXkc/lxfPHxXzXNeCJfiDPEEYbwFHFOUS9Q==",
"license": "EUPL-1.2",
"dependencies": {
"@ckpack/vue-color": "^1.6.0",
@@ -2221,11 +2221,10 @@
"@microsoft/fetch-event-source": "^2.0.1",
"@nextcloud/dialogs": "^7.4.1",
"@nextcloud/event-bus": "^3.3.3",
- "@nextcloud/files": "^3.12.2",
+ "@nextcloud/files": "^4.0.0",
"@nextcloud/notify_push": "^1.4.0",
"@nextcloud/password-confirmation": "^6.1.0",
"@toast-ui/editor": "^3.2.2",
- "@types/react": "^18.0.0",
"@uiw/codemirror-theme-github": "^4.25.8",
"@vue-flow/background": "^1.3.2",
"@vue-flow/core": "^1.48.2",
@@ -2235,12 +2234,11 @@
"ajv-formats": "^3.0.1",
"apexcharts": "^4.7.0",
"codemirror": "^6.0.0",
- "dompurify": "^3.0.0",
+ "commander": "^14.0.3",
"leaflet": "^1.9.0",
"leaflet.markercluster": "^1.5.3",
"linkifyjs": "^4.3.3",
"lodash": "^4.17.21",
- "marked": "^12.0.0",
"style-mod": "^4.0.0",
"vue-codemirror6": "^1.4.3",
"vue3-apexcharts": "~1.8.0",
@@ -2259,6 +2257,7 @@
"@nextcloud/initial-state": "^2.2.0 || ^3.0.0",
"@nextcloud/l10n": "^2.0.0 || ^3.0.0",
"@nextcloud/router": "^2.0.0 || ^3.0.0",
+ "@nextcloud/stylelint-config": "^3.2.2",
"@nextcloud/vue": "^9.0.0",
"@vueuse/core": "^11.0.0 || ^14.0.0",
"axe-core": "^4.10.0",
@@ -2267,20 +2266,18 @@
"eslint": "^8.56.0 || ^9.0.0 || ^10.0.0",
"eslint-plugin-vue": "^9.21.0 || ^10.0.0",
"gridstack": "^12.0.0 || ^13.0.0",
- "marked": "^12.0.0",
+ "marked": ">=12 <19",
"pinia": "^2.0.0 || ^3.0.0 || ^4.0.0",
+ "stylelint": "^17.9.1",
"vue": "^3.5.0",
"vue-eslint-parser": "^9.4.0 || ^10.0.0",
"vue-material-design-icons": "^5.0.0"
},
"peerDependenciesMeta": {
- "axe-core": {
+ "@nextcloud/stylelint-config": {
"optional": true
},
- "dexie": {
- "optional": true
- },
- "dompurify": {
+ "axe-core": {
"optional": true
},
"eslint": {
@@ -2289,7 +2286,7 @@
"eslint-plugin-vue": {
"optional": true
},
- "marked": {
+ "stylelint": {
"optional": true
},
"vue-eslint-parser": {
@@ -2297,18 +2294,6 @@
}
}
},
- "node_modules/@conduction/nextcloud-vue/node_modules/marked": {
- "version": "12.0.2",
- "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz",
- "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==",
- "license": "MIT",
- "bin": {
- "marked": "bin/marked.js"
- },
- "engines": {
- "node": ">= 18"
- }
- },
"node_modules/@csstools/color-helpers": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.1.tgz",
@@ -5275,66 +5260,6 @@
"node": "^20 || ^22 || ^24"
}
},
- "node_modules/@nextcloud/dialogs/node_modules/@nextcloud/files": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-4.0.0.tgz",
- "integrity": "sha512-TmecnZIS+PGWGtRh7RpGEboCT4K6iTbHULUcfR6hs3eEzjDVsCc1Ldf8popGY/70lbpdlfYle8xbXnPIo3qaXA==",
- "license": "AGPL-3.0-or-later",
- "dependencies": {
- "@nextcloud/auth": "^2.5.3",
- "@nextcloud/capabilities": "^1.2.1",
- "@nextcloud/l10n": "^3.4.1",
- "@nextcloud/logger": "^3.0.3",
- "@nextcloud/paths": "^3.0.0",
- "@nextcloud/router": "^3.1.0",
- "@nextcloud/sharing": "^0.3.0",
- "is-svg": "^6.1.0",
- "typescript-event-target": "^1.1.2",
- "webdav": "^5.9.0"
- },
- "engines": {
- "node": "^24.0.0"
- }
- },
- "node_modules/@nextcloud/dialogs/node_modules/@nextcloud/files/node_modules/@nextcloud/files": {
- "version": "3.12.2",
- "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.2.tgz",
- "integrity": "sha512-vBo8tf3Xh6efiF8CrEo3pKj9AtvAF6RdDGO1XKL65IxV8+UUd9Uxl2lUExHlzoDRRczCqfGfaWfRRaFhYqce5Q==",
- "license": "AGPL-3.0-or-later",
- "optional": true,
- "dependencies": {
- "@nextcloud/auth": "^2.5.3",
- "@nextcloud/capabilities": "^1.2.1",
- "@nextcloud/l10n": "^3.4.1",
- "@nextcloud/logger": "^3.0.3",
- "@nextcloud/paths": "^3.0.0",
- "@nextcloud/router": "^3.1.0",
- "@nextcloud/sharing": "^0.3.0",
- "cancelable-promise": "^4.3.1",
- "is-svg": "^6.1.0",
- "typescript-event-target": "^1.1.1",
- "webdav": "^5.8.0"
- },
- "engines": {
- "node": "^20.0.0 || ^22.0.0 || ^24.0.0"
- }
- },
- "node_modules/@nextcloud/dialogs/node_modules/@nextcloud/files/node_modules/@nextcloud/sharing": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@nextcloud/sharing/-/sharing-0.3.0.tgz",
- "integrity": "sha512-kV7qeUZvd1fTKeFyH+W5Qq5rNOqG9rLATZM3U9MBxWXHJs3OxMqYQb8UQ3NYONzsX3zDGJmdQECIGHm1ei2sCA==",
- "license": "GPL-3.0-or-later",
- "dependencies": {
- "@nextcloud/initial-state": "^3.0.0",
- "is-svg": "^6.1.0"
- },
- "engines": {
- "node": "^20.0.0 || ^22.0.0 || ^24.0.0"
- },
- "optionalDependencies": {
- "@nextcloud/files": "^3.12.0"
- }
- },
"node_modules/@nextcloud/eslint-config": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/@nextcloud/eslint-config/-/eslint-config-9.0.1.tgz",
@@ -5402,10 +5327,32 @@
}
},
"node_modules/@nextcloud/files": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-4.0.0.tgz",
+ "integrity": "sha512-TmecnZIS+PGWGtRh7RpGEboCT4K6iTbHULUcfR6hs3eEzjDVsCc1Ldf8popGY/70lbpdlfYle8xbXnPIo3qaXA==",
+ "license": "AGPL-3.0-or-later",
+ "dependencies": {
+ "@nextcloud/auth": "^2.5.3",
+ "@nextcloud/capabilities": "^1.2.1",
+ "@nextcloud/l10n": "^3.4.1",
+ "@nextcloud/logger": "^3.0.3",
+ "@nextcloud/paths": "^3.0.0",
+ "@nextcloud/router": "^3.1.0",
+ "@nextcloud/sharing": "^0.3.0",
+ "is-svg": "^6.1.0",
+ "typescript-event-target": "^1.1.2",
+ "webdav": "^5.9.0"
+ },
+ "engines": {
+ "node": "^24.0.0"
+ }
+ },
+ "node_modules/@nextcloud/files/node_modules/@nextcloud/files": {
"version": "3.12.2",
"resolved": "https://registry.npmjs.org/@nextcloud/files/-/files-3.12.2.tgz",
"integrity": "sha512-vBo8tf3Xh6efiF8CrEo3pKj9AtvAF6RdDGO1XKL65IxV8+UUd9Uxl2lUExHlzoDRRczCqfGfaWfRRaFhYqce5Q==",
"license": "AGPL-3.0-or-later",
+ "optional": true,
"dependencies": {
"@nextcloud/auth": "^2.5.3",
"@nextcloud/capabilities": "^1.2.1",
@@ -6927,22 +6874,6 @@
"undici-types": "~8.3.0"
}
},
- "node_modules/@types/prop-types": {
- "version": "15.7.15",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
- "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
- "license": "MIT"
- },
- "node_modules/@types/react": {
- "version": "18.3.31",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz",
- "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==",
- "license": "MIT",
- "dependencies": {
- "@types/prop-types": "*",
- "csstype": "^3.2.2"
- }
- },
"node_modules/@types/semver": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz",
@@ -9536,7 +9467,8 @@
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/cancelable-promise/-/cancelable-promise-4.3.1.tgz",
"integrity": "sha512-A/8PwLk/T7IJDfUdQ68NR24QHa8rIlnN/stiJEBo6dmVUkD4K14LswG0w3VwdeK/o7qOwRUR1k2MhK5Rpy2m7A==",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true
},
"node_modules/caniuse-lite": {
"version": "1.0.30001810",
@@ -9878,7 +9810,6 @@
"version": "14.0.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
"integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=20"
diff --git a/package.json b/package.json
index 3f80fbe12..2e4d53577 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
"dependencies": {
"@babel/core": "^7.22.9",
"@codemirror/lang-json": "^6.0.0",
- "@conduction/nextcloud-vue": "^2.37.0",
+ "@conduction/nextcloud-vue": "^3.2.0",
"@nextcloud/auth": "^2.6.0",
"@nextcloud/axios": "^2.5.0",
"@nextcloud/capabilities": "^1.2.1",
diff --git a/src/App.vue b/src/App.vue
index 83e9381f7..1987ef141 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -22,7 +22,6 @@
:customComponents="customComponents"
:registry="registry"
:pageTypes="pageTypes"
- :formatters="formatters"
appId="stackiq"
:translate="translateForApp"
:permissions="permissions"
@@ -76,7 +75,6 @@ import OrganisationSwitcher from './components/organisations/OrganisationSwitche
import Dialogs from './dialogs/Dialogs.vue'
import Modals from './modals/Modals.vue'
import { setActiveOrganisationUuid } from './composables/orClient.js'
-import { createConnectionFormatters } from './services/connectionRegistry.js'
import { settingsStore } from './store/store.js'
export default {
@@ -150,17 +148,6 @@ export default {
data() {
return {
- /**
- * Named cell formatters merged over CnAppRoot's built-ins.
- * `connectionStatus` and `connectionSettingsLabel` render the
- * Integrations page (adopt-connection-registry); nextcloud-vue
- * 2.39.0 ships neither as a built-in. Before this change the app
- * passed no formatters at all.
- */
- formatters: createConnectionFormatters((source) =>
- ncT('stackiq', source),
- ),
-
objectSidebarState: reactive({
active: false,
open: true,
diff --git a/src/services/connectionRegistry.js b/src/services/connectionRegistry.js
index 081d40bf5..af895e94a 100644
--- a/src/services/connectionRegistry.js
+++ b/src/services/connectionRegistry.js
@@ -2,15 +2,14 @@
// Copyright (C) 2026 Conduction B.V.
/**
- * The Integrations page's two formatters and its Add integration handler.
+ * The Integrations page's Add integration handler.
*
* The rows on that page are integriq's `app_connection` objects (hydra change
- * connection-registry, design D8). The installed @conduction/nextcloud-vue
- * 2.39.0 ships neither formatter, so stackiq carries this copy until a
- * release with the built-ins is pinned. The names are the contract's, so the
- * copies across the fleet stay interchangeable.
+ * connection-registry, design D8). Its two formatters, `connectionStatus` and
+ * `connectionSettingsLabel`, are built into @conduction/nextcloud-vue from
+ * 3.2.0, so CnAppRoot supplies them and stackiq no longer carries a copy.
*
- * Pure: the translator, the URL builder and the navigation are passed in, so
+ * Pure: the URL builder and the navigation are passed in, so
* the module runs under vitest's node environment with nothing mocked.
*
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
@@ -23,62 +22,6 @@
export const INTEGRIQ_CONNECTIONS_PATH =
'/apps/integriq/connections?app=stackiq&link=1'
-/**
- * The English label for each of the six registry statuses (design D3).
- *
- * `limited` came with hydra#673: the connection works in part.
- */
-export const CONNECTION_STATUS_LABELS = Object.freeze({
- configured: 'Configured',
- limited: 'Limited',
- unconfigured: 'Not configured',
- simulated: 'Simulated',
- unavailable: 'Not available',
- error: 'Error',
-})
-
-/**
- * Build the two connection formatters around a translator.
- *
- * @param {function(string): string} translate Translates an English source string for this app.
- * @return {{connectionStatus: function(unknown): string, connectionSettingsLabel: function(unknown): string}} The formatters, keyed by their manifest names.
- * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
- */
-export function createConnectionFormatters(translate) {
- return {
- /**
- * The label for a status. An unknown value renders itself, because a
- * status the app cannot name is still a status the admin should see.
- *
- * @param {unknown} value The row's `status`.
- * @return {string} The label, the raw value, or '' when missing.
- * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
- */
- connectionStatus(value) {
- const source =
- typeof value === 'string'
- && Object.hasOwn(CONNECTION_STATUS_LABELS, value)
- ? CONNECTION_STATUS_LABELS[value]
- : null
- return source ? translate(source) : String(value ?? '')
- },
-
- /**
- * The Open settings link text, or '' when the row has nowhere to send a
- * reader. An empty text makes the link cell fall through to plain text.
- *
- * @param {unknown} value The row's `settingsUrl`.
- * @return {string} The link text, or ''.
- * @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
- */
- connectionSettingsLabel(value) {
- return typeof value === 'string' && value.length > 0
- ? translate('Open settings')
- : ''
- },
- }
-}
-
/**
* Build the Add integration header-action handler.
*
diff --git a/tests/Unit/Service/ConnectionReportCallersTest.php b/tests/Unit/Service/ConnectionReportCallersTest.php
index 449b06082..153ac5fa6 100644
--- a/tests/Unit/Service/ConnectionReportCallersTest.php
+++ b/tests/Unit/Service/ConnectionReportCallersTest.php
@@ -226,15 +226,13 @@ private function eol(?ConnectionReportService $reports, bool $enabled): EolSyncS
}//end eol()
/**
- * An EOL settings save hands the saved config to the reporter.
+ * An EOL settings save asks the reporter for a refresh.
*
* @return void
*/
public function testAnEolSaveAsksForARefresh(): void {
$reports = $this->reporter();
- $reports->expects($this->once())->method('eolSyncConfigSaved')->with(
- $this->callback(callback: static fn (array $config): bool => $config['enabled'] === false && $config['register'] === 'integriq')
- );
+ $reports->expects($this->once())->method('eolSyncConfigSaved')->with();
$result = $this->eol(reports: $reports, enabled: false)->updateConfig(['enabled' => false]);
diff --git a/tests/Unit/Service/ConnectionReportServiceTest.php b/tests/Unit/Service/ConnectionReportServiceTest.php
index 9afe6d45e..391deb02c 100644
--- a/tests/Unit/Service/ConnectionReportServiceTest.php
+++ b/tests/Unit/Service/ConnectionReportServiceTest.php
@@ -235,7 +235,7 @@ public function testAFailingEmailReadNeverEscapes(): void {
}//end testAFailingEmailReadNeverEscapes()
/**
- * A peer change refreshes, and reports only a state that blocks federation.
+ * A peer change refreshes, and reports only a state that blocks federation, never the switch.
*
* @return void
*/
@@ -243,7 +243,8 @@ public function testAPeerChangeReportsOnlyABlockingState(): void {
$service = $this->service();
$service->federationPeersChanged(status: ['available' => false, 'enabled' => true, 'peers' => [['url' => 'https://a.example']]]);
- $service->federationPeersChanged(status: ['available' => true, 'enabled' => false, 'peers' => [['url' => 'https://a.example']]]);
+ // Off with no peers: the switch outranks "no peer catalog", so nothing is reported.
+ $service->federationPeersChanged(status: ['available' => true, 'enabled' => false, 'peers' => []]);
$service->federationPeersChanged(status: ['available' => true, 'enabled' => true, 'peers' => []]);
$this->assertFalse(
condition: $service->federationPeersChanged(status: ['available' => true, 'enabled' => true, 'peers' => [['url' => 'https://a.example']]])
@@ -254,7 +255,6 @@ public function testAPeerChangeReportsOnlyABlockingState(): void {
'refresh:federation',
'report:federation:unavailable',
'refresh:federation',
- 'report:federation:unconfigured',
'refresh:federation',
'report:federation:unconfigured',
'refresh:federation',
@@ -262,8 +262,7 @@ public function testAPeerChangeReportsOnlyABlockingState(): void {
actual: $this->sentSummary()
);
$this->assertStringContainsString(needle: 'OpenCatalogi', haystack: $this->sent[1]->message);
- $this->assertStringContainsString(needle: 'federation_enabled', haystack: $this->sent[3]->message);
- $this->assertStringContainsString(needle: 'no peer catalog', haystack: $this->sent[5]->message);
+ $this->assertStringContainsString(needle: 'no peer catalog', haystack: $this->sent[4]->message);
}//end testAPeerChangeReportsOnlyABlockingState()
/**
@@ -284,7 +283,10 @@ public function testAPullMapsItsOutcome(): void {
actual: $service->describePull(pull: ['ok' => true, 'peers' => [['peer' => 'https://a.example'] + $ok]])
);
$this->assertSame(expected: 'unconfigured', actual: $service->describePull(pull: ['ok' => true, 'peers' => []])[0]);
- $this->assertSame(expected: 'unconfigured', actual: $service->describePull(pull: ['ok' => false, 'reason' => 'federation disabled'])[0]);
+ $this->assertNull(
+ actual: $service->describePull(pull: ['ok' => false, 'reason' => 'federation disabled']),
+ message: 'the federation switch reads a switched-off pull, so nothing is reported'
+ );
$this->assertSame(expected: 'unavailable', actual: $service->describePull(pull: ['ok' => false, 'reason' => 'OpenCatalogi unavailable'])[0]);
$this->assertSame(
expected: ['error', 'The last federation pull failed: something else'],
@@ -345,33 +347,38 @@ public function testAPullMessageCarriesOnlyTheHostAndAShortReason(): void {
* @return void
*/
public function testAPullReportsWithoutARefresh(): void {
- $this->assertTrue(condition: $this->service()->federationPulled(pull: ['ok' => false, 'reason' => 'federation disabled']));
- $this->assertSame(expected: ['report:federation:unconfigured'], actual: $this->sentSummary());
+ $service = $this->service();
+
+ $this->assertFalse(condition: $service->federationPulled(pull: ['ok' => false, 'reason' => 'federation disabled']));
+ $this->assertTrue(condition: $service->federationPulled(pull: ['ok' => false, 'reason' => 'OpenCatalogi unavailable']));
+ $this->assertSame(expected: ['report:federation:unavailable'], actual: $this->sentSummary());
}//end testAPullReportsWithoutARefresh()
/**
- * An EOL settings save refreshes, and reports only a switched-off sync.
+ * An EOL settings save refreshes and reports nothing, and a switched-off run reports nothing.
+ *
+ * The `eol-feed` switch reads `enabled` inside `eol_sync_config`, so
+ * integriq resolves `disabled` itself.
*
* @return void
*/
- public function testAnEolSaveReportsOnlyASwitchedOffSync(): void {
+ public function testAnEolSaveOnlyRefreshes(): void {
$service = $this->service();
- $this->assertTrue(condition: $service->eolSyncConfigSaved(config: ['enabled' => false]));
- $this->assertFalse(condition: $service->eolSyncConfigSaved(config: ['enabled' => true]));
+ $this->assertTrue(condition: $service->eolSyncConfigSaved());
+ $this->assertFalse(condition: $service->eolSyncRan(runStatus: ['available' => false, 'reason' => 'disabled']));
- $this->assertSame(expected: ['refresh:eol-feed', 'report:eol-feed:unconfigured', 'refresh:eol-feed'], actual: $this->sentSummary());
- }//end testAnEolSaveReportsOnlyASwitchedOffSync()
+ $this->assertSame(expected: ['refresh:eol-feed'], actual: $this->sentSummary());
+ }//end testAnEolSaveOnlyRefreshes()
/**
- * Every reason EolSyncService records maps to a status, and an unknown one reads error.
+ * Every reason EolSyncService records maps to a status, a switched-off sync to nothing, and an unknown one reads error.
*
* @return void
*/
public function testEachEolRunOutcomeMapsToTheDesignedStatus(): void {
$service = $this->service();
$expected = [
- 'disabled' => 'unconfigured',
'openregister-not-installed' => 'unavailable',
'object-service-unavailable' => 'error',
'module-schema-not-configured' => 'unconfigured',
@@ -386,6 +393,7 @@ public function testEachEolRunOutcomeMapsToTheDesignedStatus(): void {
);
}
+ $this->assertNull(actual: $service->describeEolRun(runStatus: ['available' => false, 'reason' => 'disabled']));
$this->assertStringContainsString(
needle: 'endoflife.date source in integriq',
haystack: $service->describeEolRun(runStatus: ['available' => false, 'reason' => 'eol-register-or-schema-not-found'])[1]
@@ -413,7 +421,7 @@ public function testTheEolReasonsAreTheOnesTheSyncRecords(): void {
$recorded = array_values(array_unique($matches[1]));
sort($recorded);
- $known = array_keys(ConnectionReportService::EOL_REASONS);
+ $known = [...array_keys(ConnectionReportService::EOL_REASONS), ConnectionReportService::EOL_REASON_SWITCHED_OFF];
sort($known);
$this->assertNotSame(expected: [], actual: $recorded);
@@ -435,8 +443,8 @@ public function testWithoutIntegriqNothingIsSentOrLogged(): void {
$this->assertFalse(condition: $service->emailSettingsSaved());
$this->assertFalse(condition: $service->federationPeersChanged(status: ['available' => false]));
$this->assertFalse(condition: $service->federationPulled(pull: ['ok' => false, 'reason' => 'federation disabled']));
- $this->assertFalse(condition: $service->eolSyncConfigSaved(config: ['enabled' => false]));
- $this->assertFalse(condition: $service->eolSyncRan(runStatus: ['available' => false, 'reason' => 'disabled']));
+ $this->assertFalse(condition: $service->eolSyncConfigSaved());
+ $this->assertFalse(condition: $service->eolSyncRan(runStatus: ['available' => false, 'reason' => 'object-service-unavailable']));
}//end testWithoutIntegriqNothingIsSentOrLogged()
/**
@@ -483,7 +491,7 @@ public function testAThrowingListenerNeverEscapes(): void {
$service = new ConnectionReportService(eventDispatcher: $dispatcher, emailService: $this->emailService, logger: $this->logger);
- $this->assertFalse(condition: $service->eolSyncRan(runStatus: ['available' => false, 'reason' => 'disabled']));
- $this->assertFalse(condition: $service->eolSyncConfigSaved(config: ['enabled' => true]));
+ $this->assertFalse(condition: $service->eolSyncRan(runStatus: ['available' => false, 'reason' => 'object-service-unavailable']));
+ $this->assertFalse(condition: $service->eolSyncConfigSaved());
}//end testAThrowingListenerNeverEscapes()
}//end class
diff --git a/tests/Unit/Settings/ConnectionsDeclarationTest.php b/tests/Unit/Settings/ConnectionsDeclarationTest.php
index 9b82677b9..9dad4350f 100644
--- a/tests/Unit/Settings/ConnectionsDeclarationTest.php
+++ b/tests/Unit/Settings/ConnectionsDeclarationTest.php
@@ -36,10 +36,12 @@
*
* The rules mirror integriq's `lib/Settings/connections.schema.json` on
* `development` field for field, including the hydra#673 amendments
- * (`adapter.jsonPath`, `adapter.simulatedValues`, `reportedOnly`). That schema
- * is not a dependency of this repo, so the rules are restated here. The file
- * was also validated against the schema itself, fetched from integriq
- * `development` with `gh api`, when this test was written.
+ * (`adapter.jsonPath`, `adapter.simulatedValues`, `reportedOnly`) and the
+ * hydra#677 ones (`switch`, `disabledMessage`). That schema is not a
+ * dependency of this repo, so the rules are restated here. The file was also
+ * validated against the schema itself, fetched from integriq `development`
+ * with `gh api` (last changed in 64b437fc2df24827985ce6e919fe5e47c5205617,
+ * integriq#2024), when each amendment was adopted.
*
* @coversNothing
*/
@@ -61,6 +63,8 @@ class ConnectionsDeclarationTest extends TestCase {
'reportedOnly' => 'boolean',
'available' => 'boolean',
'unavailableMessage' => 'string',
+ 'switch' => 'array',
+ 'disabledMessage' => 'string',
'unconfiguredMessage' => 'string',
'sourceTemplate' => 'string',
];
@@ -77,6 +81,17 @@ class ConnectionsDeclarationTest extends TestCase {
'simulatedMessage' => 'string',
];
+ /**
+ * The fields the schema allows inside `switch`, with their JSON type.
+ *
+ * @var array
+ */
+ private const SWITCH_FIELD_TYPES = [
+ 'configKey' => 'string',
+ 'jsonPath' => 'string',
+ 'offValues' => 'array',
+ ];
+
/**
* The three connections, in page order.
*
@@ -190,6 +205,11 @@ public function testEveryEntryHasTheShapeIntegriqValidates(): void {
$this->assertSame(expected: self::FIELD_TYPES[$field], actual: $this->jsonType(value: $value), message: $key . '.' . $field);
}
+ foreach (($connection['switch'] ?? []) as $field => $value) {
+ $this->assertArrayHasKey(key: $field, array: self::SWITCH_FIELD_TYPES, message: $key . '.switch.' . $field . ' is not a schema field');
+ $this->assertSame(expected: self::SWITCH_FIELD_TYPES[$field], actual: $this->jsonType(value: $value), message: $key . '.switch.' . $field);
+ }
+
foreach (($connection['adapter'] ?? []) as $field => $value) {
$this->assertArrayHasKey(key: $field, array: self::ADAPTER_FIELD_TYPES, message: $key . '.adapter.' . $field . ' is not a schema field');
$this->assertSame(expected: self::ADAPTER_FIELD_TYPES[$field], actual: $this->jsonType(value: $value), message: $key . '.adapter.' . $field);
@@ -285,8 +305,9 @@ public function testOnlyTheNullTransportReadsSimulated(): void {
/**
* Federation and the end-of-life feed are reported only, and neither guesses from settings.
*
- * `federation_enabled` is a boolean key, which integriq's reader counts as
- * filled whatever it holds, and `eol_sync_config` is filled after any save.
+ * A filled `federation_enabled` or `eol_sync_config` says the feature may
+ * run, not that a peer or the feed answered, so neither is required config.
+ * Each carries its on/off setting as a `switch` instead.
*
* @return void
*/
@@ -304,6 +325,34 @@ public function testFederationAndTheFeedAreReportedOnly(): void {
$this->assertArrayNotHasKey(key: 'requiredConfig', array: $byKey['email']);
}//end testFederationAndTheFeedAreReportedOnly()
+ /**
+ * Federation and the end-of-life sync are switched off through the settings stackiq reads.
+ *
+ * Neither switch lists `offValues`, so integriq reads it as off when the
+ * value is empty: unset, `false`, `0`, or a missing `enabled` inside the
+ * blob (hydra connection-registry D2, D4 rule 2b, D12 items 6 and 7). Both
+ * defaults in the code are off, so an unset key reading off is the truth.
+ *
+ * @return void
+ */
+ public function testFederationAndTheSyncDeclareTheirSwitches(): void {
+ $byKey = $this->connectionsByKey();
+
+ $this->assertSame(expected: ['configKey' => 'federation_enabled'], actual: $byKey['federation']['switch']);
+ $this->assertSame(expected: ['configKey' => 'eol_sync_config', 'jsonPath' => 'enabled'], actual: $byKey['eol-feed']['switch']);
+ $this->assertArrayNotHasKey(key: 'switch', array: $byKey['email']);
+ foreach (['federation', 'eol-feed'] as $key) {
+ $this->assertStringContainsString(needle: 'switched off', haystack: $byKey[$key]['disabledMessage'], message: $key);
+ }
+
+ $federation = (string) file_get_contents($this->root() . '/lib/Service/Federation/FederationConfig.php');
+ $this->assertStringContainsString(needle: "getValueBool(Application::APP_ID, 'federation_enabled', false)", haystack: $federation);
+
+ $settings = (string) file_get_contents($this->root() . '/lib/Service/SettingsService.php');
+ $this->assertStringContainsString(needle: "EOL_SYNC_CONFIG_KEY = 'eol_sync_config'", haystack: $settings);
+ $this->assertStringContainsString(needle: "'enabled' => (\$decoded['enabled'] ?? false) === true", haystack: $settings);
+ }//end testFederationAndTheSyncDeclareTheirSwitches()
+
/**
* The end-of-life feed offers integriq's endoflife.date source.
*
diff --git a/tests/vitest/connectionRegistry.spec.js b/tests/vitest/connectionRegistry.spec.js
index 8853490a3..3e25f0e34 100644
--- a/tests/vitest/connectionRegistry.spec.js
+++ b/tests/vitest/connectionRegistry.spec.js
@@ -1,3 +1,4 @@
+// @vitest-environment jsdom
/**
* SPDX-License-Identifier: EUPL-1.2
* SPDX-FileCopyrightText: 2026 Conduction B.V.
@@ -9,16 +10,23 @@
* one icon by NAME. A misspelled name renders a raw enum, no glyph, or an Add
* integration that does nothing, and none of them logs a thing. So this spec
* reads the real fragment and checks every name against what has to answer it.
+ * The two formatters are @conduction/nextcloud-vue built-ins since 3.2.0, so
+ * their names are checked against the installed library, not a local copy.
+ *
+ * The library's map is IMPORTED and called, not read as text. A regex over the
+ * module source answers about the file on disk, which is one step beside the
+ * question: whether the formatter the page resolves actually returns the label.
+ * The import reaches @nextcloud/auth through formatMetric, which wants a
+ * `window`, so this file runs on jsdom rather than the suite's default node.
*
* @spec openspec/changes/adopt-connection-registry/specs/admin-integrations/spec.md#requirement-req-stackiq-conn-003-an-admin-reads-the-connections-on-an-integrations-page
*/
+import { BUILT_IN_FORMATTERS } from '@conduction/nextcloud-vue/src/utils/builtInFormatters.js'
import * as fs from 'fs'
import * as path from 'path'
import { describe, expect, it } from 'vitest'
import {
- CONNECTION_STATUS_LABELS,
- createConnectionFormatters,
createConnectionHandlers,
INTEGRIQ_CONNECTIONS_PATH,
} from '../../src/services/connectionRegistry.js'
@@ -29,60 +37,23 @@ const fragment = JSON.parse(read('src', 'manifest.d', 'connection-registry.json'
const page = fragment.pages.find((p) => p.id === 'Integrations')
const menu = fragment.menu.find((m) => m.id === 'IntegrationsMenu')
-/** A translator that marks what it translated, so a missing call shows. */
-const translate = (source) => `t:${source}`
-
-describe('connection formatters', () => {
- const formatters = createConnectionFormatters(translate)
-
- it('labels all six statuses, limited included', () => {
- expect(Object.keys(CONNECTION_STATUS_LABELS).sort()).toEqual([
- 'configured',
- 'error',
- 'limited',
- 'simulated',
- 'unavailable',
- 'unconfigured',
- ])
- expect(formatters.connectionStatus('configured')).toBe('t:Configured')
- expect(formatters.connectionStatus('limited')).toBe('t:Limited')
- expect(formatters.connectionStatus('unconfigured')).toBe('t:Not configured')
- expect(formatters.connectionStatus('simulated')).toBe('t:Simulated')
- expect(formatters.connectionStatus('unavailable')).toBe('t:Not available')
- expect(formatters.connectionStatus('error')).toBe('t:Error')
- })
-
- // A connection that works in part is neither working nor broken, so it must
- // not borrow either label.
- it('keeps limited apart from configured, not available and error', () => {
- const limited = formatters.connectionStatus('limited')
- expect(limited).not.toBe(formatters.connectionStatus('configured'))
- expect(limited).not.toBe(formatters.connectionStatus('unavailable'))
- expect(limited).not.toBe(formatters.connectionStatus('error'))
- })
-
- it('renders an unknown status as itself and a missing one as empty', () => {
- expect(formatters.connectionStatus('degraded')).toBe('degraded')
- expect(formatters.connectionStatus('toString')).toBe('toString')
- expect(formatters.connectionStatus(null)).toBe('')
- expect(formatters.connectionStatus(undefined)).toBe('')
- })
-
- it('offers Open settings only when the row has a settings link', () => {
- expect(formatters.connectionSettingsLabel('/settings/admin/stackiq')).toBe(
- 't:Open settings',
- )
- expect(formatters.connectionSettingsLabel('')).toBe('')
- expect(formatters.connectionSettingsLabel(undefined)).toBe('')
- expect(formatters.connectionSettingsLabel(null)).toBe('')
- })
+/**
+ * The formatter registry CnAppRoot provides, built the way CnAppRoot builds it:
+ * the library's built-ins under whatever the app passes in its `formatters`
+ * prop. A same-named local formatter wins, which is why stackiq passes none.
+ *
+ * @param {object} appFormatters What the app hands CnAppRoot. Empty by default.
+ * @return {object} The merged registry, keyed by formatter name.
+ */
+function shellFormatterRegistry(appFormatters = {}) {
+ return { ...BUILT_IN_FORMATTERS, ...appFormatters }
+}
- it('ships an English and a Dutch catalogue entry for every label the page shows', () => {
+describe('connection strings', () => {
+ it('ships an English and a Dutch catalogue entry for every label the page declares', () => {
const en = JSON.parse(read('l10n', 'en.json')).translations
const nl = JSON.parse(read('l10n', 'nl.json')).translations
const labels = [
- ...Object.values(CONNECTION_STATUS_LABELS),
- 'Open settings',
page.title,
menu.label,
page.config.folderSidebar.allLabel,
@@ -93,9 +64,6 @@ describe('connection formatters', () => {
expect(en[label], `en: ${label}`).toBe(label)
expect(nl[label], `nl: ${label}`).toBeTruthy()
}
- expect(nl.Limited).toBe('Beperkt')
- // The browser reads the .js catalogue, never the .json one.
- expect(read('l10n', 'nl.js')).toContain('"Limited": "Beperkt"')
})
})
@@ -144,31 +112,59 @@ describe('the Integrations page declaration', () => {
expect(menu.visibleIf).toEqual({ appInstalled: 'integriq' })
})
- it('names only formatters and handlers that exist, and wires both into the app', () => {
- const formatters = createConnectionFormatters(translate)
+ it('names only formatters the library ships and handlers that exist, and wires the handler into the app', () => {
+ const registry = shellFormatterRegistry()
const handlers = createConnectionHandlers({
generateUrl: (p) => p,
assign: () => {},
})
- for (const column of page.config.columns.filter((c) => c.formatter)) {
- expect(typeof formatters[column.formatter], column.formatter).toBe(
- 'function',
- )
+ expect(typeof registry.date, 'the built-in formatter map was read').toBe(
+ 'function',
+ )
+ const named = page.config.columns
+ .filter((c) => c.formatter)
+ .map((c) => c.formatter)
+ expect(named.sort()).toEqual(['connectionSettingsLabel', 'connectionStatus'])
+ for (const formatter of named) {
+ expect(
+ typeof registry[formatter],
+ `@conduction/nextcloud-vue ships ${formatter}`,
+ ).toBe('function')
}
for (const action of page.config.headerActions) {
expect(typeof handlers[action.handler], action.handler).toBe('function')
}
- expect(read('src', 'App.vue')).toContain(':formatters="formatters"')
- expect(read('src', 'App.vue')).toContain(
- 'formatters: createConnectionFormatters(',
- )
expect(read('src', 'customComponents.js')).toMatch(
/^\t\.\.\.createConnectionHandlers\(\{$/m,
)
})
+ // The library labels all seven statuses. A copy of the formatter passed to
+ // CnAppRoot would win over the built-in and could predate `disabled`, which
+ // is the status the federation and eol-feed switches introduce.
+ it('lets the library label the statuses, disabled included', () => {
+ const registry = shellFormatterRegistry()
+
+ expect(registry.connectionStatus('disabled')).toBe('Switched off')
+ expect(registry.connectionStatus('unconfigured')).toBe('Not configured')
+ expect(registry.connectionStatus('configured')).toBe('Configured')
+ })
+
+ // THE SHADOW. CnAppRoot merges `{ ...BUILT_IN_FORMATTERS, ...formatters }`,
+ // so a local formatter under either name silently replaces the built-in and
+ // nothing logs. stackiq passes no formatters at all, and this states what
+ // that buys: the built-in is what the Status column resolves.
+ it('passes CnAppRoot no formatters, so nothing shadows the built-ins', () => {
+ const shadow = shellFormatterRegistry({
+ connectionStatus: () => 'a local copy answered',
+ })
+
+ expect(shadow.connectionStatus('disabled')).toBe('a local copy answered')
+ expect(read('src', 'App.vue')).not.toContain(':formatters=')
+ })
+
it('names an icon src/icons.js registers', () => {
const icons = read('src', 'icons.js')
for (const icon of [
From 07352a4fa19ad43c3abcdbbfac37e6c760b04031 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Wed, 16 Sep 2026 22:24:10 +0200
Subject: [PATCH 07/45] fix(e2e): find connection rows by their cell, not by an
anchored row name (#1056)
A row's accessible name starts with its Select row checkbox, so the anchored pattern matched 0 rows (keepiq#717). Rows are now matched through their Connection cell.
---
tests/e2e/workflows/integrations-page.spec.ts | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/tests/e2e/workflows/integrations-page.spec.ts b/tests/e2e/workflows/integrations-page.spec.ts
index 95b4053cf..c076586c0 100644
--- a/tests/e2e/workflows/integrations-page.spec.ts
+++ b/tests/e2e/workflows/integrations-page.spec.ts
@@ -99,9 +99,14 @@ test.describe('Integrations over the connection registry', () => {
}
await openIntegrations(page)
+ // Match a row through its Connection cell. A row's accessible name
+ // starts with its "Select row" checkbox, so a name anchored on the
+ // title can never match (keepiq#717).
for (const { title } of DECLARED) {
await expect(
- page.getByRole('row', { name: new RegExp(`^${title}\\b`, 'i') }),
+ page.getByRole('row').filter({
+ has: page.getByRole('cell', { name: title, exact: true }),
+ }),
).toHaveCount(1)
}
})
From 24ebea1d4a2deda16a585167160086b880f247c8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 18 Sep 2026 09:19:28 +0200
Subject: [PATCH 08/45] chore(deps-dev): bump eslint from 10.9.1 to 10.10.0
(#1047)
Bumps [eslint](https://github.com/eslint/eslint) from 10.9.1 to 10.10.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.9.1...v10.10.0)
---
updated-dependencies:
- dependency-name: eslint
dependency-version: 10.10.0
dependency-type: direct:development
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
package-lock.json | 156 ++++++++++++----------------------------------
package.json | 2 +-
2 files changed, 41 insertions(+), 117 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index f60e53540..812e36160 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -71,7 +71,7 @@
"ajv-formats": "^3.0.1",
"browserslist": "^4.28.9",
"caniuse-lite": "^1.0.30001810",
- "eslint": "^10.8.1",
+ "eslint": "^10.10.0",
"eslint-config-prettier": "^10.1.8",
"eslint-webpack-plugin": "^6.0.0",
"espree": "^11.0.0",
@@ -1987,33 +1987,6 @@
"keyv": "^5.6.0"
}
},
- "node_modules/@cacheable/memory/node_modules/@keyv/bigmap": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz",
- "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "hashery": "^1.4.0",
- "hookified": "^1.15.0"
- },
- "engines": {
- "node": ">= 18"
- },
- "peerDependencies": {
- "keyv": "^5.6.0"
- }
- },
- "node_modules/@cacheable/memory/node_modules/keyv": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz",
- "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@keyv/serialize": "^1.1.1"
- }
- },
"node_modules/@cacheable/utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz",
@@ -2025,16 +1998,6 @@
"keyv": "^5.6.0"
}
},
- "node_modules/@cacheable/utils/node_modules/keyv": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz",
- "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@keyv/serialize": "^1.1.1"
- }
- },
"node_modules/@ckpack/vue-color": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@ckpack/vue-color/-/vue-color-1.6.0.tgz",
@@ -2792,9 +2755,9 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz",
- "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==",
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz",
+ "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -5044,6 +5007,23 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@keyv/bigmap": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz",
+ "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hashery": "^1.4.0",
+ "hookified": "^1.15.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "keyv": "^5.6.0"
+ }
+ },
"node_modules/@keyv/serialize": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz",
@@ -5915,7 +5895,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5936,7 +5915,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5957,7 +5935,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5978,7 +5955,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -5999,7 +5975,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -6020,7 +5995,6 @@
"cpu": [
"arm"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -6041,7 +6015,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -6062,7 +6035,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -6083,7 +6055,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -6104,7 +6075,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -6125,7 +6095,6 @@
"cpu": [
"arm64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -6146,7 +6115,6 @@
"cpu": [
"x64"
],
- "dev": true,
"license": "MIT",
"optional": true,
"os": [
@@ -9386,16 +9354,6 @@
"qified": "^0.10.1"
}
},
- "node_modules/cacheable/node_modules/keyv": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz",
- "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@keyv/serialize": "^1.1.1"
- }
- },
"node_modules/call-bind": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
@@ -11080,9 +11038,9 @@
}
},
"node_modules/eslint": {
- "version": "10.9.1",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.9.1.tgz",
- "integrity": "sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==",
+ "version": "10.10.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.10.0.tgz",
+ "integrity": "sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw==",
"dev": true,
"license": "MIT",
"workspaces": [
@@ -11094,7 +11052,7 @@
"@eslint/config-array": "^0.23.5",
"@eslint/config-helpers": "^0.7.0",
"@eslint/core": "^1.2.1",
- "@eslint/plugin-kit": "^0.7.2",
+ "@eslint/plugin-kit": "^0.7.3",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
@@ -11109,7 +11067,7 @@
"esquery": "^1.7.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^8.0.0",
+ "file-entry-cache": "11.1.5 || >11.1.6 <12",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
"ignore": "^5.2.0",
@@ -11966,16 +11924,13 @@
}
},
"node_modules/file-entry-cache": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
- "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "version": "11.1.5",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz",
+ "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "flat-cache": "^4.0.0"
- },
- "engines": {
- "node": ">=16.0.0"
+ "flat-cache": "^6.1.23"
}
},
"node_modules/file-uri-to-path": {
@@ -12025,17 +11980,15 @@
}
},
"node_modules/flat-cache": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
- "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "version": "6.1.23",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz",
+ "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "flatted": "^3.2.9",
- "keyv": "^4.5.4"
- },
- "engines": {
- "node": ">=16"
+ "cacheable": "^2.5.0",
+ "flatted": "^3.4.2",
+ "hookified": "^1.15.0"
}
},
"node_modules/flatted": {
@@ -17200,13 +17153,6 @@
"node": ">=6"
}
},
- "node_modules/json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -17240,13 +17186,13 @@
}
},
"node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz",
+ "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "json-buffer": "3.0.1"
+ "@keyv/serialize": "^1.1.1"
}
},
"node_modules/kind-of": {
@@ -22631,28 +22577,6 @@
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
- "node_modules/stylelint/node_modules/file-entry-cache": {
- "version": "11.1.5",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz",
- "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "flat-cache": "^6.1.23"
- }
- },
- "node_modules/stylelint/node_modules/flat-cache": {
- "version": "6.1.23",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz",
- "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cacheable": "^2.5.0",
- "flatted": "^3.4.2",
- "hookified": "^1.15.0"
- }
- },
"node_modules/stylelint/node_modules/ignore": {
"version": "7.0.7",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.7.tgz",
diff --git a/package.json b/package.json
index 2e4d53577..79a3e99eb 100644
--- a/package.json
+++ b/package.json
@@ -110,7 +110,7 @@
"ajv-formats": "^3.0.1",
"browserslist": "^4.28.9",
"caniuse-lite": "^1.0.30001810",
- "eslint": "^10.8.1",
+ "eslint": "^10.10.0",
"eslint-config-prettier": "^10.1.8",
"eslint-webpack-plugin": "^6.0.0",
"espree": "^11.0.0",
From f5f9e30b719d36ca7a0f46683800d56e1d808246 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 18 Sep 2026 09:19:32 +0200
Subject: [PATCH 09/45] chore(deps): bump zod from 4.5.4 to 4.6.5 (#1046)
Bumps [zod](https://github.com/colinhacks/zod) from 4.5.4 to 4.6.5.
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](https://github.com/colinhacks/zod/compare/v4.5.4...v4.6.5)
---
updated-dependencies:
- dependency-name: zod
dependency-version: 4.6.4
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
package-lock.json | 8 ++++----
package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 812e36160..ba24ec411 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -45,7 +45,7 @@
"vue-router": "^4.6.4",
"webpack": "^5.110.3",
"webpack-cli": "^6.0.1",
- "zod": "^4.5.4"
+ "zod": "^4.6.5"
},
"devDependencies": {
"@babel/preset-env": "^7.22.9",
@@ -25269,9 +25269,9 @@
}
},
"node_modules/zod": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz",
- "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==",
+ "version": "4.6.5",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz",
+ "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
diff --git a/package.json b/package.json
index 79a3e99eb..cd34c6770 100644
--- a/package.json
+++ b/package.json
@@ -76,7 +76,7 @@
"vue-router": "^4.6.4",
"webpack": "^5.110.3",
"webpack-cli": "^6.0.1",
- "zod": "^4.5.4"
+ "zod": "^4.6.5"
},
"overrides": {
"@babel/traverse": "^7.23.2",
From 6aa62924fe31589545d93cc9f7d67bad91e2c162 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 18 Sep 2026 09:19:37 +0200
Subject: [PATCH 10/45] chore(deps): bump gridstack from 13.2.0 to 13.3.0
(#1045)
Bumps [gridstack](https://github.com/gridstack/gridstack.js) from 13.2.0 to 13.3.0.
- [Release notes](https://github.com/gridstack/gridstack.js/releases)
- [Changelog](https://github.com/gridstack/gridstack.js/blob/master/doc/CHANGES.md)
- [Commits](https://github.com/gridstack/gridstack.js/compare/v13.2.0...v13.3.0)
---
updated-dependencies:
- dependency-name: gridstack
dependency-version: 13.3.0
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
package-lock.json | 8 ++++----
package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index ba24ec411..a06ec6335 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,7 +28,7 @@
"css-loader": "~7.1.1",
"dexie": "^4.4.5",
"dompurify": "^3.4.12",
- "gridstack": "^13.2.0",
+ "gridstack": "^13.3.0",
"lodash": "^4.17.21",
"marked": "^18.0.11",
"node-polyfill-webpack-plugin": "4.1.0",
@@ -12476,9 +12476,9 @@
"license": "ISC"
},
"node_modules/gridstack": {
- "version": "13.2.0",
- "resolved": "https://registry.npmjs.org/gridstack/-/gridstack-13.2.0.tgz",
- "integrity": "sha512-+ImmOx6qd1wiF0EagY7e/pPdngh/6s0FM+r9hh4d8AsXslO51iHEuoAF7CMrXCFr0Xqd0X4WS/bqRLXtEUThug==",
+ "version": "13.3.0",
+ "resolved": "https://registry.npmjs.org/gridstack/-/gridstack-13.3.0.tgz",
+ "integrity": "sha512-1tqFd3/hb3CSOJWFG8aFleCGWT6Gqx/hnjRT78ocnixp0XPk5Aa6Uxkm0qn9VHFwLrEdOFb+ZXtQZT+a/IdS3g==",
"funding": [
{
"type": "paypal",
diff --git a/package.json b/package.json
index cd34c6770..5c01c5b2b 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
"css-loader": "~7.1.1",
"dexie": "^4.4.5",
"dompurify": "^3.4.12",
- "gridstack": "^13.2.0",
+ "gridstack": "^13.3.0",
"lodash": "^4.17.21",
"marked": "^18.0.11",
"node-polyfill-webpack-plugin": "4.1.0",
From 0d5bf0690308d11277982bd41fef20eb5f5eb61c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 18 Sep 2026 09:19:43 +0200
Subject: [PATCH 11/45] chore(deps): bump dexie from 4.4.5 to 4.4.6 (#1041)
Bumps [dexie](https://github.com/dexie/Dexie.js) from 4.4.5 to 4.4.6.
- [Release notes](https://github.com/dexie/Dexie.js/releases)
- [Commits](https://github.com/dexie/Dexie.js/compare/v4.4.5...v4.4.6)
---
updated-dependencies:
- dependency-name: dexie
dependency-version: 4.4.6
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
package-lock.json | 8 ++++----
package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index a06ec6335..aa3dbd5d7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -26,7 +26,7 @@
"axe-core": "^4.12.1",
"babel-loader": "^10.1.1",
"css-loader": "~7.1.1",
- "dexie": "^4.4.5",
+ "dexie": "^4.4.6",
"dompurify": "^3.4.12",
"gridstack": "^13.3.0",
"lodash": "^4.17.21",
@@ -10625,9 +10625,9 @@
}
},
"node_modules/dexie": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.4.5.tgz",
- "integrity": "sha512-wWCHdihT3dmlUSuNhn5mMZDWSpG0suxjAni7YjjiZdzabZcKmy3uNZGZ7AeYYXBoLbpSXX35fikPLkPC44Osiw==",
+ "version": "4.4.6",
+ "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.4.6.tgz",
+ "integrity": "sha512-hJP/BO6mjB+tX6hToIO1kmxYLNmun90wYbfcoAoLpKEyDYal/k33dg0TAfoUe2TDsbbLoVIzljJ3BN2UbR5EOg==",
"license": "Apache-2.0"
},
"node_modules/diffie-hellman": {
diff --git a/package.json b/package.json
index 5c01c5b2b..619ad3adf 100644
--- a/package.json
+++ b/package.json
@@ -57,7 +57,7 @@
"axe-core": "^4.12.1",
"babel-loader": "^10.1.1",
"css-loader": "~7.1.1",
- "dexie": "^4.4.5",
+ "dexie": "^4.4.6",
"dompurify": "^3.4.12",
"gridstack": "^13.3.0",
"lodash": "^4.17.21",
From 9a70ea2959f390009975070235944051bdf542ca Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 19 Sep 2026 10:59:00 +0200
Subject: [PATCH 12/45] fix(routes): two entries shared a route name, so one
route never registered (#1059)
settings#getArchiMateConfig is declared at /api/archimate/config and at
/api/archimate/status with no postfix on either. A route name carries neither
URL nor verb, so the two register as one and the later declaration wins:
GET /api/archimate/config is a 404.
Which of the two survives depends on line order alone, and the survivor is the
one the settings store polls, inside a catch with an empty body. postfix on the
second entry gives each its own name. Measured with Nextcloud's own RouteParser:
declared=132 registered=131 before, 132 after. No URL or verb changes.
RouteNameUniquenessTest asserts on each entry's registration key and is
mutation-checked against the old routes file.
---
appinfo/routes.php | 7 +-
.../Unit/AppInfo/RouteNameUniquenessTest.php | 143 ++++++++++++++++++
2 files changed, 149 insertions(+), 1 deletion(-)
create mode 100644 tests/Unit/AppInfo/RouteNameUniquenessTest.php
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 5401a68b3..b6495fb85 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -126,7 +126,12 @@
// ArchiMate focused endpoints
['name' => 'settings#getArchiMateConfig', 'url' => '/api/archimate/config', 'verb' => 'GET'],
['name' => 'settings#updateArchiMateConfig', 'url' => '/api/archimate/config', 'verb' => 'POST'],
- ['name' => 'settings#getArchiMateConfig', 'url' => '/api/archimate/status', 'verb' => 'GET'],
+ // A route name carries no URL, so without a 'postfix' this entry and the
+ // GET '/api/archimate/config' one above register under the same name and
+ // only the last declared survives. This one won on line order, which left
+ // the config read a 404 and made the store's polling endpoint depend on
+ // nothing but the order of these two lines.
+ ['name' => 'settings#getArchiMateConfig', 'url' => '/api/archimate/status', 'verb' => 'GET', 'postfix' => 'Status'],
// Email focused endpoints
['name' => 'settings#getEmailConfig', 'url' => '/api/email/config', 'verb' => 'GET'],
diff --git a/tests/Unit/AppInfo/RouteNameUniquenessTest.php b/tests/Unit/AppInfo/RouteNameUniquenessTest.php
new file mode 100644
index 000000000..ac146e6a4
--- /dev/null
+++ b/tests/Unit/AppInfo/RouteNameUniquenessTest.php
@@ -0,0 +1,143 @@
+
+ * @copyright 2026 Conduction B.V.
+ * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * SPDX-License-Identifier: EUPL-1.2
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
+ *
+ * @spec exclude Mechanical invariant of appinfo/routes.php, not a product requirement.
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Stackiq\Tests\Unit\AppInfo;
+
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Nextcloud names a route after its controller, its action and its `postfix`,
+ * and after nothing else. `OC\AppFramework\Routing\RouteParser::processRoute()`
+ * builds `strtolower($appName . '.' . $controller . '.' . $action . $postfix)`,
+ * and `RouteCollection::add()` OVERWRITES an entry that already carries that
+ * name.
+ *
+ * Neither the URL nor the verb is part of the name. So two entries that point
+ * at the same controller action and declare no `postfix` are one route, and the
+ * last one declared is the one that survives. Nothing warns, and `routes.php`
+ * still reads as though both are there.
+ *
+ * 🔴 THIS APP LOST ONE OF 132 ROUTES THAT WAY. `settings#getArchiMateConfig`
+ * was declared twice, at `/api/archimate/config` and at
+ * `/api/archimate/status`, with no `postfix` on either. The later declaration
+ * wins, so `GET /api/archimate/status` answers and `GET /api/archimate/config`
+ * is a 404 that no part of this repo mentions.
+ *
+ * Which of the two survives is decided by line order alone, and that is the
+ * part worth a test. `src/store/modules/settings.js` polls
+ * `/api/archimate/status` from `loadArchiMateStatus()` and from
+ * `refreshArchiMateStatus()`, and both wrap the fetch in a `catch` with an
+ * empty body. Swap those two lines in `routes.php` and the ArchiMate import and
+ * export progress stops updating, silently, with no error anywhere.
+ *
+ * 🔑 Unit tests cannot see this. They call the controller action directly, and
+ * an action with a full test suite and no reachable route answers exactly like
+ * one that works. So the assertion below is on the registration KEY of each
+ * entry, not on the file parsing or on the array being non-empty.
+ */
+class RouteNameUniquenessTest extends TestCase {
+
+ /**
+ * Read the declared route entries.
+ *
+ * @return array>> The route file.
+ */
+ private function routeFile(): array {
+ $routes = include dirname(__DIR__, 3) . '/appinfo/routes.php';
+ $this->assertIsArray($routes, 'appinfo/routes.php must return an array');
+
+ return $routes;
+ }
+
+ /**
+ * The key Nextcloud registers a route under, minus the app name.
+ *
+ * @param array $route One entry from the route file.
+ *
+ * @return string The registration key.
+ */
+ private function registrationKey(array $route): string {
+ return strtolower($route['name'] . ($route['postfix'] ?? ''));
+ }
+
+ /**
+ * No two entries may register under the same key.
+ *
+ * @return void
+ */
+ public function testEveryDeclaredRouteRegistersUnderItsOwnName(): void {
+ $file = $this->routeFile();
+
+ foreach (['routes', 'ocs'] as $section) {
+ $seen = [];
+
+ foreach (($file[$section] ?? []) as $entry) {
+ $key = $this->registrationKey($entry);
+
+ $this->assertArrayNotHasKey(
+ $key,
+ $seen,
+ sprintf(
+ "Two '%s' entries register as '%s', so Nextcloud keeps only the last one.\n"
+ . " kept: %s %s\n"
+ . " OVERWRITTEN: %s %s\n"
+ . "Give each entry its own 'postfix'.",
+ $section,
+ $key,
+ $entry['verb'] ?? 'GET',
+ $entry['url'] ?? '?',
+ $seen[$key]['verb'] ?? 'GET',
+ $seen[$key]['url'] ?? '?'
+ )
+ );
+
+ $seen[$key] = $entry;
+ }
+ }
+
+ }//end testEveryDeclaredRouteRegistersUnderItsOwnName()
+
+ /**
+ * Name both URLs, so a lost one is named and not just counted.
+ *
+ * @return void
+ */
+ public function testBothArchimateReadRoutesAreRoutedAgain(): void {
+ $entries = $this->routeFile()['routes'];
+
+ $byKey = [];
+ foreach ($entries as $entry) {
+ $byKey[$this->registrationKey($entry)] = ($entry['verb'] ?? 'GET') . ' ' . $entry['url'];
+ }
+
+ $this->assertSame(
+ 'GET /api/archimate/status',
+ ($byKey['settings#getarchimateconfigstatus'] ?? null),
+ 'the ArchiMate status endpoint the settings store polls must keep its own route name'
+ );
+ $this->assertSame(
+ 'GET /api/archimate/config',
+ ($byKey['settings#getarchimateconfig'] ?? null),
+ 'the ArchiMate config endpoint was the one that lost, and must be reachable'
+ );
+
+ }//end testBothArchimateReadRoutesAreRoutedAgain()
+
+}//end class
From da5c86a91069e0585d9e8fab0c5989a939c4b084 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Tue, 22 Sep 2026 13:29:08 +0200
Subject: [PATCH 13/45] chore(deps): move nextcloud-vue back to the 2.x line
The 3.x line was withdrawn on 2026-09-19. npm dist-tags now give latest =
2.55.1, the 2.x releases were published after the 3.x ones that day, and only
the v2 tags survive. A range of ^3.2.0 matches only 3.x, so this app could
never resolve the next release.
2.55.1 is a strict superset of 3.4.0: every one of the 621 CJS and 536 ESM
export names is present, no published file is missing, and package.json is
identical apart from the version. Verified by unpacking both tarballs.
---
package-lock.json | 8 ++++----
package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index aa3dbd5d7..2f65f7188 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,7 @@
"dependencies": {
"@babel/core": "^7.22.9",
"@codemirror/lang-json": "^6.0.0",
- "@conduction/nextcloud-vue": "^3.2.0",
+ "@conduction/nextcloud-vue": "^2.55.1",
"@nextcloud/auth": "^2.6.0",
"@nextcloud/axios": "^2.5.0",
"@nextcloud/capabilities": "^1.2.1",
@@ -2165,9 +2165,9 @@
}
},
"node_modules/@conduction/nextcloud-vue": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-3.2.0.tgz",
- "integrity": "sha512-jRKOE/xpLnsk9L8i2G6loifDJpRC+ORCsnfkpySDwAT3MRTriKDRXkc/lxfPHxXzXNeCJfiDPEEYbwFHFOUS9Q==",
+ "version": "2.55.1",
+ "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.55.1.tgz",
+ "integrity": "sha512-QIM7xZHg3odrULrB+AUPq4uDLQ2eBKcpRf3dsMCBSjmLA58RQTj25EC3nlfR/AJzr4KuvS3Ai95UPM4E/2tfIw==",
"license": "EUPL-1.2",
"dependencies": {
"@ckpack/vue-color": "^1.6.0",
diff --git a/package.json b/package.json
index 619ad3adf..1e7d13474 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
"dependencies": {
"@babel/core": "^7.22.9",
"@codemirror/lang-json": "^6.0.0",
- "@conduction/nextcloud-vue": "^3.2.0",
+ "@conduction/nextcloud-vue": "^2.55.1",
"@nextcloud/auth": "^2.6.0",
"@nextcloud/axios": "^2.5.0",
"@nextcloud/capabilities": "^1.2.1",
From b81b532c1d39c01425ff6200dcd9acc87b6ecd7a Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Fri, 25 Sep 2026 20:21:40 +0200
Subject: [PATCH 14/45] feat(parity): start stackiq's capability matrix (work
in progress)
173 rows in 12 areas against five competitor columns, competitor cells
from the intelligence database. Stackiq's own column is not read yet.
---
openspec/parity/capabilities.json | 2910 +++++++++++++++++++++++++++++
1 file changed, 2910 insertions(+)
create mode 100644 openspec/parity/capabilities.json
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
new file mode 100644
index 000000000..d885fb5e8
--- /dev/null
+++ b/openspec/parity/capabilities.json
@@ -0,0 +1,2910 @@
+{
+ "comparedOn": "2026-09-25",
+ "category": "Stackiq is a software and application catalogue for public-sector organisations, mapped to the GEMMA reference architecture. It does two jobs in one product: it is the back office and API of a national, public market-transparency catalogue (suppliers publish what they offer, municipalities record what they use and how it connects, everything is plotted on GEMMA reference components), and it gives one organisation a portfolio view of its own landscape (contracts, lifecycle, licences, vulnerabilities, compliance). So it competes first with the VNG GEMMA Softwarecatalogus it is built to succeed (its requirements are the VNG issues in issues.md), second with application portfolio and enterprise architecture tools that municipalities buy for the same landscape (SAP LeanIX, BlueDolphin), and third with the CMDB and IT asset tools that already hold a municipality's software list (GLPI, TOPdesk). It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose. Correct this paragraph if the category is wrong: the areas, the phrasing and the columns all follow from it.",
+ "columnsWhy": "Five competitor columns. VNG GEMMA Softwarecatalogus is the incumbent and the requirement source. SAP LeanIX is the application portfolio management reference and BlueDolphin (ValueBlue) the Dutch ArchiMate-first EA tool sold to municipalities. GLPI is the open-source ITAM and CMDB with the deepest research on file (a source reading by the procest lane on 2026-09-14 on top of the docs pass), and TOPdesk is the service management and CMDB suite most Dutch municipalities already run. Left out: Backstage, Port, Cortex, OpsLevel, Compass and other developer portals (a different buyer and a catalog-info.yaml model); ServiceNow CMDB, Flexera/Snow, BMC Helix and Alfabet (enterprise-priced, and the licence and SAM rows below already carry the ideas they would add); Ardoq, MEGA HOPEX, BiZZdesign, Sparx, Archi and the other EA tools (LeanIX and BlueDolphin stand for the class); i-doit, Snipe-IT, Lansweeper, OCS, Ralph, NetBox, Device42 and CMDBuild (discovery and hardware, where GLPI stands for the open-source class); and Atlas Governance, Kong, Gravitee, Apigee, Postman, SwaggerHub, Stoplight, RapidAPI and Sensus BPM, which are linked to softwarecatalog in the intelligence database but are board, API gateway or process tools and noise for this product.",
+ "corpus": {
+ "repo": "ConductionNL/concurrentie-analyse (intelligence database)",
+ "file": "competitor_features, canonical_features and competitor_apps for app_slug softwarecatalog; stackiq issues.md for the VNG requirements"
+ },
+ "systems": [
+ {
+ "key": "stackiq",
+ "name": "Stackiq",
+ "vendor": "Conduction",
+ "isSelf": true,
+ "readOn": "2026-09-25"
+ },
+ {
+ "key": "vng-softwarecatalogus",
+ "name": "GEMMA Softwarecatalogus",
+ "vendor": "VNG Realisatie",
+ "readOn": "2026-07-23",
+ "evidenceGrade": "docs-only",
+ "unknownReason": "Not covered by the 20 intelligence rows for this system (a docs pass dated 2026-04-12 and 2026-07-23); the public site was not driven."
+ },
+ {
+ "key": "sap-leanix",
+ "name": "SAP LeanIX",
+ "vendor": "SAP",
+ "readOn": "2026-07-23",
+ "evidenceGrade": "docs-only",
+ "unknownReason": "Not covered by the 24 intelligence rows for this system (docs passes dated 2026-04-12 and 2026-07-23); no trial was opened."
+ },
+ {
+ "key": "bluedolphin",
+ "name": "BlueDolphin",
+ "vendor": "ValueBlue",
+ "readOn": "2026-07-23",
+ "evidenceGrade": "docs-only",
+ "unknownReason": "Not covered by the 22 intelligence rows for this system (docs passes dated 2026-04-12 and 2026-07-23); no trial was opened."
+ },
+ {
+ "key": "glpi",
+ "name": "GLPI",
+ "vendor": "Teclib",
+ "readOn": "2026-07-23",
+ "evidenceGrade": "docs-only",
+ "unknownReason": "Not covered by the GLPI rows read for this product (a docs pass dated 2026-07-23) or by the procest lane's source reading of 2026-09-14, which answered case-management questions."
+ },
+ {
+ "key": "topdesk",
+ "name": "TOPdesk",
+ "vendor": "TOPdesk",
+ "readOn": "2026-07-23",
+ "evidenceGrade": "docs-only",
+ "unknownReason": "Not covered by the 50 intelligence rows for this system (docs passes dated 2026-04-10 to 2026-07-23); the product was not driven."
+ }
+ ],
+ "areas": [
+ {
+ "key": "landscape",
+ "name": "Application landscape register",
+ "name_nl": "Applicatielandschap registreren"
+ },
+ {
+ "key": "connections",
+ "name": "Integrations and dependencies",
+ "name_nl": "Koppelingen en afhankelijkheden"
+ },
+ {
+ "key": "architecture",
+ "name": "GEMMA and ArchiMate",
+ "name_nl": "GEMMA en ArchiMate"
+ },
+ {
+ "key": "compliance",
+ "name": "Standards, BIO and compliance",
+ "name_nl": "Standaarden, BIO en compliance"
+ },
+ {
+ "key": "market",
+ "name": "Supplier offering and market transparency",
+ "name_nl": "Aanbod en markttransparantie"
+ },
+ {
+ "key": "lifecycle",
+ "name": "Lifecycle, roadmap and rationalisation",
+ "name_nl": "Levenscyclus, roadmap en rationalisatie"
+ },
+ {
+ "key": "contracts",
+ "name": "Contracts, licences and costs",
+ "name_nl": "Contracten, licenties en kosten"
+ },
+ {
+ "key": "security",
+ "name": "Vulnerabilities and software supply chain",
+ "name_nl": "Kwetsbaarheden en softwareketen"
+ },
+ {
+ "key": "organisations",
+ "name": "Organisations, accounts and access",
+ "name_nl": "Organisaties, accounts en toegang"
+ },
+ {
+ "key": "sharing",
+ "name": "Open data, federation and APIs",
+ "name_nl": "Open data, federatie en API's"
+ },
+ {
+ "key": "insight",
+ "name": "Search, dashboards and reports",
+ "name_nl": "Zoeken, dashboards en rapportages"
+ },
+ {
+ "key": "operations",
+ "name": "Discovery and IT operations",
+ "name_nl": "Discovery en IT-beheer"
+ }
+ ],
+ "providers": [
+ {
+ "key": "stackiq",
+ "name": "Stackiq",
+ "kind": "self"
+ },
+ {
+ "key": "openregister",
+ "name": "OpenRegister",
+ "kind": "app"
+ },
+ {
+ "key": "opencatalogi",
+ "name": "OpenCatalogi",
+ "kind": "app"
+ },
+ {
+ "key": "decidiq",
+ "name": "Decidiq (app id decidesk)",
+ "kind": "app"
+ },
+ {
+ "key": "integriq",
+ "name": "Integriq (app id openconnector)",
+ "kind": "app"
+ },
+ {
+ "key": "portaliq",
+ "name": "Portaliq",
+ "kind": "app"
+ },
+ {
+ "key": "nextcloud",
+ "name": "Nextcloud",
+ "kind": "platform"
+ }
+ ],
+ "capabilities": [
+ {
+ "id": "land-register-application",
+ "area": "landscape",
+ "name": "Register an application your organisation uses, with its supplier, description and status.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
+ "glpi": "partial",
+ "topdesk": "partial",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map. | docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape",
+ "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | docs, intelligence competitor_features#27422 'Fact Sheets & Data Model' (2026-04-12): Flexible data model for applications, processes, IT components",
+ "bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository. | docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
+ "glpi": "docs, intelligence competitor_features#48900 'Software inventory & catalog' (2026-07-23): Detects installed software and normalises into a software catalog. | docs, intelligence competitor_features#3267 'Software Catalog' (2026-03-28): Manage software licenses and installations | Rated partial because software is an inventoried asset, not a described application.",
+ "topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | docs, intelligence competitor_features#27387 'CMDB / Configuration Management' (2026-04-12): Configuration database for registering IT objects like laptops, software, infrastructure | Rated partial because software is a CMDB object among assets.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-application-modules",
+ "area": "landscape",
+ "name": "Break an application into modules and see which module belongs to which product.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated partial because fact sheets separate Application from IT Component.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-module-versions",
+ "area": "landscape",
+ "name": "Record the released versions of a module, with the date each came into use.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "partial",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48900 'Software inventory & catalog' (2026-07-23): Detects installed software and normalises into a software catalog. | Rated partial because installed versions come from inventory.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-usage-record",
+ "area": "landscape",
+ "name": "Record that your organisation uses a module, as a usage separate from the product itself.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "partial",
+ "bluedolphin": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
+ "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers.",
+ "bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-suite",
+ "area": "landscape",
+ "name": "Bundle several existing applications into one suite that is offered as a single product.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-services",
+ "area": "landscape",
+ "name": "Register a service a supplier delivers on top of one or more applications, such as hosting or support.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48838 'Supplier product offering (aanbod) registration' (2026-07-23): ICT suppliers publish their product offering for the municipal market with global functionality descriptions. | Rated partial because offering registration covers products; services not named in the reading.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-sectors",
+ "area": "landscape",
+ "name": "Tag applications with the government sectors they are meant for.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-application-owner",
+ "area": "landscape",
+ "name": "Name the business owner and the technical owner responsible for an application.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | Rated partial because surveys go to application owners, so ownership is modelled.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-custom-fields",
+ "area": "landscape",
+ "name": "Add your own fields to an application without a developer changing the data model.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because flexible fact sheet data model.",
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141835 '11.17 Custom object type management': GLPI 11 ships admin-defined itemtypes with custom fields and capabilities (`src/Glpi/CustomObject/AbstractDefinition.php`, `src/Glpi/Asset/AssetDefinition.php`, `src/Glpi/Asset/CustomFieldDefinition.php`), but the machin | Rated yes because custom asset definitions and custom fields, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-bulk-import",
+ "area": "landscape",
+ "name": "Import an existing application list in bulk from a spreadsheet or file.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#27428 'EAM Automation' (2026-04-12): Automated data collection from ServiceNow, Jira, cloud providers | Rated partial because automated collection from ServiceNow, Jira and cloud.",
+ "bluedolphin": "docs, intelligence competitor_features#48971 'Data import (Excel)' (2026-07-23): Bulk import of application/portfolio data.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-migrate-legacy",
+ "area": "landscape",
+ "name": "Bring over what was registered in the previous catalogue so nobody has to type it in again.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-detail-page",
+ "area": "landscape",
+ "name": "Open one application and see its versions, usages, contracts and compliance on one page.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
+ "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because fact sheet is the per-application page.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-bulk-edit",
+ "area": "landscape",
+ "name": "Select many catalogue entries at once and publish, lock or delete them together.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-duplicate-merge",
+ "area": "landscape",
+ "name": "Merge two catalogue entries that turn out to describe the same thing.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-data-quality-survey",
+ "area": "landscape",
+ "name": "Ask application owners through a survey to confirm or correct their entries.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | docs, intelligence competitor_features#27423 'Survey-Based Data Collection' (2026-04-12): Crowdsource architecture data from application owners",
+ "bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-completeness-score",
+ "area": "landscape",
+ "name": "See how complete and up to date each application's entry is, as a score.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-demo-data",
+ "area": "landscape",
+ "name": "Load a set of example data so a new installation can be tried out straight away.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-guided-wizard",
+ "area": "landscape",
+ "name": "Add an application, service or connection through a step-by-step wizard instead of a bare form.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-sbom-components",
+ "area": "landscape",
+ "name": "See the third-party components a module version is built from.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "land-hosting-model",
+ "area": "landscape",
+ "name": "Record whether an application runs on premises, as SaaS or at a hosting party.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | Rated partial because SaaS is tracked as a class of application.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-register-connection",
+ "area": "connections",
+ "name": "Register a connection between two applications, with its direction and the standard it uses.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "yes",
+ "bluedolphin": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
+ "sap-leanix": "docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
+ "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | Rated partial because ArchiMate flow relations.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-external-provision",
+ "area": "connections",
+ "name": "Record a connection from an application to a national provision such as a basisregistratie.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48841 'National provisions (landelijke voorzieningen) linking' (2026-07-23): Records links between applications and national government provisions.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-list-page",
+ "area": "connections",
+ "name": "Browse all connections in the catalogue in one list and open each one.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-per-application",
+ "area": "connections",
+ "name": "See every connection an application has, from that application's own page.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-diagram",
+ "area": "connections",
+ "name": "See the connections between applications drawn as a diagram.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model. | docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
+ "bluedolphin": "docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models. | docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145369 'C-case-core-38 The graph of what a case is linked to is drawn, and exported.': glpi: Impact graph (Tools, front/impactitem.php, impactcsv.php, src/Impact.php) Lane findings: D-glpi-40. | Rated yes because impact graph, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-impact-analysis",
+ "area": "connections",
+ "name": "Before changing or retiring an application, see what depends on it.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "yes",
+ "glpi": "yes",
+ "topdesk": "partial",
+ "stackiq": "unknown",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
+ "glpi": "docs, intelligence competitor_features#48902 'CMDB & configuration relations' (2026-07-23): CI relationships and impact analysis.",
+ "topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | Rated partial because relations between assets.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-usage-of-connection",
+ "area": "connections",
+ "name": "Record that your organisation actually runs a given connection, not only that it exists.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-shared-with-others",
+ "area": "connections",
+ "name": "See which connections you run together with other organisations.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-type-filter",
+ "area": "connections",
+ "name": "Filter connections by type, such as an API, a file exchange or a message.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-api-catalogue",
+ "area": "connections",
+ "name": "Keep the APIs an application exposes in the catalogue next to the application.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#27425 'API Management' (2026-04-12): Catalog and manage APIs across the application landscape",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-export-graph",
+ "area": "connections",
+ "name": "Export the graph of what an application is linked to, for use elsewhere.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145369 'C-case-core-38 The graph of what a case is linked to is drawn, and exported.': glpi: Impact graph (Tools, front/impactitem.php, impactcsv.php, src/Impact.php) Lane findings: D-glpi-40. | Rated yes because impactcsv export, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "conn-integration-registry",
+ "area": "connections",
+ "name": "Add and check the organisation's outside integrations from one integrations overview.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-refcomp-mapping",
+ "area": "architecture",
+ "name": "Place an application on the GEMMA reference components it fulfils.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48835 'Reference component mapping (referentiecomponenten)' (2026-07-23): Maps each registered software product onto GEMMA reference components/domains so functionality is comparable across suppliers. | docs, intelligence competitor_features#27551 'Reference Component Linking' (2026-04-12): Link software to GEMMA reference components",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-gemma-views",
+ "area": "architecture",
+ "name": "Open a GEMMA architecture view with your own applications drawn inside it.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map. | Rated yes because landscape auto-plotted on the reference component map.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-shared-overlay",
+ "area": "architecture",
+ "name": "On a GEMMA view, see which applications you share with partner organisations, drawn differently from your own.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48844 'Municipal cooperation / shared-service management' (2026-07-23): Manages gemeente-samenwerking (shared service centres) registering a joint landscape.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-import-amef",
+ "area": "architecture",
+ "name": "Import an ArchiMate model file in the Open Group exchange format.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27459 'ArchiMate & BPMN Support' (2026-04-12): Full ArchiMate and BPMN modeling in one platform | Rated yes because full ArchiMate support; import format not named in the reading.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-export-amef",
+ "area": "architecture",
+ "name": "Export the catalogue as an ArchiMate file that opens in Archi or another modelling tool.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27554 'ArchiMate Export' (2026-04-12): Export to ArchiMate format for use in architecture tools",
+ "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-export-org",
+ "area": "architecture",
+ "name": "Export one organisation's landscape plotted on GEMMA as its own ArchiMate file.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape | docs, intelligence competitor_features#27554 'ArchiMate Export' (2026-04-12): Export to ArchiMate format for use in architecture tools | Rated yes because map and export the municipality's landscape.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-round-trip",
+ "area": "architecture",
+ "name": "Check that a model survives import and export without losing elements or relations.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-import-progress",
+ "area": "architecture",
+ "name": "Follow a long model import while it runs, and cancel it if needed.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-gemma-api",
+ "area": "architecture",
+ "name": "Retrieve the GEMMA architecture itself through an API.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-definitions",
+ "area": "architecture",
+ "name": "Read the definition of a GEMMA term in place while working in the catalogue.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-capability-map",
+ "area": "architecture",
+ "name": "Map applications to business capabilities or functions and see the map.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | docs, intelligence competitor_features#27420 'Business Capability Mapping' (2026-04-12): Map applications to business capabilities and processes",
+ "bluedolphin": "docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-modelling",
+ "area": "architecture",
+ "name": "Draw and edit architecture models yourself inside the tool.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model.",
+ "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-process-mapping",
+ "area": "architecture",
+ "name": "Model business processes and link them to the applications that support them.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27464 'Process Mapping' (2026-04-12): Map processes, applications, data, and technology",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-scenarios",
+ "area": "architecture",
+ "name": "Model a future-state landscape and compare it with today's.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#27419 'IT Transformation' (2026-04-12): Plan and execute cloud migrations and modernization | Rated partial because transformation planning.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-gap-analysis",
+ "area": "architecture",
+ "name": "Find reference components that no application in your landscape covers.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "arch-ai-diagram",
+ "area": "architecture",
+ "name": "Have a diagram drafted for you by an assistant from a description.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#48970 'AI-powered diagramming' (2026-07-23): AI assists diagram generation. | docs, intelligence competitor_features#27461 'AI-Powered Diagramming' (2026-04-12): Auto-generate BPMN diagrams with built-in AI",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-standards-register",
+ "area": "compliance",
+ "name": "Browse a register of the standards applications are expected to support.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48840 'Standards support declaration' (2026-07-23): Suppliers declare which standards (StUF, ZGW/Zaakgericht APIs, etc.) a product supports. | docs, intelligence competitor_features#27556 'Standards Mapping' (2026-04-12): Map software to Forum Standaardisatie standards",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-declare-standard",
+ "area": "compliance",
+ "name": "Declare that an application supports a specific version of a standard.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48840 'Standards support declaration' (2026-07-23): Suppliers declare which standards (StUF, ZGW/Zaakgericht APIs, etc.) a product supports.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-evidence",
+ "area": "compliance",
+ "name": "Attach a test report or other evidence to a compliance claim.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-verified-vs-claimed",
+ "area": "compliance",
+ "name": "Tell a verified compliance claim apart from one the supplier only asserts.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-matrix",
+ "area": "compliance",
+ "name": "See applications against chosen standards in one matrix, cell by cell.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-bulk-sync-standards",
+ "area": "compliance",
+ "name": "Bring the standards set of many applications up to date in one action.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-bio-measures",
+ "area": "compliance",
+ "name": "Browse the BIO information security measures with their theme and level.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-bio-assessment",
+ "area": "compliance",
+ "name": "Record which BIO measures an application meets and which it does not.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-dpia",
+ "area": "compliance",
+ "name": "Record whether a data protection impact assessment has been done for an application.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-forum-standaardisatie",
+ "area": "compliance",
+ "name": "Check an application against the Forum Standaardisatie comply-or-explain list.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27556 'Standards Mapping' (2026-04-12): Map software to Forum Standaardisatie standards",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-health-scoring",
+ "area": "compliance",
+ "name": "Score the correctness and completeness of the register against a rule set.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "comp-audit-questionnaire",
+ "area": "compliance",
+ "name": "Send a compliance questionnaire to a supplier and keep the answers with the application.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders. | Rated partial because questionnaires collect portfolio data.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-supplier-offering",
+ "area": "market",
+ "name": "As a supplier, publish the applications and services you offer to government.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48838 'Supplier product offering (aanbod) registration' (2026-07-23): ICT suppliers publish their product offering for the municipal market with global functionality descriptions. | docs, intelligence competitor_features#27555 'Vendor Registration' (2026-04-12): ICT providers register their software offerings",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-offer-accept",
+ "area": "market",
+ "name": "As a supplier, accept or decline a usage another organisation has claimed of your product.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-find-software",
+ "area": "market",
+ "name": "Find software for a task by filtering the whole market on reference component and standard.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27553 'ICT Market Orientation' (2026-04-12): Find and compare software from registered ICT providers",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-supplier-directory",
+ "area": "market",
+ "name": "Browse all organisations that offer applications or services, with search and filters.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-compare-peers",
+ "area": "market",
+ "name": "See which software comparable organisations use for the same reference component.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48837 'Cross-municipality software comparison' (2026-07-23): Municipalities compare used software and connections with peer gemeenten; core network-effect value. | docs, intelligence competitor_features#27552 'Municipality Comparison' (2026-04-12): Compare application landscapes between municipalities",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-who-uses-it",
+ "area": "market",
+ "name": "See which organisations use a given application.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48837 'Cross-municipality software comparison' (2026-07-23): Municipalities compare used software and connections with peer gemeenten; core network-effect value.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-contact-peers",
+ "area": "market",
+ "name": "Get in touch with other organisations that use the same product.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27557 'Contact & Collaboration' (2026-04-12): Connect with municipalities using similar products",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-supplier-roadmap",
+ "area": "market",
+ "name": "Read a supplier's declared roadmap and planned releases for a product.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48839 'Product roadmap / planning declaration' (2026-07-23): Suppliers declare product planning and release roadmap per product.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-reviews",
+ "area": "market",
+ "name": "Write a review with a rating of an application you use.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-review-moderation",
+ "area": "market",
+ "name": "Hold a submitted review for moderation before others can read it.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-rating-aggregate",
+ "area": "market",
+ "name": "See the average rating and number of reviews of an application.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-contacts-per-product",
+ "area": "market",
+ "name": "Name different contact persons per product a supplier offers.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-vendor-master-data",
+ "area": "market",
+ "name": "Keep one record per supplier that every product and contract points to.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because Provider fact sheet.",
+ "topdesk": "docs, intelligence competitor_features#48932 'Contract & vendor management' (2026-07-23): Track supplier contracts and operational agreements.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-hide-landscape-from-vendors",
+ "area": "market",
+ "name": "Keep your application landscape and connections hidden from suppliers.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "mkt-free-public-service",
+ "area": "market",
+ "name": "Use the catalogue free of charge as a municipality or supplier.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "no",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
+ "sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
+ "glpi": "docs, intelligence competitor_features#48912 '100% open source (GPL)' (2026-07-23): Fully GPL; no license fees, broad device coverage.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-phase",
+ "area": "lifecycle",
+ "name": "See which lifecycle phase each application in use is in, such as planned, in use or being phased out.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "partial",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
+ "topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | Rated partial because replacement timelines on assets.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-eol-warning",
+ "area": "lifecycle",
+ "name": "Get a warning before an application or version falls out of support.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-eol-feed",
+ "area": "lifecycle",
+ "name": "Fill in end-of-support dates automatically from a public end-of-life feed.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | Rated partial because obsolescence tracking; source of dates not named.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-roadmap",
+ "area": "lifecycle",
+ "name": "See per organisation which applications are replaced when, on a roadmap.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-planned-replacement",
+ "area": "lifecycle",
+ "name": "Record which application is planned to replace another.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-time-classification",
+ "area": "lifecycle",
+ "name": "Classify each application as tolerate, invest, migrate or eliminate.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-overlap",
+ "area": "lifecycle",
+ "name": "Find applications that overlap because they fulfil the same reference component.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | Rated partial because rationalisation through capability map.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-rationalisation-report",
+ "area": "lifecycle",
+ "name": "Open a report of overlapping and ageing software for rationalisation.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R). | docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-version-in-use",
+ "area": "lifecycle",
+ "name": "Record which version of an application your organisation currently runs.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-new-version-notice",
+ "area": "lifecycle",
+ "name": "Get notified when a supplier publishes a new version of an application you use.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-tech-obsolescence",
+ "area": "lifecycle",
+ "name": "Track the lifecycle of the underlying technology, such as a database or framework, not only the application.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-strategy-link",
+ "area": "lifecycle",
+ "name": "Link applications to the strategic goals they serve.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#27466 'Strategy Alignment' (2026-04-12): Connect architecture to strategic objectives",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "life-maintenance-window",
+ "area": "lifecycle",
+ "name": "Follow planned maintenance announced for an application.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-register",
+ "area": "contracts",
+ "name": "Register a contract for a service with its number, type, term and cost.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "glpi": "docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets. | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145509 'C-parties-and-contacts-1 A contract is a record with its own term and costs, linked to the party it binds and the cases raised under it': glpi: Contracts (Management, Contracts, front/contract_item.php, contractcost.php, ticket_contract.php) Lane findings: D-glpi-49.",
+ "topdesk": "docs, intelligence competitor_features#48932 'Contract & vendor management' (2026-07-23): Track supplier contracts and operational agreements.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-expiry-alert",
+ "area": "contracts",
+ "name": "Get warned before a contract expires.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS renewal dates.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-status",
+ "area": "contracts",
+ "name": "See each contract's status move from active to expiring to expired on its own.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-approval",
+ "area": "contracts",
+ "name": "Only let a contract become active after an approval decision is recorded.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-renewal",
+ "area": "contracts",
+ "name": "Raise a renewal of a contract as a decision and see its outcome on the contract.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-per-application",
+ "area": "contracts",
+ "name": "See the contracts behind an application from that application's page.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets. | Rated yes because contracts tracked against assets.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-yearly-cost",
+ "area": "contracts",
+ "name": "See what the portfolio costs per year across its contracts.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS cost.",
+ "glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts | docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-licence-model",
+ "area": "contracts",
+ "name": "Record the licence model of an application, such as open source, per user or per organisation.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48901 'License management' (2026-07-23): Track license entitlements, compliance and expirations.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-licence-posture",
+ "area": "contracts",
+ "name": "See the licence posture of the whole portfolio, such as the share that is open source.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-seat-count",
+ "area": "contracts",
+ "name": "Track the number of licences bought against the number in use.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48901 'License management' (2026-07-23): Track license entitlements, compliance and expirations. | docs, intelligence competitor_features#3270 'License Management' (2026-03-28): Track software licenses, compliance, and expiration",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-effective-licence-position",
+ "area": "contracts",
+ "name": "Compute entitlement against measured consumption to defend a licence audit.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-budget",
+ "area": "contracts",
+ "name": "Charge software costs against a budget with a period.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145790 'C-reporting-1 A budget the case costs are charged against, with a period.': glpi: Budgets (Management, Budgets, front/budget.php) Lane findings: D-glpi-37. | Rated yes because budgets, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-depreciation",
+ "area": "contracts",
+ "name": "Depreciate the purchase cost of software over its useful life.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "partial",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts | Rated partial because TCO tracking.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-documents",
+ "area": "contracts",
+ "name": "Keep the signed contract document with the contract record.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ctr-saas-spend",
+ "area": "contracts",
+ "name": "See SaaS subscriptions and their spend, including ones bought outside IT.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-vulnerability-register",
+ "area": "security",
+ "name": "Register a known vulnerability with its CVE code and severity score.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-affected-versions",
+ "area": "security",
+ "name": "Link a vulnerability to the module versions it affects.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-exposure",
+ "area": "security",
+ "name": "See which organisations and usages are exposed to a vulnerability.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-vulnerability-alert",
+ "area": "security",
+ "name": "Get an alert when a vulnerability is reported for software you use.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-sbom-import",
+ "area": "security",
+ "name": "Import a software bill of materials in CycloneDX or SPDX for a version.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-cve-feed",
+ "area": "security",
+ "name": "Match the catalogue automatically against a public CVE feed.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-risk-score",
+ "area": "security",
+ "name": "Give each application a risk score from its vulnerabilities and support status.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks | Rated partial because technology risk.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-patch-status",
+ "area": "security",
+ "name": "See whether the version you run has been patched against a given vulnerability.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "sec-vulnerability-page",
+ "area": "security",
+ "name": "Browse all vulnerabilities in one list and open the details of each.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-register",
+ "area": "organisations",
+ "name": "Register an organisation, such as a municipality, supplier or cooperation, with its type.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27555 'Vendor Registration' (2026-04-12): ICT providers register their software offerings | docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-self-registration",
+ "area": "organisations",
+ "name": "Let a new organisation sign itself up without an account.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-moderation",
+ "area": "organisations",
+ "name": "Review a self-registered organisation in a queue before it becomes active.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-status",
+ "area": "organisations",
+ "name": "Move an organisation between concept, active and inactive.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-contact-persons",
+ "area": "organisations",
+ "name": "Keep the contact persons of an organisation with their roles.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27557 'Contact & Collaboration' (2026-04-12): Connect with municipalities using similar products",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-contact-to-account",
+ "area": "organisations",
+ "name": "Turn a contact person into a user account with the right role automatically.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-invite-colleagues",
+ "area": "organisations",
+ "name": "Give a colleague access to your organisation's part of the catalogue.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-multi-membership",
+ "area": "organisations",
+ "name": "Act for more than one organisation with one account and switch between them.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-cooperation",
+ "area": "organisations",
+ "name": "Register a cooperation of organisations and the landscape they share.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48844 'Municipal cooperation / shared-service management' (2026-07-23): Manages gemeente-samenwerking (shared service centres) registering a joint landscape.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-merge",
+ "area": "organisations",
+ "name": "Merge two organisations after a municipal reorganisation or takeover, keeping their relations.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-merge-dry-run",
+ "area": "organisations",
+ "name": "See what a merge of organisations would change before it is carried out.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "partial",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#146004 'C-configuration-95 The product shows what an import or a migration will change before it writes.': glpi: Form export and import (Form/ExportController.php, Form/Import/Step1IndexController.php through Step4ExecuteController.php) Lane findings: D-glpi-11. | Rated partial because import previews before writing; not for merges, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-roles",
+ "area": "organisations",
+ "name": "Map catalogue roles such as administrator, buyer and civil servant onto user groups.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141837 '11.19 User, role and department administration in the app': `/front/user.form.php`, `/front/profile.form.php` (`src/Profile.php`, `src/ProfileRight.php:46`), `/front/group.form.php`, and the three-way user x profile x entity grant `src/Profile_User.php:320` with a recursive flag | Rated yes because user, profile and entity administration, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-data-segregation",
+ "area": "organisations",
+ "name": "Keep each organisation's records visible only to that organisation unless published.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48910 'Multi-entity (tenant) segregation' (2026-07-23): Hierarchical entities for multi-org / multi-department isolation.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-hierarchy",
+ "area": "organisations",
+ "name": "Make the first user of an organisation its administrator and manager of later users.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-sso",
+ "area": "organisations",
+ "name": "Sign in with the organisation's own identity provider.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48908 'LDAP / SSO' (2026-07-23): Directory authentication and SSO.",
+ "topdesk": "docs, intelligence competitor_features#48935 'SSO integration' (2026-07-23): SAML / SSO authentication.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-directory-sync",
+ "area": "organisations",
+ "name": "Keep users and groups in step with a directory such as LDAP.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48908 'LDAP / SSO' (2026-07-23): Directory authentication and SSO. | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141776 '5.11 Contact import and change subscriptions from registries': LDAP import and periodic re-sync of users and groups (`src/AuthLDAP.php`, `/front/ldap.import.php`, `/front/ldap.group.import.php`) with `src/RuleRight.php` mapping directory attributes to profiles; nothing subscribes to",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-password-change",
+ "area": "organisations",
+ "name": "Change your own password and see your own account details.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "org-activation-mail",
+ "area": "organisations",
+ "name": "Send registration, activation and account mails from templates an administrator can edit.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141830 '11.12 E-mail template library': `src/NotificationTemplate.php` with per-language bodies (`src/NotificationTemplateTranslation.php`), bound to events and delivery modes by `src/Notification_NotificationTemplate.php`, at `/front/notificationtemplate.php` | Rated yes because notification templates, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-public-browse",
+ "area": "sharing",
+ "name": "Let anyone browse the published catalogue without signing in.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-publish",
+ "area": "sharing",
+ "name": "Publish or withdraw a single catalogue entry as open data.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-open-data-privacy",
+ "area": "sharing",
+ "name": "Publish usage as open data without exposing personal contact details.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-federation-announce",
+ "area": "sharing",
+ "name": "Announce your catalogue in a shared directory so other catalogues can find it.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-federation-pull",
+ "area": "sharing",
+ "name": "Pull published entries from peer catalogues, marked with where they came from.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-federation-peers",
+ "area": "sharing",
+ "name": "Add or remove the peer catalogues you exchange with.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-rest-api",
+ "area": "sharing",
+ "name": "Read and write catalogue data through a REST API.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48867 'REST & GraphQL API' (2026-07-23): Programmatic access to the workspace graph.",
+ "bluedolphin": "docs, intelligence competitor_features#48972 'REST API' (2026-07-23): Programmatic integration with other systems.",
+ "glpi": "docs, intelligence competitor_features#48907 'REST API (HLAPI 2.x)' (2026-07-23): High-level REST API expanding object coverage in GLPI 11.",
+ "topdesk": "docs, intelligence competitor_features#48933 'REST API' (2026-07-23): Open REST API for integrations.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-public-api",
+ "area": "sharing",
+ "name": "Give developers a secure public API over the supplier offering.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "no",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141847 '12.19 Public data API with certificates or API keys': the API is fully authenticated, never public: user tokens plus optional app tokens with IP allow-listing (`apirest.md:62-67`, `src/APIClient.php:42`) and OAuth2 with scopes (`src/Glpi/OAuth/`). No anonymous public datase | Rated no because API is always authenticated, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-api-docs",
+ "area": "sharing",
+ "name": "Read generated documentation of the catalogue API.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141846 '12.18 OpenAPI documentation': auto-generated from route attributes: `src/Glpi/Api/HL/OpenAPIGenerator.php` with `src/Glpi/Api/HL/Doc/`, versioned per route (`#[RouteVersion]`, router at `src/Glpi/Api/HL/Router.php:98`); the legacy API is documented i | Rated yes because OpenAPI generator, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-export",
+ "area": "sharing",
+ "name": "Export your own catalogue data for use elsewhere.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape",
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141818 '10.3 Export list results to CSV or XLSX': `src/Glpi/Search/Output/Csv.php`, `Xlsx.php`, `Ods.php` and `Pdf.php`, mapped at `src/Glpi/Search/SearchEngine.php:108-130` | Rated yes because CSV, XLSX, ODS, PDF export, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-portal",
+ "area": "sharing",
+ "name": "Show catalogue content on a shared external portal next to other apps' content.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-ai-assistant",
+ "area": "sharing",
+ "name": "Let an AI assistant query and update the catalogue through a tool interface.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-itsm-integration",
+ "area": "sharing",
+ "name": "Exchange application data with the organisation's service management tool.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
+ "glpi": "unknown",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48866 'Out-of-the-box integrations (ServiceNow, Signavio, SAP)' (2026-07-23): Pre-built connectors sync CMDB, process and ERP data.",
+ "bluedolphin": "docs, intelligence competitor_features#48973 'TOPdesk integration' (2026-07-23): Connector to TOPdesk asset/service data. | docs, intelligence competitor_features#27465 'TOPdesk Integration' (2026-04-12): Available on TOPdesk Marketplace for IT landscape insights",
+ "topdesk": "docs, intelligence competitor_features#48934 'Marketplace integrations (Lansweeper, ValueBlue)' (2026-07-23): Pre-built connectors incl. Lansweeper discovery and ValueBlue EA. | docs, intelligence competitor_features#27391 'Marketplace Integrations' (2026-04-12): TOPdesk Marketplace with third-party integrations including Lansweeper, BlueDolphin",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-webhooks",
+ "area": "sharing",
+ "name": "Notify another system automatically when a catalogue entry changes.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "share-self-hosted",
+ "area": "sharing",
+ "name": "Run the catalogue on your own infrastructure instead of the vendor's cloud.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "no",
+ "bluedolphin": "no",
+ "glpi": "yes",
+ "topdesk": "partial",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
+ "bluedolphin": "docs, intelligence competitor_features#27467 'SaaS Platform' (2026-04-12): Cloud-native SaaS, no installation required",
+ "glpi": "docs, intelligence competitor_features#48912 '100% open source (GPL)' (2026-07-23): Fully GPL; no license fees, broad device coverage.",
+ "topdesk": "docs, intelligence competitor_features#26346 'SaaS Platform' (2026-04-10): Cloud-hosted SaaS platform with automatic updates | Rated partial because offered as SaaS; on-premises not in the reading.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-faceted-search",
+ "area": "insight",
+ "name": "Search the catalogue and narrow the results with facets such as reference component and supplier.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#27553 'ICT Market Orientation' (2026-04-12): Find and compare software from registered ICT providers",
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141806 '9.2 Advanced search with per-case-type fields': the search engine is strong, with ~160 ticket search options (`src/Ticket.php:2670`), nested criteria groups, `AND`/`OR`/`AND NOT`/`OR NOT` (`src/Glpi/Search/SearchEngine.php:551-564`), cross-itemtype meta-criteria, but | Rated yes because search engine with nested criteria, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-saved-view",
+ "area": "insight",
+ "name": "Save a filtered view of the catalogue and open it again later.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141807 '9.3 Personal saved searches': `src/SavedSearch.php:52`, `is_private` default 1, personal ordering (`:824`) and a default per itemtype (`src/SavedSearch_User.php:94-115`), at `/front/savedsearch.php` | Rated yes because saved searches, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-dashboard",
+ "area": "insight",
+ "name": "Open a dashboard with counts of organisations, applications and contracts.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports. | docs, intelligence competitor_features#27424 'Dashboards & Reports' (2026-04-12): Real-time dashboards for CIO-level reporting",
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141816 '10.1 Configurable KPI dashboards (count, gauge, chart)': `src/Glpi/Dashboard/Grid.php:67` with 20 widget types: pie, donut, half pie/donut, bars, lines, areas, stacked and horizontal variants, big number, multiple numbers, summary numbers, markdown, search result, article list",
+ "topdesk": "docs, intelligence competitor_features#48936 'Reporting & dashboards' (2026-07-23): Operational reporting and dashboards.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-concept-orgs-widget",
+ "area": "insight",
+ "name": "See organisations still waiting in concept on the Nextcloud dashboard.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-reports-page",
+ "area": "insight",
+ "name": "Pick a ready-made report from a list and open it.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145791 'C-reporting-2 A canned report the product ships, run without building it.': glpi: Reports (Tools, Reports, front/report.default.php, report.dynamic.php, report.year.php, report.state.php, report.reservation.php, report.contract.php) Lane findings: D-glpi-35. | Rated yes because canned reports, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-custom-report",
+ "area": "insight",
+ "name": "Build your own report over the whole portfolio and export it.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141816 '10.1 Configurable KPI dashboards (count, gauge, chart)': `src/Glpi/Dashboard/Grid.php:67` with 20 widget types: pie, donut, half pie/donut, bars, lines, areas, stacked and horizontal variants, big number, multiple numbers, summary numbers, markdown, search result, article list",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-export-list",
+ "area": "insight",
+ "name": "Export a filtered list to a spreadsheet.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141818 '10.3 Export list results to CSV or XLSX': `src/Glpi/Search/Output/Csv.php`, `Xlsx.php`, `Ods.php` and `Pdf.php`, mapped at `src/Glpi/Search/SearchEngine.php:108-130` | Rated yes because source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-scheduled-report",
+ "area": "insight",
+ "name": "Have a report sent to named people on a schedule.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-audit-trail",
+ "area": "insight",
+ "name": "Look back at who changed what in the catalogue, and when.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141820 '10.5 Audit or event log viewer with filters and export': two logs, both searchable and exportable through the search engine: `src/Log.php:48` field-level object history (Historical tab, `src/Ticket.php:887`) and `src/Glpi/Event.php:63` the system/event log at `/front/logs.php` | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141852 '13.9 Audit trail including reads and views': writes are covered thoroughly: `src/Log.php:48` field-level history on every object, `src/Glpi/Event.php:63` the system log including logins (`src/Auth.php:1149-1163`), `src/RuleMatchedLog.php` for rule decisions. Reads | Rated yes because field-level history, source-read 2026-09-14.",
+ "topdesk": "docs, intelligence competitor_features#26345 'Audit Trail' (2026-04-10): Complete audit trail of all service management actions",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-live-updates",
+ "area": "insight",
+ "name": "See a list update by itself when someone else changes an entry.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#48969 'Real-time collaboration' (2026-07-23): Multiple stakeholders collaborate on models. | Rated partial because real-time collaboration on models.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-notifications",
+ "area": "insight",
+ "name": "Receive in-app notifications about changes that concern you.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "partial",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141783 '6.8 In-app notifications (bell)': `MODE_AJAX` is a wired delivery mode (`src/Notification_NotificationTemplate.php:55-59`, `getModes()` at `:381-398`, implementation `src/NotificationAjax.php`), rendering as a browser toast rather than a persistent inbox | Rated partial because toast delivery, not an inbox, source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-cost-report",
+ "area": "insight",
+ "name": "See a report of software cost per organisation or per domain.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "partial",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-feature-roadmap",
+ "area": "insight",
+ "name": "See in the app which features are available, in beta or coming soon.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-progress",
+ "area": "insight",
+ "name": "Follow the progress of a long synchronisation or import.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145875 'C-configuration-20 A long running administrative operation reports its progress.': glpi: Progress on a long operation (src/Glpi/Controller/ProgressController.php, Traits/AsyncOperationProgressControllerTrait.php) Lane findings: D-glpi-29. | Rated yes because source-read 2026-09-14.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ins-kb",
+ "area": "insight",
+ "name": "Keep knowledge articles about applications in a searchable knowledge base.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48909 'Knowledge base' (2026-07-23): Built-in KB with FAQ publishing.",
+ "topdesk": "docs, intelligence competitor_features#48931 'Knowledge base' (2026-07-23): Knowledge management and published articles.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-agent-inventory",
+ "area": "operations",
+ "name": "Discover the software installed on workstations and servers automatically with an agent.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48899 'Native inventory (GLPI Agent)' (2026-07-23): Built-in agent (ex-FusionInventory) discovers hardware/software automatically. | docs, intelligence competitor_features#3269 'Inventory' (2026-03-28): Automatic inventory discovery with FusionInventory agent",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-network-discovery",
+ "area": "operations",
+ "name": "Discover devices on the network automatically.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48911 'Network / SNMP discovery' (2026-07-23): SNMP network equipment inventory.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-saas-discovery",
+ "area": "operations",
+ "name": "Discover SaaS applications in use that nobody registered.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-hardware-assets",
+ "area": "operations",
+ "name": "Register hardware such as laptops and servers alongside software.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#3266 'IT Asset Management' (2026-03-28): Track hardware, software, and network assets",
+ "topdesk": "docs, intelligence competitor_features#27388 'Asset Management' (2026-04-12): Track hardware and software assets, locations, and assignments",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-ci-relations",
+ "area": "operations",
+ "name": "Record configuration items and their relations in a CMDB.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "glpi": "docs, intelligence competitor_features#48902 'CMDB & configuration relations' (2026-07-23): CI relationships and impact analysis.",
+ "topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | docs, intelligence competitor_features#27387 'CMDB / Configuration Management' (2026-04-12): Configuration database for registering IT objects like laptops, software, infrastructure",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-reconciliation",
+ "area": "operations",
+ "name": "Deduplicate and reconcile records that arrive from several sources.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-tickets",
+ "area": "operations",
+ "name": "Log incidents and requests against an application.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48903 'ITIL helpdesk / ticketing' (2026-07-23): Full incident/request ticketing with the assets module.",
+ "topdesk": "docs, intelligence competitor_features#48927 'Incident / ticket management' (2026-07-23): Core ITSM incident and request handling.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-change",
+ "area": "operations",
+ "name": "Run a change on an application through an approval workflow.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#3277 'Change Management' (2026-03-28): ITIL change management with approval workflows",
+ "topdesk": "docs, intelligence competitor_features#48929 'Change management' (2026-07-23): Structured change workflows with action sequences.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-sla",
+ "area": "operations",
+ "name": "Track service level targets for an application or supplier.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48904 'SLA management' (2026-07-23): SLA targets and escalation rules.",
+ "topdesk": "docs, intelligence competitor_features#48930 'SLA management' (2026-07-23): Service-level target tracking and reporting.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-self-service",
+ "area": "operations",
+ "name": "Let end users request software through a self-service portal.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "topdesk": "docs, intelligence competitor_features#48928 'Self-service portal' (2026-07-23): End-user portal for requests and knowledge, reduces direct support load.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-plugins",
+ "area": "operations",
+ "name": "Extend the product with plugins installed from a marketplace.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48906 'Plugin ecosystem' (2026-07-23): Large plugin marketplace (FormCreator, GenericObject, etc.). | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145919 'C-configuration-48 An extension is found, installed, updated and removed from inside the product.': glpi: Marketplace (Setup, Plugins, front/marketplace.php, marketplace.download.php, front/plugin.php) Lane findings: D-glpi-45.",
+ "topdesk": "docs, intelligence competitor_features#27391 'Marketplace Integrations' (2026-04-12): TOPdesk Marketplace with third-party integrations including Lansweeper, BlueDolphin",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-mobile",
+ "area": "operations",
+ "name": "Use the product from a native mobile app.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "yes",
+ "stackiq": "unknown",
+ "evidence": {
+ "topdesk": "docs, intelligence competitor_features#48937 'Mobile app' (2026-07-23): Native mobile operator app.",
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ },
+ {
+ "id": "ops-scheduled-sync",
+ "area": "operations",
+ "name": "Run the organisation and contact synchronisation on a schedule and see when it last ran.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "unknown",
+ "evidence": {
+ "stackiq": "not checked: the code reading for this row is under way"
+ }
+ }
+ ],
+ "pending": []
+}
From 67f640843254efc34395742d00d782308a7a1ce9 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Fri, 25 Sep 2026 20:40:27 +0200
Subject: [PATCH 15/45] feat(parity): rate stackiq's own column from the code
134 rated rows and 39 pending across 12 areas. Every own rating carries
a path and a line, a reachedOn and, on sibling rows, the owning repo.
---
openspec/parity/capabilities.json | 3603 +++++++++++++++++++++--------
1 file changed, 2690 insertions(+), 913 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index d885fb5e8..c797863ad 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -165,14 +165,25 @@
"bluedolphin": "yes",
"glpi": "partial",
"topdesk": "partial",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:592 Modules page (FacetedCatalogIndexView, schema module) with the library CnIndexPage create form at src/views/FacetedCatalogIndexView.vue:108; lib/Settings/softwarecatalogus_register.json:6777 module schema has name, shortDescription/longDescription and provider (Supplier) but NO status property; status lives on usage (register.json:2654, enum Acquisition..In production) which has no page",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Modules /modules (menu Applications), Add button",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "high",
+ "note": "An application with supplier and description can be registered on the Modules page, but the module schema has no status field, and the per-organisation usage that carries a status has no page to create it on. The Modules list also cannot open ModuleDetail: its standalone CnIndexPage (FacetedCatalogIndexView.vue:108-117) binds no @view/@row-click, so the View action is inert.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map. | docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape",
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | docs, intelligence competitor_features#27422 'Fact Sheets & Data Model' (2026-04-12): Flexible data model for applications, processes, IT components",
"bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository. | docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
"glpi": "docs, intelligence competitor_features#48900 'Software inventory & catalog' (2026-07-23): Detects installed software and normalises into a software catalog. | docs, intelligence competitor_features#3267 'Software Catalog' (2026-03-28): Manage software licenses and installations | Rated partial because software is an inventoried asset, not a described application.",
"topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | docs, intelligence competitor_features#27387 'CMDB / Configuration Management' (2026-04-12): Configuration database for registering IT objects like laptops, software, infrastructure | Rated partial because software is a CMDB object among assets.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:592 Modules page (FacetedCatalogIndexView, schema module) with the library CnIndexPage create form at src/views/FacetedCatalogIndexView.vue:108; lib/Settings/softwarecatalogus_register.json:6777 module schema has name, shortDescription/longDescription and provider (Supplier) but NO status property; status lives on usage (register.json:2654, enum Acquisition..In production) which has no page"
}
},
{
@@ -185,10 +196,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Suites /suites and SuiteDetail /suites/:id (Related panel); ModuleDetail Related panel shows suites that include it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "low",
+ "note": "Stackiq's 'module' is the whole application, so there is no breakdown of one application into modules. The nearest thing is a suite (product) listing its applications, which answers 'which module belongs to which product' but not the decomposition.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated partial because fact sheets separate Application from IT Component.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')"
}
},
{
@@ -201,28 +223,21 @@
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:915 Moduleversies type:index (columns version, module, dateInUse, status) + :937 ModuleversieDetail; register.json:7649 moduleVersion schema with dateInUse (register.json:7746), dateInDevelopment, dateEndSupport, dateWithdrawn",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Module versions /moduleversies (menu), Add + detail /moduleversies/:id; also ModuleDetail md-versions list (src/manifest.json:504, allowCreate false)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "lifecycle-and-end-of-support",
+ "featureConfidence": "medium",
+ "note": "A version is created on the Module versions index with its module and date in use, and opens on its own detail page.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48900 'Software inventory & catalog' (2026-07-23): Detects installed software and normalises into a software catalog. | Rated partial because installed versions come from inventory.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "land-usage-record",
- "area": "landscape",
- "name": "Record that your organisation uses a module, as a usage separate from the product itself.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "partial",
- "bluedolphin": "partial",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
- "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers.",
- "bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:915 Moduleversies type:index (columns version, module, dateInUse, status) + :937 ModuleversieDetail; register.json:7649 moduleVersion schema with dateInUse (register.json:7746), dateInDevelopment, dateEndSupport, dateWithdrawn"
}
},
{
@@ -235,25 +250,47 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/dialogs/SuiteWizardDialog.vue:183 onSubmit saves a suite via objectStore.saveObject('suite') with applications[] (src/utils/suiteWizard.js:44 requires at least one); mounted by src/views/suites/SuitesIndexView.vue:46 on manifest page Suites (src/manifest.json:666)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Suites /suites (menu), New suite wizard",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "medium",
+ "note": "A three-step wizard bundles existing applications into one suite. Caveat: a row click on the Suites list only toggles selection (the library returns before emitting row-click when selectable, SuitesIndexView.vue:35), so SuiteDetail is not opened from the list, and its data widget includes stale field names (src/manifest.json:683 beschrijvingKort, contactpersoon).",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/dialogs/SuiteWizardDialog.vue:183 onSubmit saves a suite via objectStore.saveObject('suite') with applications[] (src/utils/suiteWizard.js:44 requires at least one); mounted by src/views/suites/SuitesIndexView.vue:46 on manifest page Suites (src/manifest.json:666)"
}
},
{
"id": "land-services",
"area": "landscape",
- "name": "Register a service a supplier delivers on top of one or more applications, such as hosting or support.",
+ "name": "Register a service a supplier delivers on top of applications, such as hosting or support.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:647 Diensten page (FacetedCatalogIndexView, schema catalogService) with the CnIndexPage create form; register.json:1324 catalogService with provider (required), modules[] (register.json:1419) and type enum Functional/Application/Technical management, Implementation support, Training, Licence reseller (register.json:1459)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Services /diensten (menu), Add button",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "offering-and-usage-listings",
+ "featureConfidence": "medium",
+ "note": "A supplier's service over one or more applications is registered on the Services page. There is no 'hosting' service type (technical management is the nearest), and services have no detail page, so a row cannot be opened.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48838 'Supplier product offering (aanbod) registration' (2026-07-23): ICT suppliers publish their product offering for the municipal market with global functionality descriptions. | Rated partial because offering registration covers products; services not named in the reading.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:647 Diensten page (FacetedCatalogIndexView, schema catalogService) with the CnIndexPage create form; register.json:1324 catalogService with provider (required), modules[] (register.json:1419) and type enum Functional/Application/Technical management, Implementation support, Training, Licence reseller (register.json:1459)"
}
},
{
@@ -266,9 +303,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "specified",
+ "evidence": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "A sector schema exists, but no application, service or organisation can be tagged with a sector and no page lists sectors.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395"
}
},
{
@@ -281,10 +327,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Modules /modules create/edit form (Contact person field)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "low",
+ "note": "One contact person per application can be set, but there is no separate business owner and technical owner. ModuleDetail's data widget includes 'contactpersoon', a key the schema no longer has, so the contact may not show there.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | Rated partial because surveys go to application owners, so ownership is modelled.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')"
}
},
{
@@ -297,11 +354,21 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "Looked in src/manifest.json, src/views, lib/Controller: no field-definition or schema-extension UI in stackiq; the data model is fixed in lib/Settings/softwarecatalogus_register.json",
+ "owner": "ConductionNL/openregister",
+ "ownerNote": "reader wrote: ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "Stackiq offers no way to add fields. Editing the schema in OpenRegister's own admin UI is possible there, but that is an OpenRegister feature, not a stackiq page.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because flexible fact sheet data model.",
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141835 '11.17 Custom object type management': GLPI 11 ships admin-defined itemtypes with custom fields and capabilities (`src/Glpi/CustomObject/AbstractDefinition.php`, `src/Glpi/Asset/AssetDefinition.php`, `src/Glpi/Asset/CustomFieldDefinition.php`), but the machin | Rated yes because custom asset definitions and custom fields, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "Looked in src/manifest.json, src/views, lib/Controller: no field-definition or schema-extension UI in stackiq; the data model is fixed in lib/Settings/softwarecatalogus_register.json"
}
},
{
@@ -314,26 +381,20 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "Library CnIndexPage (@conduction/nextcloud-vue 2.55.1, package-lock) showMassImport default true (CnIndexPage.vue:1599) and self-mode handleMassImport (selfModeActions.js:168) POSTs to /apps/openregister/api/registers/{register}/import with the schema for CSV (selfModeIO.js:82); rendered on the Modules page's CnIndexPage (src/views/FacetedCatalogIndexView.vue:108)",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "Modules /modules, Import in the index actions (also every type:index page)",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "The generic index page offers a file import (CSV per schema, or a register-wide JSON/Excel) that OpenRegister executes. Nothing stackiq-specific maps a spreadsheet's supplier names to organisation references, so relation columns must already hold identifiers.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27428 'EAM Automation' (2026-04-12): Automated data collection from ServiceNow, Jira, cloud providers | Rated partial because automated collection from ServiceNow, Jira and cloud.",
"bluedolphin": "docs, intelligence competitor_features#48971 'Data import (Excel)' (2026-07-23): Bulk import of application/portfolio data.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "land-migrate-legacy",
- "area": "landscape",
- "name": "Bring over what was registered in the previous catalogue so nobody has to type it in again.",
- "origin": "competitor",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "Library CnIndexPage (@conduction/nextcloud-vue 2.55.1, package-lock) showMassImport default true (CnIndexPage.vue:1599) and self-mode handleMassImport (selfModeActions.js:168) POSTs to /apps/openregister/api/registers/{register}/import with the schema for CSV (selfModeIO.js:82); rendered on the Modules page's CnIndexPage (src/views/FacetedCatalogIndexView.vue:108)"
}
},
{
@@ -346,11 +407,22 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:491 ModuleDetail: md-versions (:504), md-compliance (:503), md-related generic Related panel (:502); no contract widget (catalogContract links to service/usage, register.json:3250, not to module); md-data include lists stale keys beschrijvingKort/beschrijvingLang/contactpersoon (:500)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleDetail /modules/:id, reached from OrganisatieDetail Applications list (src/manifest.json:417 rowRoute ModuleDetail); NOT from the Modules list (FacetedCatalogIndexView.vue:108 binds no @view/@row-click)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "medium",
+ "note": "The application page shows versions and compliance claims, and usages only as untyped entries in the generic Related panel. Contracts are not shown. The page cannot be opened from the Applications list itself, and its data widget asks for three field names the schema no longer has, so the descriptions do not render.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because fact sheet is the per-application page.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:491 ModuleDetail: md-versions (:504), md-compliance (:503), md-related generic Related panel (:502); no contract widget (catalogContract links to service/usage, register.json:3250, not to module); md-data include lists stale keys beschrijvingKort/beschrijvingLang/contactpersoon (:500)"
}
},
{
@@ -363,9 +435,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "Library CnIndexPage mass delete/copy/export (showMassDelete default true, CnIndexPage.vue:1617; selfModeActions.js:63 handleMassDelete) on index pages; stackiq's MassPublishObjects/MassLockObjects dialogs (src/dialogs/Dialogs.vue:8-14) are only opened from src/modals/object/ViewObject.vue:4865, and ViewObject is only mounted for modals 'viewOrganisatie'/'viewContactpersoon' (src/modals/Modals.vue:7,19) which nothing in src/ sets",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Any index page (e.g. Module versions /moduleversies): select rows, mass delete; publish and lock: nothing reaches them",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "open-data-publishing",
+ "featureConfidence": "low",
+ "note": "Many entries can be selected and deleted together through the library index page. The mass publish and mass lock dialogs exist but hang off a view modal no page opens, and the publish endpoint (lib/Controller/PublicationController.php, PUT /api/publication/...) has no frontend caller.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "Library CnIndexPage mass delete/copy/export (showMassDelete default true, CnIndexPage.vue:1617; selfModeActions.js:63 handleMassDelete) on index pages; stackiq's MassPublishObjects/MassLockObjects dialogs (src/dialogs/Dialogs.vue:8-14) are only opened from src/modals/object/ViewObject.vue:4865, and ViewObject is only mounted for modals 'viewOrganisatie'/'viewContactpersoon' (src/modals/Modals.vue:7,19) which nothing in src/ sets"
}
},
{
@@ -378,9 +461,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/components/organisations/OrganisationMergePanel.vue:46 (admin-only controls) mounted as OrganisatieDetail bodyWidget org-merge (src/manifest.json:430); lib/Controller/MergeController.php:106 execute with isAdmin check at :142; generic src/modals/object/MergeObject.vue only mounted for modal 'mergeOrganisatie' which nothing sets",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "OrganisatieDetail /organisaties/:id, Merge panel (admins only)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Only organisations can be merged, with a dry run first, and only by a Nextcloud admin. Applications, services and other entries have no merge.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/components/organisations/OrganisationMergePanel.vue:46 (admin-only controls) mounted as OrganisatieDetail bodyWidget org-merge (src/manifest.json:430); lib/Controller/MergeController.php:106 execute with isAdmin check at :142; generic src/modals/object/MergeObject.vue only mounted for modal 'mergeOrganisatie' which nothing sets"
}
},
{
@@ -393,11 +485,20 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No survey, attestation or owner-confirmation code in lib/ or src/ (searched survey/enquete/confirm entry)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Nothing asks owners to confirm or correct their entries.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | docs, intelligence competitor_features#27423 'Survey-Based Data Collection' (2026-04-12): Crowdsource architecture data from application owners",
"bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No survey, attestation or owner-confirmation code in lib/ or src/ (searched survey/enquete/confirm entry)"
}
},
{
@@ -410,9 +511,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No page scores how complete or current an entry is.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)"
}
},
{
@@ -425,9 +535,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:3 setup wizard step load-demo-data (:24); lib/Controller/SetupController.php:202 runAction load-demo-data (AuthorizedAdminSetting); lib/Service/DemoDataService.php:202 install() imports lib/Settings/stackiq_mock_register.json (120 objects, 6 per schema) through OpenRegister ConfigurationService::importFromApp",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "First-run setup wizard (admin), step 'Load example data'",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "An admin picks the demo dataset in the setup wizard and it is imported through OpenRegister. Admin-only, which suits an installation task.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:3 setup wizard step load-demo-data (:24); lib/Controller/SetupController.php:202 runAction load-demo-data (AuthorizedAdminSetting); lib/Service/DemoDataService.php:202 install() imports lib/Settings/stackiq_mock_register.json (120 objects, 6 per schema) through OpenRegister ConfigurationService::importFromApp"
}
},
{
@@ -440,9 +559,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/dialogs/SuiteWizardDialog.vue (3 steps) is the only wizard, opened from src/views/suites/SuitesIndexView.vue:46; applications, services and connections use the bare CnIndexPage form (FacetedCatalogIndexView.vue:108) or nothing",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Suites /suites, New suite wizard only",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Only suites get a step-by-step wizard. Applications and services are added through a plain form, and connections have no page at all.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/dialogs/SuiteWizardDialog.vue (3 steps) is the only wizard, opened from src/views/suites/SuitesIndexView.vue:46; applications, services and connections use the bare CnIndexPage form (FacetedCatalogIndexView.vue:108) or nothing"
}
},
{
@@ -455,9 +583,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/components/sbom/SbomComponentsPanel.vue lists sbomComponent rows (name/version/purl/licenses) as the ModuleversieDetail 'Components' sidebar tab (src/manifest.json:961); register.json:7920 sbomComponent schema",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleversieDetail /moduleversies/:id, sidebar tab Components",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "A module version's page lists the third-party components imported from its SBOM.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/components/sbom/SbomComponentsPanel.vue lists sbomComponent rows (name/version/purl/licenses) as the ModuleversieDetail 'Components' sidebar tab (src/manifest.json:961); register.json:7920 sbomComponent schema"
}
},
{
@@ -470,28 +607,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:6869 module.cloudDienstverleningsmodel enum On-premises, IaaS, PaaS, SaaS; register.json:6906 hostingLocation and hostingJurisdiction; usage.cloudDienstverleningsmodel (register.json:3050); on ModuleDetail md-data include (src/manifest.json:500)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Modules /modules create/edit form; ModuleDetail data widget",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "medium",
+ "note": "The application form records on-premises, IaaS, PaaS or SaaS plus hosting location and jurisdiction. There is no field naming the hosting party itself.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | Rated partial because SaaS is tracked as a class of application.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "conn-register-connection",
- "area": "connections",
- "name": "Register a connection between two applications, with its direction and the standard it uses.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "yes",
- "bluedolphin": "partial",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
- "sap-leanix": "docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
- "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | Rated partial because ArchiMate flow relations.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register.json:6869 module.cloudDienstverleningsmodel enum On-premises, IaaS, PaaS, SaaS; register.json:6906 hostingLocation and hostingJurisdiction; usage.cloudDienstverleningsmodel (register.json:3050); on ModuleDetail md-data include (src/manifest.json:500)"
}
},
{
@@ -504,10 +634,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: OpenRegister objects API",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "low",
+ "note": "The field for a national provision exists on the connection schema, but with no connection page nobody can fill it in stackiq.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48841 'National provisions (landelijke voorzieningen) linking' (2026-07-23): Records links between applications and national government provisions.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection"
}
},
{
@@ -520,10 +661,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "specified",
+ "evidence": "No manifest page with schema connection (src/manifest.json and src/manifest.d/*.json); the Integrations page (src/manifest.d/connection-registry.json:23) lists integriq app_connection, explicitly not stackiq's connection schema (its _note)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "medium",
+ "note": "There is no list of connections in the catalogue. The Integrations page lists outside integrations, a different thing.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No manifest page with schema connection (src/manifest.json and src/manifest.d/*.json); the Integrations page (src/manifest.d/connection-registry.json:23) lists integriq app_connection, explicitly not stackiq's connection schema (its _note)"
}
},
{
@@ -536,10 +688,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleDetail /modules/:id, Related panel (untyped); API /api/koppelingen-gebruik/{uuid}",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "low",
+ "note": "Connections that reference an application should appear among the untyped related objects on its page, but there is no connections section and nothing to open. The dedicated per-application endpoint is API only.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/"
}
},
{
@@ -552,12 +715,23 @@
"bluedolphin": "yes",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No diagram rendering in src/ (no graph library; src/store/modules/view.js GET /api/views has no importer outside itself); lib/Service/ArchiMateExportService.php exports GEMMA views as ArchiMate XML without koppeling objects (no 'koppeling' in lib/Service/ArchiMate*)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "low",
+ "note": "No page draws connections. The ArchiMate export can be opened in Archi, but it carries GEMMA views and usages, not the catalogue's connections.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model. | docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
"bluedolphin": "docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models. | docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145369 'C-case-core-38 The graph of what a case is linked to is drawn, and exported.': glpi: Impact graph (Tools, front/impactitem.php, impactcsv.php, src/Impact.php) Lane findings: D-glpi-40. | Rated yes because impact graph, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No diagram rendering in src/ (no graph library; src/store/modules/view.js GET /api/views has no importer outside itself); lib/Service/ArchiMateExportService.php exports GEMMA views as ArchiMate XML without koppeling objects (no 'koppeling' in lib/Service/ArchiMate*)"
}
},
{
@@ -570,42 +744,21 @@
"bluedolphin": "yes",
"glpi": "yes",
"topdesk": "partial",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:502 ModuleDetail md-related (library CnRelatedObjectsWidget: /used lists every object that references this module: usages, connections, suites, services, vulnerabilities); no dependency or impact computation in lib/ or src/",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "ModuleDetail /modules/:id, Related panel",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "The only way to see what depends on an application is the generic list of objects that reference it, which OpenRegister's relation index fills. There is no impact view or retirement check.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
"glpi": "docs, intelligence competitor_features#48902 'CMDB & configuration relations' (2026-07-23): CI relationships and impact analysis.",
"topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | Rated partial because relations between assets.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "conn-usage-of-connection",
- "area": "connections",
- "name": "Record that your organisation actually runs a given connection, not only that it exists.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "conn-shared-with-others",
- "area": "connections",
- "name": "See which connections you run together with other organisations.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:502 ModuleDetail md-related (library CnRelatedObjectsWidget: /used lists every object that references this module: usages, connections, suites, services, vulnerabilities); no dependency or impact computation in lib/ or src/"
}
},
{
@@ -618,9 +771,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "specified",
+ "evidence": "register.json:3563 connection.type enum (file transfer, digikoppeling, message que, webservices, api, ...) exists, but no connection list page to filter",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The type field exists but there is no connection list to filter.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register.json:3563 connection.type enum (file transfer, digikoppeling, message que, webservices, api, ...) exists, but no connection list page to filter"
}
},
{
@@ -633,10 +795,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Stackiq has no record for an API an application exposes.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27425 'API Management' (2026-04-12): Catalog and manage APIs across the application landscape",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label"
}
},
{
@@ -649,10 +820,21 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it (nearest: admin settings ArchiMate organisation export)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "low",
+ "note": "The organisation ArchiMate export carries modules and usages but not connections, so an application's link graph cannot be exported.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145369 'C-case-core-38 The graph of what a case is linked to is drawn, and exported.': glpi: Impact graph (Tools, front/impactitem.php, impactcsv.php, src/Impact.php) Lane findings: D-glpi-40. | Rated yes because impactcsv export, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*"
}
},
{
@@ -665,57 +847,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "arch-refcomp-mapping",
- "area": "architecture",
- "name": "Place an application on the GEMMA reference components it fulfils.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48835 'Reference component mapping (referentiecomponenten)' (2026-07-23): Maps each registered software product onto GEMMA reference components/domains so functionality is comparable across suppliers. | docs, intelligence competitor_features#27551 'Reference Component Linking' (2026-04-12): Link software to GEMMA reference components",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "arch-gemma-views",
- "area": "architecture",
- "name": "Open a GEMMA architecture view with your own applications drawn inside it.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map. | Rated yes because landscape auto-plotted on the reference component map.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "arch-shared-overlay",
- "area": "architecture",
- "name": "On a GEMMA view, see which applications you share with partner organisations, drawn differently from your own.",
- "origin": "own-code",
- "vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.d/connection-registry.json:23 Integrations page (register integriq, schema app_connection) with visibleIf appInstalled 'integriq' (:17) and permission admin (:15,:27); Add integration handler leaves for integriq (src/services/connectionRegistry.js:43); rows synced from lib/Settings/connections.json (email, federation, eol-feed); status worked out by integriq",
+ "owner": "ConductionNL/integriq"
+ },
+ "reachedOn": "Integrations /settings/integrations (settings menu, admin, only when app id 'integriq' is installed)",
+ "provider": "integriq",
+ "providerHow": "read-from-code",
+ "note": "With integriq installed, an admin sees stackiq's three integrations and their checked status on one page, and Add integration opens integriq. Without integriq the page is hidden, and the checking is integriq's.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48844 'Municipal cooperation / shared-service management' (2026-07-23): Manages gemeente-samenwerking (shared service centres) registering a joint landscape.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.d/connection-registry.json:23 Integrations page (register integriq, schema app_connection) with visibleIf appInstalled 'integriq' (:17) and permission admin (:15,:27); Add integration handler leaves for integriq (src/services/connectionRegistry.js:43); rows synced from lib/Settings/connections.json (email, federation, eol-feed); status worked out by integriq"
}
},
{
@@ -728,10 +871,21 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:96 POST /api/archimate/import -> lib/Controller/SettingsController.php:1490 importArchiMate (isAdmin check :1496) -> lib/Service/ArchiMateImportService.php (5961 lines); UI src/views/settings/sections/ArchiMateImportExport.vue:32 file input + :791 importArchiMateFile",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section ArchiMate Import/Export (Nextcloud admin settings, stackiq section)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "high",
+ "note": "Works end to end but only a Nextcloud admin can import: the endpoint rejects non-admins and the upload control lives only on the admin settings page.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27459 'ArchiMate & BPMN Support' (2026-04-12): Full ArchiMate and BPMN modeling in one platform | Rated yes because full ArchiMate support; import format not named in the reading.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "appinfo/routes.php:96 POST /api/archimate/import -> lib/Controller/SettingsController.php:1490 importArchiMate (isAdmin check :1496) -> lib/Service/ArchiMateImportService.php (5961 lines); UI src/views/settings/sections/ArchiMateImportExport.vue:32 file input + :791 importArchiMateFile"
}
},
{
@@ -744,11 +898,22 @@
"bluedolphin": "partial",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:97 POST /api/archimate/export -> lib/Controller/SettingsController.php:1615 exportArchiMate (admin or org-admin via verifyOrgExportPermission :1735) -> lib/Service/ArchiMateService.php:232 exportToArchiMate (docblock: organization filter 'currently not implemented'); UI ArchiMateImportExport.vue:591 'Export Base' button",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section ArchiMate Import/Export, button Export Base",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "high",
+ "note": "The export produces a downloadable AMEF XML, but only from the admin settings page; organisation admins may call the API but have no page for it.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27554 'ArchiMate Export' (2026-04-12): Export to ArchiMate format for use in architecture tools",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "appinfo/routes.php:97 POST /api/archimate/export -> lib/Controller/SettingsController.php:1615 exportArchiMate (admin or org-admin via verifyOrgExportPermission :1735) -> lib/Service/ArchiMateService.php:232 exportToArchiMate (docblock: organization filter 'currently not implemented'); UI ArchiMateImportExport.vue:591 'Export Base' button"
}
},
{
@@ -761,10 +926,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:98 GET /api/archimate/export/organization/{organizationUuid} -> lib/Controller/SettingsController.php:1685 exportOrgArchiMate -> lib/Service/ArchiMateService.php:302 -> lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications in GEMMA view copies; UI ArchiMateImportExport.vue:602 'Organization Export' with Modules/Deelnames/Gebruik checkboxes",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section ArchiMate Import/Export, organisation select + Organization Export",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "high",
+ "note": "Complete logic, but reachable only on the admin settings page; an ordinary organisation user cannot export its own landscape from a stackiq page.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape | docs, intelligence competitor_features#27554 'ArchiMate Export' (2026-04-12): Export to ArchiMate format for use in architecture tools | Rated yes because map and export the municipality's landscape.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "appinfo/routes.php:98 GET /api/archimate/export/organization/{organizationUuid} -> lib/Controller/SettingsController.php:1685 exportOrgArchiMate -> lib/Service/ArchiMateService.php:302 -> lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications in GEMMA view copies; UI ArchiMateImportExport.vue:602 'Organization Export' with Modules/Deelnames/Gebruik checkboxes"
}
},
{
@@ -777,9 +953,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:107 POST /api/archimate/test-round-trip -> lib/Controller/SettingsController.php:2886 (@NoAdminRequired, any logged-in user) -> lib/Service/ArchiMateService.php:1496 testRoundTrip: reads $importResult['imported_count'] (:1528), a key no import path sets, and compares it to exportToArchiMate's 'exported_count' which is the literal string 'calculated_in_export_service' (:271), so it can never report success; it also imports a test model into the live register",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it: src/store/modules/settings.js:1953 testRoundTrip action has no caller",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "medium",
+ "note": "There is an endpoint, but its comparison is broken (a missing key against a placeholder string) and no page calls it. The compare_archimate.py/.php scripts in the repo root are developer tools, not a user capability.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "appinfo/routes.php:107 POST /api/archimate/test-round-trip -> lib/Controller/SettingsController.php:2886 (@NoAdminRequired, any logged-in user) -> lib/Service/ArchiMateService.php:1496 testRoundTrip: reads $importResult['imported_count'] (:1528), a key no import path sets, and compares it to exportToArchiMate's 'exported_count' which is the literal string 'calculated_in_export_service' (:271), so it can never report success; it also imports a test model into the live register"
}
},
{
@@ -792,24 +979,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "arch-gemma-api",
- "area": "architecture",
- "name": "Retrieve the GEMMA architecture itself through an API.",
- "origin": "competitor",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "building",
+ "evidence": "appinfo/routes.php:103 POST /api/archimate/import/cancel -> lib/Service/SettingsService.php:5200 calls ArchiMateService::cancelArchiMateImport(), which does not exist in lib/Service/ArchiMateService.php (Error, not caught by catch(\\Exception)); routes.php:119-120 /api/progress/{operationId} read ProgressTracker, but the ArchiMate import never writes to it (only SbomImportService gets it, lib/AppInfo/Application.php:507); ArchiMateImportExport.vue:538 shows only a spinner, no cancel button",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section ArchiMate Import/Export shows a spinner during import; nothing shows progress or offers cancel",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "medium",
+ "note": "The import runs as one blocking request with a spinner. The cancel endpoint calls a missing method and import progress is never recorded, so neither following nor cancelling works.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "appinfo/routes.php:103 POST /api/archimate/import/cancel -> lib/Service/SettingsService.php:5200 calls ArchiMateService::cancelArchiMateImport(), which does not exist in lib/Service/ArchiMateService.php (Error, not caught by catch(\\Exception)); routes.php:119-120 /api/progress/{operationId} read ProgressTracker, but the ArchiMate import never writes to it (only SbomImportService gets it, lib/AppInfo/Application.php:507); ArchiMateImportExport.vue:538 shows only a spinner, no cancel button"
}
},
{
@@ -822,9 +1005,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json StandaardDetail /standaarden/:id st-data widget shows all element fields (documentation, gemmaNotes) of a standard; FacetedCatalogIndexView.vue:150 shows reference components by name only",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Standaarden /standaarden and StandaardDetail /standaarden/:id for standards; no page for reference components or other GEMMA terms, and no in-place definition while working",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "low",
+ "note": "You can open a standard's page and read its definition, but reference components and other GEMMA terms have no page and there is no inline definition where they appear.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json StandaardDetail /standaarden/:id st-data widget shows all element fields (documentation, gemmaNotes) of a standard; FacetedCatalogIndexView.vue:150 shows reference components by name only"
}
},
{
@@ -837,11 +1031,22 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "module.referenceComponents / usage.usedForReferenceComponents in lib/Settings/softwarecatalogus_register.json hold the application-to-reference-component mapping; lib/Service/ArchiMateExportService.php:2734 draws it only into exported view copies",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Modules /modules facet by reference component (a list, not a map); the map itself only in Archi after the admin org export",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "medium",
+ "note": "The mapping to GEMMA reference components exists, but there is no map view in stackiq; you only see it as a facet list or in Archi after an admin export.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | docs, intelligence competitor_features#27420 'Business Capability Mapping' (2026-04-12): Map applications to business capabilities and processes",
"bluedolphin": "docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "module.referenceComponents / usage.usedForReferenceComponents in lib/Settings/softwarecatalogus_register.json hold the application-to-reference-component mapping; lib/Service/ArchiMateExportService.php:2734 draws it only into exported view copies"
}
},
{
@@ -854,11 +1059,20 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "src/manifest.json has no page for the view or element schema beyond Standaarden; no diagram editor in src/views or src/components",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Models are imported and exported as ArchiMate files; nothing lets a user draw or edit a model inside stackiq.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model.",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json has no page for the view or element schema beyond Standaarden; no diagram editor in src/views or src/components"
}
},
{
@@ -871,10 +1085,19 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no process schema in lib/Settings/softwarecatalogus_register.json (20 schemas listed under components.schemas); no process page in src/manifest.json",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Business processes are not modelled; the only link applications have is to GEMMA reference components.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27464 'Process Mapping' (2026-04-12): Map processes, applications, data, and technology",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "no process schema in lib/Settings/softwarecatalogus_register.json (20 schemas listed under components.schemas); no process page in src/manifest.json"
}
},
{
@@ -887,10 +1110,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "searched src/manifest.json and the register for scenario/future-state/toekomst: nothing; usage.status 'Planned' and plannedReplacement (register) are per-usage fields, not a comparable landscape",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Planned usage and planned replacements exist per record, but there is no future-state model and no comparison with today.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27419 'IT Transformation' (2026-04-12): Plan and execute cloud migrations and modernization | Rated partial because transformation planning.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "searched src/manifest.json and the register for scenario/future-state/toekomst: nothing; usage.status 'Planned' and plannedReplacement (register) are per-usage fields, not a comparable landscape"
}
},
{
@@ -903,10 +1135,19 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "grep for uncovered/gap/coverage in lib and src found nothing; lib/Service/FacetService.php counts modules per reference component but never lists components with zero coverage",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No report or view lists reference components that no application in your landscape covers.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "grep for uncovered/gap/coverage in lib and src found nothing; lib/Service/FacetService.php counts modules per reference component but never lists components with zero coverage"
}
},
{
@@ -919,10 +1160,19 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no diagram generation in lib/Service or src; no AI integration for diagrams",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Nothing drafts diagrams.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48970 'AI-powered diagramming' (2026-07-23): AI assists diagram generation. | docs, intelligence competitor_features#27461 'AI-Powered Diagramming' (2026-04-12): Auto-generate BPMN diagrams with built-in AI",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "no diagram generation in lib/Service or src; no AI integration for diagrams"
}
},
{
@@ -935,26 +1185,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json page Standaarden /standaarden (index on @resolve:amef_register schema element, filter gemmaType=standaard, columns name/gemmaThema/gemmaStatus/url) and StandaardDetail /standaarden/:id with compliance claims per standard; menu entry Standards (order 50)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Standaarden /standaarden, menu Standards; detail StandaardDetail /standaarden/:id",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "high",
+ "note": "The GEMMA standards imported with the AMEF model are browsable on their own page with a detail view that lists compliance claims.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48840 'Standards support declaration' (2026-07-23): Suppliers declare which standards (StUF, ZGW/Zaakgericht APIs, etc.) a product supports. | docs, intelligence competitor_features#27556 'Standards Mapping' (2026-04-12): Map software to Forum Standaardisatie standards",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "comp-declare-standard",
- "area": "compliance",
- "name": "Declare that an application supports a specific version of a standard.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48840 'Standards support declaration' (2026-07-23): Suppliers declare which standards (StUF, ZGW/Zaakgericht APIs, etc.) a product supports.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json page Standaarden /standaarden (index on @resolve:amef_register schema element, filter gemmaType=standaard, columns name/gemmaThema/gemmaStatus/url) and StandaardDetail /standaarden/:id with compliance claims per standard; menu entry Standards (order 50)"
}
},
{
@@ -967,9 +1212,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json compliancy.evidence (file, pdf/jpeg/png/doc, 10 MB), compliancy.url, compliancy.evidenceReference; src/manifest.json KompliantieDetail cm-files widget type integration integrationId files 'Evidence documents'",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "KompliantieDetail /komplianties/:id, Evidence documents widget; evidence URL/file fields on the compliance form",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "high",
+ "note": "Evidence can be attached as a file, a URL or a Nextcloud Files link on the compliance claim's page.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.evidence (file, pdf/jpeg/png/doc, 10 MB), compliancy.url, compliancy.evidenceReference; src/manifest.json KompliantieDetail cm-files widget type integration integrationId files 'Evidence documents'"
}
},
{
@@ -982,9 +1238,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/utils/complianceMatrix.js:9-17 cell state verified = compliancy record with evidence (hasEvidence :107 checks evidence/evidenceReference/url), claimed = link without evidence; rendered by src/views/ComplianceMatrixView.vue",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ComplianceMatrix /compliance-matrix (menu Reports & Compliance > Compliance matrix)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "high",
+ "note": "The matrix separates claims with evidence from claims without, but 'verified' only means evidence is attached: no one reviews or approves the evidence, so a supplier-uploaded document counts as verified.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/utils/complianceMatrix.js:9-17 cell state verified = compliancy record with evidence (hasEvidence :107 checks evidence/evidenceReference/url), claimed = link without evidence; rendered by src/views/ComplianceMatrixView.vue"
}
},
{
@@ -997,9 +1264,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json ComplianceMatrix /compliance-matrix custom page -> src/customComponents.js ComplianceMatrixView -> src/views/ComplianceMatrixView.vue (modules x selected standard versions or BIO measures, src/utils/complianceMatrix.js:270 columns)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ComplianceMatrix /compliance-matrix, menu Reports & Compliance > Compliance matrix",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "high",
+ "note": "A filter-first matrix of applications against chosen standard versions (or BIO measures), cell by cell with verified/claimed/none.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json ComplianceMatrix /compliance-matrix custom page -> src/customComponents.js ComplianceMatrixView -> src/views/ComplianceMatrixView.vue (modules x selected standard versions or BIO measures, src/utils/complianceMatrix.js:270 columns)"
}
},
{
@@ -1012,9 +1290,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:275 POST /api/bulk-sync-standards -> lib/Controller/SettingsController.php:3598 (isAdmin check) -> lib/Service/ModuleComplianceService.php:527 bulkSyncModuleStandards (reads up to 1000 compliancy records and updates module standards); UI src/views/settings/sections/StatisticsOverview.vue:79 button -> src/modals/BulkSyncDialog.vue:321",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings, Statistics overview section, bulk sync button",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "medium",
+ "note": "One action updates every module's standards from its compliance records, but only a Nextcloud admin can run it and it stops at 1000 compliance records.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "appinfo/routes.php:275 POST /api/bulk-sync-standards -> lib/Controller/SettingsController.php:3598 (isAdmin check) -> lib/Service/ModuleComplianceService.php:527 bulkSyncModuleStandards (reads up to 1000 compliancy records and updates module standards); UI src/views/settings/sections/StatisticsOverview.vue:79 button -> src/modals/BulkSyncDialog.vue:321"
}
},
{
@@ -1027,9 +1316,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json BioMaatregelen /bio-maatregelen index (columns code,name,thema,bioVersion,bbnNiveau) and BioMaatregelDetail; register property is bbnLevel (lib/Settings/softwarecatalogus_register.json bioMeasure), so the bbnNiveau column is empty; no BIO catalogue is seeded (only 6 demo objects in lib/Settings/stackiq_mock_register.json)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "BioMaatregelen /bio-maatregelen, menu BIO measures; detail BioMaatregelDetail /bio-maatregelen/:id",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "medium",
+ "note": "The page exists and shows the theme, but the level column is wired to a key that does not exist (bbnNiveau vs bbnLevel; level only shows on the detail page), and the BIO measures are not shipped, so someone has to type them in.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json BioMaatregelen /bio-maatregelen index (columns code,name,thema,bioVersion,bbnNiveau) and BioMaatregelDetail; register property is bbnLevel (lib/Settings/softwarecatalogus_register.json bioMeasure), so the bbnNiveau column is empty; no BIO catalogue is seeded (only 6 demo objects in lib/Settings/stackiq_mock_register.json)"
}
},
{
@@ -1042,9 +1342,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json compliancy.bioMeasure links a module to a BIO measure; src/manifest.json ModuleDetail md-compliance lists claims incl. bioMaatregel column, BioMaatregelDetail bm-compliance lists modules per measure; compliancy has no status/met-not-met field",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Komplianties /komplianties (create a claim with a BIO measure); ComplianceMatrix /compliance-matrix with BIO measures as columns",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "medium",
+ "note": "You can record that an application meets a BIO measure, but there is no way to record that it does not meet one: the absence of a claim is the only negative, which cannot be told apart from 'not assessed'. The md-compliance column key 'bioMaatregel' also differs from the property bioMeasure.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.bioMeasure links a module to a BIO measure; src/manifest.json ModuleDetail md-compliance lists claims incl. bioMaatregel column, BioMaatregelDetail bm-compliance lists modules per measure; compliancy has no status/met-not-met field"
}
},
{
@@ -1057,9 +1368,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json module.dpiaStatus (enum not required/required/executed), dpiaDate, dpiaNextAssessment, dpiaDocumentRef; src/manifest.json ModuleDetail md-data includes the DPIA fields; Modules /modules quick filter 'Without DPIA (BBN2+)'",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleDetail /modules/:id Application data widget; Modules /modules column dpiaStatus and 'Without DPIA' quick filter",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "low",
+ "note": "DPIA status, date, next review and document link are fields on the application and shown and filterable on the Applications pages. The scheduled 'dpia-review-overdue' notification is only a register declaration.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json module.dpiaStatus (enum not required/required/executed), dpiaDate, dpiaNextAssessment, dpiaDocumentRef; src/manifest.json ModuleDetail md-data includes the DPIA fields; Modules /modules quick filter 'Without DPIA (BBN2+)'"
}
},
{
@@ -1072,10 +1394,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "grep for forum standaardisatie / pas toe of leg uit / comply-or-explain in lib and src: no hits; standards come only from the GEMMA AMEF import (element gemmaType=standaard)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "There is no list or check for the Forum Standaardisatie comply-or-explain list; only GEMMA standards imported with the model.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27556 'Standards Mapping' (2026-04-12): Map software to Forum Standaardisatie standards",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "grep for forum standaardisatie / pas toe of leg uit / comply-or-explain in lib and src: no hits; standards come only from the GEMMA AMEF import (element gemmaType=standaard)"
}
},
{
@@ -1088,9 +1419,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "grep for completeness/health score/quality score in lib and src: no hits; lib/Command/ReferencesAuditCommand.php:34 (occ stackiq:references:audit) only audits cross-app uuid references, it is not a scored rule set",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No rule-based score of register correctness or completeness exists on any page.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "grep for completeness/health score/quality score in lib and src: no hits; lib/Command/ReferencesAuditCommand.php:34 (occ stackiq:references:audit) only audits cross-app uuid references, it is not a scored rule set"
}
},
{
@@ -1103,10 +1443,19 @@
"bluedolphin": "partial",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "grep for questionnaire/vragenlijst in lib and src: no hits; no questionnaire schema in lib/Settings/softwarecatalogus_register.json",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Nothing sends questionnaires to suppliers or stores their answers.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders. | Rated partial because questionnaires collect portfolio data.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "grep for questionnaire/vragenlijst in lib and src: no hits; no questionnaire schema in lib/Settings/softwarecatalogus_register.json"
}
},
{
@@ -1119,25 +1468,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:592 Modules and :647 Diensten are FacetedCatalogIndexView over schema module/catalogService (CnIndexPage, showAdd default true); lib/Settings/softwarecatalogus_register.json:6779 module has provider + publicationDate (visible on form) and public read when publicationDate <= now or registeredBy Supplier",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Applications /modules and Services /diensten (main menu), create via the index Add form",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "offering-and-usage-listings",
+ "featureConfidence": "medium",
+ "note": "A supplier in aanbod-beheerder creates modules and services on the index pages and publishes them by setting publicationDate in the form. The dedicated publish endpoint (PUT /api/publication/...) is not called by any page (src/utils/openDataProjection.js has no importer).",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48838 'Supplier product offering (aanbod) registration' (2026-07-23): ICT suppliers publish their product offering for the municipal market with global functionality descriptions. | docs, intelligence competitor_features#27555 'Vendor Registration' (2026-04-12): ICT providers register their software offerings",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "mkt-offer-accept",
- "area": "market",
- "name": "As a supplier, accept or decline a usage another organisation has claimed of your product.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:592 Modules and :647 Diensten are FacetedCatalogIndexView over schema module/catalogService (CnIndexPage, showAdd default true); lib/Settings/softwarecatalogus_register.json:6779 module has provider + publicationDate (visible on form) and public read when publicationDate <= now or registeredBy Supplier"
}
},
{
@@ -1150,10 +1495,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/FacetService.php:109 DIMENSIONS referenceComponent, standard, applicationService, domain for schemas module and catalogService (:102); src/views/FacetedCatalogIndexView.vue:108 CnFacetSidebar narrows CnIndexPage; route GET /api/facets/{schema} called from src/services/facets.js",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Applications /modules and Services /diensten, GEMMA facet sidebar",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "medium",
+ "note": "Live facet counts on reference component and standard narrow the module and service lists. Scope is whatever the RBAC read rules let the viewer see (published entries are public).",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27553 'ICT Market Orientation' (2026-04-12): Find and compare software from registered ICT providers",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/FacetService.php:109 DIMENSIONS referenceComponent, standard, applicationService, domain for schemas module and catalogService (:102); src/views/FacetedCatalogIndexView.vue:108 CnFacetSidebar narrows CnIndexPage; route GET /api/facets/{schema} called from src/services/facets.js"
}
},
{
@@ -1166,41 +1522,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "mkt-compare-peers",
- "area": "market",
- "name": "See which software comparable organisations use for the same reference component.",
- "origin": "competitor",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48837 'Cross-municipality software comparison' (2026-07-23): Municipalities compare used software and connections with peer gemeenten; core network-effect value. | docs, intelligence competitor_features#27552 'Municipality Comparison' (2026-04-12): Compare application landscapes between municipalities",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "mkt-who-uses-it",
- "area": "market",
- "name": "See which organisations use a given application.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:386 Organisaties type:index over schema organization with status filter and OrganisatieCard; register :2022 organization.type is facetable (Municipality/Supplier/Collaboration/Community); public read of Active suppliers in organization authorization (:2467)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Organisations /organisaties (main menu)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The Organisations index lists organisations with search, a type facet and a status filter. There is no filter for 'offers at least one product'; type Supplier is the proxy.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48837 'Cross-municipality software comparison' (2026-07-23): Municipalities compare used software and connections with peer gemeenten; core network-effect value.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:386 Organisaties type:index over schema organization with status filter and OrganisatieCard; register :2022 organization.type is facetable (Municipality/Supplier/Collaboration/Community); public read of Active suppliers in organization authorization (:2467)"
}
},
{
@@ -1213,10 +1546,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "Looked in src/components, src/views and lib/Controller for any contact or messaging between organisations sharing a module: none. Usage read rules (register :3137) hide other organisations' usages from municipalities.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Nothing lets an organisation find or contact other organisations using the same product.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27557 'Contact & Collaboration' (2026-04-12): Connect with municipalities using similar products",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "Looked in src/components, src/views and lib/Controller for any contact or messaging between organisations sharing a module: none. Usage read rules (register :3137) hide other organisations' usages from municipalities."
}
},
{
@@ -1229,10 +1571,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register :7651 moduleVersion with status enum in development/in use/end of support/withdrawn and dateInDevelopment/dateInUse/dateEndSupport, read public; src/manifest.json:915 Moduleversies index + ModuleversieDetail",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Module versions /moduleversies (main menu)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "maintenance-and-supplier-roadmap",
+ "featureConfidence": "medium",
+ "note": "A supplier can register a future version with status 'in development' and planned dates, which reads as a crude release plan. There is no roadmap view or declared roadmap; the overlay marks maintenance-and-supplier-roadmap as 'soon'.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48839 'Product roadmap / planning declaration' (2026-07-23): Suppliers declare product planning and release roadmap per product.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register :7651 moduleVersion with status enum in development/in use/end of support/withdrawn and dateInDevelopment/dateInUse/dateEndSupport, read public; src/manifest.json:915 Moduleversies index + ModuleversieDetail"
}
},
{
@@ -1245,24 +1598,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "mkt-review-moderation",
- "area": "market",
- "name": "Hold a submitted review for moderation before others can read it.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:514 ModuleDetail bodyWidget ReviewsPanel; src/components/reviews/ReviewsPanel.vue:63 opens SubmitReviewModal; POST /api/reviews -> lib/Service/ReviewService.php:232 stamps author and forces status pending; rating 1..10 in software-review schema (:3961)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleDetail /modules/:id, Reviews panel 'write a review'",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "reviews",
+ "featureConfidence": "high",
+ "note": "Logged-in users write a rated review from the application page. Services have no detail page, so only applications can be reviewed there.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:514 ModuleDetail bodyWidget ReviewsPanel; src/components/reviews/ReviewsPanel.vue:63 opens SubmitReviewModal; POST /api/reviews -> lib/Service/ReviewService.php:232 stamps author and forces status pending; rating 1..10 in software-review schema (:3961)"
}
},
{
@@ -1275,9 +1624,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/ReviewAggregateService.php:51 approved-only average + count; GET /api/reviews/aggregate (PublicPage) called from src/utils/reviewAggregate.js imported by src/components/reviews/ReviewsPanel.vue",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleDetail /modules/:id, Reviews panel",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "reviews",
+ "featureConfidence": "high",
+ "note": "The application page shows the approved-only average and count. Services have no detail page, so the aggregate is not shown for them.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/ReviewAggregateService.php:51 approved-only average + count; GET /api/reviews/aggregate (PublicPage) called from src/utils/reviewAggregate.js imported by src/components/reviews/ReviewsPanel.vue"
}
},
{
@@ -1290,9 +1650,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register :6856 module.contactPerson -> contactPerson with x-relation-filter organization = @object.provider; catalogService and suite also carry contactPerson; src/manifest.json:500 ModuleDetail md-data include lists 'contactpersoon', 'beschrijvingKort', 'beschrijvingLang', which are not module properties (renamed to contactPerson/shortDescription/longDescription)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Applications /modules create/edit form; not shown on ModuleDetail /modules/:id",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Each product can point at its own contact person of the supplier through the form. The application page's data widget names the old Dutch keys, so the product's contact person (and its descriptions) do not show there; the same stale keys are on SuiteDetail (src/manifest.json:683).",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register :6856 module.contactPerson -> contactPerson with x-relation-filter organization = @object.provider; catalogService and suite also carry contactPerson; src/manifest.json:500 ModuleDetail md-data include lists 'contactpersoon', 'beschrijvingKort', 'beschrijvingLang', which are not module properties (renamed to contactPerson/shortDescription/longDescription)"
}
},
{
@@ -1305,221 +1674,204 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "register :2022 organization (one record, type Supplier); module.provider (:6921) and catalogService.provider (:3762) are $ref organization; catalogContract points at service (+usage), register :3252; OrganisatieDetail src/manifest.json:403 lists the supplier's services and applications",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Organisations /organisaties and OrganisatieDetail /organisaties/:id (services and applications lists)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "One organisation record is the supplier; products reference it and the detail page lists them. A contract reaches the supplier only through its service, not by its own field.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because Provider fact sheet.",
"topdesk": "docs, intelligence competitor_features#48932 'Contract & vendor management' (2026-07-23): Track supplier contracts and operational agreements.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "mkt-hide-landscape-from-vendors",
- "area": "market",
- "name": "Keep your application landscape and connections hidden from suppliers.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "mkt-free-public-service",
- "area": "market",
- "name": "Use the catalogue free of charge as a municipality or supplier.",
- "origin": "competitor",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "no",
- "bluedolphin": "unknown",
- "glpi": "yes",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
- "sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
- "glpi": "docs, intelligence competitor_features#48912 '100% open source (GPL)' (2026-07-23): Fully GPL; no license fees, broad device coverage.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register :2022 organization (one record, type Supplier); module.provider (:6921) and catalogService.provider (:3762) are $ref organization; catalogContract points at service (+usage), register :3252; OrganisatieDetail src/manifest.json:403 lists the supplier's services and applications"
}
},
{
"id": "life-phase",
"area": "lifecycle",
- "name": "See which lifecycle phase each application in use is in, such as planned, in use or being phased out.",
+ "name": "See the lifecycle phase of each application in use: planned, in use or being phased out.",
"origin": "own-code",
"vng-softwarecatalogus": "no",
"sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "partial",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json LifecycleRoadmap /portfolio-roadmap custom page -> src/views/LifecycleRoadmapView.vue:55 groups the selected organisation's usages by phase, derived from usage dates by src/utils/lifecyclePhase.js derivePhase (:408); usage.status enum Acquisition/Planned/In production/To be phased out/Phased out in lib/Settings/softwarecatalogus_register.json",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "LifecycleRoadmap /portfolio-roadmap, menu Portfolio roadmap",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "portfolio-roadmap",
+ "featureConfidence": "high",
+ "note": "Pick an organisation and its applications in use are grouped by derived lifecycle phase. The usage records themselves cannot be created or edited on any stackiq page (see life-planned-replacement).",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
"sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
"topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | Rated partial because replacement timelines on assets.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json LifecycleRoadmap /portfolio-roadmap custom page -> src/views/LifecycleRoadmapView.vue:55 groups the selected organisation's usages by phase, derived from usage dates by src/utils/lifecyclePhase.js derivePhase (:408); usage.status enum Acquisition/Planned/In production/To be phased out/Phased out in lib/Settings/softwarecatalogus_register.json"
}
},
{
- "id": "life-eol-warning",
+ "id": "life-roadmap",
"area": "lifecycle",
- "name": "Get a warning before an application or version falls out of support.",
+ "name": "See per organisation which applications are replaced when, on a roadmap.",
"origin": "own-code",
"vng-softwarecatalogus": "no",
"sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/views/LifecycleRoadmapView.vue:28 organisation select, :55 phase groups, :96-110 phase-out date, planned replacement and link to the replacing module (:400 plannedReplacement, :423 plannedReplacementDate), ordered by nearest urgency (:428)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "LifecycleRoadmap /portfolio-roadmap, menu Portfolio roadmap",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "portfolio-roadmap",
+ "featureConfidence": "high",
+ "note": "Per organisation it shows which applications are phased out or replaced and when; it is a grouped list ordered by urgency rather than a timeline chart.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
- "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
- "stackiq": "not checked: the code reading for this row is under way"
+ "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
+ "stackiq": "src/views/LifecycleRoadmapView.vue:28 organisation select, :55 phase groups, :96-110 phase-out date, planned replacement and link to the replacing module (:400 plannedReplacement, :423 plannedReplacementDate), ordered by nearest urgency (:428)"
}
},
{
- "id": "life-eol-feed",
+ "id": "life-overlap",
"area": "lifecycle",
- "name": "Fill in end-of-support dates automatically from a public end-of-life feed.",
+ "name": "Find applications that overlap because they fulfil the same reference component.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "grep for overlap/redundant in lib and src finds only code comments and the Reports card description (src/manifest.json:1031 'Overlapping and ageing software'); lib/Service/PortfolioReportService.php computes TIME quadrants, EOL exposure, cloud share and cost, no grouping by reference component; the /modules facet counts modules per reference component across the whole catalogue, not your landscape",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Nothing finds applications in your landscape that fulfil the same reference component; the Reports card promises 'overlapping' software but the report does not compute it.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | Rated partial because obsolescence tracking; source of dates not named.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | Rated partial because rationalisation through capability map.",
+ "stackiq": "grep for overlap/redundant in lib and src finds only code comments and the Reports card description (src/manifest.json:1031 'Overlapping and ageing software'); lib/Service/PortfolioReportService.php computes TIME quadrants, EOL exposure, cloud share and cost, no grouping by reference component; the /modules facet counts modules per reference component across the whole catalogue, not your landscape"
}
},
{
- "id": "life-roadmap",
+ "id": "life-rationalisation-report",
"area": "lifecycle",
- "name": "See per organisation which applications are replaced when, on a roadmap.",
+ "name": "Open a report of overlapping and ageing software for rationalisation.",
"origin": "own-code",
- "vng-softwarecatalogus": "no",
+ "vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:303 GET /api/portfolio-report -> lib/Controller/PortfolioReportController.php -> lib/Service/PortfolioReportService.php + PortfolioReportDerivation.php; UI src/views/organisaties/PortfolioReport.vue (TIME chart :112, quadrant summary :126 with EOL exposure/cloud/cost, rows :176, CSV export :50)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "PortfolioReport /portfolio-report, from Reports /reports card 'Portfolio rationalization' (footer menu Reports)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The report covers ageing software (EOL exposure) with TIME quadrants, cost and a CSV export, but not overlap, even though its card says 'overlapping and ageing'.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
- "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
- "stackiq": "not checked: the code reading for this row is under way"
+ "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R). | docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
+ "stackiq": "appinfo/routes.php:303 GET /api/portfolio-report -> lib/Controller/PortfolioReportController.php -> lib/Service/PortfolioReportService.php + PortfolioReportDerivation.php; UI src/views/organisaties/PortfolioReport.vue (TIME chart :112, quadrant summary :126 with EOL exposure/cloud/cost, rows :176, CSV export :50)"
}
},
{
- "id": "life-planned-replacement",
+ "id": "life-version-in-use",
"area": "lifecycle",
- "name": "Record which application is planned to replace another.",
+ "name": "Record which version of an application your organisation currently runs.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json usage.moduleVersion ($ref moduleVersion); read by src/views/LifecycleRoadmapView.vue:397 for EOL state; ModuleversieDetail mv-related shows related usages; no usage create/edit page in src/manifest.json",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "used on LifecycleRoadmap /portfolio-roadmap and ModuleversieDetail /moduleversies/:id; nothing in stackiq records it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "lifecycle-and-end-of-support",
+ "featureConfidence": "low",
+ "note": "The version an organisation runs is a field on its usage and drives the EOL badges, but no stackiq page lets the organisation set or change it.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json usage.moduleVersion ($ref moduleVersion); read by src/views/LifecycleRoadmapView.vue:397 for EOL state; ModuleversieDetail mv-related shows related usages; no usage create/edit page in src/manifest.json"
}
},
{
- "id": "life-time-classification",
+ "id": "life-new-version-notice",
"area": "lifecycle",
- "name": "Classify each application as tolerate, invest, migrate or eliminate.",
+ "name": "Get notified when a supplier publishes a new version of an application you use.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "yes",
+ "sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "specified",
+ "evidence": "lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications module-version-published (trigger created, recipients object-acl manage + group software-catalog-admins); no notification code in lib (no INotificationManager use)",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "nothing reaches it for a using organisation",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "feature": "notifications",
+ "featureConfidence": "medium",
+ "note": "The only rule is a register declaration, and it addresses the version's own managers and catalogue admins, not the organisations that use the application, so even if OpenRegister dispatches it a user of the application is not told.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications module-version-published (trigger created, recipients object-acl manage + group software-catalog-admins); no notification code in lib (no INotificationManager use)"
}
},
{
- "id": "life-overlap",
+ "id": "life-tech-obsolescence",
"area": "lifecycle",
- "name": "Find applications that overlap because they fulfil the same reference component.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "partial",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | Rated partial because rationalisation through capability map.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "life-rationalisation-report",
- "area": "lifecycle",
- "name": "Open a report of overlapping and ageing software for rationalisation.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "yes",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R). | docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "life-version-in-use",
- "area": "lifecycle",
- "name": "Record which version of an application your organisation currently runs.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "life-new-version-notice",
- "area": "lifecycle",
- "name": "Get notified when a supplier publishes a new version of an application you use.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "life-tech-obsolescence",
- "area": "lifecycle",
- "name": "Track the lifecycle of the underlying technology, such as a database or framework, not only the application.",
+ "name": "Track the lifecycle of underlying technology, such as a database or framework, not only applications.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "lib/Settings/softwarecatalogus_register.json sbomComponent has name/version/purl/licenses/type/hashes/bomRef/vexCveIds, no lifecycle or EOL field; the EOL feed (lib/Service/EolSyncService.php:290) only stamps versions of modules with eolProductSlug; no relation from an application to the platform it runs on",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "You could register a database as its own 'System software' module and feed its EOL, but nothing ties it to the applications that depend on it; SBOM components carry no lifecycle.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json sbomComponent has name/version/purl/licenses/type/hashes/bomRef/vexCveIds, no lifecycle or EOL field; the EOL feed (lib/Service/EolSyncService.php:290) only stamps versions of modules with eolProductSlug; no relation from an application to the platform it runs on"
}
},
{
@@ -1532,10 +1884,19 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no goal/strategy schema among the 20 in lib/Settings/softwarecatalogus_register.json; grep for strateg/doel in src/manifest.json: none",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Strategic goals are not modelled.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#27466 'Strategy Alignment' (2026-04-12): Connect architecture to strategic objectives",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "no goal/strategy schema among the 20 in lib/Settings/softwarecatalogus_register.json; grep for strateg/doel in src/manifest.json: none"
}
},
{
@@ -1548,44 +1909,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "ctr-register",
- "area": "contracts",
- "name": "Register a contract for a service with its number, type, term and cost.",
- "origin": "own-code",
- "vng-softwarecatalogus": "no",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "yes",
- "topdesk": "yes",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
- "glpi": "docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets. | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145509 'C-parties-and-contacts-1 A contract is a record with its own term and costs, linked to the party it binds and the cases raised under it': glpi: Contracts (Management, Contracts, front/contract_item.php, contractcost.php, ticket_contract.php) Lane findings: D-glpi-49.",
- "topdesk": "docs, intelligence competitor_features#48932 'Contract & vendor management' (2026-07-23): Track supplier contracts and operational agreements.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "ctr-expiry-alert",
- "area": "contracts",
- "name": "Get warned before a contract expires.",
- "origin": "own-code",
- "vng-softwarecatalogus": "no",
- "sap-leanix": "partial",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "specified",
+ "evidence": "openspec/features.overlay.json maintenance-and-supplier-roadmap status 'soon'; no maintenance schema in lib/Settings/softwarecatalogus_register.json and no page in src/manifest.json",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "maintenance-and-supplier-roadmap",
+ "featureConfidence": "high",
+ "note": "Listed as 'soon' in the feature overlay; nothing is built.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
- "sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS renewal dates.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "openspec/features.overlay.json maintenance-and-supplier-roadmap status 'soon'; no maintenance schema in lib/Settings/softwarecatalogus_register.json and no page in src/manifest.json"
}
},
{
@@ -1598,24 +1935,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "ctr-approval",
- "area": "contracts",
- "name": "Only let a contract become active after an approval decision is recorded.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/ContractStatusService.php:77 shouldExpire and :114 expirePastContracts set Active -> Expired when endDate < now; lib/BackgroundJob/ContractStatusJob.php:57 daily, registered in appinfo/info.xml:99",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Contracts /contracten status column and quick filters",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "contract-administration",
+ "featureConfidence": "high",
+ "note": "A daily job moves Active contracts past their end date to Expired on its own. There is no 'expiring' state in the enum, so the middle step of the row does not exist.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/ContractStatusService.php:77 shouldExpire and :114 expirePastContracts set Active -> Expired when endDate < now; lib/BackgroundJob/ContractStatusJob.php:57 daily, registered in appinfo/info.xml:99"
}
},
{
@@ -1628,9 +1961,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/components/contracts/ContractApprovalPanel.vue:183 canSubmitRenewal for status Expired; POST /api/contracts/{uuid}/approval/renewal -> ContractApprovalService.php:254 with decisionType contract-renewal; lib/EventListener/DecisionConcludedListener.php projects the outcome (approvalState, status Active) via DECISION_CONCLUDED_EVENTS registered in lib/AppInfo/Application.php:830",
+ "owner": "ConductionNL/decidiq",
+ "ownerNote": "reader wrote: ConductionNL/stackiq + ConductionNL/decidiq"
+ },
+ "reachedOn": "ContractDetail /contracten/:id, Approval panel 'Submit renewal' and approval state",
+ "provider": "decidiq",
+ "providerHow": "read-from-code",
+ "feature": "contract-renewal-approval",
+ "featureConfidence": "high",
+ "note": "An expired contract can be raised for renewal as a decidiq decision and the outcome shows on the contract's approval panel. It needs the decidiq app installed; without it the panel hides the action.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/components/contracts/ContractApprovalPanel.vue:183 canSubmitRenewal for status Expired; POST /api/contracts/{uuid}/approval/renewal -> ContractApprovalService.php:254 with decisionType contract-renewal; lib/EventListener/DecisionConcludedListener.php projects the outcome (approvalState, status Active) via DECISION_CONCLUDED_EVENTS registered in lib/AppInfo/Application.php:830"
}
},
{
@@ -1643,10 +1988,21 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "contract-administration",
+ "featureConfidence": "medium",
+ "note": "The application page has no contracts list, and a contract links to a usage and a service rather than the application, so there is no path from an application to its contracts in the UI.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets. | Rated yes because contracts tracked against assets.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it"
}
},
{
@@ -1659,11 +2015,22 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/PortfolioReportDerivation.php:163 annualisedCost (Monthly x12, Annually x1, One-off separate); lib/Service/PortfolioReportService.php:337 sumContractCost per quadrant; src/views/organisaties/PortfolioReport.vue:167 and :248 show annualised cost; src/utils/contractCost.js:111 totalAnnualisedCost used by src/views/LicensePostureView.vue per vendor",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Reports /reports -> Portfolio rationalization /portfolio-report; License posture /license-posture per-vendor rollup",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "contract-administration",
+ "featureConfidence": "high",
+ "note": "The portfolio report sums annualised contract cost per organisation and TIME quadrant, and the license posture page per vendor. The Dashboard only counts contracts.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS cost.",
"glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts | docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/PortfolioReportDerivation.php:163 annualisedCost (Monthly x12, Annually x1, One-off separate); lib/Service/PortfolioReportService.php:337 sumContractCost per quadrant; src/views/organisaties/PortfolioReport.vue:167 and :248 show annualised cost; src/utils/contractCost.js:111 totalAnnualisedCost used by src/views/LicensePostureView.vue per vendor"
}
},
{
@@ -1676,10 +2043,21 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register :6937 module.licentietype enum Closed source/Open source and module.licence (five open-source licence names); catalogContract.contractType enum SLA/Licence/Maintenance (:3341)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Applications /modules form and ModuleDetail /modules/:id data widget",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "license-and-seat-tracking",
+ "featureConfidence": "medium",
+ "note": "An application records open versus closed source and which open-source licence. There is no licence metric such as per user, per organisation or per seat.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48901 'License management' (2026-07-23): Track license entitlements, compliance and expirations.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register :6937 module.licentietype enum Closed source/Open source and module.licence (five open-source licence names); catalogContract.contractType enum SLA/Licence/Maintenance (:3341)"
}
},
{
@@ -1692,9 +2070,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/views/LicensePostureView.vue:11 open-source vs closed-source share weighted by in-production usage, :64 per-vendor rollup, per-organisation open-source-first report; derived in src/utils/licensePosture.js",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "License posture /license-posture (main menu)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The page shows the open-source share of the running portfolio with per-vendor and per-organisation breakdowns, computed at read time.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/views/LicensePostureView.vue:11 open-source vs closed-source share weighted by in-production usage, :64 per-vendor rollup, per-organisation open-source-first report; derived in src/utils/licensePosture.js"
}
},
{
@@ -1707,10 +2094,21 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "grep for seat/licence count across lib/, src/ and the register finds no seat or quantity field on catalogContract (:3252), module or usage",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "license-and-seat-tracking",
+ "featureConfidence": "high",
+ "note": "No field records licences bought or in use. The overlay lists license-and-seat-tracking as 'soon'.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48901 'License management' (2026-07-23): Track license entitlements, compliance and expirations. | docs, intelligence competitor_features#3270 'License Management' (2026-03-28): Track software licenses, compliance, and expiration",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "grep for seat/licence count across lib/, src/ and the register finds no seat or quantity field on catalogContract (:3252), module or usage"
}
},
{
@@ -1723,9 +2121,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No entitlement or consumption fields exist (see ctr-seat-count); no service computes a licence position in lib/Service/",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Without seat or consumption data there is nothing to compute an effective licence position from.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No entitlement or consumption fields exist (see ctr-seat-count); no service computes a licence position in lib/Service/"
}
},
{
@@ -1738,10 +2145,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "grep for budget across lib/, src/ and lib/Settings finds no budget schema or field; catalogContract has cost + costPeriod only (register :3363)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Contracts carry a cost and a period, but there is no budget to charge them against.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145790 'C-reporting-1 A budget the case costs are charged against, with a period.': glpi: Budgets (Management, Budgets, front/budget.php) Lane findings: D-glpi-37. | Rated yes because budgets, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "grep for budget across lib/, src/ and lib/Settings finds no budget schema or field; catalogContract has cost + costPeriod only (register :3363)"
}
},
{
@@ -1754,10 +2170,19 @@
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "grep for depreciation/afschrijving finds nothing in lib/, src/ or the register",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No purchase value, useful life or depreciation is recorded or computed.",
"evidence": {
"glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts | Rated partial because TCO tracking.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "grep for depreciation/afschrijving finds nothing in lib/, src/ or the register"
}
},
{
@@ -1770,9 +2195,21 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:567 ContractDetail ct-files integration 'files' (Documents panel); catalogContract.documentReference text field (register :3252)",
+ "owner": "ConductionNL/openregister",
+ "ownerNote": "reader wrote: ConductionNL/stackiq (page), files via ConductionNL/openregister + Nextcloud Files"
+ },
+ "reachedOn": "ContractDetail /contracten/:id, Documents panel",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "feature": "contract-administration",
+ "featureConfidence": "medium",
+ "note": "The contract page has a Documents files panel for the signed contract, plus a document reference field.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:567 ContractDetail ct-files integration 'files' (Documents panel); catalogContract.documentReference text field (register :3252)"
}
},
{
@@ -1785,10 +2222,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "usage.cloudDienstverleningsmodel (register :3050) plus contract cost; lib/Service/PortfolioReportService.php:302 per-usage annualised cost and cloud-transition share; src/views/organisaties/PortfolioReport.vue:166 cloudTransitionLabel per row",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Reports /reports -> Portfolio rationalization /portfolio-report",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The portfolio report shows each application in use with its cloud model and annualised cost, which lets you pick out SaaS spend. There is no SaaS subscription list and nothing discovers purchases made outside IT.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "usage.cloudDienstverleningsmodel (register :3050) plus contract cost; lib/Service/PortfolioReportService.php:302 per-usage annualised cost and cloud-transition share; src/views/organisaties/PortfolioReport.vue:166 cloudTransitionLabel per row"
}
},
{
@@ -1801,10 +2247,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/views/KwetsbaarhedenView.vue:378 reportVulnerability opens the generic ObjectModal for 'vulnerability'; register.json:1619 vulnerability schema with cveCode (pattern CVE-yyyy-n, :1679) and cvssScore 0-10",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Vulnerabilities /kwetsbaarheden (menu), Report vulnerability",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "A vulnerability is registered with CVE code and CVSS score, and a severity band is derived from the score.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/views/KwetsbaarhedenView.vue:378 reportVulnerability opens the generic ObjectModal for 'vulnerability'; register.json:1619 vulnerability schema with cveCode (pattern CVE-yyyy-n, :1679) and cvssScore 0-10"
}
},
{
@@ -1817,39 +2272,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "sec-exposure",
- "area": "security",
- "name": "See which organisations and usages are exposed to a vulnerability.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "sec-vulnerability-alert",
- "area": "security",
- "name": "Get an alert when a vulnerability is reported for software you use.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:1701 vulnerability.modules links to module (applications), not moduleVersion; version level only via read-time SBOM match (src/utils/sbomVulnerabilityMatch.js, sbomComponent.vexCveIds register.json:8024) on the ModuleversieDetail Components tab",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Vulnerabilities /kwetsbaarheden form (Affected applications); ModuleversieDetail Components tab shows matches",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "A vulnerability links to applications, not to specific versions. Per-version affectedness only shows as a computed match against a version's imported SBOM.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register.json:1701 vulnerability.modules links to module (applications), not moduleVersion; version level only via read-time SBOM match (src/utils/sbomVulnerabilityMatch.js, sbomComponent.vexCveIds register.json:8024) on the ModuleversieDetail Components tab"
}
},
{
@@ -1862,9 +2296,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/components/sbom/SbomComponentsPanel.vue:53-90 upload control (.json) -> POST /api/moduleversies/{uuid}/sbom (appinfo/routes.php:92) -> lib/Controller/SbomController.php:129 importSbom -> lib/Service/SbomParserService.php:77 parse (CycloneDX JSON) and :127 parseSpdx (SPDX 2.x JSON)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleversieDetail /moduleversies/:id, sidebar tab Components, upload",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "An SBOM in CycloneDX JSON or SPDX 2.x JSON can be uploaded for a version. XML and tag-value formats are not accepted.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/components/sbom/SbomComponentsPanel.vue:53-90 upload control (.json) -> POST /api/moduleversies/{uuid}/sbom (appinfo/routes.php:92) -> lib/Controller/SbomController.php:129 importSbom -> lib/Service/SbomParserService.php:77 parse (CycloneDX JSON) and :127 parseSpdx (SPDX 2.x JSON)"
}
},
{
@@ -1877,9 +2320,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "decided-no",
+ "evidence": "src/utils/sbomVulnerabilityMatch.js header: 'no HTTP request to an external advisory feed is ever made'; lib/Service/EolSyncService.php syncs endoflife.date support dates, not CVEs",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Matching is deliberately local, against vulnerabilities typed into the catalogue. No public CVE feed is read.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/utils/sbomVulnerabilityMatch.js header: 'no HTTP request to an external advisory feed is ever made'; lib/Service/EolSyncService.php syncs endoflife.date support dates, not CVEs"
}
},
{
@@ -1892,10 +2344,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "src/utils/vulnerabilitySeverity.js derives a severity band per vulnerability from CVSS; no per-application risk score in lib/ or src/ (searched risk)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Only individual vulnerabilities get a severity band. No application gets a combined score from its vulnerabilities and support status.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks | Rated partial because technology risk.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/utils/vulnerabilitySeverity.js derives a severity band per vulnerability from CVSS; no per-application risk score in lib/ or src/ (searched risk)"
}
},
{
@@ -1908,9 +2369,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "register.json:1619 vulnerability has no fixed-in version field; src/utils/vulnerabilityExposure.js computeExposure carries the deployed moduleVersion per usage but nothing compares it to a fix",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The exposure row shows which version is deployed, but no record says which version fixes the vulnerability, so patch status cannot be seen.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register.json:1619 vulnerability has no fixed-in version field; src/utils/vulnerabilityExposure.js computeExposure carries the deployed moduleVersion per usage but nothing compares it to a fix"
}
},
{
@@ -1923,9 +2393,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:969 Kwetsbaarheden custom page -> src/views/KwetsbaarhedenView.vue table with severity tabs; row click openDetail (:417) opens the record in the generic ObjectModal",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Vulnerabilities /kwetsbaarheden (menu)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "All vulnerabilities are listed with severity filters and each opens in the record form. The separate KwetsbaarheidDetail page is not what a row opens.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:969 Kwetsbaarheden custom page -> src/views/KwetsbaarhedenView.vue table with severity tabs; row click openDetail (:417) opens the record in the generic ObjectModal"
}
},
{
@@ -1938,25 +2417,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:386 Organisaties type:index over schema organization (Add form); register :2022 organization.type enum Municipality/Supplier/Collaboration/Community, required contactsUid + type",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Organisations /organisaties (main menu), Add form; walkthrough step create-organisatie",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Organisations are created on the index with their type. The required contactsUid is a Nextcloud Contacts UID the form asks for as text, which is awkward but does not block the capability.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27555 'Vendor Registration' (2026-04-12): ICT providers register their software offerings | docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "org-self-registration",
- "area": "organisations",
- "name": "Let a new organisation sign itself up without an account.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:386 Organisaties type:index over schema organization (Add form); register :2022 organization.type enum Municipality/Supplier/Collaboration/Community, required contactsUid + type"
}
},
{
@@ -1969,9 +2442,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/views/settings/StackiqSettings.vue:92 ModerationQueue (type organisation) -> src/utils/adminApi.js -> GET /api/moderation/pending, POST /api/moderation/{uuid}/approve|reject; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; lib/Service/ModerationService.php:230 approval sets registrationStatus active and stamps publicationDate (:173)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section 'Registration moderation' (Nextcloud admin settings, stackiq)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "self-registration-with-moderation",
+ "featureConfidence": "high",
+ "note": "An admin reviews pending self-registrations and approves or rejects them. Approval sets registrationStatus and publication, but leaves the separate status field at Draft, which is what user provisioning waits for (see org-status).",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/views/settings/StackiqSettings.vue:92 ModerationQueue (type organisation) -> src/utils/adminApi.js -> GET /api/moderation/pending, POST /api/moderation/{uuid}/approve|reject; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; lib/Service/ModerationService.php:230 approval sets registrationStatus active and stamps publicationDate (:173)"
}
},
{
@@ -1984,9 +2468,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "building",
+ "evidence": "register organization.status enum Draft/Active/Inactive is visible:false (:2022); src/manifest.json:403 OrganisatieDetail overrides status editable:false; src/modals/object/ChangeOrganisatieStatusDialog.vue:211 is never opened (no setDialog('changeOrganisatieStatus') in src); src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters status 'concept' and :129 writes 'actief', neither an enum value",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it (Organisations /organisaties can only filter by status)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No working path moves an organisation between Draft, Active and Inactive: the field is hidden on the form and locked on the detail page, the status dialog is orphaned, and the Nextcloud dashboard widget still uses the old Dutch values so it lists nothing and would write an invalid value.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "register organization.status enum Draft/Active/Inactive is visible:false (:2022); src/manifest.json:403 OrganisatieDetail overrides status editable:false; src/modals/object/ChangeOrganisatieStatusDialog.vue:211 is never opened (no setDialog('changeOrganisatieStatus') in src); src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters status 'concept' and :129 writes 'actief', neither an enum value"
}
},
{
@@ -1999,25 +2492,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:418 OrganisatieDetail org-contactpersonen object-list (role, roles) with rowRoute ContactpersoonDetail; register :1788 contactPerson (contactsUid, role, organization, roles enum of catalogue roles)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "OrganisatieDetail /organisaties/:id 'Contact persons' list -> ContactpersoonDetail /contactpersonen/:id",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Contact persons are listed on the organisation with their function and roles. The Contactpersonen index page exists but has no menu entry.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27557 'Contact & Collaboration' (2026-04-12): Connect with municipalities using similar products",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "org-contact-to-account",
- "area": "organisations",
- "name": "Turn a contact person into a user account with the right role automatically.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:418 OrganisatieDetail org-contactpersonen object-list (role, roles) with rowRoute ContactpersoonDetail; register :1788 contactPerson (contactsUid, role, organization, roles enum of catalogue roles)"
}
},
{
@@ -2030,9 +2517,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/components/organisations/OrganisationSwitcher.vue:48 'Manage members' (isBeheerder) opens src/modals/GrantOrganisationAccessModal.vue; POST /api/organisations/{uuid}/members -> lib/Controller/OrganisationMembersController.php:108 authorizeBeheerder then OpenRegister joinOrganisation (:123)",
+ "owner": "ConductionNL/openregister",
+ "ownerNote": "reader wrote: ConductionNL/stackiq + ConductionNL/openregister"
+ },
+ "reachedOn": "App header OrganisationSwitcher (src/App.vue:55) -> Manage members",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "A beheerder of the organisation grants an existing Nextcloud user access to it from the header switcher; membership is stored by OpenRegister. It adds existing users; it does not send an invitation to a new person.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/components/organisations/OrganisationSwitcher.vue:48 'Manage members' (isBeheerder) opens src/modals/GrantOrganisationAccessModal.vue; POST /api/organisations/{uuid}/members -> lib/Controller/OrganisationMembersController.php:108 authorizeBeheerder then OpenRegister joinOrganisation (:123)"
}
},
{
@@ -2045,25 +2542,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "org-cooperation",
- "area": "organisations",
- "name": "Register a cooperation of organisations and the landscape they share.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/components/organisations/OrganisationSwitcher.vue:197 POST /apps/openregister/api/organisations/{uuid}/set-active; mounted in src/App.vue:55",
+ "owner": "ConductionNL/openregister",
+ "ownerNote": "reader wrote: ConductionNL/stackiq + ConductionNL/openregister"
+ },
+ "reachedOn": "App header OrganisationSwitcher on every page",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "A user who belongs to several organisations switches the active one from the header; OpenRegister holds the memberships.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48844 'Municipal cooperation / shared-service management' (2026-07-23): Manages gemeente-samenwerking (shared service centres) registering a joint landscape.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/components/organisations/OrganisationSwitcher.vue:197 POST /apps/openregister/api/organisations/{uuid}/set-active; mounted in src/App.vue:55"
}
},
{
@@ -2076,9 +2567,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail; POST /api/organisaties/{uuid}/merge -> lib/Controller/MergeController.php:142 isAdmin; lib/Service/MergeOrganisatieService.php:111 re-points usage.consumer/participants, contactPerson.organization, connection.provider and @self.organisation of catalogContract/compliancy; module.provider and catalogService.provider are not re-pointed",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "OrganisatieDetail /organisaties/:id, merge panel (admin only)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "An admin can merge a municipality into another and its usages, contacts and contracts follow. A supplier takeover leaves the source's applications and services pointing at the tombstoned supplier, because module and service provider fields are not in the relation map.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail; POST /api/organisaties/{uuid}/merge -> lib/Controller/MergeController.php:142 isAdmin; lib/Service/MergeOrganisatieService.php:111 re-points usage.consumer/participants, contactPerson.organization, connection.provider and @self.organisation of catalogContract/compliancy; module.provider and catalogService.provider are not re-pointed"
}
},
{
@@ -2091,10 +2591,19 @@
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/components/organisations/OrganisationMergePanel.vue:324 organisatieStore.dryRunMerge shows dryRunCounts before execute; POST /api/organisaties/{uuid}/merge/dry-run -> lib/Service/MergeOrganisatieService.php:160 dryRun",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "OrganisatieDetail /organisaties/:id, merge panel (admin only)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The merge panel shows per-type counts of what would be re-pointed before the admin confirms. It inherits the merge's blind spot: module and service provider links are not counted because they are not moved.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#146004 'C-configuration-95 The product shows what an import or a migration will change before it writes.': glpi: Form export and import (Form/ExportController.php, Form/Import/Step1IndexController.php through Step4ExecuteController.php) Lane findings: D-glpi-11. | Rated partial because import previews before writing; not for merges, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/components/organisations/OrganisationMergePanel.vue:324 organisatieStore.dryRunMerge shows dryRunCounts before execute; POST /api/organisaties/{uuid}/merge/dry-run -> lib/Service/MergeOrganisatieService.php:160 dryRun"
}
},
{
@@ -2107,41 +2616,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/views/settings/StackiqSettings.vue:80 UserGroupsConfiguration -> GET/POST /api/user-groups/config (src/store/modules/settings.js:830); lib/Controller/SettingsController.php:3379; lib/Service/Stackiq/GroupHandler.php:103 generic groups, :167 fixed role groups (aanbod-beheerder, gebruik-beheerder, ...), group choice by organisation type (:471)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section 'User groups'",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "An admin configures which groups count as generic users, organisation admins and super users. The catalogue roles themselves map to fixed, hard-coded group names and by organisation type, so an admin cannot map e.g. 'buyer' onto a group of their choice.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141837 '11.19 User, role and department administration in the app': `/front/user.form.php`, `/front/profile.form.php` (`src/Profile.php`, `src/ProfileRight.php:46`), `/front/group.form.php`, and the three-way user x profile x entity grant `src/Profile_User.php:320` with a recursive flag | Rated yes because user, profile and entity administration, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "org-data-segregation",
- "area": "organisations",
- "name": "Keep each organisation's records visible only to that organisation unless published.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "yes",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "glpi": "docs, intelligence competitor_features#48910 'Multi-entity (tenant) segregation' (2026-07-23): Hierarchical entities for multi-org / multi-department isolation.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "org-hierarchy",
- "area": "organisations",
- "name": "Make the first user of an organisation its administrator and manager of later users.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/views/settings/StackiqSettings.vue:80 UserGroupsConfiguration -> GET/POST /api/user-groups/config (src/store/modules/settings.js:830); lib/Controller/SettingsController.php:3379; lib/Service/Stackiq/GroupHandler.php:103 generic groups, :167 fixed role groups (aanbod-beheerder, gebruik-beheerder, ...), group choice by organisation type (:471)"
}
},
{
@@ -2154,11 +2641,20 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No OIDC/SAML code in lib/ or src/; stackiq creates local Nextcloud users with a password (lib/Service/Stackiq/ContactPersonHandler.php:292)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it in stackiq; Nextcloud's own user_oidc/user_saml apps would apply platform-wide",
+ "provider": "nextcloud",
+ "providerHow": "read-from-code",
+ "note": "Stackiq does nothing for single sign-on. A Nextcloud admin can add an identity provider app, but that is the platform, not a stackiq page.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48908 'LDAP / SSO' (2026-07-23): Directory authentication and SSO.",
"topdesk": "docs, intelligence competitor_features#48935 'SSO integration' (2026-07-23): SAML / SSO authentication.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No OIDC/SAML code in lib/ or src/; stackiq creates local Nextcloud users with a password (lib/Service/Stackiq/ContactPersonHandler.php:292)"
}
},
{
@@ -2171,10 +2667,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it in stackiq; Nextcloud's user_ldap would apply platform-wide",
+ "provider": "nextcloud",
+ "providerHow": "read-from-code",
+ "note": "Stackiq has no directory sync for users or groups. Nextcloud's LDAP app could do it platform-wide, outside stackiq.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48908 'LDAP / SSO' (2026-07-23): Directory authentication and SSO. | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141776 '5.11 Contact import and change subscriptions from registries': LDAP import and periodic re-sync of users and groups (`src/AuthLDAP.php`, `/front/ldap.import.php`, `/front/ldap.group.import.php`) with `src/RuleRight.php` mapping directory attributes to profiles; nothing subscribes to",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/"
}
},
{
@@ -2187,9 +2692,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/components/ContactpersonenList.vue:115 'Change Password' opens src/dialogs/ChangePasswordDialog.vue -> POST /api/contactpersonen/change-password -> lib/Controller/ContactpersonenController.php:718, self-reset allowed at :753; GET /api/me (:1578) used only by src/App.vue and OrganisationSwitcher",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Organisations /organisaties card -> contact persons view -> Change Password on your own row",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "A user can change their own password from their contact row in the organisation card, which is hard to find. There is no 'my account' page in stackiq; /api/me feeds only the organisation switcher. Nextcloud's personal settings do both natively.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/components/ContactpersonenList.vue:115 'Change Password' opens src/dialogs/ChangePasswordDialog.vue -> POST /api/contactpersonen/change-password -> lib/Controller/ContactpersonenController.php:718, self-reset allowed at :753; GET /api/me (:1578) used only by src/App.vue and OrganisationSwitcher"
}
},
{
@@ -2202,26 +2716,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/SymfonyEmailService.php:466 registration, :553 activation, :641 user creation mails from templates; src/views/settings/sections/EmailConfiguration.vue:902 saveTemplate is a stub that logs 'not yet implemented in the backend' and still shows success; backend POST /api/email/templates/{templateName} (lib/Controller/SettingsController.php:2194) has no caller in src/; lib/Settings/connections.json email adapter reports the 'null' transport as simulated",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section 'Email configuration', Templates tab (save does not persist)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The mails are sent from templates, but the admin template editor's Save button does not call the backend and reports success anyway, so an administrator cannot edit a template from the UI. The transport defaults to 'null', which sends nothing until configured.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141830 '11.12 E-mail template library': `src/NotificationTemplate.php` with per-language bodies (`src/NotificationTemplateTranslation.php`), bound to events and delivery modes by `src/Notification_NotificationTemplate.php`, at `/front/notificationtemplate.php` | Rated yes because notification templates, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "share-public-browse",
- "area": "sharing",
- "name": "Let anyone browse the published catalogue without signing in.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/SymfonyEmailService.php:466 registration, :553 activation, :641 user creation mails from templates; src/views/settings/sections/EmailConfiguration.vue:902 saveTemplate is a stub that logs 'not yet implemented in the backend' and still shows success; backend POST /api/email/templates/{templateName} (lib/Controller/SettingsController.php:2194) has no caller in src/; lib/Settings/connections.json email adapter reports the 'null' transport as simulated"
}
},
{
@@ -2234,9 +2741,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Controller/PublicationController.php:87 publish/depublish (routes.php:208-209, PUT/DELETE /api/publication/{objectType}/{uuid}) with an IDOR guard; lib/Service/PublicationService.php:51 publishable types catalogService, module, connection, organization. No src/ caller of /api/publication (only a comment in src/utils/openDataProjection.js). The publish buttons in src/modals/object/ViewObject.vue:4854 are unreachable: Modals.vue renders ViewObject only for modal 'viewOrganisatie'/'viewContactpersoon', which nothing sets. Workaround: publicationDate/depublicationDate are visible, editable fields on module/catalogService/organization/connection (lib/Settings/softwarecatalogus_register.json:6777 schema).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only for the publish action: PUT /api/publication/{objectType}/{uuid}/publish, no stackiq page calls it; a user can only set the publicationDate field by hand in the edit form on Applications /modules or Services /diensten",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "open-data-publishing",
+ "featureConfidence": "high",
+ "note": "The dedicated publish/withdraw endpoint is complete and guarded but no page calls it, and the old modal publish buttons are dead code. The only UI path is typing a publication or depublication date into the generic edit form.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Controller/PublicationController.php:87 publish/depublish (routes.php:208-209, PUT/DELETE /api/publication/{objectType}/{uuid}) with an IDOR guard; lib/Service/PublicationService.php:51 publishable types catalogService, module, connection, organization. No src/ caller of /api/publication (only a comment in src/utils/openDataProjection.js). The publish buttons in src/modals/object/ViewObject.vue:4854 are unreachable: Modals.vue renders ViewObject only for modal 'viewOrganisatie'/'viewContactpersoon', which nothing sets. Workaround: publicationDate/depublicationDate are visible, editable fields on module/catalogService/organization/connection (lib/Settings/softwarecatalogus_register.json:6777 schema)."
}
},
{
@@ -2249,9 +2767,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "building",
+ "evidence": "src/utils/openDataProjection.js:36 STRIPPED_FIELDS (PII projection) is imported by nothing in src/ and has no PHP counterpart (grep 'projection' in lib/ finds none). Usage schema read rule lib/Settings/softwarecatalogus_register.json:3150 has no public group; lib/Controller/GebruikController.php:102 returns an empty result to anonymous callers.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "open-data-publishing",
+ "featureConfidence": "high",
+ "note": "Usage (gebruik) is not published as open data at all: anonymous callers get an empty envelope and the usage schema has no public read rule. The PII-stripping projection exists only as an unused, unit-tested JS util.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/utils/openDataProjection.js:36 STRIPPED_FIELDS (PII projection) is imported by nothing in src/ and has no PHP counterpart (grep 'projection' in lib/ finds none). Usage schema read rule lib/Settings/softwarecatalogus_register.json:3150 has no public group; lib/Controller/GebruikController.php:102 returns an empty result to anonymous callers."
}
},
{
@@ -2264,9 +2793,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/Federation/FederationService.php:215 announce() calls OpenCatalogi BroadcastService->broadcast(directory URL); only caller is lib/BackgroundJob/FederationSyncJob.php:73. Off by default: lib/Service/Federation/FederationConfig.php:56 federation_enabled=false; lib/Settings/connections.json lists federation as switch-only via occ. isAvailable() is class_exists('OCA\\\\OpenCatalogi\\\\Service\\\\DirectoryService') (FederationService.php:95).",
+ "owner": "ConductionNL/opencatalogi"
+ },
+ "reachedOn": "admin settings section Catalog federation shows status only; announce runs only from the background job after an admin sets federation_enabled with occ",
+ "provider": "opencatalogi",
+ "providerHow": "read-from-code",
+ "feature": "federation-between-catalogues",
+ "featureConfidence": "high",
+ "note": "The announce hop is a real call into OpenCatalogi, but it is off by default, can only be switched on with occ, has no announce button, and needs OpenCatalogi installed.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/Federation/FederationService.php:215 announce() calls OpenCatalogi BroadcastService->broadcast(directory URL); only caller is lib/BackgroundJob/FederationSyncJob.php:73. Off by default: lib/Service/Federation/FederationConfig.php:56 federation_enabled=false; lib/Settings/connections.json lists federation as switch-only via occ. isAvailable() is class_exists('OCA\\\\OpenCatalogi\\\\Service\\\\DirectoryService') (FederationService.php:95)."
}
},
{
@@ -2279,9 +2819,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/Federation/FederationService.php:434 fetchPeerCatalog() calls OpenCatalogi DirectoryService->getDirectory(['url' => $peerUrl]); OpenCatalogi's getDirectory (opencatalogi lib/Service/DirectoryService.php:2409, also on origin/development) reads only filters/limit/offset/include-federated and ignores 'url', so it returns this instance's own directory listings, not the peer's published entries. Provenance marking itself is built: lib/Service/Federation/FederationMerger.php:239 stamps _source.instance. Mirrors are written into the organization schema (FederationService.php:56 PEER_MIRROR_TYPE). No src/ code reads _source, so no page shows where an entry came from.",
+ "owner": "ConductionNL/opencatalogi"
+ },
+ "reachedOn": "admin settings section Catalog federation, Pull now button (src/views/settings/sections/FederationSettings.vue:332)",
+ "provider": "opencatalogi",
+ "providerHow": "read-from-code",
+ "feature": "federation-between-catalogues",
+ "featureConfidence": "high",
+ "note": "The pull does not fetch the peer: the peer URL is passed as a parameter OpenCatalogi ignores, so what gets mirrored is the local directory listing. Provenance is stamped on mirrors but no page displays it. Federation is also off by default.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/Federation/FederationService.php:434 fetchPeerCatalog() calls OpenCatalogi DirectoryService->getDirectory(['url' => $peerUrl]); OpenCatalogi's getDirectory (opencatalogi lib/Service/DirectoryService.php:2409, also on origin/development) reads only filters/limit/offset/include-federated and ignores 'url', so it returns this instance's own directory listings, not the peer's published entries. Provenance marking itself is built: lib/Service/Federation/FederationMerger.php:239 stamps _source.instance. Mirrors are written into the organization schema (FederationService.php:56 PEER_MIRROR_TYPE). No src/ code reads _source, so no page shows where an entry came from."
}
},
{
@@ -2294,9 +2845,20 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Controller/FederationController.php:86 addPeer / removePeer (routes.php:246-247), #[AuthorizedAdminSetting(StackiqAdmin)]; lib/Service/Federation/FederationService.php:157/191 with an SSRF host guard; UI src/views/settings/sections/FederationSettings.vue:283 (POST) and :307 (DELETE), mounted from src/views/settings/StackiqSettings.vue:114.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section Catalog federation (Nextcloud admin settings > Stackiq)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "federation-between-catalogues",
+ "featureConfidence": "high",
+ "note": "Adding and removing peers works end to end, but only for a Nextcloud admin in the admin settings, and the peers are only used by a pull that currently fetches the wrong data (see share-federation-pull).",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Controller/FederationController.php:86 addPeer / removePeer (routes.php:246-247), #[AuthorizedAdminSetting(StackiqAdmin)]; lib/Service/Federation/FederationService.php:157/191 with an SSRF host guard; UI src/views/settings/sections/FederationSettings.vue:283 (POST) and :307 (DELETE), mounted from src/views/settings/StackiqSettings.vue:114."
}
},
{
@@ -2309,29 +2871,22 @@
"bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "Every catalogue entity is an OpenRegister object (src/manifest.json pages read register @resolve:voorzieningen_register), so OpenRegister's /apps/openregister/api/objects/{register}/{schema} CRUD applies, gated by the schema authorization rules (lib/Settings/softwarecatalogus_register.json:6777 module and others). Stackiq adds its own routed endpoints in appinfo/routes.php (e.g. :202 /api/aanbod, :255-261 /api/aangeboden-gebruik, :298 /api/gebruik, :303 /api/portfolio-report).",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "API: /apps/openregister/api/objects plus stackiq /api/*; the stackiq pages themselves use the same API",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "Read and write through a REST API is live through OpenRegister, with stackiq's own role-scoped endpoints on top.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48867 'REST & GraphQL API' (2026-07-23): Programmatic access to the workspace graph.",
"bluedolphin": "docs, intelligence competitor_features#48972 'REST API' (2026-07-23): Programmatic integration with other systems.",
"glpi": "docs, intelligence competitor_features#48907 'REST API (HLAPI 2.x)' (2026-07-23): High-level REST API expanding object coverage in GLPI 11.",
"topdesk": "docs, intelligence competitor_features#48933 'REST API' (2026-07-23): Open REST API for integrations.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "share-public-api",
- "area": "sharing",
- "name": "Give developers a secure public API over the supplier offering.",
- "origin": "competitor",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "no",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141847 '12.19 Public data API with certificates or API keys': the API is fully authenticated, never public: user tokens plus optional app tokens with IP allow-listing (`apirest.md:62-67`, `src/APIClient.php:42`) and OAuth2 with scopes (`src/Glpi/OAuth/`). No anonymous public datase | Rated no because API is always authenticated, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "Every catalogue entity is an OpenRegister object (src/manifest.json pages read register @resolve:voorzieningen_register), so OpenRegister's /apps/openregister/api/objects/{register}/{schema} CRUD applies, gated by the schema authorization rules (lib/Settings/softwarecatalogus_register.json:6777 module and others). Stackiq adds its own routed endpoints in appinfo/routes.php (e.g. :202 /api/aanbod, :255-261 /api/aangeboden-gebruik, :298 /api/gebruik, :303 /api/portfolio-report)."
}
},
{
@@ -2344,10 +2899,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261), both login-only. Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: GET /api/views/docs and /api/aangeboden-gebruik/docs; docs site https://stackiq.conduction.nl (Documentation footer link)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The generated OpenAPI file is empty. What exists is hand-written: two JSON doc endpoints and markdown pages. OpenRegister may generate an OAS per register, but stackiq does not surface it.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141846 '12.18 OpenAPI documentation': auto-generated from route attributes: `src/Glpi/Api/HL/OpenAPIGenerator.php` with `src/Glpi/Api/HL/Doc/`, versioned per route (`#[RouteVersion]`, router at `src/Glpi/Api/HL/Router.php:98`); the legacy API is documented i | Rated yes because OpenAPI generator, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261), both login-only. Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint."
}
},
{
@@ -2360,41 +2924,22 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "ArchiMate export lib/Controller/SettingsController.php:1615 (POST /api/archimate/export) and :1685 per-organisation export (GET /api/archimate/export/organization/{uuid}), called only from src/views/settings/sections/ArchiMateImportExport.vue (admin settings, StackiqSettings.vue:86). CSV export of the portfolio report: lib/Controller/PortfolioReportController.php:105, button src/views/organisaties/PortfolioReport.vue:567. No index page opts into the library's CSV/Excel export (no allowExport in src/manifest.json).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section ArchiMate Import/Export; Portfolio rationalization /portfolio-report (Export CSV, one organisation at a time)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "medium",
+ "note": "A full ArchiMate export exists but is only reached from admin settings. The one export on a user page is the portfolio report CSV, and the catalogue list pages offer no export.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape",
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141818 '10.3 Export list results to CSV or XLSX': `src/Glpi/Search/Output/Csv.php`, `Xlsx.php`, `Ods.php` and `Pdf.php`, mapped at `src/Glpi/Search/SearchEngine.php:108-130` | Rated yes because CSV, XLSX, ODS, PDF export, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "share-portal",
- "area": "sharing",
- "name": "Show catalogue content on a shared external portal next to other apps' content.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "share-ai-assistant",
- "area": "sharing",
- "name": "Let an AI assistant query and update the catalogue through a tool interface.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "ArchiMate export lib/Controller/SettingsController.php:1615 (POST /api/archimate/export) and :1685 per-organisation export (GET /api/archimate/export/organization/{uuid}), called only from src/views/settings/sections/ArchiMateImportExport.vue (admin settings, StackiqSettings.vue:86). CSV export of the portfolio report: lib/Controller/PortfolioReportController.php:105, button src/views/organisaties/PortfolioReport.vue:567. No index page opts into the library's CSV/Excel export (no allowExport in src/manifest.json)."
}
},
{
@@ -2407,46 +2952,49 @@
"bluedolphin": "yes",
"glpi": "unknown",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No ITSM connector: lib/Settings/connections.json lists only email, federation and eol-feed; grep for topdesk/servicenow/itsm in lib/ and src/ finds nothing.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No integration with a service management tool exists.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48866 'Out-of-the-box integrations (ServiceNow, Signavio, SAP)' (2026-07-23): Pre-built connectors sync CMDB, process and ERP data.",
"bluedolphin": "docs, intelligence competitor_features#48973 'TOPdesk integration' (2026-07-23): Connector to TOPdesk asset/service data. | docs, intelligence competitor_features#27465 'TOPdesk Integration' (2026-04-12): Available on TOPdesk Marketplace for IT landscape insights",
"topdesk": "docs, intelligence competitor_features#48934 'Marketplace integrations (Lansweeper, ValueBlue)' (2026-07-23): Pre-built connectors incl. Lansweeper discovery and ValueBlue EA. | docs, intelligence competitor_features#27391 'Marketplace Integrations' (2026-04-12): TOPdesk Marketplace with third-party integrations including Lansweeper, BlueDolphin",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No ITSM connector: lib/Settings/connections.json lists only email, federation and eol-feed; grep for topdesk/servicenow/itsm in lib/ and src/ finds nothing."
}
},
{
- "id": "share-webhooks",
+ "id": "share-self-hosted",
"area": "sharing",
- "name": "Notify another system automatically when a catalogue entry changes.",
+ "name": "Run the catalogue on your own infrastructure instead of the vendor's cloud.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "share-self-hosted",
- "area": "sharing",
- "name": "Run the catalogue on your own infrastructure instead of the vendor's cloud.",
- "origin": "competitor",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "no",
- "bluedolphin": "no",
- "glpi": "yes",
- "topdesk": "partial",
- "stackiq": "unknown",
+ "sap-leanix": "no",
+ "bluedolphin": "no",
+ "glpi": "yes",
+ "topdesk": "partial",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/info.xml: a Nextcloud app (id stackiq, EUPL-1.2) installed on the customer's own Nextcloud with OpenRegister; stackiq-compose.yaml at repo root for a local stack.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "the whole app runs on the customer's own Nextcloud",
+ "provider": "nextcloud",
+ "providerHow": "read-from-code",
+ "note": "As a Nextcloud app it runs on whatever infrastructure hosts the Nextcloud instance.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
"bluedolphin": "docs, intelligence competitor_features#27467 'SaaS Platform' (2026-04-12): Cloud-native SaaS, no installation required",
"glpi": "docs, intelligence competitor_features#48912 '100% open source (GPL)' (2026-07-23): Fully GPL; no license fees, broad device coverage.",
"topdesk": "docs, intelligence competitor_features#26346 'SaaS Platform' (2026-04-10): Cloud-hosted SaaS platform with automatic updates | Rated partial because offered as SaaS; on-premises not in the reading.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "appinfo/info.xml: a Nextcloud app (id stackiq, EUPL-1.2) installed on the customer's own Nextcloud with OpenRegister; stackiq-compose.yaml at repo root for a local stack."
}
},
{
@@ -2459,11 +3007,22 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/FacetService.php:109 DIMENSIONS = referenceComponent, standard, applicationService, domain (GET /api/facets/{schema}, routes.php:195); src/views/FacetedCatalogIndexView.vue renders CnFacetSidebar with these plus search, on the Applications and Services pages. Supplier is only a column (src/manifest.json Modules config columns 'provider'), not a facet, although the module schema marks provider facetable.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Applications /modules and Services /diensten (FacetedCatalogIndexView)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "low",
+ "note": "Search plus reference-component, standard, application-service and domain facets work. Supplier is not offered as a facet, which is half of the row's example.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27553 'ICT Market Orientation' (2026-04-12): Find and compare software from registered ICT providers",
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141806 '9.2 Advanced search with per-case-type fields': the search engine is strong, with ~160 ticket search options (`src/Ticket.php:2670`), nested criteria groups, `AND`/`OR`/`AND NOT`/`OR NOT` (`src/Glpi/Search/SearchEngine.php:551-564`), cross-itemtype meta-criteria, but | Rated yes because search engine with nested criteria, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Service/FacetService.php:109 DIMENSIONS = referenceComponent, standard, applicationService, domain (GET /api/facets/{schema}, routes.php:195); src/views/FacetedCatalogIndexView.vue renders CnFacetSidebar with these plus search, on the Applications and Services pages. Supplier is only a column (src/manifest.json Modules config columns 'provider'), not a facet, although the module schema marks provider facetable."
}
},
{
@@ -2476,10 +3035,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/views/FacetedCatalogIndexView.vue:68 Saved views menu (save current filters, list, apply); src/store/modules/facets.js:404 saveCurrentAsView POSTs to OpenRegister /apps/openregister/api/views (:61), fetchSavedViews :361 reads them back.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Applications /modules and Services /diensten, Saved views menu",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "A user can save the facet and search selection as a named view and reopen it. Storage is OpenRegister's views API. It covers only those two pages.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141807 '9.3 Personal saved searches': `src/SavedSearch.php:52`, `is_private` default 1, personal ordering (`:824`) and a default per itemtype (`src/SavedSearch_User.php:94-115`), at `/front/savedsearch.php` | Rated yes because saved searches, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/views/FacetedCatalogIndexView.vue:68 Saved views menu (save current filters, list, apply); src/store/modules/facets.js:404 saveCurrentAsView POSTs to OpenRegister /apps/openregister/api/views (:61), fetchSavedViews :361 reads them back."
}
},
{
@@ -2492,12 +3060,21 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:72 Dashboard page with stat widgets kpi-organisations, kpi-modules, kpi-services, kpi-contracts (source metric count on organization/module/catalogService/catalogContract) plus catalog-panels.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Dashboard / (first menu entry)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The dashboard shows counts of organisations, applications, services and contracts. The counts are computed by OpenRegister through the library stat widget.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports. | docs, intelligence competitor_features#27424 'Dashboards & Reports' (2026-04-12): Real-time dashboards for CIO-level reporting",
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141816 '10.1 Configurable KPI dashboards (count, gauge, chart)': `src/Glpi/Dashboard/Grid.php:67` with 20 widget types: pie, donut, half pie/donut, bars, lines, areas, stacked and horizontal variants, big number, multiple numbers, summary numbers, markdown, search result, article list",
"topdesk": "docs, intelligence competitor_features#48936 'Reporting & dashboards' (2026-07-23): Operational reporting and dashboards.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:72 Dashboard page with stat widgets kpi-organisations, kpi-modules, kpi-services, kpi-contracts (source metric count on organization/module/catalogService/catalogContract) plus catalog-panels."
}
},
{
@@ -2510,9 +3087,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Dashboard/ConceptOrganisatiesWidget.php registered at lib/AppInfo/Application.php:760; src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters organisations on status === 'concept', but the status enum is Draft/Active/Inactive/merged (lib/Settings/softwarecatalogus_register.json:2321) after lib/Repair/RenameDutchCatalogValues.php:76 renamed 'Concept' to 'Draft'. Accept writes status 'actief' (:129), which is not in the enum either.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Nextcloud dashboard widget 'Concept organisaties'",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The widget is registered and loads, but it filters on a status value the data no longer holds, so it always lists nothing. Its accept button would write an invalid status.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Dashboard/ConceptOrganisatiesWidget.php registered at lib/AppInfo/Application.php:760; src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters organisations on status === 'concept', but the status enum is Draft/Active/Inactive/merged (lib/Settings/softwarecatalogus_register.json:2321) after lib/Repair/RenameDutchCatalogValues.php:76 renamed 'Concept' to 'Draft'. Accept writes status 'actief' (:129), which is not in the enum either."
}
},
{
@@ -2525,10 +3111,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:1021 Reports page (type reports) with one card, Portfolio rationalization, routing to src/manifest.json PortfolioReport /portfolio-report (PortfolioReportView, GET /api/portfolio-report routes.php:303).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Reports /reports (footer menu), one card to Portfolio rationalization /portfolio-report",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The report picker exists and opens a working report. The list holds exactly one report.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145791 'C-reporting-2 A canned report the product ships, run without building it.': glpi: Reports (Tools, Reports, front/report.default.php, report.dynamic.php, report.year.php, report.state.php, report.reservation.php, report.contract.php) Lane findings: D-glpi-35. | Rated yes because canned reports, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:1021 Reports page (type reports) with one card, Portfolio rationalization, routing to src/manifest.json PortfolioReport /portfolio-report (PortfolioReportView, GET /api/portfolio-report routes.php:303)."
}
},
{
@@ -2541,11 +3136,22 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No report builder in src/ or lib/. The only report is the fixed Gartner TIME portfolio report (lib/Controller/PortfolioReportController.php, CSV at :105). The overlay lists portfolio-reporting as status 'soon'.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "portfolio-reporting",
+ "featureConfidence": "high",
+ "note": "Users cannot build their own report. The one fixed portfolio report can be exported as CSV, but it is not configurable.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141816 '10.1 Configurable KPI dashboards (count, gauge, chart)': `src/Glpi/Dashboard/Grid.php:67` with 20 widget types: pie, donut, half pie/donut, bars, lines, areas, stacked and horizontal variants, big number, multiple numbers, summary numbers, markdown, search result, article list",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No report builder in src/ or lib/. The only report is the fixed Gartner TIME portfolio report (lib/Controller/PortfolioReportController.php, CSV at :105). The overlay lists portfolio-reporting as status 'soon'."
}
},
{
@@ -2558,10 +3164,21 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "Portfolio report CSV: lib/Controller/PortfolioReportController.php:105 (DataDownloadResponse text/csv), button src/views/organisaties/PortfolioReport.vue:567. No index page sets the library's allowExport (grep allowExport/exportable in src/manifest.json and the register finds nothing), so Applications, Contracts and the other lists have no export.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Portfolio rationalization /portfolio-report, Export CSV",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "portfolio-reporting",
+ "featureConfidence": "low",
+ "note": "One fixed report exports to CSV for a selected organisation. The filtered catalogue lists cannot be exported.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141818 '10.3 Export list results to CSV or XLSX': `src/Glpi/Search/Output/Csv.php`, `Xlsx.php`, `Ods.php` and `Pdf.php`, mapped at `src/Glpi/Search/SearchEngine.php:108-130` | Rated yes because source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "Portfolio report CSV: lib/Controller/PortfolioReportController.php:105 (DataDownloadResponse text/csv), button src/views/organisaties/PortfolioReport.vue:567. No index page sets the library's allowExport (grep allowExport/exportable in src/manifest.json and the register finds nothing), so Applications, Contracts and the other lists have no export."
}
},
{
@@ -2574,58 +3191,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "ins-audit-trail",
- "area": "insight",
- "name": "Look back at who changed what in the catalogue, and when.",
- "origin": "competitor",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "yes",
- "topdesk": "yes",
- "stackiq": "unknown",
- "evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141820 '10.5 Audit or event log viewer with filters and export': two logs, both searchable and exportable through the search engine: `src/Log.php:48` field-level object history (Historical tab, `src/Ticket.php:887`) and `src/Glpi/Event.php:63` the system/event log at `/front/logs.php` | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141852 '13.9 Audit trail including reads and views': writes are covered thoroughly: `src/Log.php:48` field-level history on every object, `src/Glpi/Event.php:63` the system log including logins (`src/Auth.php:1149-1163`), `src/RuleMatchedLog.php` for rule decisions. Reads | Rated yes because field-level history, source-read 2026-09-14.",
- "topdesk": "docs, intelligence competitor_features#26345 'Audit Trail' (2026-04-10): Complete audit trail of all service management actions",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "ins-live-updates",
- "area": "insight",
- "name": "See a list update by itself when someone else changes an entry.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "partial",
- "glpi": "unknown",
- "topdesk": "unknown",
- "stackiq": "unknown",
- "evidence": {
- "bluedolphin": "docs, intelligence competitor_features#48969 'Real-time collaboration' (2026-07-23): Multiple stakeholders collaborate on models. | Rated partial because real-time collaboration on models.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "ins-notifications",
- "area": "insight",
- "name": "Receive in-app notifications about changes that concern you.",
- "origin": "own-code",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "partial",
- "topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No scheduled report or report mail job: lib/BackgroundJob/ holds only ContractStatusJob, EolSyncJob, FederationSyncJob and OrganizationContactSyncJob; grep for report scheduling in lib/ and src/ finds nothing.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Reports cannot be scheduled or sent to people.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141783 '6.8 In-app notifications (bell)': `MODE_AJAX` is a wired delivery mode (`src/Notification_NotificationTemplate.php:55-59`, `getModes()` at `:381-398`, implementation `src/NotificationAjax.php`), rendering as a browser toast rather than a persistent inbox | Rated partial because toast delivery, not an inbox, source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No scheduled report or report mail job: lib/BackgroundJob/ holds only ContractStatusJob, EolSyncJob, FederationSyncJob and OrganizationContactSyncJob; grep for report scheduling in lib/ and src/ finds nothing."
}
},
{
@@ -2638,10 +3215,21 @@
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/views/LicensePostureView.vue:84 per-vendor rollup with annual cost from contracts (src/utils/licensePosture.js perVendorRollup); src/views/organisaties/PortfolioReport.vue:143 annualised and one-off cost per TIME quadrant for one selected organisation (lib/Service/PortfolioReportService.php via GET /api/portfolio-report).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "License posture /license-posture (per vendor); Portfolio rationalization /portfolio-report (per selected organisation)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "contract-administration",
+ "featureConfidence": "medium",
+ "note": "Cost is reported per vendor and, within the portfolio report, for one organisation at a time. There is no cross-organisation or per-domain cost report.",
"evidence": {
"glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/views/LicensePostureView.vue:84 per-vendor rollup with annual cost from contracts (src/utils/licensePosture.js perVendorRollup); src/views/organisaties/PortfolioReport.vue:143 annualised and one-off cost per TIME quadrant for one selected organisation (lib/Service/PortfolioReportService.php via GET /api/portfolio-report)."
}
},
{
@@ -2654,9 +3242,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:1048 FeaturesRoadmap page (type roadmap, line 1050), footer menu entry FeaturesRoadmapMenu; content from openspec/features.overlay.json statuses stable/beta/soon.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Features & roadmap /features-roadmap (footer menu)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The page lists features with their status. Note that the overlay feeding it is a self-description and may be stale in the app's favour.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "src/manifest.json:1048 FeaturesRoadmap page (type roadmap, line 1050), footer menu entry FeaturesRoadmapMenu; content from openspec/features.overlay.json statuses stable/beta/soon."
}
},
{
@@ -2669,10 +3266,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Controller/SettingsController.php:1289 getProgress and :1360 streamProgress (routes.php:119-120) serve lib/Service/ProgressTracker.php, used only by lib/Service/MergeOrganisatieService.php; no src/ caller of /api/progress. The admin ArchiMate import shows a spinner then the final objects-processed count (src/views/settings/sections/ArchiMateImportExport.vue:103). Organisation sync shows a status block with last sync time and organisations to process (src/views/settings/sections/OrganizationSynchronization.vue:211).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings sections Organization Synchronization and ArchiMate Import/Export (status and result only); progress endpoints API only",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "A progress API exists but no page reads it. Admins see a sync status and final import results, not the progress of a running job.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145875 'C-configuration-20 A long running administrative operation reports its progress.': glpi: Progress on a long operation (src/Glpi/Controller/ProgressController.php, Traits/AsyncOperationProgressControllerTrait.php) Lane findings: D-glpi-29. | Rated yes because source-read 2026-09-14.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/Controller/SettingsController.php:1289 getProgress and :1360 streamProgress (routes.php:119-120) serve lib/Service/ProgressTracker.php, used only by lib/Service/MergeOrganisatieService.php; no src/ caller of /api/progress. The admin ArchiMate import shows a spinner then the final objects-processed count (src/views/settings/sections/ArchiMateImportExport.vue:103). Organisation sync shows a status block with last sync time and organisations to process (src/views/settings/sections/OrganizationSynchronization.vue:211)."
}
},
{
@@ -2685,11 +3291,20 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No knowledge-article schema among the register's schemas (sector, suite, catalogService, vulnerability, contactPerson, organization, usage, catalogContract, connection, software-review, element, view, model, property-definition, relation, module, compliancy, bioMeasure, moduleVersion, sbomComponent in lib/Settings/softwarecatalogus_register.json); ModuleDetail only has a Documentation files panel.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "There is no knowledge base. Files can be attached to an application, but that is not searchable articles.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48909 'Knowledge base' (2026-07-23): Built-in KB with FAQ publishing.",
"topdesk": "docs, intelligence competitor_features#48931 'Knowledge base' (2026-07-23): Knowledge management and published articles.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No knowledge-article schema among the register's schemas (sector, suite, catalogService, vulnerability, contactPerson, organization, usage, catalogContract, connection, software-review, element, view, model, property-definition, relation, module, compliancy, bioMeasure, moduleVersion, sbomComponent in lib/Settings/softwarecatalogus_register.json); ModuleDetail only has a Documentation files panel."
}
},
{
@@ -2702,10 +3317,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No discovery agent or agent-ingest endpoint in lib/ or appinfo/routes.php. The nearest capability is SBOM import per module version (lib/Controller/SbomController.php:129), which records components of a known release, not installed software.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Stackiq is a catalogue, and nothing discovers installed software.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48899 'Native inventory (GLPI Agent)' (2026-07-23): Built-in agent (ex-FusionInventory) discovers hardware/software automatically. | docs, intelligence competitor_features#3269 'Inventory' (2026-03-28): Automatic inventory discovery with FusionInventory agent",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No discovery agent or agent-ingest endpoint in lib/ or appinfo/routes.php. The nearest capability is SBOM import per module version (lib/Controller/SbomController.php:129), which records components of a known release, not installed software."
}
},
{
@@ -2718,10 +3342,19 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No network scanning code in lib/ or routes (appinfo/routes.php).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No device discovery.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48911 'Network / SNMP discovery' (2026-07-23): SNMP network equipment inventory.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No network scanning code in lib/ or routes (appinfo/routes.php)."
}
},
{
@@ -2734,10 +3367,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No SaaS or SSO-log discovery code in lib/; lib/Settings/connections.json has no such source.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No discovery of unregistered SaaS use.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No SaaS or SSO-log discovery code in lib/; lib/Settings/connections.json has no such source."
}
},
{
@@ -2750,11 +3392,20 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No hardware schema in lib/Settings/softwarecatalogus_register.json (schemas are software, organisation, contract and GEMMA model types only).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Only software is registered, not hardware.",
"evidence": {
"glpi": "docs, intelligence competitor_features#3266 'IT Asset Management' (2026-03-28): Track hardware, software, and network assets",
"topdesk": "docs, intelligence competitor_features#27388 'Asset Management' (2026-04-12): Track hardware and software assets, locations, and assignments",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No hardware schema in lib/Settings/softwarecatalogus_register.json (schemas are software, organisation, contract and GEMMA model types only)."
}
},
{
@@ -2767,12 +3418,21 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "Applications (module lib/Settings/softwarecatalogus_register.json:6777), versions (moduleVersion :7649), suites (suite :1135) and application-to-application connections (connection :3563) with relations; ModuleDetail and SuiteDetail show a Related panel. No manifest page has register+schema 'connection' or 'usage', so connections are not listed or created on their own page.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Applications /modules/:id and Suites /suites/:id Related panels; no page for connections",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The landscape and its relations are recorded as catalogue objects, not as a CMDB with CI classes. Connections (koppelingen) have no index or detail page of their own.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
"glpi": "docs, intelligence competitor_features#48902 'CMDB & configuration relations' (2026-07-23): CI relationships and impact analysis.",
"topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | docs, intelligence competitor_features#27387 'CMDB / Configuration Management' (2026-04-12): Configuration database for registering IT objects like laptops, software, infrastructure",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "Applications (module lib/Settings/softwarecatalogus_register.json:6777), versions (moduleVersion :7649), suites (suite :1135) and application-to-application connections (connection :3563) with relations; ModuleDetail and SuiteDetail show a Related panel. No manifest page has register+schema 'connection' or 'usage', so connections are not listed or created on their own page."
}
},
{
@@ -2785,9 +3445,18 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "Organisation merge: src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail, calling /api/organisaties/{uuid}/merge/dry-run and /merge (src/store/modules/organisatie.js:486/524, lib/Controller/MergeController.php:106, admin-only body guard). Federation mirrors are reconciled per peer by lib/Service/Federation/FederationMerger.php.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Organisation /organisaties/:id, Merge organisation panel (admin only)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "An admin can merge duplicate organisations with a dry run. Nothing deduplicates applications or reconciles records arriving from several sources.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "Organisation merge: src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail, calling /api/organisaties/{uuid}/merge/dry-run and /merge (src/store/modules/organisatie.js:486/524, lib/Controller/MergeController.php:106, admin-only body guard). Federation mirrors are reconciled per peer by lib/Service/Federation/FederationMerger.php."
}
},
{
@@ -2800,11 +3469,20 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No incident or request schema or endpoint in lib/Settings/softwarecatalogus_register.json or appinfo/routes.php.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "No ticketing.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48903 'ITIL helpdesk / ticketing' (2026-07-23): Full incident/request ticketing with the assets module.",
"topdesk": "docs, intelligence competitor_features#48927 'Incident / ticket management' (2026-07-23): Core ITSM incident and request handling.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No incident or request schema or endpoint in lib/Settings/softwarecatalogus_register.json or appinfo/routes.php."
}
},
{
@@ -2817,11 +3495,20 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No change-request workflow for applications. The only approval flow is for contracts: src/components/contracts/ContractApprovalPanel.vue on ContractDetail via /api/contracts/{uuid}/approval (routes.php:35-37), delegated to decidiq.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "Contracts go through an approval, but changes to an application do not.",
"evidence": {
"glpi": "docs, intelligence competitor_features#3277 'Change Management' (2026-03-28): ITIL change management with approval workflows",
"topdesk": "docs, intelligence competitor_features#48929 'Change management' (2026-07-23): Structured change workflows with action sequences.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No change-request workflow for applications. The only approval flow is for contracts: src/components/contracts/ContractApprovalPanel.vue on ContractDetail via /api/contracts/{uuid}/approval (routes.php:35-37), delegated to decidiq."
}
},
{
@@ -2834,11 +3521,20 @@
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "catalogContract.contractType enum includes 'SLA' (lib/Settings/softwarecatalogus_register.json:3344) as a label only; no service-level target, measurement or breach fields in any schema.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "A contract can be typed as SLA, but no service level targets are recorded or tracked.",
"evidence": {
"glpi": "docs, intelligence competitor_features#48904 'SLA management' (2026-07-23): SLA targets and escalation rules.",
"topdesk": "docs, intelligence competitor_features#48930 'SLA management' (2026-07-23): Service-level target tracking and reporting.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "catalogContract.contractType enum includes 'SLA' (lib/Settings/softwarecatalogus_register.json:3344) as a label only; no service-level target, measurement or breach fields in any schema."
}
},
{
@@ -2851,27 +3547,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls.",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "End users cannot request software.",
"evidence": {
"topdesk": "docs, intelligence competitor_features#48928 'Self-service portal' (2026-07-23): End-user portal for requests and knowledge, reduces direct support load.",
- "stackiq": "not checked: the code reading for this row is under way"
- }
- },
- {
- "id": "ops-plugins",
- "area": "operations",
- "name": "Extend the product with plugins installed from a marketplace.",
- "origin": "competitor",
- "vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
- "glpi": "yes",
- "topdesk": "yes",
- "stackiq": "unknown",
- "evidence": {
- "glpi": "docs, intelligence competitor_features#48906 'Plugin ecosystem' (2026-07-23): Large plugin marketplace (FormCreator, GenericObject, etc.). | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145919 'C-configuration-48 An extension is found, installed, updated and removed from inside the product.': glpi: Marketplace (Setup, Plugins, front/marketplace.php, marketplace.download.php, front/plugin.php) Lane findings: D-glpi-45.",
- "topdesk": "docs, intelligence competitor_features#27391 'Marketplace Integrations' (2026-04-12): TOPdesk Marketplace with third-party integrations including Lansweeper, BlueDolphin",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls."
}
},
{
@@ -2884,10 +3572,19 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "yes",
- "stackiq": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "No mobile app or mobile-specific surface in the repo; the app is the Nextcloud web UI (src/manifest.json).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "nextcloud",
+ "providerHow": "read-from-code",
+ "note": "There is no native mobile app.",
"evidence": {
"topdesk": "docs, intelligence competitor_features#48937 'Mobile app' (2026-07-23): Native mobile operator app.",
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "No mobile app or mobile-specific surface in the repo; the app is the Nextcloud web UI (src/manifest.json)."
}
},
{
@@ -2900,11 +3597,1091 @@
"bluedolphin": "unknown",
"glpi": "unknown",
"topdesk": "unknown",
- "stackiq": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/BackgroundJob/OrganizationContactSyncJob.php:75 TimedJob every 300 s calling performScheduledSync; admin section src/views/settings/sections/CronjobConfiguration.vue:56 shows each job's interval and an enable switch; src/views/settings/sections/OrganizationSynchronization.vue:211 shows Last Sync from app config last_sync_time (lib/Service/OrganizationSyncService.php:1609, written by recordSyncTime :1674).",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings sections Cronjob configuration and Organization Synchronization",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "automatic-user-provisioning",
+ "featureConfidence": "medium",
+ "note": "The sync runs on a schedule and its last run time is shown, but only an admin can see and configure it, which is the rule for partial.",
"evidence": {
- "stackiq": "not checked: the code reading for this row is under way"
+ "stackiq": "lib/BackgroundJob/OrganizationContactSyncJob.php:75 TimedJob every 300 s calling performScheduledSync; admin section src/views/settings/sections/CronjobConfiguration.vue:56 shows each job's interval and an enable switch; src/views/settings/sections/OrganizationSynchronization.vue:211 shows Last Sync from app config last_sync_time (lib/Service/OrganizationSyncService.php:1609, written by recordSyncTime :1674)."
}
}
],
- "pending": []
+ "pending": [
+ {
+ "id": "land-usage-record",
+ "area": "landscape",
+ "name": "Record that your organisation uses a module, as a usage separate from the product itself.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "partial",
+ "bluedolphin": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: /api/aangeboden-gebruik/*, /api/gebruik and OpenRegister objects API; read-only on Portfolio roadmap /portfolio-roadmap",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "offering-and-usage-listings",
+ "featureConfidence": "high",
+ "note": "The usage schema models this separation properly, but no stackiq page creates or edits a usage: the ObjectModal accepts type 'usage' (src/modals/Modals.vue:38) yet nothing opens it. Usages are only read by the roadmap, compliance matrix and vulnerability views.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
+ "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers.",
+ "bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository.",
+ "stackiq": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/"
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend create usage (gebruik) records through /api/aangeboden-gebruik or the OpenRegister objects API, and is that frontend part of what stackiq ships?"
+ },
+ {
+ "id": "land-migrate-legacy",
+ "area": "landscape",
+ "name": "Bring over what was registered in the previous catalogue, so nobody types it again.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "There is no importer for the previous VNG Softwarecatalogus's registrations. The repair steps only rename stackiq's own earlier data, and the ArchiMate import brings in the GEMMA model, not organisations' entries.",
+ "evidence": {
+ "stackiq": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets"
+ },
+ "pendingQuestion": "Is the data from the previous VNG Softwarecatalogus meant to be brought over by a one-off migration outside this repo (for example an OpenRegister register import of an export file)?"
+ },
+ {
+ "id": "conn-register-connection",
+ "area": "connections",
+ "name": "Register a connection between two applications, with its direction and the standard it uses.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "yes",
+ "bluedolphin": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: OpenRegister objects API; no stackiq page",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "medium",
+ "note": "The connection model with direction and standard is complete, and the demo data ships six, but no stackiq page creates or edits one.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
+ "sap-leanix": "docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
+ "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | Rated partial because ArchiMate flow relations.",
+ "stackiq": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it"
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend register koppelingen through the OpenRegister objects API, and does it count as part of stackiq?"
+ },
+ {
+ "id": "conn-usage-of-connection",
+ "area": "connections",
+ "name": "Record that your organisation actually runs a given connection, not only that it exists.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "offering-and-usage-listings",
+ "featureConfidence": "medium",
+ "note": "The model records which connections a usage runs, but neither usages nor connections have a page.",
+ "evidence": {
+ "stackiq": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller"
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend let an organisation record the connections it runs, through /api/koppelingen-gebruik or the objects API?"
+ },
+ {
+ "id": "conn-shared-with-others",
+ "area": "connections",
+ "name": "See which connections you run together with other organisations.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: /api/aangeboden-gebruik/deelnemers",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "shared-usage-on-gemma-views",
+ "featureConfidence": "medium",
+ "note": "Shared usage (with the connections it carries) is answerable through the API, but no stackiq page shows it.",
+ "evidence": {
+ "stackiq": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/"
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend show shared connections from /api/aangeboden-gebruik/deelnemers?"
+ },
+ {
+ "id": "arch-refcomp-mapping",
+ "area": "architecture",
+ "name": "Place an application on the GEMMA reference components it fulfils.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Modules /modules (FacetedCatalogIndexView) filters by reference component (read only); no stackiq page sets the mapping: module form hides it (hideOnForm), usage has no page",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "high",
+ "note": "The mapping is stored and can be filtered on, but no stackiq screen writes it: the module field is hideOnForm and the usage schema has no index or edit page; writes come through ArchiMate import, the OpenRegister objects API or the external VNG frontend.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48835 'Reference component mapping (referentiecomponenten)' (2026-07-23): Maps each registered software product onto GEMMA reference components/domains so functionality is comparable across suppliers. | docs, intelligence competitor_features#27551 'Reference Component Linking' (2026-04-12): Link software to GEMMA reference components",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules"
+ },
+ "pendingQuestion": "Does the Modules page's CnIndexPage create/edit dialog in nextcloud-vue 2.55.1 render module.referenceComponents (hideOnForm:true, items.$ref element in the AMEF register) as a working multiselect of reference components? nextcloud-vue's fieldsFromSchema (src/utils/schema.js:529) does not check hideOnForm."
+ },
+ {
+ "id": "arch-gemma-views",
+ "area": "architecture",
+ "name": "Open a GEMMA architecture view with your own applications drawn inside it.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: GET /api/views (src/store/modules/view.js:89 defines a store but nothing imports useViewStore); the drawn view is only visible in Archi after 'Organization Export' on admin settings section ArchiMate Import/Export",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "medium",
+ "note": "No stackiq page renders a GEMMA view. The enriched view data is served for an external frontend, and the org export draws applications into view copies that open in Archi.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map. | Rated yes because landscape auto-plotted on the reference component map.",
+ "stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export"
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend render /api/views/{id} with include_gebruik, and is that frontend in scope for stackiq's column?"
+ },
+ {
+ "id": "arch-shared-overlay",
+ "area": "architecture",
+ "name": "On a GEMMA view, see the applications you share with partners, drawn apart from your own.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/ViewService.php:1187 getDeelnamesGebruikData + :924 tags shared usage with _type='deelnames' and _sourceOrganization; lib/Service/ArchiMateExportService.php:3005 org export gives every nested application the same green fillColor, deelnames only get their own folder (:3086)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: GET /api/views/{viewId}?include_deelnames_gebruik=true; org ArchiMate export from admin settings section ArchiMate Import/Export (Deelnames checkbox)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "shared-usage-on-gemma-views",
+ "featureConfidence": "high",
+ "note": "The API separates shared usage from own usage and names the source organisation, but nothing in stackiq draws it; in the ArchiMate export shared applications get the same style as own ones, so they are not drawn differently.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48844 'Municipal cooperation / shared-service management' (2026-07-23): Manages gemeente-samenwerking (shared service centres) registering a joint landscape.",
+ "stackiq": "lib/Service/ViewService.php:1187 getDeelnamesGebruikData + :924 tags shared usage with _type='deelnames' and _sourceOrganization; lib/Service/ArchiMateExportService.php:3005 org export gives every nested application the same green fillColor, deelnames only get their own folder (:3086)"
+ },
+ "pendingQuestion": "Does the external VNG frontend draw deelnames nodes differently from own usage on a GEMMA view?"
+ },
+ {
+ "id": "arch-gemma-api",
+ "area": "architecture",
+ "name": "Retrieve the GEMMA architecture itself through an API.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:185-187 GET /api/views, /api/views/docs, /api/views/{viewId} -> lib/Controller/ViewController.php:82,218 (@NoAdminRequired) -> lib/Service/ViewService.php:108,166 read views from the AMEF register; GEMMA elements are element objects in the AMEF register, readable through the OpenRegister objects API",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: GET /api/views and /api/views/{viewId} (authenticated), plus OpenRegister /api/objects on the AMEF register for elements",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "low",
+ "note": "A pure API row: the views endpoint is routed, authorised for logged-in users and returns the imported GEMMA views; elements come through OpenRegister's generic objects API.",
+ "evidence": {
+ "stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/docs, /api/views/{viewId} -> lib/Controller/ViewController.php:82,218 (@NoAdminRequired) -> lib/Service/ViewService.php:108,166 read views from the AMEF register; GEMMA elements are element objects in the AMEF register, readable through the OpenRegister objects API"
+ },
+ "pendingQuestion": "Is the view API reachable without a Nextcloud login (no #[PublicPage] on ViewController), and does the row require public access?"
+ },
+ {
+ "id": "comp-declare-standard",
+ "area": "compliance",
+ "name": "Declare that an application supports a specific version of a standard.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json compliancy.standardVersion ($ref element, queryParams gemmaType=standaardversie) + compliancy.module + compliancy.standardGemma (string); src/manifest.json Komplianties /komplianties index on the voorzieningen register; ModuleDetail md-compliance object-list has allowCreate:false; module.standardVersions is hideOnForm",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Komplianties /komplianties (menu Reports & Compliance > Compliance), generic create form",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "standards-compliance",
+ "featureConfidence": "high",
+ "note": "A compliance record can be created on the Compliance index, but the standard-version relation points at element objects that live in the AMEF register while the page works on the voorzieningen register, so the version picker may not resolve; the free-text standardGemma field is the fallback. Not offered from the application page itself.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48840 'Standards support declaration' (2026-07-23): Suppliers declare which standards (StUF, ZGW/Zaakgericht APIs, etc.) a product supports.",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.standardVersion ($ref element, queryParams gemmaType=standaardversie) + compliancy.module + compliancy.standardGemma (string); src/manifest.json Komplianties /komplianties index on the voorzieningen register; ModuleDetail md-compliance object-list has allowCreate:false; module.standardVersions is hideOnForm"
+ },
+ "pendingQuestion": "On /komplianties, does the create form's standardVersion select (items $ref element, which lives only in the AMEF register) list standard versions, or does it resolve against the voorzieningen register and come back empty/404 as the Standaarden page did before its register fix?"
+ },
+ {
+ "id": "mkt-offer-accept",
+ "area": "market",
+ "name": "As a supplier, accept or decline a usage another organisation has claimed of your product.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Controller/AanbodController.php:200 acceptAanbod and :303 denyAanbod, lib/Service/AanbodService.php:289 checks the active organisation is aanbieder or afnemer then re-owns the object; routes appinfo/routes.php PUT /api/aanbod/{uuid}/accept, DELETE /api/aanbod/{uuid}/deny; also /api/aangeboden-gebruik/{id}/set-self and /deny",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: /api/aanbod and /api/aangeboden-gebruik, no stackiq page calls them (grep of src finds no caller)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "offering-and-usage-listings",
+ "featureConfidence": "high",
+ "note": "The accept/decline logic is complete and authorised, but nothing in src/ calls it, so only the external VNG frontend or a script can use it. There is also no stackiq page for usage (gebruik) records at all.",
+ "evidence": {
+ "stackiq": "lib/Controller/AanbodController.php:200 acceptAanbod and :303 denyAanbod, lib/Service/AanbodService.php:289 checks the active organisation is aanbieder or afnemer then re-owns the object; routes appinfo/routes.php PUT /api/aanbod/{uuid}/accept, DELETE /api/aanbod/{uuid}/deny; also /api/aangeboden-gebruik/{id}/set-self and /deny"
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend (not in this repo) call PUT /api/aanbod/{uuid}/accept and /api/aangeboden-gebruik/{id}/set-self, and is that frontend part of what we ship?"
+ },
+ {
+ "id": "mkt-compare-peers",
+ "area": "market",
+ "name": "See which software comparable organisations use for the same reference component.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Controller/ViewController.php (routes GET /api/views, /api/views/{viewId}) enriches GEMMA views with shared usage (deelnames); src/store/modules/view.js:89 calls it but no component imports that store",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: GET /api/views, the only caller is src/store/modules/view.js which no mounted component uses",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "shared-usage-on-gemma-views",
+ "featureConfidence": "high",
+ "note": "The shared-usage enrichment on GEMMA views exists server-side but no stackiq page renders it, so a user cannot see peers' software per reference component in this app.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48837 'Cross-municipality software comparison' (2026-07-23): Municipalities compare used software and connections with peer gemeenten; core network-effect value. | docs, intelligence competitor_features#27552 'Municipality Comparison' (2026-04-12): Compare application landscapes between municipalities",
+ "stackiq": "lib/Controller/ViewController.php (routes GET /api/views, /api/views/{viewId}) enriches GEMMA views with shared usage (deelnames); src/store/modules/view.js:89 calls it but no component imports that store"
+ },
+ "pendingQuestion": "Does the external VNG frontend render /api/views with the deelnames enrichment, and does that count as a stackiq page?"
+ },
+ {
+ "id": "mkt-who-uses-it",
+ "area": "market",
+ "name": "See which organisations use a given application.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register :2656 usage (consumer, module); usage read rule lets aanbod-beheerder read usages where provider = own organisation (:3137); ModuleDetail md-related widget src/manifest.json:491; GET /api/koppelingen-gebruik/{uuid} and /api/gebruik in lib/Controller/AangebodenGebruikController.php, lib/Controller/GebruikController.php",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleDetail /modules/:id 'Vendor & services' related panel (supplier only, via RBAC); otherwise API only: /api/koppelingen-gebruik, /api/gebruik",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "offering-and-usage-listings",
+ "featureConfidence": "medium",
+ "note": "There is no usage page and no 'used by' list on the application page. A supplier may see usages of its own product through the generic related panel, other roles see only their own usages; the per-product usage endpoints have no caller in src/.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48837 'Cross-municipality software comparison' (2026-07-23): Municipalities compare used software and connections with peer gemeenten; core network-effect value.",
+ "stackiq": "register :2656 usage (consumer, module); usage read rule lets aanbod-beheerder read usages where provider = own organisation (:3137); ModuleDetail md-related widget src/manifest.json:491; GET /api/koppelingen-gebruik/{uuid} and /api/gebruik in lib/Controller/AangebodenGebruikController.php, lib/Controller/GebruikController.php"
+ },
+ "pendingQuestion": "Does the generic 'related' widget on ModuleDetail list usage objects that point at the module (inverse relation), and for which roles?"
+ },
+ {
+ "id": "mkt-review-moderation",
+ "area": "market",
+ "name": "Hold a submitted review for moderation before others can read it.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/ReviewService.php:232 forces pending; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; src/views/settings/StackiqSettings.vue:98 ModerationQueue type=software-review via src/utils/adminApi.js; lib/Settings/register.d/catalog-ratings.json public read only matches status approved but every catalogue group reads all reviews and may create them",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "admin settings section 'Review moderation'; the Reviews /reviews index also lists reviews",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "reviews",
+ "featureConfidence": "high",
+ "note": "The ReviewsPanel path holds reviews as pending and an admin approves them in settings. But the generic Reviews index /reviews shows pending reviews to every catalogue group and its Add form writes software-review through OpenRegister directly, where status (enum incl. approved) is a visible form field, so moderation can be bypassed.",
+ "evidence": {
+ "stackiq": "lib/Service/ReviewService.php:232 forces pending; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; src/views/settings/StackiqSettings.vue:98 ModerationQueue type=software-review via src/utils/adminApi.js; lib/Settings/register.d/catalog-ratings.json public read only matches status approved but every catalogue group reads all reviews and may create them"
+ },
+ "pendingQuestion": "Does the installed OpenRegister let a catalogue user create a software-review with status=approved through /reviews (the generic create), bypassing ReviewService?"
+ },
+ {
+ "id": "mkt-hide-landscape-from-vendors",
+ "area": "market",
+ "name": "Keep your application landscape and connections hidden from suppliers.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register usage authorization (:3137) reads scoped to _organisation or consumer; aanbod-beheerder also reads usages where provider = own organisation; connection read (:3855) public when published and by provider; openspec/specs/vendor-visibility-rbac",
+ "owner": "ConductionNL/openregister",
+ "ownerNote": "reader wrote: ConductionNL/stackiq (rules), executed by ConductionNL/openregister"
+ },
+ "reachedOn": "no page: enforced by OpenRegister RBAC on every read",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "The register declares organisation-scoped reads, so a supplier sees only usages of its own products and published connections. This rests on the installed OpenRegister executing the declared match rules.",
+ "evidence": {
+ "stackiq": "register usage authorization (:3137) reads scoped to _organisation or consumer; aanbod-beheerder also reads usages where provider = own organisation; connection read (:3855) public when published and by provider; openspec/specs/vendor-visibility-rbac"
+ },
+ "pendingQuestion": "Does the installed OpenRegister enforce the declared authorization.read match rules (e.g. {group: aanbod-beheerder, match: {provider: $organisation}}) on usage and connection reads?"
+ },
+ {
+ "id": "mkt-free-public-service",
+ "area": "market",
+ "name": "Use the catalogue free of charge as a municipality or supplier.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "no",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; module/catalogService/organization carry public read rules for published entries; public intake POST /api/intake/register",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "no page: a property of the app and its licence",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The software is free and published entries are publicly readable, but the repo ships no hosted public catalogue; the public-facing frontend is the external VNG one.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
+ "sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
+ "glpi": "docs, intelligence competitor_features#48912 '100% open source (GPL)' (2026-07-23): Fully GPL; no license fees, broad device coverage.",
+ "stackiq": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; module/catalogService/organization carry public read rules for published entries; public intake POST /api/intake/register"
+ },
+ "pendingQuestion": "Is a hosted, free-of-charge stackiq instance offered to municipalities and suppliers (the competitor offer is a public service, not software)?"
+ },
+ {
+ "id": "life-eol-warning",
+ "area": "lifecycle",
+ "name": "Get a warning before an application or version falls out of support.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/views/LifecycleRoadmapView.vue:73-86 EOL passed/approaching/withdrawn badges with EOL_WINDOW_DAYS=180 (:143); lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications eol-approaching (scheduled, dateEndSupport withinNext P180D, recipients software-catalog-admins + object-acl manage) is a declaration only; no notification code in lib (no INotificationManager use)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "LifecycleRoadmap /portfolio-roadmap badges; push warning only if OpenRegister executes the declared rule",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "lifecycle-and-end-of-support",
+ "featureConfidence": "high",
+ "note": "You see an 'approaching end of support' badge when you open the roadmap. A pushed warning rests only on a register declaration, and that rule addresses catalogue admins and the version's managers, not the organisations using the application.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
+ "stackiq": "src/views/LifecycleRoadmapView.vue:73-86 EOL passed/approaching/withdrawn badges with EOL_WINDOW_DAYS=180 (:143); lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications eol-approaching (scheduled, dateEndSupport withinNext P180D, recipients software-catalog-admins + object-acl manage) is a declaration only; no notification code in lib (no INotificationManager use)"
+ },
+ "pendingQuestion": "Does the installed OpenRegister dispatch the scheduled x-openregister-notifications rule 'eol-approaching' on moduleVersion, and to whom?"
+ },
+ {
+ "id": "life-eol-feed",
+ "area": "lifecycle",
+ "name": "Fill in end-of-support dates automatically from a public end-of-life feed.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/BackgroundJob/EolSyncJob.php (registered appinfo/info.xml:101) + appinfo/routes.php:292-295 /api/eol-sync/* -> lib/Service/EolSyncService.php:145 run() reads eol_cycle objects via OpenRegister ObjectService (:328), stamps dateEndSupport on module versions via EolMatcherService; enabled defaults to false (lib/Service/SettingsService.php:7211); lib/Settings/connections.json eol-feed is a switch, off until enabled; the cycles are fetched by integriq's endoflife-date source",
+ "owner": "ConductionNL/integriq"
+ },
+ "reachedOn": "admin settings section End-of-life feed sync (src/views/settings/sections/EolSyncSettings.vue); results visible on ModuleversieDetail and LifecycleRoadmap",
+ "provider": "integriq",
+ "providerHow": "read-from-code",
+ "feature": "lifecycle-and-end-of-support",
+ "featureConfidence": "high",
+ "note": "The matcher is complete, but it is off by default, only an admin can switch it on, each module needs an eolProductSlug, and the feed data only exists when integriq's endoflife.date source is provisioned.",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | Rated partial because obsolescence tracking; source of dates not named.",
+ "stackiq": "lib/BackgroundJob/EolSyncJob.php (registered appinfo/info.xml:101) + appinfo/routes.php:292-295 /api/eol-sync/* -> lib/Service/EolSyncService.php:145 run() reads eol_cycle objects via OpenRegister ObjectService (:328), stamps dateEndSupport on module versions via EolMatcherService; enabled defaults to false (lib/Service/SettingsService.php:7211); lib/Settings/connections.json eol-feed is a switch, off until enabled; the cycles are fetched by integriq's endoflife-date source"
+ },
+ "pendingQuestion": "Is integriq's endoflife-date source (eol_product/eol_cycle register) provisioned on a default install, so that switching the sync on actually finds cycles?"
+ },
+ {
+ "id": "life-planned-replacement",
+ "area": "lifecycle",
+ "name": "Record which application is planned to replace another.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json usage.plannedReplacement ($ref module) + plannedReplacementDate; read by src/views/LifecycleRoadmapView.vue:400; no usage page in src/manifest.json and navigationStore.setModal('usage') is never called (src/modals/Modals.vue:38 lists usage but nothing opens it)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "shown on LifecycleRoadmap /portfolio-roadmap; nothing in stackiq records it (OpenRegister objects API or the external VNG frontend only)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "portfolio-roadmap",
+ "featureConfidence": "high",
+ "note": "The planned replacement is stored per usage and displayed on the roadmap, but no stackiq page lets you record it.",
+ "evidence": {
+ "stackiq": "lib/Settings/softwarecatalogus_register.json usage.plannedReplacement ($ref module) + plannedReplacementDate; read by src/views/LifecycleRoadmapView.vue:400; no usage page in src/manifest.json and navigationStore.setModal('usage') is never called (src/modals/Modals.vue:38 lists usage but nothing opens it)"
+ },
+ "pendingQuestion": "Is the external VNG Softwarecatalogus frontend (which writes usage objects) counted as part of stackiq for this row?"
+ },
+ {
+ "id": "life-time-classification",
+ "area": "lifecycle",
+ "name": "Classify each application as tolerate, invest, migrate or eliminate.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json usage.timeClassification enum Tolerate/Invest/Migrate/Eliminate + timeRationale + timeReviewDate; read by lib/Service/PortfolioReportService.php and rendered in src/views/organisaties/PortfolioReport.vue:112 quadrant chart; src/modals/object/ObjectModal.vue:178 has the enum select but is never opened for usage",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "PortfolioReport /portfolio-report (via Reports /reports card) shows the classification; no stackiq page sets it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The TIME classification is stored and reported per quadrant, but there is no page in stackiq where a user classifies an application.",
+ "evidence": {
+ "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json usage.timeClassification enum Tolerate/Invest/Migrate/Eliminate + timeRationale + timeReviewDate; read by lib/Service/PortfolioReportService.php and rendered in src/views/organisaties/PortfolioReport.vue:112 quadrant chart; src/modals/object/ObjectModal.vue:178 has the enum select but is never opened for usage"
+ },
+ "pendingQuestion": "Is the external VNG frontend or OpenRegister's generic object editor the intended place to set timeClassification, and does it count here?"
+ },
+ {
+ "id": "ctr-register",
+ "area": "contracts",
+ "name": "Register a contract for a service with its number, type, term and cost.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:527 Contracten type:index over catalogContract (contractNumber, contractType, startDate, endDate, cost, status); register :3252 catalogContract requires service AND usage; no manifest page has schema usage (grep src/manifest.json)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Contracts /contracten (main menu), Add form",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "contract-administration",
+ "featureConfidence": "high",
+ "note": "All the fields are on the contract form, but a contract requires a usage (gebruik) record and no stackiq page can create one, so on a fresh install the form cannot be completed without data from elsewhere (demo data, API, external frontend).",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "glpi": "docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets. | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145509 'C-parties-and-contacts-1 A contract is a record with its own term and costs, linked to the party it binds and the cases raised under it': glpi: Contracts (Management, Contracts, front/contract_item.php, contractcost.php, ticket_contract.php) Lane findings: D-glpi-49.",
+ "topdesk": "docs, intelligence competitor_features#48932 'Contract & vendor management' (2026-07-23): Track supplier contracts and operational agreements.",
+ "stackiq": "src/manifest.json:527 Contracten type:index over catalogContract (contractNumber, contractType, startDate, endDate, cost, status); register :3252 catalogContract requires service AND usage; no manifest page has schema usage (grep src/manifest.json)"
+ },
+ "pendingQuestion": "Does the installed OpenRegister accept a catalogContract without the required usage (schema hardValidation false), and can the related-object picker create a usage inline?"
+ },
+ {
+ "id": "ctr-expiry-alert",
+ "area": "contracts",
+ "name": "Get warned before a contract expires.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "no",
+ "sap-leanix": "partial",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "specified",
+ "evidence": "lib/Settings/softwarecatalogus_register.json:3255 x-openregister-notifications contract-expiry filters status equals 'Actief' but the status enum is Active/Expired/In negotiation (:3428), and the subject uses {{contractNummer}}/{{eindDatum}} while fields are contractNumber/endDate; Contracten quick filter 'Expiring / expired' filters status Expired only (src/manifest.json:527)",
+ "owner": "ConductionNL/openregister",
+ "ownerNote": "reader wrote: ConductionNL/stackiq (declaration), dispatch by ConductionNL/openregister"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "feature": "notifications",
+ "featureConfidence": "high",
+ "note": "The only expiry warning is a declared OpenRegister notification whose filter value 'Actief' never matches the English status 'Active', so even if OpenRegister dispatches it, no contract qualifies. No page shows contracts that are about to expire.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS renewal dates.",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json:3255 x-openregister-notifications contract-expiry filters status equals 'Actief' but the status enum is Active/Expired/In negotiation (:3428), and the subject uses {{contractNummer}}/{{eindDatum}} while fields are contractNumber/endDate; Contracten quick filter 'Expiring / expired' filters status Expired only (src/manifest.json:527)"
+ },
+ "pendingQuestion": "Does the installed OpenRegister dispatch scheduled x-openregister-notifications, and does it compare the filter value case/locale-insensitively (it cannot map 'Actief' to 'Active')?"
+ },
+ {
+ "id": "ctr-approval",
+ "area": "contracts",
+ "name": "Only let a contract become active after an approval decision is recorded.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/ContractApprovalService.php:254 submitForApproval dispatches OCA\\Decidiq\\Event\\DecisionRequestedEvent (fail-closed), :412 projectOutcome sets status Active only on approved; src/manifest.json:579 ContractApprovalPanel on ContractDetail; but register :3428 status enum incl. Active is an editable form field and approvalState (register.d/contracts-to-decidesk.json) is not readOnly; the declared x-openregister-lifecycle uses Dutch states 'In onderhandeling'/'Actief' that match no enum value",
+ "owner": "ConductionNL/decidiq",
+ "ownerNote": "reader wrote: ConductionNL/stackiq + ConductionNL/decidiq"
+ },
+ "reachedOn": "ContractDetail /contracten/:id, Approval panel 'Submit for approval' (needs decidiq installed)",
+ "provider": "decidiq",
+ "providerHow": "read-from-code",
+ "feature": "contract-renewal-approval",
+ "featureConfidence": "high",
+ "note": "The approval path through decidiq works and only an approved outcome sets Active. Nothing stops a user from creating or editing a contract with status Active directly in the generic form, so 'only after an approval' is not enforced.",
+ "evidence": {
+ "stackiq": "lib/Service/ContractApprovalService.php:254 submitForApproval dispatches OCA\\Decidiq\\Event\\DecisionRequestedEvent (fail-closed), :412 projectOutcome sets status Active only on approved; src/manifest.json:579 ContractApprovalPanel on ContractDetail; but register :3428 status enum incl. Active is an editable form field and approvalState (register.d/contracts-to-decidesk.json) is not readOnly; the declared x-openregister-lifecycle uses Dutch states 'In onderhandeling'/'Actief' that match no enum value"
+ },
+ "pendingQuestion": "Does the installed OpenRegister enforce x-openregister-lifecycle transitions on catalogContract.status, given its states are Dutch ('Actief') and the enum is English ('Active')?"
+ },
+ {
+ "id": "sec-exposure",
+ "area": "security",
+ "name": "See which organisations and usages are exposed to a vulnerability.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/utils/vulnerabilityExposure.js:54 in-production join vulnerability.modules -> usage.module -> usage.consumer; count shown in the list (src/views/KwetsbaarhedenView.vue:111); per-organisation rows in VulnerabilityExposurePanel on KwetsbaarheidDetail tab (src/manifest.json:997), but a list row opens the edit modal, not the detail page (KwetsbaarhedenView.vue:417)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Vulnerabilities /kwetsbaarheden, Exposed usages column; KwetsbaarheidDetail /kwetsbaarheden/:id Exposure tab has no confirmed entry point",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "The list shows how many in-production usages are exposed to each vulnerability. The per-organisation exposure lives on a detail tab the list does not open, so a user sees the count but not reliably who is exposed.",
+ "evidence": {
+ "stackiq": "src/utils/vulnerabilityExposure.js:54 in-production join vulnerability.modules -> usage.module -> usage.consumer; count shown in the list (src/views/KwetsbaarhedenView.vue:111); per-organisation rows in VulnerabilityExposurePanel on KwetsbaarheidDetail tab (src/manifest.json:997), but a list row opens the edit modal, not the detail page (KwetsbaarhedenView.vue:417)"
+ },
+ "pendingQuestion": "Is KwetsbaarheidDetail reachable from any page, for example by clicking a vulnerability in ModuleDetail's Related panel?"
+ },
+ {
+ "id": "sec-vulnerability-alert",
+ "area": "security",
+ "name": "Get an alert when a vulnerability is reported for software you use.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "specified",
+ "evidence": "register.json:1622 x-openregister-notifications 'vulnerability-reported' on vulnerability, trigger created, channels nc-notification + email, recipients group software-catalog-admins and object-acl manage (a declaration only)",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "Declaration in the register; fires on create from Vulnerabilities /kwetsbaarheden",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "feature": "notifications",
+ "featureConfidence": "high",
+ "note": "The alert is declared, not code in stackiq, and it goes to catalogue admins and the record's managers, not to the organisations that use the affected software.",
+ "evidence": {
+ "stackiq": "register.json:1622 x-openregister-notifications 'vulnerability-reported' on vulnerability, trigger created, channels nc-notification + email, recipients group software-catalog-admins and object-acl manage (a declaration only)"
+ },
+ "pendingQuestion": "Does the installed OpenRegister dispatch the x-openregister-notifications 'vulnerability-reported' rule on the vulnerability schema, and can recipients be the consumers of the affected modules?"
+ },
+ {
+ "id": "org-self-registration",
+ "area": "organisations",
+ "name": "Let a new organisation sign itself up without an account.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Controller/IntakeController.php:74 PublicPage + AnonRateLimit(5/h) on POST /api/intake/register; lib/Service/IntakeService.php:146 forces registrationStatus pending, publicationDate null; no caller in src/. Separately, organization authorization.create includes 'public' (register :2467)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: POST /api/intake/register, no stackiq page calls it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "self-registration-with-moderation",
+ "featureConfidence": "high",
+ "note": "The anonymous sign-up endpoint is complete and lands in moderation, but stackiq has no sign-up form. The schema also grants 'public' create on organization, so an anonymous generic OpenRegister create could skip the intake's pending stamp.",
+ "evidence": {
+ "stackiq": "lib/Controller/IntakeController.php:74 PublicPage + AnonRateLimit(5/h) on POST /api/intake/register; lib/Service/IntakeService.php:146 forces registrationStatus pending, publicationDate null; no caller in src/. Separately, organization authorization.create includes 'public' (register :2467)"
+ },
+ "pendingQuestion": "Does the external VNG frontend post to /api/intake/register, and does OpenRegister's generic public create on organization let an anonymous caller set registrationStatus/status/publicationDate directly?"
+ },
+ {
+ "id": "org-contact-to-account",
+ "area": "organisations",
+ "name": "Turn a contact person into a user account with the right role automatically.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Controller/ContactpersonenController.php:393 convertToUser -> lib/Service/Stackiq/ContactPersonHandler.php:292 createUserAccount reads objectData['email'] (:299); automatic path lib/EventListener/StackiqEventListener.php -> lib/Service/ContactpersoonService.php:128 also reads contactData['email']; contactPerson schema (:1788) declares no email (identity moved to Nextcloud Contacts via contactsUid); UI: src/components/ContactpersonenList.vue:97 'Convert to User' inside OrganisatieCard",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Organisations /organisaties card -> 'Bekijk contactpersonen' toggle -> Convert to User (org admins)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "automatic-user-provisioning",
+ "featureConfidence": "high",
+ "note": "Conversion and role-based group assignment exist, manual and automatic on create for active organisations. Both read an email field the contact schema no longer has, so a contact created through the current form (contactsUid only) fails with 'No email address found' unless it carries legacy data.",
+ "evidence": {
+ "stackiq": "lib/Controller/ContactpersonenController.php:393 convertToUser -> lib/Service/Stackiq/ContactPersonHandler.php:292 createUserAccount reads objectData['email'] (:299); automatic path lib/EventListener/StackiqEventListener.php -> lib/Service/ContactpersoonService.php:128 also reads contactData['email']; contactPerson schema (:1788) declares no email (identity moved to Nextcloud Contacts via contactsUid); UI: src/components/ContactpersonenList.vue:97 'Convert to User' inside OrganisatieCard"
+ },
+ "pendingQuestion": "Does a contactPerson created via the current form reach createUserAccount with an email (e.g. resolved from Nextcloud Contacts by contactsUid somewhere I did not find), or does conversion fail for every post-migration contact?"
+ },
+ {
+ "id": "org-cooperation",
+ "area": "organisations",
+ "name": "Register a cooperation of organisations and the landscape they share.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register organization.type 'Collaboration' + participants/deelnames (:2236); usage.participants (:2718); shared landscape endpoint GET /api/aangeboden-gebruik/deelnemers (lib/Controller/AangebodenGebruikController.php) has no caller in src/",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Organisations /organisaties form (type Collaboration, participants); shared landscape API only",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "shared-usage-on-gemma-views",
+ "featureConfidence": "medium",
+ "note": "A cooperation can be registered with its participant organisations. The landscape it shares is only exposed through the deelnemers API and the unrendered view enrichment; no page shows it, and there is no usage page to record it.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48844 'Municipal cooperation / shared-service management' (2026-07-23): Manages gemeente-samenwerking (shared service centres) registering a joint landscape.",
+ "stackiq": "register organization.type 'Collaboration' + participants/deelnames (:2236); usage.participants (:2718); shared landscape endpoint GET /api/aangeboden-gebruik/deelnemers (lib/Controller/AangebodenGebruikController.php) has no caller in src/"
+ },
+ "pendingQuestion": "Does the external VNG frontend show a cooperation's shared landscape from /api/aangeboden-gebruik/deelnemers?"
+ },
+ {
+ "id": "org-data-segregation",
+ "area": "organisations",
+ "name": "Keep each organisation's records visible only to that organisation unless published.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "specified",
+ "evidence": "register authorization.read rules with {match: {_organisation: $organisation}} on catalogContract (:3474), contactPerson (:1788), usage (:3137), connection (:3855); public reads only for published entries; lib/Controller/ContactpersonenController.php:293 org guard on the custom endpoint",
+ "owner": "ConductionNL/openregister",
+ "ownerNote": "reader wrote: ConductionNL/stackiq (rules), executed by ConductionNL/openregister"
+ },
+ "reachedOn": "no page: enforced by OpenRegister RBAC/multitenancy on every list and detail page",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "Organisation-scoped reads are declared per schema and the custom endpoints add their own guards. Whether generic pages are actually segregated depends on OpenRegister executing those match rules.",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48910 'Multi-entity (tenant) segregation' (2026-07-23): Hierarchical entities for multi-org / multi-department isolation.",
+ "stackiq": "register authorization.read rules with {match: {_organisation: $organisation}} on catalogContract (:3474), contactPerson (:1788), usage (:3137), connection (:3855); public reads only for published entries; lib/Controller/ContactpersonenController.php:293 org guard on the custom endpoint"
+ },
+ "pendingQuestion": "Does the installed OpenRegister evaluate authorization.read match rules with $organisation on the generic object list and detail endpoints the stackiq pages use?"
+ },
+ {
+ "id": "org-hierarchy",
+ "area": "organisations",
+ "name": "Make the first user of an organisation its administrator and manager of later users.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Service/Stackiq/ContactPersonHandler.php:646 first contact of an organisation gets the organisation-admin groups; lib/Service/Stackiq/HierarchyHandler.php:79 ensureOrganizationBeheerder and :130 setupManagerRelationships make later users report to the primary beheerder",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "no page: runs when a contact is converted to a user (see org-contact-to-account)",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "automatic-user-provisioning",
+ "featureConfidence": "medium",
+ "note": "The first user of an organisation becomes its admin and later users get that admin as manager. It rides on the contact-to-account path, which reads an email field the current contact schema lacks, so it only fires for contacts that carry one.",
+ "evidence": {
+ "stackiq": "lib/Service/Stackiq/ContactPersonHandler.php:646 first contact of an organisation gets the organisation-admin groups; lib/Service/Stackiq/HierarchyHandler.php:79 ensureOrganizationBeheerder and :130 setupManagerRelationships make later users report to the primary beheerder"
+ },
+ "pendingQuestion": "Same as org-contact-to-account: does conversion get an email for a post-migration contact?"
+ },
+ {
+ "id": "share-public-browse",
+ "area": "sharing",
+ "name": "Let anyone browse the published catalogue without signing in.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json:7307 module authorization.read grants group public on publicationDate<=$now (and, separately, on registeredBy=Supplier); lib/Settings/softwarecatalogus_register.json:1559 catalogService same; suite read is plain 'public' (lib/Settings/softwarecatalogus_register.json:1270). No stackiq route is #[PublicPage] except intake/review aggregate/gebruik (lib/Controller/GebruikController.php:102 returns an empty envelope to anonymous callers). The app's pages are all behind Nextcloud login (appinfo/routes.php:313 SPA catch-all).",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "API only: anonymous reads go through OpenRegister's objects API; no stackiq page is reachable without signing in",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "feature": "open-data-publishing",
+ "featureConfidence": "medium",
+ "note": "Anonymous browsing rests on RBAC read rules declared in the register and executed by OpenRegister; stackiq ships no public page, and the browsing surface is the external VNG Softwarecatalogus frontend, which is not in this repo. Note the module rule also exposes every registeredBy=Supplier module regardless of publication date.",
+ "evidence": {
+ "vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json:7307 module authorization.read grants group public on publicationDate<=$now (and, separately, on registeredBy=Supplier); lib/Settings/softwarecatalogus_register.json:1559 catalogService same; suite read is plain 'public' (lib/Settings/softwarecatalogus_register.json:1270). No stackiq route is #[PublicPage] except intake/review aggregate/gebruik (lib/Controller/GebruikController.php:102 returns an empty envelope to anonymous callers). The app's pages are all behind Nextcloud login (appinfo/routes.php:313 SPA catch-all)."
+ },
+ "pendingQuestion": "Does the installed OpenRegister honour the {group: public, match: {publicationDate: {$lte: $now}}} read rule on module/catalogService for an anonymous GET /apps/openregister/api/objects, and which public frontend (the external VNG Softwarecatalogus site) is the intended browse surface?"
+ },
+ {
+ "id": "share-public-api",
+ "area": "sharing",
+ "name": "Give developers a secure public API over the supplier offering.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "no",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "Anonymous read of the supplier offering depends on declared rules: lib/Settings/softwarecatalogus_register.json:7307 module read includes public on publicationDate<=$now and on registeredBy=Supplier; lib/Settings/softwarecatalogus_register.json:1559 catalogService public on publicationDate. Stackiq's own offering endpoint lib/Controller/AanbodController.php (routes.php:202) is authenticated-only (@NoAdminRequired + in-body guard). Rate limit only on GebruikController (#[AnonRateLimit]).",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "API only: OpenRegister objects API for anonymous reads; no stackiq page",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "There is no dedicated developer-facing public API: public access to the offering is whatever OpenRegister executes from the declared read rules, and stackiq's own offering endpoint requires login.",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141847 '12.19 Public data API with certificates or API keys': the API is fully authenticated, never public: user tokens plus optional app tokens with IP allow-listing (`apirest.md:62-67`, `src/APIClient.php:42`) and OAuth2 with scopes (`src/Glpi/OAuth/`). No anonymous public datase | Rated no because API is always authenticated, source-read 2026-09-14.",
+ "stackiq": "Anonymous read of the supplier offering depends on declared rules: lib/Settings/softwarecatalogus_register.json:7307 module read includes public on publicationDate<=$now and on registeredBy=Supplier; lib/Settings/softwarecatalogus_register.json:1559 catalogService public on publicationDate. Stackiq's own offering endpoint lib/Controller/AanbodController.php (routes.php:202) is authenticated-only (@NoAdminRequired + in-body guard). Rate limit only on GebruikController (#[AnonRateLimit])."
+ },
+ "pendingQuestion": "Does the installed OpenRegister execute the module/catalogService public read rules for anonymous API callers, and is any API key or rate limit applied to that public surface?"
+ },
+ {
+ "id": "share-portal",
+ "area": "sharing",
+ "name": "Show catalogue content on a shared external portal next to other apps' content.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Portal/PortalContributionProvider.php:130 getContribution() declares read-only, organisation-scoped collections (catalogService, usage, catalogContract, compliancy) for the vendor-org and participant-org audiences. Portaliq discovers it by FQCN from the Stackiq in appinfo/info.xml (portaliq lib/Contribution/PortalProviderLocator.php:49/77). No info.xml dependency; inert without portaliq.",
+ "owner": "ConductionNL/portaliq"
+ },
+ "reachedOn": "Portaliq external portal (not a stackiq page), only for signed-in portal subjects of a supplier or participant organisation",
+ "provider": "portaliq",
+ "providerHow": "read-from-code",
+ "note": "The contribution is declarative and read-only, and it covers only an organisation's own records for portal subjects. It shows nothing publicly, and the create/accept actions are deferred per its own docblock.",
+ "evidence": {
+ "stackiq": "lib/Portal/PortalContributionProvider.php:130 getContribution() declares read-only, organisation-scoped collections (catalogService, usage, catalogContract, compliancy) for the vendor-org and participant-org audiences. Portaliq discovers it by FQCN from the Stackiq in appinfo/info.xml (portaliq lib/Contribution/PortalProviderLocator.php:49/77). No info.xml dependency; inert without portaliq."
+ },
+ "pendingQuestion": "Does the installed portaliq render stackiq's contribution (its PortalProviderLocator iterating installed apps), and is that portal live for any stackiq customer?"
+ },
+ {
+ "id": "share-ai-assistant",
+ "area": "sharing",
+ "name": "Let an AI assistant query and update the catalogue through a tool interface.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "none",
+ "evidence": "No MCP, tool-provider, TaskProcessing or ContextChat code in stackiq lib/ or src/ (grep 'mcp|ToolProvider|assistant|TaskProcessing|ContextChat' in lib/ finds nothing). OpenRegister ships a generic MCP endpoint (openregister appinfo/routes.php:1969 /api/mcp/v1/discover and the JSON-RPC endpoint) over all registers.",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "nothing in stackiq reaches it; only OpenRegister's generic MCP endpoint",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "Stackiq has nothing of its own here. An AI client could only reach catalogue objects through OpenRegister's generic MCP server, if it covers the voorzieningen register.",
+ "evidence": {
+ "stackiq": "No MCP, tool-provider, TaskProcessing or ContextChat code in stackiq lib/ or src/ (grep 'mcp|ToolProvider|assistant|TaskProcessing|ContextChat' in lib/ finds nothing). OpenRegister ships a generic MCP endpoint (openregister appinfo/routes.php:1969 /api/mcp/v1/discover and the JSON-RPC endpoint) over all registers."
+ },
+ "pendingQuestion": "Does OpenRegister's MCP server expose the voorzieningen register's objects (module, catalogService, organization) for read and write to an AI client with a stackiq user's rights?"
+ },
+ {
+ "id": "share-webhooks",
+ "area": "sharing",
+ "name": "Notify another system automatically when a catalogue entry changes.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "none",
+ "evidence": "Stackiq has no webhook code. The Flows page (src/manifest.json:1057, settings-section menu entry FlowsMenu) authors OpenRegister's native flows scoped to app stackiq; OpenRegister's flow event catalogue has object.created/object.updated (openregister lib/Service/Flow/EventCatalogService.php:53-54), and OpenRegister has its own webhooks admin (openregister appinfo/routes.php:1909).",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "Flows /flows (settings section of the app navigation); webhooks only in OpenRegister's own admin UI",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "Change notification to another system is possible only through OpenRegister machinery: its webhooks UI, or a flow authored on stackiq's Flows page. Stackiq itself sends nothing.",
+ "evidence": {
+ "stackiq": "Stackiq has no webhook code. The Flows page (src/manifest.json:1057, settings-section menu entry FlowsMenu) authors OpenRegister's native flows scoped to app stackiq; OpenRegister's flow event catalogue has object.created/object.updated (openregister lib/Service/Flow/EventCatalogService.php:53-54), and OpenRegister has its own webhooks admin (openregister appinfo/routes.php:1909)."
+ },
+ "pendingQuestion": "Can a flow created on stackiq's Flows page be triggered by object.updated on a catalogue schema and make an outbound HTTP call to an external system?"
+ },
+ {
+ "id": "ins-audit-trail",
+ "area": "insight",
+ "name": "Look back at who changed what in the catalogue, and when.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:436 (and 10 more detail pages: ContactpersoonDetail, ModuleDetail, ContractDetail, SuiteDetail, StandaardDetail, BioMaatregelDetail, ReviewDetail, KompliantieDetail, ModuleversieDetail, KwetsbaarheidDetail) declare a sidebar tab History with widget type audit, which reads OpenRegister's audit trail for that one object.",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "History sidebar tab on the detail pages, e.g. Organisation /organisaties/:id",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "feature": "audit-trail-view",
+ "featureConfidence": "high",
+ "note": "Per-record history is shown on 11 detail pages, backed by OpenRegister's audit trail. There is no catalogue-wide view of who changed what, and the overlay itself lists audit-trail-view as 'soon'.",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141820 '10.5 Audit or event log viewer with filters and export': two logs, both searchable and exportable through the search engine: `src/Log.php:48` field-level object history (Historical tab, `src/Ticket.php:887`) and `src/Glpi/Event.php:63` the system/event log at `/front/logs.php` | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141852 '13.9 Audit trail including reads and views': writes are covered thoroughly: `src/Log.php:48` field-level history on every object, `src/Glpi/Event.php:63` the system log including logins (`src/Auth.php:1149-1163`), `src/RuleMatchedLog.php` for rule decisions. Reads | Rated yes because field-level history, source-read 2026-09-14.",
+ "topdesk": "docs, intelligence competitor_features#26345 'Audit Trail' (2026-04-10): Complete audit trail of all service management actions",
+ "stackiq": "src/manifest.json:436 (and 10 more detail pages: ContactpersoonDetail, ModuleDetail, ContractDetail, SuiteDetail, StandaardDetail, BioMaatregelDetail, ReviewDetail, KompliantieDetail, ModuleversieDetail, KwetsbaarheidDetail) declare a sidebar tab History with widget type audit, which reads OpenRegister's audit trail for that one object."
+ },
+ "pendingQuestion": "Is OpenRegister's audit trail enabled for the voorzieningen register on a default install, so the History tab shows entries?"
+ },
+ {
+ "id": "ins-live-updates",
+ "area": "insight",
+ "name": "See a list update by itself when someone else changes an entry.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/composables/useLiveCollections.js:40 subscribes via the library's useObjectSubscription; used in src/views/KwetsbaarhedenView.vue:197, LicensePostureView.vue:209, LifecycleRoadmapView.vue:184, ComplianceMatrixView.vue:326, PortfolioReport.vue:323. The standard index pages (Contracts, Organisations and others) rely on whatever the library's CnIndexPage does.",
+ "owner": "ConductionNL/openregister",
+ "ownerNote": "reader wrote: ConductionNL/nextcloud-vue"
+ },
+ "reachedOn": "Vulnerabilities /kwetsbaarheden, License posture /license-posture, Portfolio roadmap /portfolio-roadmap, Compliance matrix /compliance-matrix, Portfolio rationalization /portfolio-report",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "Five custom pages subscribe to collection events and refetch on a change. Whether the event ever arrives depends on OpenRegister and the push transport, which this repo cannot show.",
+ "evidence": {
+ "bluedolphin": "docs, intelligence competitor_features#48969 'Real-time collaboration' (2026-07-23): Multiple stakeholders collaborate on models. | Rated partial because real-time collaboration on models.",
+ "stackiq": "src/composables/useLiveCollections.js:40 subscribes via the library's useObjectSubscription; used in src/views/KwetsbaarhedenView.vue:197, LicensePostureView.vue:209, LifecycleRoadmapView.vue:184, ComplianceMatrixView.vue:326, PortfolioReport.vue:323. The standard index pages (Contracts, Organisations and others) rely on whatever the library's CnIndexPage does."
+ },
+ "pendingQuestion": "Does the installed OpenRegister publish or-collection-{register}-{schema} events over a transport (notify_push or SSE) that the nc-vue liveUpdatesPlugin receives, so these pages update without a reload?"
+ },
+ {
+ "id": "ins-notifications",
+ "area": "insight",
+ "name": "Receive in-app notifications about changes that concern you.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "partial",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "specified",
+ "evidence": "Only declarations: x-openregister-notifications on vulnerability (lib/Settings/softwarecatalogus_register.json:1622), usage (:2662), catalogContract (:3253), software-review (:3962), module (:6781), moduleVersion (:7652). Stackiq has no INotifier or notification code of its own (grep in lib/). The contract-expiry rule filters status equals 'Actief' (lib/Settings/softwarecatalogus_register.json:3255) while the enum is Active/Expired/In negotiation, so it can never match.",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "Nextcloud notifications bell, if OpenRegister dispatches the declared rules; no stackiq page",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "feature": "notifications",
+ "featureConfidence": "high",
+ "note": "Every notification rests on a declaration OpenRegister must execute. At least one rule (contract expiry) filters on a stale Dutch status value and would never fire, and its subject template uses fields (contractNummer, eindDatum) the schema no longer has.",
+ "evidence": {
+ "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141783 '6.8 In-app notifications (bell)': `MODE_AJAX` is a wired delivery mode (`src/Notification_NotificationTemplate.php:55-59`, `getModes()` at `:381-398`, implementation `src/NotificationAjax.php`), rendering as a browser toast rather than a persistent inbox | Rated partial because toast delivery, not an inbox, source-read 2026-09-14.",
+ "stackiq": "Only declarations: x-openregister-notifications on vulnerability (lib/Settings/softwarecatalogus_register.json:1622), usage (:2662), catalogContract (:3253), software-review (:3962), module (:6781), moduleVersion (:7652). Stackiq has no INotifier or notification code of its own (grep in lib/). The contract-expiry rule filters status equals 'Actief' (lib/Settings/softwarecatalogus_register.json:3255) while the enum is Active/Expired/In negotiation, so it can never match."
+ },
+ "pendingQuestion": "Does the installed OpenRegister dispatch the x-openregister-notifications rules on vulnerability, software-review, moduleVersion and the scheduled rules on catalogContract/usage/module, as Nextcloud notifications to the listed recipients?"
+ },
+ {
+ "id": "ops-plugins",
+ "area": "operations",
+ "name": "Extend the product with plugins installed from a marketplace.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "src/manifest.json:225 Store page (type store, footer menu StoreMenu) over the OpenRegister store plane, with store.types openregister.configset and openregister.flows; its own note says that with no registry configured it shows only the app's built-in items.",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "Store /store (footer menu)",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "note": "The store installs configuration sets and flows, not code plugins, and it depends on a registry being configured.",
+ "evidence": {
+ "glpi": "docs, intelligence competitor_features#48906 'Plugin ecosystem' (2026-07-23): Large plugin marketplace (FormCreator, GenericObject, etc.). | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145919 'C-configuration-48 An extension is found, installed, updated and removed from inside the product.': glpi: Marketplace (Setup, Plugins, front/marketplace.php, marketplace.download.php, front/plugin.php) Lane findings: D-glpi-45.",
+ "topdesk": "docs, intelligence competitor_features#27391 'Marketplace Integrations' (2026-04-12): TOPdesk Marketplace with third-party integrations including Lansweeper, BlueDolphin",
+ "stackiq": "src/manifest.json:225 Store page (type store, footer menu StoreMenu) over the OpenRegister store plane, with store.types openregister.configset and openregister.flows; its own note says that with no registry configured it shows only the app's built-in items."
+ },
+ "pendingQuestion": "Is a store registry configured on a default install, and are any stackiq configuration sets published to it?"
+ }
+ ]
}
From 22466d6b4cf5f2d80aaf4cddffc1568c92147a00 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 13:30:16 +0200
Subject: [PATCH 16/45] fix(parity): apply cross-lane corrections to the
capability matrix
Later parity lanes read other products and found ratings and wording in
this matrix that their code contradicts. Corrected rows carry readOn
2026-09-26 and name the cross-product evidence.
---
openspec/parity/capabilities.json | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index c797863ad..a34da246e 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -2902,8 +2902,9 @@
"stackiq": "partial",
"built": {
"state": "built",
- "evidence": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261), both login-only. Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint.",
- "owner": "ConductionNL/stackiq"
+ "evidence": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261). The views docs endpoint is login-only; the aangeboden-gebruik docs endpoint is @PublicPage (AangebodenGebruikController.php:860), so anyone can read it (corrected 2026-09-26). Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint.",
+ "owner": "ConductionNL/stackiq",
+ "readOn": "2026-09-26"
},
"reachedOn": "API only: GET /api/views/docs and /api/aangeboden-gebruik/docs; docs site https://stackiq.conduction.nl (Documentation footer link)",
"provider": "stackiq",
@@ -2911,7 +2912,7 @@
"note": "The generated OpenAPI file is empty. What exists is hand-written: two JSON doc endpoints and markdown pages. OpenRegister may generate an OAS per register, but stackiq does not surface it.",
"evidence": {
"glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141846 '12.18 OpenAPI documentation': auto-generated from route attributes: `src/Glpi/Api/HL/OpenAPIGenerator.php` with `src/Glpi/Api/HL/Doc/`, versioned per route (`#[RouteVersion]`, router at `src/Glpi/Api/HL/Router.php:98`); the legacy API is documented i | Rated yes because OpenAPI generator, source-read 2026-09-14.",
- "stackiq": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261), both login-only. Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint."
+ "stackiq": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261). The views docs endpoint is login-only; the aangeboden-gebruik docs endpoint is @PublicPage (AangebodenGebruikController.php:860), so anyone can read it (corrected 2026-09-26). Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint."
}
},
{
@@ -4042,8 +4043,9 @@
"stackiq": "partial",
"built": {
"state": "built",
- "evidence": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; module/catalogService/organization carry public read rules for published entries; public intake POST /api/intake/register",
- "owner": "ConductionNL/stackiq"
+ "evidence": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; catalogService and organization carry public read rules for published entries; module's public read also admits every object with registeredBy Supplier, a rule with no publication-date or status condition (lib/Settings/softwarecatalogus_register.json:7322-7327, corrected 2026-09-26); public intake POST /api/intake/register",
+ "owner": "ConductionNL/stackiq",
+ "readOn": "2026-09-26"
},
"reachedOn": "no page: a property of the app and its licence",
"provider": "stackiq",
@@ -4053,7 +4055,7 @@
"vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
"sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
"glpi": "docs, intelligence competitor_features#48912 '100% open source (GPL)' (2026-07-23): Fully GPL; no license fees, broad device coverage.",
- "stackiq": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; module/catalogService/organization carry public read rules for published entries; public intake POST /api/intake/register"
+ "stackiq": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; catalogService and organization carry public read rules for published entries; module's public read also admits every object with registeredBy Supplier, a rule with no publication-date or status condition (lib/Settings/softwarecatalogus_register.json:7322-7327, corrected 2026-09-26); public intake POST /api/intake/register"
},
"pendingQuestion": "Is a hosted, free-of-charge stackiq instance offered to municipalities and suppliers (the competitor offer is a public service, not software)?"
},
From 511d78e96dfa9d7a7ce8932f1b315c07a88b0817 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 22:57:36 +0200
Subject: [PATCH 17/45] chore(parity): fold r-glpi packs 1-2 (GLPI source read
at 11.0.9)
---
openspec/parity/capabilities.json | 55 ++++++++++++++++++-------------
1 file changed, 32 insertions(+), 23 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index a34da246e..52669b510 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -163,7 +163,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
"bluedolphin": "yes",
- "glpi": "partial",
+ "glpi": "yes",
"topdesk": "partial",
"stackiq": "partial",
"built": {
@@ -181,7 +181,7 @@
"vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map. | docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape",
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | docs, intelligence competitor_features#27422 'Fact Sheets & Data Model' (2026-04-12): Flexible data model for applications, processes, IT components",
"bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository. | docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
- "glpi": "docs, intelligence competitor_features#48900 'Software inventory & catalog' (2026-07-23): Detects installed software and normalises into a software catalog. | docs, intelligence competitor_features#3267 'Software Catalog' (2026-03-28): Manage software licenses and installations | Rated partial because software is an inventoried asset, not a described application.",
+ "glpi": "source read at 11.0.9: src/Appliance.php:46 class Appliance is GLPI's application itemtype; install/mysql/glpi-empty.sql:8935 glpi_appliances carries name, comment (description), manufacturers_id and states_id (status); src/Appliance.php:350 search option Status; supplier through the Management tab Infocom (install/mysql/glpi-empty.sql:3263 glpi_infocoms.suppliers_id) and Contract_Item (src/Appliance.php:99); menu src/Html.php:1300 lists Appliance under Management, served by src/Glpi/Kernel/Listener/RequestListener/LegacyItemtypeRouteListener.php:100. Reached on: Management > Appliances (front/appliance.php).",
"topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | docs, intelligence competitor_features#27387 'CMDB / Configuration Management' (2026-04-12): Configuration database for registering IT objects like laptops, software, infrastructure | Rated partial because software is a CMDB object among assets.",
"stackiq": "src/manifest.json:592 Modules page (FacetedCatalogIndexView, schema module) with the library CnIndexPage create form at src/views/FacetedCatalogIndexView.vue:108; lib/Settings/softwarecatalogus_register.json:6777 module schema has name, shortDescription/longDescription and provider (Supplier) but NO status property; status lives on usage (register.json:2654, enum Acquisition..In production) which has no page"
}
@@ -194,7 +194,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -210,7 +210,8 @@
"note": "Stackiq's 'module' is the whole application, so there is no breakdown of one application into modules. The nearest thing is a suite (product) listing its applications, which answers 'which module belongs to which product' but not the decomposition.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated partial because fact sheets separate Application from IT Component.",
- "stackiq": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')"
+ "stackiq": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')",
+ "glpi": "source read at 11.0.9: src/Appliance_Item.php:45 links an Appliance to member items; src/autoload/CFG_GLPI.php:562 appliance_types includes Software, Appliance, Database and DatabaseInstance, so an application can be split into software and sub-appliances on its Items tab (src/Appliance.php:98). There is no module entity that belongs to a supplier product: grep -i 'module' src/Software.php src/Appliance.php returns no module concept. Reached on: Management > Appliances > Items tab."
}
},
{
@@ -236,7 +237,7 @@
"featureConfidence": "medium",
"note": "A version is created on the Module versions index with its module and date in use, and opens on its own detail page.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48900 'Software inventory & catalog' (2026-07-23): Detects installed software and normalises into a software catalog. | Rated partial because installed versions come from inventory.",
+ "glpi": "source read at 11.0.9: src/SoftwareVersion.php:42 SoftwareVersion child of Software, table install/mysql/glpi-empty.sql:6900 glpi_softwareversions with name, states_id, operatingsystems_id but no release or in-use date; the only date is per installation, install/mysql/glpi-empty.sql:1074 glpi_items_softwareversions.date_install. Reached on: Assets > Software > Versions tab (front/softwareversion.form.php).",
"stackiq": "src/manifest.json:915 Moduleversies type:index (columns version, module, dateInUse, status) + :937 ModuleversieDetail; register.json:7649 moduleVersion schema with dateInUse (register.json:7746), dateInDevelopment, dateEndSupport, dateWithdrawn"
}
},
@@ -248,7 +249,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -263,7 +264,8 @@
"featureConfidence": "medium",
"note": "A three-step wizard bundles existing applications into one suite. Caveat: a row click on the Suites list only toggles selection (the library returns before emitting row-click when selectable, SuitesIndexView.vue:35), so SuiteDetail is not opened from the list, and its data widget includes stale field names (src/manifest.json:683 beschrijvingKort, contactpersoon).",
"evidence": {
- "stackiq": "src/dialogs/SuiteWizardDialog.vue:183 onSubmit saves a suite via objectStore.saveObject('suite') with applications[] (src/utils/suiteWizard.js:44 requires at least one); mounted by src/views/suites/SuitesIndexView.vue:46 on manifest page Suites (src/manifest.json:666)"
+ "stackiq": "src/dialogs/SuiteWizardDialog.vue:183 onSubmit saves a suite via objectStore.saveObject('suite') with applications[] (src/utils/suiteWizard.js:44 requires at least one); mounted by src/views/suites/SuitesIndexView.vue:46 on manifest page Suites (src/manifest.json:666)",
+ "glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:562 appliance_types contains Appliance and Software, so an Appliance can bundle existing appliances and software through src/Appliance_Item.php:45 (table install/mysql/glpi-empty.sql:8979 glpi_appliances_items). There is no notion of offering the bundle as a product to others. Reached on: Management > Appliances > Items tab."
}
},
{
@@ -274,7 +276,7 @@
"vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -290,7 +292,8 @@
"note": "A supplier's service over one or more applications is registered on the Services page. There is no 'hosting' service type (technical management is the nearest), and services have no detail page, so a row cannot be opened.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48838 'Supplier product offering (aanbod) registration' (2026-07-23): ICT suppliers publish their product offering for the municipal market with global functionality descriptions. | Rated partial because offering registration covers products; services not named in the reading.",
- "stackiq": "src/manifest.json:647 Diensten page (FacetedCatalogIndexView, schema catalogService) with the CnIndexPage create form; register.json:1324 catalogService with provider (required), modules[] (register.json:1419) and type enum Functional/Application/Technical management, Implementation support, Training, Licence reseller (register.json:1459)"
+ "stackiq": "src/manifest.json:647 Diensten page (FacetedCatalogIndexView, schema catalogService) with the CnIndexPage create form; register.json:1324 catalogService with provider (required), modules[] (register.json:1419) and type enum Functional/Application/Technical management, Implementation support, Training, Licence reseller (register.json:1459)",
+ "glpi": "source read at 11.0.9: no supplier service itemtype; services are held as contracts, src/ContractType.php:37 admin dropdown of contract types (for example hosting or support), install/mysql/glpi-empty.sql:1550 glpi_contracts_suppliers ties the contract to a Supplier and install/mysql/glpi-empty.sql:1536 glpi_contracts_items ties it to the Appliance or Software it covers. Reached on: Management > Contracts (front/contract.php), Suppliers tab."
}
},
{
@@ -301,7 +304,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -314,7 +317,8 @@
"providerHow": "read-from-code",
"note": "A sector schema exists, but no application, service or organisation can be tagged with a sector and no page lists sectors.",
"evidence": {
- "stackiq": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395"
+ "stackiq": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395",
+ "glpi": "source read at 11.0.9: no government sector concept, grep -i 'sector' over src/*.php and locales/glpi.pot hits only menu sectorization (src/Html.php:1019); the nearest holder is the single-valued Appliance type dropdown install/mysql/glpi-empty.sql:8941 appliancetypes_id, or an admin custom dropdown (install/mysql/glpi-empty.sql:10113 glpi_dropdowns_dropdowndefinitions) used as a field of a custom asset. Multi-valued tagging needs the separate tag plugin (github.com/pluginsGLPI/tag, not read). Reached on: Management > Appliances, Appliance type field."
}
},
{
@@ -325,7 +329,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -341,7 +345,8 @@
"note": "One contact person per application can be set, but there is no separate business owner and technical owner. ModuleDetail's data widget includes 'contactpersoon', a key the schema no longer has, so the contact may not show there.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | Rated partial because surveys go to application owners, so ownership is modelled.",
- "stackiq": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')"
+ "stackiq": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')",
+ "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:8935 glpi_appliances holds users_id and users_id_tech; src/Appliance.php:186 search option User and src/Appliance.php:195 Group (business side), src/Appliance.php:240 'Technician in charge' and the 'Group in charge' option a few lines below (technical side). Reached on: Management > Appliances, form fields User, Group, Technician in charge, Group in charge."
}
},
{
@@ -352,7 +357,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "yes",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -367,7 +372,7 @@
"note": "Stackiq offers no way to add fields. Editing the schema in OpenRegister's own admin UI is possible there, but that is an OpenRegister feature, not a stackiq page.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because flexible fact sheet data model.",
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141835 '11.17 Custom object type management': GLPI 11 ships admin-defined itemtypes with custom fields and capabilities (`src/Glpi/CustomObject/AbstractDefinition.php`, `src/Glpi/Asset/AssetDefinition.php`, `src/Glpi/Asset/CustomFieldDefinition.php`), but the machin | Rated yes because custom asset definitions and custom fields, source-read 2026-09-14.",
+ "glpi": "source read at 11.0.9: native custom fields exist only for admin defined custom asset types, src/Glpi/Asset/CustomFieldDefinition.php:52 child of AssetDefinition (install/mysql/glpi-empty.sql:10159 glpi_assets_customfielddefinitions keyed on assets_assetdefinitions_id), set up under Setup > Asset definitions (src/Html.php:1330). The core Appliance and Software types take no custom fields in core; that needs the fields plugin, read at pluginsGLPI/fields tag 1.24.5, inc/container.class.php:91 containers with a list of itemtypes. Reached on: Setup > Asset definitions > Custom fields; or plugin Fields.",
"stackiq": "Looked in src/manifest.json, src/views, lib/Controller: no field-definition or schema-extension UI in stackiq; the data model is fixed in lib/Settings/softwarecatalogus_register.json"
}
},
@@ -379,7 +384,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -394,7 +399,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27428 'EAM Automation' (2026-04-12): Automated data collection from ServiceNow, Jira, cloud providers | Rated partial because automated collection from ServiceNow, Jira and cloud.",
"bluedolphin": "docs, intelligence competitor_features#48971 'Data import (Excel)' (2026-07-23): Bulk import of application/portfolio data.",
- "stackiq": "Library CnIndexPage (@conduction/nextcloud-vue 2.55.1, package-lock) showMassImport default true (CnIndexPage.vue:1599) and self-mode handleMassImport (selfModeActions.js:168) POSTs to /apps/openregister/api/registers/{register}/import with the schema for CSV (selfModeIO.js:82); rendered on the Modules page's CnIndexPage (src/views/FacetedCatalogIndexView.vue:108)"
+ "stackiq": "Library CnIndexPage (@conduction/nextcloud-vue 2.55.1, package-lock) showMassImport default true (CnIndexPage.vue:1599) and self-mode handleMassImport (selfModeActions.js:168) POSTs to /apps/openregister/api/registers/{register}/import with the schema for CSV (selfModeIO.js:82); rendered on the Modules page's CnIndexPage (src/views/FacetedCatalogIndexView.vue:108)",
+ "glpi": "source read at 11.0.9: core has CSV export only (src/Glpi/Csv/ holds CsvResponse and export classes, no importer) and no spreadsheet import of assets or appliances. Bulk import is the separate datainjection plugin, read at pluginsGLPI/datainjection tag 2.15.11: inc/backendcsv.class.php CSV backend and inc/applianceinjection.class.php:33 PluginDatainjectionApplianceInjection extends Appliance; setup.php:36 requires GLPI 11.0.5 or later. Reached on: plugin Data injection (Tools > Data injection)."
}
},
{
@@ -405,7 +411,7 @@
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -422,7 +428,8 @@
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because fact sheet is the per-application page.",
- "stackiq": "src/manifest.json:491 ModuleDetail: md-versions (:504), md-compliance (:503), md-related generic Related panel (:502); no contract widget (catalogContract links to service/usage, register.json:3250, not to module); md-data include lists stale keys beschrijvingKort/beschrijvingLang/contactpersoon (:500)"
+ "stackiq": "src/manifest.json:491 ModuleDetail: md-versions (:504), md-compliance (:503), md-related generic Related panel (:502); no contract widget (catalogContract links to service/usage, register.json:3250, not to module); md-data include lists stale keys beschrijvingKort/beschrijvingLang/contactpersoon (:500)",
+ "glpi": "source read at 11.0.9: src/Appliance.php:98 onwards defineTabs puts Items, Contracts, Documents, Management (Infocom), Certificates, Domains, Knowledge base, Tickets, Problems, Changes and Impact on the one appliance page; versions sit on the separate Software page (src/SoftwareVersion.php:42), and no compliance tab exists (grep -i 'complian' src/Appliance.php returns nothing). Reached on: Management > Appliances > appliance form tabs."
}
},
{
@@ -433,7 +440,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -448,7 +455,8 @@
"featureConfidence": "low",
"note": "Many entries can be selected and deleted together through the library index page. The mass publish and mass lock dialogs exist but hang off a view modal no page opens, and the publish endpoint (lib/Controller/PublicationController.php, PUT /api/publication/...) has no frontend caller.",
"evidence": {
- "stackiq": "Library CnIndexPage mass delete/copy/export (showMassDelete default true, CnIndexPage.vue:1617; selfModeActions.js:63 handleMassDelete) on index pages; stackiq's MassPublishObjects/MassLockObjects dialogs (src/dialogs/Dialogs.vue:8-14) are only opened from src/modals/object/ViewObject.vue:4865, and ViewObject is only mounted for modals 'viewOrganisatie'/'viewContactpersoon' (src/modals/Modals.vue:7,19) which nothing in src/ sets"
+ "stackiq": "Library CnIndexPage mass delete/copy/export (showMassDelete default true, CnIndexPage.vue:1617; selfModeActions.js:63 handleMassDelete) on index pages; stackiq's MassPublishObjects/MassLockObjects dialogs (src/dialogs/Dialogs.vue:8-14) are only opened from src/modals/object/ViewObject.vue:4865, and ViewObject is only mounted for modals 'viewOrganisatie'/'viewContactpersoon' (src/modals/Modals.vue:7,19) which nothing in src/ sets",
+ "glpi": "source read at 11.0.9: every search list offers massive actions, src/MassiveAction.php:666 Update (any field, for example status), src/MassiveAction.php:698 Put in trashbin, src/MassiveAction.php:652 Delete permanently, src/MassiveAction.php:656 Restore. There is no publish state; locking applies to inventory fields only. Reached on: any list, for example Management > Appliances, Actions button."
}
},
{
@@ -459,7 +467,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -472,7 +480,8 @@
"providerHow": "read-from-code",
"note": "Only organisations can be merged, with a dry run first, and only by a Nextcloud admin. Applications, services and other entries have no merge.",
"evidence": {
- "stackiq": "src/components/organisations/OrganisationMergePanel.vue:46 (admin-only controls) mounted as OrganisatieDetail bodyWidget org-merge (src/manifest.json:430); lib/Controller/MergeController.php:106 execute with isAdmin check at :142; generic src/modals/object/MergeObject.vue only mounted for modal 'mergeOrganisatie' which nothing sets"
+ "stackiq": "src/components/organisations/OrganisationMergePanel.vue:46 (admin-only controls) mounted as OrganisatieDetail bodyWidget org-merge (src/manifest.json:430); lib/Controller/MergeController.php:106 execute with isAdmin check at :142; generic src/modals/object/MergeObject.vue only mounted for modal 'mergeOrganisatie' which nothing sets",
+ "glpi": "source read at 11.0.9: src/Software.php:109 'Merging' tab on a recursive software, src/Software.php:926 showMergeCandidates lists same named software, src/Software.php:997 massive action Merge, src/Software.php:1011 private function merge moves versions and licences into the kept entry; dropdowns get Replace, src/CommonDropdown.php:680. Reached on: Assets > Software > Merging tab."
}
},
{
From 913f72f8b01111c1b2863e9d8600461883ba388a Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:00:20 +0200
Subject: [PATCH 18/45] chore(parity): fold r-glpi packs 3-7 and errata
---
openspec/parity/capabilities.json | 141 ++++++++++++++++++------------
1 file changed, 84 insertions(+), 57 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index 52669b510..3273482a8 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -492,7 +492,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -507,7 +507,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | docs, intelligence competitor_features#27423 'Survey-Based Data Collection' (2026-04-12): Crowdsource architecture data from application owners",
"bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders.",
- "stackiq": "No survey, attestation or owner-confirmation code in lib/ or src/ (searched survey/enquete/confirm entry)"
+ "stackiq": "No survey, attestation or owner-confirmation code in lib/ or src/ (searched survey/enquete/confirm entry)",
+ "glpi": "source read at 11.0.9: the native form builder (src/Glpi/Form/Form.php:92) only has ITIL destinations, src/Glpi/Form/Destination/ holds FormDestinationTicket, FormDestinationChange and FormDestinationProblem, so a form answer opens a ticket but never confirms or updates an appliance record; the only 'survey' in core is ticket satisfaction (src/Central.php:220). No owner review campaign exists."
}
},
{
@@ -518,7 +519,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -531,7 +532,8 @@
"providerHow": "read-from-code",
"note": "No page scores how complete or current an entry is.",
"evidence": {
- "stackiq": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)"
+ "stackiq": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)",
+ "glpi": "source read at 11.0.9: grep -ril 'completeness' over src/ templates/ locales/glpi.pot returns nothing; no score of how filled in an item is exists in core."
}
},
{
@@ -542,7 +544,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -555,7 +557,8 @@
"providerHow": "read-from-code",
"note": "An admin picks the demo dataset in the setup wizard and it is imported through OpenRegister. Admin-only, which suits an installation task.",
"evidence": {
- "stackiq": "src/manifest.json:3 setup wizard step load-demo-data (:24); lib/Controller/SetupController.php:202 runAction load-demo-data (AuthorizedAdminSetting); lib/Service/DemoDataService.php:202 install() imports lib/Settings/stackiq_mock_register.json (120 objects, 6 per schema) through OpenRegister ConfigurationService::importFromApp"
+ "stackiq": "src/manifest.json:3 setup wizard step load-demo-data (:24); lib/Controller/SetupController.php:202 runAction load-demo-data (AuthorizedAdminSetting); lib/Service/DemoDataService.php:202 install() imports lib/Settings/stackiq_mock_register.json (120 objects, 6 per schema) through OpenRegister ConfigurationService::importFromApp",
+ "glpi": "source read at 11.0.9: grep -ril 'demo data\\|sample data' over src/ templates/ locales/glpi.pot returns nothing and src/Glpi/Console/ has no demo loader; example data exists only as test fixtures under tests/, not shipped as a feature."
}
},
{
@@ -566,7 +569,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -579,7 +582,8 @@
"providerHow": "read-from-code",
"note": "Only suites get a step-by-step wizard. Applications and services are added through a plain form, and connections have no page at all.",
"evidence": {
- "stackiq": "src/dialogs/SuiteWizardDialog.vue (3 steps) is the only wizard, opened from src/views/suites/SuitesIndexView.vue:46; applications, services and connections use the bare CnIndexPage form (FacetedCatalogIndexView.vue:108) or nothing"
+ "stackiq": "src/dialogs/SuiteWizardDialog.vue (3 steps) is the only wizard, opened from src/views/suites/SuitesIndexView.vue:46; applications, services and connections use the bare CnIndexPage form (FacetedCatalogIndexView.vue:108) or nothing",
+ "glpi": "source read at 11.0.9: grep -ril 'wizard' over src/ templates/ locales/glpi.pot returns nothing for item creation; appliances are added through the plain form only (install/mysql/glpi-empty.sql:8935 glpi_appliances has no is_template column)."
}
},
{
@@ -590,7 +594,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -603,7 +607,8 @@
"providerHow": "read-from-code",
"note": "A module version's page lists the third-party components imported from its SBOM.",
"evidence": {
- "stackiq": "src/components/sbom/SbomComponentsPanel.vue lists sbomComponent rows (name/version/purl/licenses) as the ModuleversieDetail 'Components' sidebar tab (src/manifest.json:961); register.json:7920 sbomComponent schema"
+ "stackiq": "src/components/sbom/SbomComponentsPanel.vue lists sbomComponent rows (name/version/purl/licenses) as the ModuleversieDetail 'Components' sidebar tab (src/manifest.json:961); register.json:7920 sbomComponent schema",
+ "glpi": "source read at 11.0.9: grep -ril 'sbom\\|cyclonedx\\|spdx' over src/ templates/ locales/glpi.pot returns nothing; software versions carry no component list (install/mysql/glpi-empty.sql:6900 glpi_softwareversions)."
}
},
{
@@ -614,7 +619,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -630,7 +635,8 @@
"note": "The application form records on-premises, IaaS, PaaS or SaaS plus hosting location and jurisdiction. There is no field naming the hosting party itself.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | Rated partial because SaaS is tracked as a class of application.",
- "stackiq": "register.json:6869 module.cloudDienstverleningsmodel enum On-premises, IaaS, PaaS, SaaS; register.json:6906 hostingLocation and hostingJurisdiction; usage.cloudDienstverleningsmodel (register.json:3050); on ModuleDetail md-data include (src/manifest.json:500)"
+ "stackiq": "register.json:6869 module.cloudDienstverleningsmodel enum On-premises, IaaS, PaaS, SaaS; register.json:6906 hostingLocation and hostingJurisdiction; usage.cloudDienstverleningsmodel (register.json:3050); on ModuleDetail md-data include (src/manifest.json:500)",
+ "glpi": "source read at 11.0.9: no hosting model field; the closest holders are the admin editable Environment dropdown on an appliance, src/Appliance.php:277 ApplianceEnvironment search option (install/mysql/glpi-empty.sql:8945 applianceenvironments_id), plus locations_id and the Appliance type dropdown. grep -i 'saas' over src/ finds nothing; 'On-premise' in locales/glpi.pot:12997 is only an icon label. Reached on: Management > Appliances, Environment field."
}
},
{
@@ -641,7 +647,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -657,7 +663,8 @@
"note": "The field for a national provision exists on the connection schema, but with no connection page nobody can fill it in stackiq.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48841 'National provisions (landelijke voorzieningen) linking' (2026-07-23): Records links between applications and national government provisions.",
- "stackiq": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection"
+ "stackiq": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection",
+ "glpi": "source read at 11.0.9: no national provision concept (grep -ril 'basisregistratie' src/ locales/glpi.pot returns nothing); a provision can be held as another Appliance and linked through an impact relation, install/mysql/glpi-empty.sql:1247 glpi_impactrelations (source item, impacted item, name), with Appliance enabled for impact at src/autoload/CFG_GLPI.php:649. Reached on: Appliance > Impact analysis tab, Add relation."
}
},
{
@@ -668,7 +675,7 @@
"vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -684,7 +691,8 @@
"note": "There is no list of connections in the catalogue. The Integrations page lists outside integrations, a different thing.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
- "stackiq": "No manifest page with schema connection (src/manifest.json and src/manifest.d/*.json); the Integrations page (src/manifest.d/connection-registry.json:23) lists integriq app_connection, explicitly not stackiq's connection schema (its _note)"
+ "stackiq": "No manifest page with schema connection (src/manifest.json and src/manifest.d/*.json); the Integrations page (src/manifest.d/connection-registry.json:23) lists integriq app_connection, explicitly not stackiq's connection schema (its _note)",
+ "glpi": "source read at 11.0.9: src/ImpactRelation.php:39 ImpactRelation has only prepareInputForAdd and getIDFromInput (src/ImpactRelation.php:47, :107), no search options and no list page; relations are only seen per item in the Impact analysis tab (src/Impact.php:91)."
}
},
{
@@ -695,7 +703,7 @@
"vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -711,7 +719,8 @@
"note": "Connections that reference an application should appear among the untyped related objects on its page, but there is no connections section and nothing to open. The dedicated per-application endpoint is API only.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
- "stackiq": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/"
+ "stackiq": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/",
+ "glpi": "source read at 11.0.9: src/Impact.php:91 getTabNameForItem adds the 'Impact analysis' tab (src/Impact.php:80) to every impact enabled itemtype, Appliance and Software included (src/autoload/CFG_GLPI.php:649 and :663), with a list view src/Impact.php:270 displayListView of every related item in both directions. Reached on: Management > Appliances > Impact analysis tab."
}
},
{
@@ -739,7 +748,7 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model. | docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
"bluedolphin": "docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models. | docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145369 'C-case-core-38 The graph of what a case is linked to is drawn, and exported.': glpi: Impact graph (Tools, front/impactitem.php, impactcsv.php, src/Impact.php) Lane findings: D-glpi-40. | Rated yes because impact graph, source-read 2026-09-14.",
+ "glpi": "source read at 11.0.9: src/Impact.php:252 displayGraphView and src/Impact.php:1559 makeDataForCytoscape draw the relation network, with editing tools add asset, add relation, add group at src/Impact.php:1160. Reached on: Appliance > Impact analysis tab, graph view.",
"stackiq": "No diagram rendering in src/ (no graph library; src/store/modules/view.js GET /api/views has no importer outside itself); lib/Service/ArchiMateExportService.php exports GEMMA views as ArchiMate XML without koppeling objects (no 'koppeling' in lib/Service/ArchiMate*)"
}
},
@@ -765,7 +774,7 @@
"note": "The only way to see what depends on an application is the generic list of objects that reference it, which OpenRegister's relation index fills. There is no impact view or retirement check.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
- "glpi": "docs, intelligence competitor_features#48902 'CMDB & configuration relations' (2026-07-23): CI relationships and impact analysis.",
+ "glpi": "source read at 11.0.9: src/Impact.php:49 class Impact 'Impact analysis', src/Impact.php:713 bfs walks the graph by direction and src/Impact.php:612 buildListData lists what is impacted, with ongoing tickets, problems and changes on impacted items (src/Impact.php:313). Reached on: Tools > Impact analysis (src/Html.php:1309) and the item's Impact analysis tab.",
"topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | Rated partial because relations between assets.",
"stackiq": "src/manifest.json:502 ModuleDetail md-related (library CnRelatedObjectsWidget: /used lists every object that references this module: usages, connections, suites, services, vulnerabilities); no dependency or impact computation in lib/ or src/"
}
@@ -778,7 +787,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -791,7 +800,8 @@
"providerHow": "read-from-code",
"note": "The type field exists but there is no connection list to filter.",
"evidence": {
- "stackiq": "register.json:3563 connection.type enum (file transfer, digikoppeling, message que, webservices, api, ...) exists, but no connection list page to filter"
+ "stackiq": "register.json:3563 connection.type enum (file transfer, digikoppeling, message que, webservices, api, ...) exists, but no connection list page to filter",
+ "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1247 glpi_impactrelations has only a free name besides the two endpoints, no connection type (API, file, message), so there is nothing to filter on; the graph settings (src/Impact.php:1167 impact_settings) cover depth and direction."
}
},
{
@@ -802,7 +812,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -816,7 +826,8 @@
"note": "Stackiq has no record for an API an application exposes.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27425 'API Management' (2026-04-12): Catalog and manage APIs across the application landscape",
- "stackiq": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label"
+ "stackiq": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label",
+ "glpi": "source read at 11.0.9: no API entity in core, grep -ril 'openapi' src/*.php finds no itemtype for exposed APIs; an admin can define an 'API' custom asset type (src/Html.php:1330 Setup > Asset definitions, src/Glpi/Asset/AssetDefinition.php) and attach it to the application as an Appliance item (src/Appliance_Item.php:45) or impact relation (install/mysql/glpi-empty.sql:1247). Reached on: Setup > Asset definitions, then Appliance > Items tab."
}
},
{
@@ -842,7 +853,7 @@
"featureConfidence": "low",
"note": "The organisation ArchiMate export carries modules and usages but not connections, so an application's link graph cannot be exported.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145369 'C-case-core-38 The graph of what a case is linked to is drawn, and exported.': glpi: Impact graph (Tools, front/impactitem.php, impactcsv.php, src/Impact.php) Lane findings: D-glpi-40. | Rated yes because impactcsv export, source-read 2026-09-14.",
+ "glpi": "source read at 11.0.9: front/impactcsv.php streams Glpi\\Csv\\ImpactCsvExport for an item, linked from the impact list view at src/Impact.php:393; the graph Download button src/Impact.php:1165 calls js/impact.js:2528 download, which writes PNG (js/impact.js:2539) or JPEG (js/impact.js:2546). Reached on: Appliance > Impact analysis tab, Download and CSV export.",
"stackiq": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*"
}
},
@@ -854,7 +865,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -867,7 +878,8 @@
"providerHow": "read-from-code",
"note": "With integriq installed, an admin sees stackiq's three integrations and their checked status on one page, and Add integration opens integriq. Without integriq the page is hidden, and the checking is integriq's.",
"evidence": {
- "stackiq": "src/manifest.d/connection-registry.json:23 Integrations page (register integriq, schema app_connection) with visibleIf appInstalled 'integriq' (:17) and permission admin (:15,:27); Add integration handler leaves for integriq (src/services/connectionRegistry.js:43); rows synced from lib/Settings/connections.json (email, federation, eol-feed); status worked out by integriq"
+ "stackiq": "src/manifest.d/connection-registry.json:23 Integrations page (register integriq, schema app_connection) with visibleIf appInstalled 'integriq' (:17) and permission admin (:15,:27); Add integration handler leaves for integriq (src/services/connectionRegistry.js:43); rows synced from lib/Settings/connections.json (email, federation, eol-feed); status worked out by integriq",
+ "glpi": "source read at 11.0.9: outside integrations are set up on separate Setup pages, not one overview: src/Html.php:1331 Webhook, src/Html.php:1333 OAuthClient and MailCollector, Auth (LDAP, SSO) on src/Html.php:1332; src/Webhook.php:64 Webhook and src/OAuthClient.php:45 OAuthClient each have their own list. Reached on: Setup > Webhooks, Setup > OAuth clients, Setup > Authentication."
}
},
{
@@ -878,7 +890,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -894,7 +906,8 @@
"note": "Works end to end but only a Nextcloud admin can import: the endpoint rejects non-admins and the upload control lives only on the admin settings page.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27459 'ArchiMate & BPMN Support' (2026-04-12): Full ArchiMate and BPMN modeling in one platform | Rated yes because full ArchiMate support; import format not named in the reading.",
- "stackiq": "appinfo/routes.php:96 POST /api/archimate/import -> lib/Controller/SettingsController.php:1490 importArchiMate (isAdmin check :1496) -> lib/Service/ArchiMateImportService.php (5961 lines); UI src/views/settings/sections/ArchiMateImportExport.vue:32 file input + :791 importArchiMateFile"
+ "stackiq": "appinfo/routes.php:96 POST /api/archimate/import -> lib/Controller/SettingsController.php:1490 importArchiMate (isAdmin check :1496) -> lib/Service/ArchiMateImportService.php (5961 lines); UI src/views/settings/sections/ArchiMateImportExport.vue:32 file input + :791 importArchiMateFile",
+ "glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma\\|togaf' over src/ templates/ locales/glpi.pot returns nothing; no model import exists."
}
},
{
@@ -905,7 +918,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "partial",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -922,7 +935,8 @@
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27554 'ArchiMate Export' (2026-04-12): Export to ArchiMate format for use in architecture tools",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
- "stackiq": "appinfo/routes.php:97 POST /api/archimate/export -> lib/Controller/SettingsController.php:1615 exportArchiMate (admin or org-admin via verifyOrgExportPermission :1735) -> lib/Service/ArchiMateService.php:232 exportToArchiMate (docblock: organization filter 'currently not implemented'); UI ArchiMateImportExport.vue:591 'Export Base' button"
+ "stackiq": "appinfo/routes.php:97 POST /api/archimate/export -> lib/Controller/SettingsController.php:1615 exportArchiMate (admin or org-admin via verifyOrgExportPermission :1735) -> lib/Service/ArchiMateService.php:232 exportToArchiMate (docblock: organization filter 'currently not implemented'); UI ArchiMateImportExport.vue:591 'Export Base' button",
+ "glpi": "source read at 11.0.9: grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing; exports are CSV, PDF and spreadsheet search output (src/Glpi/Csv/) only."
}
},
{
@@ -933,7 +947,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -949,7 +963,8 @@
"note": "Complete logic, but reachable only on the admin settings page; an ordinary organisation user cannot export its own landscape from a stackiq page.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape | docs, intelligence competitor_features#27554 'ArchiMate Export' (2026-04-12): Export to ArchiMate format for use in architecture tools | Rated yes because map and export the municipality's landscape.",
- "stackiq": "appinfo/routes.php:98 GET /api/archimate/export/organization/{organizationUuid} -> lib/Controller/SettingsController.php:1685 exportOrgArchiMate -> lib/Service/ArchiMateService.php:302 -> lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications in GEMMA view copies; UI ArchiMateImportExport.vue:602 'Organization Export' with Modules/Deelnames/Gebruik checkboxes"
+ "stackiq": "appinfo/routes.php:98 GET /api/archimate/export/organization/{organizationUuid} -> lib/Controller/SettingsController.php:1685 exportOrgArchiMate -> lib/Service/ArchiMateService.php:302 -> lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications in GEMMA view copies; UI ArchiMateImportExport.vue:602 'Organization Export' with Modules/Deelnames/Gebruik checkboxes",
+ "glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma' over src/ templates/ locales/glpi.pot returns nothing; no GEMMA plotting or per entity model export."
}
},
{
@@ -960,7 +975,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -975,7 +990,8 @@
"featureConfidence": "medium",
"note": "There is an endpoint, but its comparison is broken (a missing key against a placeholder string) and no page calls it. The compare_archimate.py/.php scripts in the repo root are developer tools, not a user capability.",
"evidence": {
- "stackiq": "appinfo/routes.php:107 POST /api/archimate/test-round-trip -> lib/Controller/SettingsController.php:2886 (@NoAdminRequired, any logged-in user) -> lib/Service/ArchiMateService.php:1496 testRoundTrip: reads $importResult['imported_count'] (:1528), a key no import path sets, and compares it to exportToArchiMate's 'exported_count' which is the literal string 'calculated_in_export_service' (:271), so it can never report success; it also imports a test model into the live register"
+ "stackiq": "appinfo/routes.php:107 POST /api/archimate/test-round-trip -> lib/Controller/SettingsController.php:2886 (@NoAdminRequired, any logged-in user) -> lib/Service/ArchiMateService.php:1496 testRoundTrip: reads $importResult['imported_count'] (:1528), a key no import path sets, and compares it to exportToArchiMate's 'exported_count' which is the literal string 'calculated_in_export_service' (:271), so it can never report success; it also imports a test model into the live register",
+ "glpi": "source read at 11.0.9: there is no model import or export to round trip, grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing."
}
},
{
@@ -986,7 +1002,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1001,7 +1017,8 @@
"featureConfidence": "medium",
"note": "The import runs as one blocking request with a spinner. The cancel endpoint calls a missing method and import progress is never recorded, so neither following nor cancelling works.",
"evidence": {
- "stackiq": "appinfo/routes.php:103 POST /api/archimate/import/cancel -> lib/Service/SettingsService.php:5200 calls ArchiMateService::cancelArchiMateImport(), which does not exist in lib/Service/ArchiMateService.php (Error, not caught by catch(\\Exception)); routes.php:119-120 /api/progress/{operationId} read ProgressTracker, but the ArchiMate import never writes to it (only SbomImportService gets it, lib/AppInfo/Application.php:507); ArchiMateImportExport.vue:538 shows only a spinner, no cancel button"
+ "stackiq": "appinfo/routes.php:103 POST /api/archimate/import/cancel -> lib/Service/SettingsService.php:5200 calls ArchiMateService::cancelArchiMateImport(), which does not exist in lib/Service/ArchiMateService.php (Error, not caught by catch(\\Exception)); routes.php:119-120 /api/progress/{operationId} read ProgressTracker, but the ArchiMate import never writes to it (only SbomImportService gets it, lib/AppInfo/Application.php:507); ArchiMateImportExport.vue:538 shows only a spinner, no cancel button",
+ "glpi": "source read at 11.0.9: no model import exists (grep -ril 'archimate' src/ returns nothing), so there is no import to follow; the generic progress endpoint src/Glpi/Controller/ProgressController.php serves other long operations."
}
},
{
@@ -1012,7 +1029,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1027,7 +1044,8 @@
"featureConfidence": "low",
"note": "You can open a standard's page and read its definition, but reference components and other GEMMA terms have no page and there is no inline definition where they appear.",
"evidence": {
- "stackiq": "src/manifest.json StandaardDetail /standaarden/:id st-data widget shows all element fields (documentation, gemmaNotes) of a standard; FacetedCatalogIndexView.vue:150 shows reference components by name only"
+ "stackiq": "src/manifest.json StandaardDetail /standaarden/:id st-data widget shows all element fields (documentation, gemmaNotes) of a standard; FacetedCatalogIndexView.vue:150 shows reference components by name only",
+ "glpi": "source read at 11.0.9: grep -ril 'gemma\\|glossary' over src/ templates/ locales/glpi.pot returns nothing; no reference term definitions ship in core."
}
},
{
@@ -1038,7 +1056,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1055,7 +1073,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | docs, intelligence competitor_features#27420 'Business Capability Mapping' (2026-04-12): Map applications to business capabilities and processes",
"bluedolphin": "docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
- "stackiq": "module.referenceComponents / usage.usedForReferenceComponents in lib/Settings/softwarecatalogus_register.json hold the application-to-reference-component mapping; lib/Service/ArchiMateExportService.php:2734 draws it only into exported view copies"
+ "stackiq": "module.referenceComponents / usage.usedForReferenceComponents in lib/Settings/softwarecatalogus_register.json hold the application-to-reference-component mapping; lib/Service/ArchiMateExportService.php:2734 draws it only into exported view copies",
+ "glpi": "source read at 11.0.9: grep -rli 'business capabilit\\|business process' over src/ and locales/glpi.pot returns nothing; 'Capacity' in src/Glpi/Asset/Capacity.php is a feature toggle for custom assets, not a business capability."
}
},
{
@@ -1066,7 +1085,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1081,7 +1100,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model.",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models.",
- "stackiq": "src/manifest.json has no page for the view or element schema beyond Standaarden; no diagram editor in src/views or src/components"
+ "stackiq": "src/manifest.json has no page for the view or element schema beyond Standaarden; no diagram editor in src/views or src/components",
+ "glpi": "source read at 11.0.9: the impact graph is an editable diagram, src/Impact.php:1160 add asset, add relation and add group tools, groups stored in install/mysql/glpi-empty.sql:1264 glpi_impactcompounds and node positions in install/mysql/glpi-empty.sql:1276 glpi_impactitems; it draws dependency graphs only, with no architecture notation or views. Reached on: Appliance > Impact analysis tab, graph edit mode."
}
},
{
@@ -1092,7 +1112,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1106,7 +1126,8 @@
"note": "Business processes are not modelled; the only link applications have is to GEMMA reference components.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27464 'Process Mapping' (2026-04-12): Map processes, applications, data, and technology",
- "stackiq": "no process schema in lib/Settings/softwarecatalogus_register.json (20 schemas listed under components.schemas); no process page in src/manifest.json"
+ "stackiq": "no process schema in lib/Settings/softwarecatalogus_register.json (20 schemas listed under components.schemas); no process page in src/manifest.json",
+ "glpi": "source read at 11.0.9: grep -rli 'business process' over src/ and locales/glpi.pot returns nothing; no process itemtype to link to applications."
}
},
{
@@ -1117,7 +1138,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1131,7 +1152,8 @@
"note": "Planned usage and planned replacements exist per record, but there is no future-state model and no comparison with today.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27419 'IT Transformation' (2026-04-12): Plan and execute cloud migrations and modernization | Rated partial because transformation planning.",
- "stackiq": "searched src/manifest.json and the register for scenario/future-state/toekomst: nothing; usage.status 'Planned' and plannedReplacement (register) are per-usage fields, not a comparable landscape"
+ "stackiq": "searched src/manifest.json and the register for scenario/future-state/toekomst: nothing; usage.status 'Planned' and plannedReplacement (register) are per-usage fields, not a comparable landscape",
+ "glpi": "source read at 11.0.9: grep -rli 'future state\\|what-if\\|scenario' over src/*.php returns nothing; the impact graph (src/Impact.php:49) shows only the current relations, with no plateau or target landscape."
}
},
{
@@ -1142,7 +1164,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1156,7 +1178,8 @@
"note": "No report or view lists reference components that no application in your landscape covers.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
- "stackiq": "grep for uncovered/gap/coverage in lib and src found nothing; lib/Service/FacetService.php counts modules per reference component but never lists components with zero coverage"
+ "stackiq": "grep for uncovered/gap/coverage in lib and src found nothing; lib/Service/FacetService.php counts modules per reference component but never lists components with zero coverage",
+ "glpi": "source read at 11.0.9: no reference component model to compare against, grep -ril 'gemma\\|reference component' over src/ locales/glpi.pot returns nothing; appliances are typed only by the free Appliance type dropdown (install/mysql/glpi-empty.sql:8941)."
}
},
{
@@ -1167,7 +1190,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1181,7 +1204,8 @@
"note": "Nothing drafts diagrams.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48970 'AI-powered diagramming' (2026-07-23): AI assists diagram generation. | docs, intelligence competitor_features#27461 'AI-Powered Diagramming' (2026-04-12): Auto-generate BPMN diagrams with built-in AI",
- "stackiq": "no diagram generation in lib/Service or src; no AI integration for diagrams"
+ "stackiq": "no diagram generation in lib/Service or src; no AI integration for diagrams",
+ "glpi": "source read at 11.0.9: grep -rli 'openai\\|llm\\|mistral\\|chatgpt\\|artificial intelligence' over src/ templates/ returns nothing; diagrams are drawn by hand in the impact graph (src/Impact.php:1160)."
}
},
{
@@ -1192,7 +1216,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1208,7 +1232,8 @@
"note": "The GEMMA standards imported with the AMEF model are browsable on their own page with a detail view that lists compliance claims.",
"evidence": {
"vng-softwarecatalogus": "docs, intelligence competitor_features#48840 'Standards support declaration' (2026-07-23): Suppliers declare which standards (StUF, ZGW/Zaakgericht APIs, etc.) a product supports. | docs, intelligence competitor_features#27556 'Standards Mapping' (2026-04-12): Map software to Forum Standaardisatie standards",
- "stackiq": "src/manifest.json page Standaarden /standaarden (index on @resolve:amef_register schema element, filter gemmaType=standaard, columns name/gemmaThema/gemmaStatus/url) and StandaardDetail /standaarden/:id with compliance claims per standard; menu entry Standards (order 50)"
+ "stackiq": "src/manifest.json page Standaarden /standaarden (index on @resolve:amef_register schema element, filter gemmaType=standaard, columns name/gemmaThema/gemmaStatus/url) and StandaardDetail /standaarden/:id with compliance claims per standard; menu entry Standards (order 50)",
+ "glpi": "source read at 11.0.9: no standards itemtype, grep -ril 'standaard\\|forum standaardisatie' src/ locales/glpi.pot returns nothing and the word standard in src/Appliance.php occurs only in addStandardTab (src/Appliance.php:100)."
}
},
{
@@ -1219,7 +1244,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1234,7 +1259,8 @@
"featureConfidence": "high",
"note": "Evidence can be attached as a file, a URL or a Nextcloud Files link on the compliance claim's page.",
"evidence": {
- "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.evidence (file, pdf/jpeg/png/doc, 10 MB), compliancy.url, compliancy.evidenceReference; src/manifest.json KompliantieDetail cm-files widget type integration integrationId files 'Evidence documents'"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.evidence (file, pdf/jpeg/png/doc, 10 MB), compliancy.url, compliancy.evidenceReference; src/manifest.json KompliantieDetail cm-files widget type integration integrationId files 'Evidence documents'",
+ "glpi": "source read at 11.0.9: any document can be attached to an appliance through the Documents tab, src/Appliance.php:100 Document_Item tab and src/Document_Item.php:46, stored in install/mysql/glpi-empty.sql:2585 glpi_documents; there is no compliance claim to attach it to. Reached on: Management > Appliances > Documents tab."
}
},
{
@@ -1245,7 +1271,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1260,7 +1286,8 @@
"featureConfidence": "high",
"note": "The matrix separates claims with evidence from claims without, but 'verified' only means evidence is attached: no one reviews or approves the evidence, so a supplier-uploaded document counts as verified.",
"evidence": {
- "stackiq": "src/utils/complianceMatrix.js:9-17 cell state verified = compliancy record with evidence (hasEvidence :107 checks evidence/evidenceReference/url), claimed = link without evidence; rendered by src/views/ComplianceMatrixView.vue"
+ "stackiq": "src/utils/complianceMatrix.js:9-17 cell state verified = compliancy record with evidence (hasEvidence :107 checks evidence/evidenceReference/url), claimed = link without evidence; rendered by src/views/ComplianceMatrixView.vue",
+ "glpi": "source read at 11.0.9: no compliance claim model, grep -rli 'complian' over src/Appliance.php src/Software.php returns nothing; nothing to mark verified or claimed (src/Appliance.php:46 fields are inventory and management fields only)."
}
},
{
From f46affcdb7186602fb2715bf5b1a60a813753723 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:12:17 +0200
Subject: [PATCH 19/45] chore(parity): fold r-docs-a (VNG Softwarecatalogus and
TOPdesk, public docs read 2026-09-26) and r-glpi packs to 29
---
openspec/parity/capabilities.json | 1251 +++++++++++++++++++----------
1 file changed, 817 insertions(+), 434 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index 3273482a8..bd7d02a32 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -178,11 +178,11 @@
"featureConfidence": "high",
"note": "An application with supplier and description can be registered on the Modules page, but the module schema has no status field, and the per-organisation usage that carries a status has no page to create it on. The Modules list also cannot open ModuleDetail: its standalone CnIndexPage (FacetedCatalogIndexView.vue:108-117) binds no @view/@row-click, so the View action is inert.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map. | docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"klik dan op de knop + achter de beschrijving van het pakket om het pakket toe te voegen aan je omgeving ... Pakketversie ... Referentiecomponenten ... Vul onder Planning bij Status in gebruik in\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus: \"Wanneer Gemeenten en samenwerkingen hun applicatielandschap hebben ingevoerd, wordt deze automatisch geplot op de GEMMA referentiecomponentenkaart\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Voeg pakket toe.",
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | docs, intelligence competitor_features#27422 'Fact Sheets & Data Model' (2026-04-12): Flexible data model for applications, processes, IT components",
"bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository. | docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
"glpi": "source read at 11.0.9: src/Appliance.php:46 class Appliance is GLPI's application itemtype; install/mysql/glpi-empty.sql:8935 glpi_appliances carries name, comment (description), manufacturers_id and states_id (status); src/Appliance.php:350 search option Status; supplier through the Management tab Infocom (install/mysql/glpi-empty.sql:3263 glpi_infocoms.suppliers_id) and Contract_Item (src/Appliance.php:99); menu src/Html.php:1300 lists Appliance under Management, served by src/Glpi/Kernel/Listener/RequestListener/LegacyItemtypeRouteListener.php:100. Reached on: Management > Appliances (front/appliance.php).",
- "topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | docs, intelligence competitor_features#27387 'CMDB / Configuration Management' (2026-04-12): Configuration database for registering IT objects like laptops, software, infrastructure | Rated partial because software is a CMDB object among assets.",
+ "topdesk": "https://docs.topdesk.com/en/migrating-objects-to-asset-management.html: \"In the new Asset Management you design your own template for each type of asset you have\" (read 2026-09-26); https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"Create a new template for software cards\" (read 2026-09-26). Applications are a self-designed asset type, no application model ships. Reached on: Modules > Asset Management > Template Designer / Asset overview > New.",
"stackiq": "src/manifest.json:592 Modules page (FacetedCatalogIndexView, schema module) with the library CnIndexPage create form at src/views/FacetedCatalogIndexView.vue:108; lib/Settings/softwarecatalogus_register.json:6777 module schema has name, shortDescription/longDescription and provider (Supplier) but NO status property; status lives on usage (register.json:2654, enum Acquisition..In production) which has no page"
}
},
@@ -211,6 +211,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated partial because fact sheets separate Application from IT Component.",
"stackiq": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')",
+ "topdesk": "unknown: assets can be linked parent to child, but no application module concept is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: the docs model a pakket and its pakketversies only, no module level is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/Appliance_Item.php:45 links an Appliance to member items; src/autoload/CFG_GLPI.php:562 appliance_types includes Software, Appliance, Database and DatabaseInstance, so an application can be split into software and sub-appliances on its Items tab (src/Appliance.php:98). There is no module entity that belongs to a supplier product: grep -i 'module' src/Software.php src/Appliance.php returns no module concept. Reached on: Management > Appliances > Items tab."
}
},
@@ -219,7 +221,7 @@
"area": "landscape",
"name": "Record the released versions of a module, with the date each came into use.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "partial",
@@ -238,7 +240,9 @@
"note": "A version is created on the Module versions index with its module and date in use, and opens on its own detail page.",
"evidence": {
"glpi": "source read at 11.0.9: src/SoftwareVersion.php:42 SoftwareVersion child of Software, table install/mysql/glpi-empty.sql:6900 glpi_softwareversions with name, states_id, operatingsystems_id but no release or in-use date; the only date is per installation, install/mysql/glpi-empty.sql:1074 glpi_items_softwareversions.date_install. Reached on: Assets > Software > Versions tab (front/softwareversion.form.php).",
- "stackiq": "src/manifest.json:915 Moduleversies type:index (columns version, module, dateInUse, status) + :937 ModuleversieDetail; register.json:7649 moduleVersion schema with dateInUse (register.json:7746), dateInDevelopment, dateEndSupport, dateWithdrawn"
+ "stackiq": "src/manifest.json:915 Moduleversies type:index (columns version, module, dateInUse, status) + :937 ModuleversieDetail; register.json:7649 moduleVersion schema with dateInUse (register.json:7746), dateInDevelopment, dateEndSupport, dateWithdrawn",
+ "topdesk": "unknown: no version records per application or module are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Titel is de naam van uw productversie ... Status geeft aan of uw product in ontwikkeling, in productie, of teruggetrokken is ... startdata van ontwikkeling, test en distributie\" (read 2026-09-26). Versions are recorded per package (pakketversie), not per module. Reached on: Supplier login > Productportfolio > product > plus (versie toevoegen)."
}
},
{
@@ -265,6 +269,8 @@
"note": "A three-step wizard bundles existing applications into one suite. Caveat: a row click on the Suites list only toggles selection (the library returns before emitting row-click when selectable, SuitesIndexView.vue:35), so SuiteDetail is not opened from the list, and its data widget includes stale field names (src/manifest.json:683 beschrijvingKort, contactpersoon).",
"evidence": {
"stackiq": "src/dialogs/SuiteWizardDialog.vue:183 onSubmit saves a suite via objectStore.saveObject('suite') with applications[] (src/utils/suiteWizard.js:44 requires at least one); mounted by src/views/suites/SuitesIndexView.vue:46 on manifest page Suites (src/manifest.json:666)",
+ "topdesk": "unknown: no suite bundling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no bundling of packages into a suite is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:562 appliance_types contains Appliance and Software, so an Appliance can bundle existing appliances and software through src/Appliance_Item.php:45 (table install/mysql/glpi-empty.sql:8979 glpi_appliances_items). There is no notion of offering the bundle as a product to others. Reached on: Management > Appliances > Items tab."
}
},
@@ -277,7 +283,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "partial",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "yes",
"built": {
"state": "built",
@@ -291,8 +297,9 @@
"featureConfidence": "medium",
"note": "A supplier's service over one or more applications is registered on the Services page. There is no 'hosting' service type (technical management is the nearest), and services have no detail page, so a row cannot be opened.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48838 'Supplier product offering (aanbod) registration' (2026-07-23): ICT suppliers publish their product offering for the municipal market with global functionality descriptions. | Rated partial because offering registration covers products; services not named in the reading.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: facet \"Ondersteunde technologie: On-premise, Dienst - Software as a Service (SAAS)\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30355: \"Onder het tabblad Technologie selecteer je de onderliggende technieken van het pakket. Veelal Saas of on-premise\" (read 2026-09-26). Hosting as SaaS is a property of a package version, no separate service record (hosting, support) is documented. Reached on: Alle pakketversies > filter Ondersteunde technologie.",
"stackiq": "src/manifest.json:647 Diensten page (FacetedCatalogIndexView, schema catalogService) with the CnIndexPage create form; register.json:1324 catalogService with provider (required), modules[] (register.json:1419) and type enum Functional/Application/Technical management, Implementation support, Training, Licence reseller (register.json:1459)",
+ "topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"Services you offer may rely on services of external suppliers. These services are called underpinning services. TOPdesk allows you to link your services to supplier services\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: \"On Call, Change (Activity), Operational Activity, Knowledge Item, Problem, and Service cards, you can link multiple assets in one go\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM > Service card > Links > Assets.",
"glpi": "source read at 11.0.9: no supplier service itemtype; services are held as contracts, src/ContractType.php:37 admin dropdown of contract types (for example hosting or support), install/mysql/glpi-empty.sql:1550 glpi_contracts_suppliers ties the contract to a Supplier and install/mysql/glpi-empty.sql:1536 glpi_contracts_items ties it to the Appliance or Software it covers. Reached on: Management > Contracts (front/contract.php), Suppliers tab."
}
},
@@ -301,7 +308,7 @@
"area": "landscape",
"name": "Tag applications with the government sectors they are meant for.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "partial",
@@ -318,6 +325,8 @@
"note": "A sector schema exists, but no application, service or organisation can be tagged with a sector and no page lists sectors.",
"evidence": {
"stackiq": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395",
+ "topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: facets \"Domein\" (Bestuur, Fysieke leefomgeving, Sociaal domein, ...) and \"Doelgroep\" (Gemeente, Generiek, Inwoners en ondernemers, Ketenpartners) (read 2026-09-26). Domains are municipal policy domains, the catalogue serves municipalities only, not other government sectors. Reached on: Alle pakketversies > filters Domein, Doelgroep.",
"glpi": "source read at 11.0.9: no government sector concept, grep -i 'sector' over src/*.php and locales/glpi.pot hits only menu sectorization (src/Html.php:1019); the nearest holder is the single-valued Appliance type dropdown install/mysql/glpi-empty.sql:8941 appliancetypes_id, or an admin custom dropdown (install/mysql/glpi-empty.sql:10113 glpi_dropdowns_dropdowndefinitions) used as a field of a custom asset. Multi-valued tagging needs the separate tag plugin (github.com/pluginsGLPI/tag, not read). Reached on: Management > Appliances, Appliance type field."
}
},
@@ -330,7 +339,7 @@
"sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -346,6 +355,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | Rated partial because surveys go to application owners, so ownership is modelled.",
"stackiq": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')",
+ "topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: \"Assignment widget : assigns locations and persons to the asset\" (read 2026-09-26). No separate business and technical owner roles are described. Reached on: Asset card > Assignment widget.",
+ "vng-softwarecatalogus": "unknown: the landscape entry fields listed (pakketversie, referentiecomponenten, technologie, status) include no business or technical owner; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30355 (read 2026-09-26)",
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:8935 glpi_appliances holds users_id and users_id_tech; src/Appliance.php:186 search option User and src/Appliance.php:195 Group (business side), src/Appliance.php:240 'Technician in charge' and the 'Group in charge' option a few lines below (technical side). Reached on: Management > Appliances, form fields User, Group, Technician in charge, Group in charge."
}
},
@@ -358,7 +369,7 @@
"sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "no",
"built": {
"state": "none",
@@ -373,7 +384,9 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because flexible fact sheet data model.",
"glpi": "source read at 11.0.9: native custom fields exist only for admin defined custom asset types, src/Glpi/Asset/CustomFieldDefinition.php:52 child of AssetDefinition (install/mysql/glpi-empty.sql:10159 glpi_assets_customfielddefinitions keyed on assets_assetdefinitions_id), set up under Setup > Asset definitions (src/Html.php:1330). The core Appliance and Software types take no custom fields in core; that needs the fields plugin, read at pluginsGLPI/fields tag 1.24.5, inc/container.class.php:91 containers with a list of itemtypes. Reached on: Setup > Asset definitions > Custom fields; or plugin Fields.",
- "stackiq": "Looked in src/manifest.json, src/views, lib/Controller: no field-definition or schema-extension UI in stackiq; the data model is fixed in lib/Settings/softwarecatalogus_register.json"
+ "stackiq": "Looked in src/manifest.json, src/views, lib/Controller: no field-definition or schema-extension UI in stackiq; the data model is fixed in lib/Settings/softwarecatalogus_register.json",
+ "topdesk": "https://docs.topdesk.com/en/creating-new-fields.html: \"Whether it is a contact person, a purchase price, or a reminder date ... Use fields in a fieldset or dataset widget to register any useful information about an asset\" (read 2026-09-26). Reached on: Asset Management > Template Designer > Fields.",
+ "vng-softwarecatalogus": "unknown: no user-defined fields are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -381,11 +394,11 @@
"area": "landscape",
"name": "Import an existing application list in bulk from a spreadsheet or file.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "no",
"sap-leanix": "partial",
"bluedolphin": "yes",
"glpi": "partial",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "yes",
"built": {
"state": "built",
@@ -400,6 +413,8 @@
"sap-leanix": "docs, intelligence competitor_features#27428 'EAM Automation' (2026-04-12): Automated data collection from ServiceNow, Jira, cloud providers | Rated partial because automated collection from ServiceNow, Jira and cloud.",
"bluedolphin": "docs, intelligence competitor_features#48971 'Data import (Excel)' (2026-07-23): Bulk import of application/portfolio data.",
"stackiq": "Library CnIndexPage (@conduction/nextcloud-vue 2.55.1, package-lock) showMassImport default true (CnIndexPage.vue:1599) and self-mode handleMassImport (selfModeActions.js:168) POSTs to /apps/openregister/api/registers/{register}/import with the schema for CSV (selfModeIO.js:82); rendered on the Modules page's CnIndexPage (src/views/FacetedCatalogIndexView.vue:108)",
+ "topdesk": "https://docs.topdesk.com/en/generate-import-file.html: \"Importing assets speeds up this task ... export an asset template to XLSX format\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-new-import.html: \"You can use a file (CSV or XLSX), connect with an MS SQL database or import from Microsoft Intune , or Lansweeper\" (read 2026-09-26). Reached on: Settings > Import settings > Asset Management imports.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"Een import vanuit die tools naar de Softwarecatalogus zodat 2-richtingverkeer mogelijk wordt voor actualisatie, is vooralsnog niet voorhanden\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/19703: inventory goes in a spreadsheet, then \"Kies met de + toets het pakket dat opgevoerd moet worden\", one package at a time (read 2026-09-26)",
"glpi": "source read at 11.0.9: core has CSV export only (src/Glpi/Csv/ holds CsvResponse and export classes, no importer) and no spreadsheet import of assets or appliances. Bulk import is the separate datainjection plugin, read at pluginsGLPI/datainjection tag 2.15.11: inc/backendcsv.class.php CSV backend and inc/applianceinjection.class.php:33 PluginDatainjectionApplianceInjection extends Appliance; setup.php:36 requires GLPI 11.0.5 or later. Reached on: plugin Data injection (Tools > Data injection)."
}
},
@@ -412,7 +427,7 @@
"sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -426,9 +441,10 @@
"featureConfidence": "medium",
"note": "The application page shows versions and compliance claims, and usages only as untyped entries in the generic Related panel. Contracts are not shown. The page cannot be opened from the Applications list itself, and its data widget asks for three field names the schema no longer has, so the descriptions do not render.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakket/archi: package page shows versions with status and start dates, \"Pakket geschikt voor (GEMMA 2) Ingevuld door (28)\", and per version the mandatory and recommended standards with support, compliancy and testrapport (read 2026-09-26). No contracts on the page. Reached on: Alle pakketten > package name.",
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because fact sheet is the per-application page.",
"stackiq": "src/manifest.json:491 ModuleDetail: md-versions (:504), md-compliance (:503), md-related generic Related panel (:502); no contract widget (catalogContract links to service/usage, register.json:3250, not to module); md-data include lists stale keys beschrijvingKort/beschrijvingLang/contactpersoon (:500)",
+ "topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: twelve widgets incl. \"History\", \"Relationships\", \"Relationship grid\", \"Documents\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: assets linked to calls, changes, services (read 2026-09-26). Versions and compliance are not part of it. Reached on: Asset card.",
"glpi": "source read at 11.0.9: src/Appliance.php:98 onwards defineTabs puts Items, Contracts, Documents, Management (Infocom), Certificates, Domains, Knowledge base, Tickets, Problems, Changes and Impact on the one appliance page; versions sit on the separate Software page (src/SoftwareVersion.php:42), and no compliance tab exists (grep -i 'complian' src/Appliance.php returns nothing). Reached on: Management > Appliances > appliance form tabs."
}
},
@@ -441,7 +457,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -456,6 +472,8 @@
"note": "Many entries can be selected and deleted together through the library index page. The mass publish and mass lock dialogs exist but hang off a view modal no page opens, and the publish endpoint (lib/Controller/PublicationController.php, PUT /api/publication/...) has no frontend caller.",
"evidence": {
"stackiq": "Library CnIndexPage mass delete/copy/export (showMassDelete default true, CnIndexPage.vue:1617; selfModeActions.js:63 handleMassDelete) on index pages; stackiq's MassPublishObjects/MassLockObjects dialogs (src/dialogs/Dialogs.vue:8-14) are only opened from src/modals/object/ViewObject.vue:4865, and ViewObject is only mounted for modals 'viewOrganisatie'/'viewContactpersoon' (src/modals/Modals.vue:7,19) which nothing in src/ sets",
+ "topdesk": "https://docs.topdesk.com/en/editing-assets-in-bulk.html: \"select multiple assets by ticking their boxes ... You can use bulk edit for updating up to 500 assets\" (read 2026-09-26); editable are assignments, drop-down, date, number, text and checkbox fields. Bulk publish or delete is not described. Reached on: Asset Management > Asset overview > select > bulk edit.",
+ "vng-softwarecatalogus": "unknown: no multi-select publish, lock or delete is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"glpi": "source read at 11.0.9: every search list offers massive actions, src/MassiveAction.php:666 Update (any field, for example status), src/MassiveAction.php:698 Put in trashbin, src/MassiveAction.php:652 Delete permanently, src/MassiveAction.php:656 Restore. There is no publish state; locking applies to inventory fields only. Reached on: any list, for example Management > Appliances, Actions button."
}
},
@@ -468,7 +486,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "no",
"stackiq": "partial",
"built": {
"state": "built",
@@ -481,6 +499,8 @@
"note": "Only organisations can be merged, with a dry run first, and only by a Nextcloud admin. Applications, services and other entries have no merge.",
"evidence": {
"stackiq": "src/components/organisations/OrganisationMergePanel.vue:46 (admin-only controls) mounted as OrganisatieDetail bodyWidget org-merge (src/manifest.json:430); lib/Controller/MergeController.php:106 execute with isAdmin check at :142; generic src/modals/object/MergeObject.vue only mounted for modal 'mergeOrganisatie' which nothing sets",
+ "topdesk": "https://docs.topdesk.com/en/migration-status.html: \"You cannot merge the two cards into one card\" (read 2026-09-26); https://tip.topdesk.com/c/239-ai-cmdb-monitoring-: roadmap card in column \"Under consideration\", \"AI can continuously scan your configuration database for duplicate records ... and surfaces them for review\" (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no merge of entries is described; the news page only mentions a pseudo-supplier \"Open Source Pakketten\" created against duplicate spellings; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/nieuws (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/Software.php:109 'Merging' tab on a recursive software, src/Software.php:926 showMergeCandidates lists same named software, src/Software.php:997 massive action Merge, src/Software.php:1011 private function merge moves versions and licences into the kept entry; dropdowns get Replace, src/CommonDropdown.php:680. Reached on: Assets > Software > Merging tab."
}
},
@@ -489,7 +509,7 @@
"area": "landscape",
"name": "Ask application owners through a survey to confirm or correct their entries.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
"bluedolphin": "yes",
"glpi": "no",
@@ -508,6 +528,8 @@
"sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | docs, intelligence competitor_features#27423 'Survey-Based Data Collection' (2026-04-12): Crowdsource architecture data from application owners",
"bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders.",
"stackiq": "No survey, attestation or owner-confirmation code in lib/ or src/ (searched survey/enquete/confirm entry)",
+ "topdesk": "unknown: Survey Management runs general surveys (and \"will reach end of life ... November 2026\"), not confirmation of entries by owners; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C7: \"Leveranciers krijgen ook periodiek notificatiemails met een aantal automatische controles en de Te corrigeren fouten staan ook op het dashboard van ingelogde leveranciers\" (read 2026-09-26); https://www.softwarecatalogus.nl/suggesties_overnemen: suppliers send suggestions that municipalities accept or decline (read 2026-09-26). No survey to application owners.",
"glpi": "source read at 11.0.9: the native form builder (src/Glpi/Form/Form.php:92) only has ITIL destinations, src/Glpi/Form/Destination/ holds FormDestinationTicket, FormDestinationChange and FormDestinationProblem, so a form answer opens a ticket but never confirms or updates an appliance record; the only 'survey' in core is ticket satisfaction (src/Central.php:220). No owner review campaign exists."
}
},
@@ -516,7 +538,7 @@
"area": "landscape",
"name": "See how complete and up to date each application's entry is, as a score.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "no",
@@ -533,7 +555,9 @@
"note": "No page scores how complete or current an entry is.",
"evidence": {
"stackiq": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)",
- "glpi": "source read at 11.0.9: grep -ril 'completeness' over src/ templates/ locales/glpi.pot returns nothing; no score of how filled in an item is exists in core."
+ "topdesk": "unknown: the only readiness score described is the AI readiness score for the knowledge base; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/voortgang-verbeteren: \"Met het aantal sterren (*) wordt een indicatie van volledigheid van ingevulde gegevens aangegeven\", criteria include referentiecomponenten filled, statuses, koppelingen and \"Datum laatste wijziging is recenter dan 3 maanden geleden\" (read 2026-09-26). Scored per organisation, not per application entry. Reached on: Homepage block Voortgang gemeenten; organisation page header.",
+ "glpi": "source read at 11.0.9: grep -ril 'completeness' over src/ templates/ locales/glpi.pot returns nothing; no score of how filled in an item is exists in core. The item form tabs (src/Appliance.php:98 onwards) show no score."
}
},
{
@@ -558,6 +582,8 @@
"note": "An admin picks the demo dataset in the setup wizard and it is imported through OpenRegister. Admin-only, which suits an installation task.",
"evidence": {
"stackiq": "src/manifest.json:3 setup wizard step load-demo-data (:24); lib/Controller/SetupController.php:202 runAction load-demo-data (AuthorizedAdminSetting); lib/Service/DemoDataService.php:202 install() imports lib/Settings/stackiq_mock_register.json (120 objects, 6 per schema) through OpenRegister ConfigurationService::importFromApp",
+ "topdesk": "unknown: no example data set is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: the catalogue is one hosted service; no loadable example data set is described (a \"VNG Realisatie Demo\" supplier appears in the live data); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'demo data\\|sample data' over src/ templates/ locales/glpi.pot returns nothing and src/Glpi/Console/ has no demo loader; example data exists only as test fixtures under tests/, not shipped as a feature."
}
},
@@ -583,6 +609,8 @@
"note": "Only suites get a step-by-step wizard. Applications and services are added through a plain form, and connections have no page at all.",
"evidence": {
"stackiq": "src/dialogs/SuiteWizardDialog.vue (3 steps) is the only wizard, opened from src/views/suites/SuitesIndexView.vue:46; applications, services and connections use the bare CnIndexPage form (FacetedCatalogIndexView.vue:108) or nothing",
+ "topdesk": "unknown: wizards exist for imports and migration, not for adding an application; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: the manuals describe forms (\"Hierna opent een formulier\"), no step-by-step wizard; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30355 (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'wizard' over src/ templates/ locales/glpi.pot returns nothing for item creation; appliances are added through the plain form only (install/mysql/glpi-empty.sql:8935 glpi_appliances has no is_template column)."
}
},
@@ -608,6 +636,8 @@
"note": "A module version's page lists the third-party components imported from its SBOM.",
"evidence": {
"stackiq": "src/components/sbom/SbomComponentsPanel.vue lists sbomComponent rows (name/version/purl/licenses) as the ModuleversieDetail 'Components' sidebar tab (src/manifest.json:961); register.json:7920 sbomComponent schema",
+ "topdesk": "unknown: no software components per version are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no third-party component list per version is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'sbom\\|cyclonedx\\|spdx' over src/ templates/ locales/glpi.pot returns nothing; software versions carry no component list (install/mysql/glpi-empty.sql:6900 glpi_softwareversions)."
}
},
@@ -616,7 +646,7 @@
"area": "landscape",
"name": "Record whether an application runs on premises, as SaaS or at a hosting party.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
@@ -636,6 +666,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | Rated partial because SaaS is tracked as a class of application.",
"stackiq": "register.json:6869 module.cloudDienstverleningsmodel enum On-premises, IaaS, PaaS, SaaS; register.json:6906 hostingLocation and hostingJurisdiction; usage.cloudDienstverleningsmodel (register.json:3050); on ModuleDetail md-data include (src/manifest.json:500)",
+ "topdesk": "unknown: only possible as a self-defined field; no hosting model is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Indien een leverancier zowel SaaS als On premise ondersteunt, kan je aangeven welke van deze twee varianten gebruikt wordt binnen de gemeente\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen > tabblad Technologie.",
"glpi": "source read at 11.0.9: no hosting model field; the closest holders are the admin editable Environment dropdown on an appliance, src/Appliance.php:277 ApplianceEnvironment search option (install/mysql/glpi-empty.sql:8945 applianceenvironments_id), plus locations_id and the Appliance type dropdown. grep -i 'saas' over src/ finds nothing; 'On-premise' in locales/glpi.pot:12997 is only an icon label. Reached on: Management > Appliances, Environment field."
}
},
@@ -662,8 +694,9 @@
"featureConfidence": "low",
"note": "The field for a national provision exists on the connection schema, but with no connection page nobody can fill it in stackiq.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48841 'National provisions (landelijke voorzieningen) linking' (2026-07-23): Records links between applications and national government provisions.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"De richting van het berichtenverkeer, de landelijke voorziening waarmee gekoppeld is/wordt, in dit geval GGK\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus: \"kunnen koppelingen tussen applicaties onderling en met Landelijke Voorzieningen vastgelegd worden\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > koppeling toevoegen.",
"stackiq": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection",
+ "topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"glpi": "source read at 11.0.9: no national provision concept (grep -ril 'basisregistratie' src/ locales/glpi.pot returns nothing); a provision can be held as another Appliance and linked through an impact relation, install/mysql/glpi-empty.sql:1247 glpi_impactrelations (source item, impacted item, name), with Appliance enabled for impact at src/autoload/CFG_GLPI.php:649. Reached on: Appliance > Impact analysis tab, Add relation."
}
},
@@ -672,7 +705,7 @@
"area": "connections",
"name": "Browse all connections in the catalogue in one list and open each one.",
"origin": "own-code",
- "vng-softwarecatalogus": "partial",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "no",
@@ -690,8 +723,9 @@
"featureConfidence": "medium",
"note": "There is no list of connections in the catalogue. The Integrations page lists outside integrations, a different thing.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle koppelingen ... staan de koppelingen van alle gemeenten en samenwerkingsverbanden ... Door te klikken op het icoontje rechts van een koppeling, krijg je nog enige detail informatie\" (read 2026-09-26). Reached on: Inlogmenu > Alle koppelingen (logged-in municipal users).",
"stackiq": "No manifest page with schema connection (src/manifest.json and src/manifest.d/*.json); the Integrations page (src/manifest.d/connection-registry.json:23) lists integriq app_connection, explicitly not stackiq's connection schema (its _note)",
+ "topdesk": "unknown: relations are shown per asset and in a graphical overview; a list of all relations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/ImpactRelation.php:39 ImpactRelation has only prepareInputForAdd and getIDFromInput (src/ImpactRelation.php:47, :107), no search options and no list page; relations are only seen per item in the Impact analysis tab (src/Impact.php:91)."
}
},
@@ -704,7 +738,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -718,8 +752,9 @@
"featureConfidence": "low",
"note": "Connections that reference an application should appear among the untyped related objects on its page, but there is no connections section and nothing to open. The dedicated per-application endpoint is API only.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Mijn pakketoverzicht ... Onder het eerste tabblad zitten de pakketten en onder het tweede tabblad de koppelingen\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: \"Door op een applicatienaam in het Models venster te klikken, zie je in de Visualiser alle koppelingen tussen die applicatie met andere applicaties\" (in Archi after export) (read 2026-09-26). No per-application connection view inside the catalogue is described. Reached on: Mijn softwarecatalogus > Koppelingen.",
"stackiq": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/",
+ "topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"Links between assets are created and managed via the Relationships widget. For current relationships with other assets, the widget shows the template's icon, the Asset ID\" (read 2026-09-26). Generic asset relations, not interfaces. Reached on: Asset card > Relationships widget.",
"glpi": "source read at 11.0.9: src/Impact.php:91 getTabNameForItem adds the 'Impact analysis' tab (src/Impact.php:80) to every impact enabled itemtype, Appliance and Software included (src/autoload/CFG_GLPI.php:649 and :663), with a list view src/Impact.php:270 displayListView of every related item in both directions. Reached on: Management > Appliances > Impact analysis tab."
}
},
@@ -728,11 +763,11 @@
"area": "connections",
"name": "See the connections between applications drawn as a diagram.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
"bluedolphin": "yes",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "no",
"built": {
"state": "none",
@@ -749,7 +784,9 @@
"sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model. | docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
"bluedolphin": "docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models. | docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
"glpi": "source read at 11.0.9: src/Impact.php:252 displayGraphView and src/Impact.php:1559 makeDataForCytoscape draw the relation network, with editing tools add asset, add relation, add group at src/Impact.php:1160. Reached on: Appliance > Impact analysis tab, graph view.",
- "stackiq": "No diagram rendering in src/ (no graph library; src/store/modules/view.js GET /api/views has no importer outside itself); lib/Service/ArchiMateExportService.php exports GEMMA views as ArchiMate XML without koppeling objects (no 'koppeling' in lib/Service/ArchiMate*)"
+ "stackiq": "No diagram rendering in src/ (no graph library; src/store/modules/view.js GET /api/views has no importer outside itself); lib/Service/ArchiMateExportService.php exports GEMMA views as ArchiMate XML without koppeling objects (no 'koppeling' in lib/Service/ArchiMate*)",
+ "topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"After you define the relationship between assets, you can use the graphical overview to see a visual representation of their relationship\" (read 2026-09-26). Reached on: Asset card > graphical overview.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30890: \"Tekenen van een view met koppelingen ... Een koppeling is gemodelleerd als een Archimate flow relatie\" (read 2026-09-26). Diagrams are drawn in Archi after an AMEFF export, not in the catalogue."
}
},
{
@@ -757,7 +794,7 @@
"area": "connections",
"name": "Before changing or retiring an application, see what depends on it.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "yes",
"glpi": "yes",
@@ -775,8 +812,9 @@
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
"glpi": "source read at 11.0.9: src/Impact.php:49 class Impact 'Impact analysis', src/Impact.php:713 bfs walks the graph by direction and src/Impact.php:612 buildListData lists what is impacted, with ongoing tickets, problems and changes on impacted items (src/Impact.php:313). Reached on: Tools > Impact analysis (src/Html.php:1309) and the item's Impact analysis tab.",
- "topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | Rated partial because relations between assets.",
- "stackiq": "src/manifest.json:502 ModuleDetail md-related (library CnRelatedObjectsWidget: /used lists every object that references this module: usages, connections, suites, services, vulnerabilities); no dependency or impact computation in lib/ or src/"
+ "topdesk": "https://docs.topdesk.com/en/managing-disruptions-in-your-asset-management-process.html: \"you want to know how far the reach of the disruption is ... the operational/impacted status for assets ... Status impacts are also only shown in the graphical overview when a link type is used\" (read 2026-09-26). Disruption impact, not a pre-change dependency analysis. Reached on: Asset card > General widget > Determine status automatically.",
+ "stackiq": "src/manifest.json:502 ModuleDetail md-related (library CnRelatedObjectsWidget: /used lists every object that references this module: usages, connections, suites, services, vulnerabilities); no dependency or impact computation in lib/ or src/",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Pakketversies die niet meer in gebruik zijn, kunnen verwijderd worden waarbij feedback gegeven wordt over de koppelingen die ook automatisch verwijderd zullen worden\" (read 2026-09-26). Only on delete, no dependency analysis."
}
},
{
@@ -801,6 +839,8 @@
"note": "The type field exists but there is no connection list to filter.",
"evidence": {
"stackiq": "register.json:3563 connection.type enum (file transfer, digikoppeling, message que, webservices, api, ...) exists, but no connection list page to filter",
+ "topdesk": "unknown: custom link types exist, but filtering relations by type is not described; https://tip.topdesk.com/c/90-graphical-overview-improvements is still under consideration; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: connections carry a standard and \"het soort overdracht\" (upload naar portaal, webservices), but the docs do not name a type filter on the connection list; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo (read 2026-09-26)",
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1247 glpi_impactrelations has only a free name besides the two endpoints, no connection type (API, file, message), so there is nothing to filter on; the graph settings (src/Impact.php:1167 impact_settings) cover depth and direction."
}
},
@@ -827,6 +867,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27425 'API Management' (2026-04-12): Catalog and manage APIs across the application landscape",
"stackiq": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label",
+ "topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no register of APIs an application exposes is described; standards are declared instead; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"glpi": "source read at 11.0.9: no API entity in core, grep -ril 'openapi' src/*.php finds no itemtype for exposed APIs; an admin can define an 'API' custom asset type (src/Html.php:1330 Setup > Asset definitions, src/Glpi/Asset/AssetDefinition.php) and attach it to the application as an Appliance item (src/Appliance_Item.php:45) or impact relation (install/mysql/glpi-empty.sql:1247). Reached on: Setup > Asset definitions, then Appliance > Items tab."
}
},
@@ -835,7 +877,7 @@
"area": "connections",
"name": "Export the graph of what an application is linked to, for use elsewhere.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
@@ -854,7 +896,9 @@
"note": "The organisation ArchiMate export carries modules and usages but not connections, so an application's link graph cannot be exported.",
"evidence": {
"glpi": "source read at 11.0.9: front/impactcsv.php streams Glpi\\Csv\\ImpactCsvExport for an item, linked from the impact list view at src/Impact.php:393; the graph Download button src/Impact.php:1165 calls js/impact.js:2528 download, which writes PNG (js/impact.js:2539) or JPEG (js/impact.js:2546). Reached on: Appliance > Impact analysis tab, Download and CSV export.",
- "stackiq": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*"
+ "stackiq": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*",
+ "topdesk": "unknown: exporting the relation graph is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: \"Pakketten én koppelingen worden in 1 model geëxporteerd ... AMEFF-export\" (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Mijn koppelingen: Knop [Exporteren] op tabblad Koppelingen\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten or Koppelingen > Exporteren > AMEFF-export."
}
},
{
@@ -866,7 +910,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "partial",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -879,6 +923,8 @@
"note": "With integriq installed, an admin sees stackiq's three integrations and their checked status on one page, and Add integration opens integriq. Without integriq the page is hidden, and the checking is integriq's.",
"evidence": {
"stackiq": "src/manifest.d/connection-registry.json:23 Integrations page (register integriq, schema app_connection) with visibleIf appInstalled 'integriq' (:17) and permission admin (:15,:27); Add integration handler leaves for integriq (src/services/connectionRegistry.js:43); rows synced from lib/Settings/connections.json (email, federation, eol-feed); status worked out by integriq",
+ "topdesk": "https://docs.topdesk.com/en/connections.html: \"TOPdesk offers a storage space for usernames, passwords, and authentication tokens used in automated actions ... Better overview: Observe when specific credentials are applied\" (read 2026-09-26); https://docs.topdesk.com/en/using-the-automated-actions-overview.html: \"contains all asset actions, webhooks, scheduled actions ... The last execution status\" (read 2026-09-26). Reached on: Settings > Connections; Action Management > Automated Actions.",
+ "vng-softwarecatalogus": "unknown: no overview of the catalogue's own outside integrations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"glpi": "source read at 11.0.9: outside integrations are set up on separate Setup pages, not one overview: src/Html.php:1331 Webhook, src/Html.php:1333 OAuthClient and MailCollector, Auth (LDAP, SSO) on src/Html.php:1332; src/Webhook.php:64 Webhook and src/OAuthClient.php:45 OAuthClient each have their own list. Reached on: Setup > Webhooks, Setup > OAuth clients, Setup > Authentication."
}
},
@@ -907,7 +953,9 @@
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27459 'ArchiMate & BPMN Support' (2026-04-12): Full ArchiMate and BPMN modeling in one platform | Rated yes because full ArchiMate support; import format not named in the reading.",
"stackiq": "appinfo/routes.php:96 POST /api/archimate/import -> lib/Controller/SettingsController.php:1490 importArchiMate (isAdmin check :1496) -> lib/Service/ArchiMateImportService.php (5961 lines); UI src/views/settings/sections/ArchiMateImportExport.vue:32 file input + :791 importArchiMateFile",
- "glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma\\|togaf' over src/ templates/ locales/glpi.pot returns nothing; no model import exists."
+ "topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: only export to AMEFF is documented; importing an ArchiMate file into the catalogue is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma\\|togaf' over src/ templates/ locales/glpi.pot returns nothing; no model import exists. Import paths in core are inventory (src/Glpi/Inventory/Inventory.php:106) and form import (src/Glpi/Controller/Form/Import/), neither for models."
}
},
{
@@ -933,10 +981,11 @@
"featureConfidence": "high",
"note": "The export produces a downloadable AMEF XML, but only from the admin settings page; organisation admins may call the API but have no page for it.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27554 'ArchiMate Export' (2026-04-12): Export to ArchiMate format for use in architecture tools",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: \"De softwarecatalogus ondersteund een koppeling met architectuurtools. Dit wordt gedaan via de exportfunctionaliteit van een ArchiMate Exchange Format-bestand ... Archi (Open Source), Bizzdesign, Mavim, Sparx, Dragon1 en Value Blue\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Exporteren > AMEFF-export.",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
"stackiq": "appinfo/routes.php:97 POST /api/archimate/export -> lib/Controller/SettingsController.php:1615 exportArchiMate (admin or org-admin via verifyOrgExportPermission :1735) -> lib/Service/ArchiMateService.php:232 exportToArchiMate (docblock: organization filter 'currently not implemented'); UI ArchiMateImportExport.vue:591 'Export Base' button",
- "glpi": "source read at 11.0.9: grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing; exports are CSV, PDF and spreadsheet search output (src/Glpi/Csv/) only."
+ "topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing; exports are CSV, PDF and spreadsheet search output (src/Glpi/Csv/) only. Export formats are src/Glpi/Search/Output/Csv.php:38 and src/Glpi/Search/Output/Pdf.php:43 and the spreadsheet siblings."
}
},
{
@@ -962,9 +1011,10 @@
"featureConfidence": "high",
"note": "Complete logic, but reachable only on the admin settings page; an ordinary organisation user cannot export its own landscape from a stackiq page.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape | docs, intelligence competitor_features#27554 'ArchiMate Export' (2026-04-12): Export to ArchiMate format for use in architecture tools | Rated yes because map and export the municipality's landscape.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: export file named \"GEMMA_Softwarecatalogus__ameff_model\" (read 2026-09-26); https://www.softwarecatalogus.nl/Archi_modellen_samenvoegen: \"De export van de Softwarecatalogus bevat de GEMMA en alle pakketten en koppelingen van de gemeente\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: \"GEMMA views met daarop geplot de pakketten van de gemeente\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Exporteren > AMEFF-export.",
"stackiq": "appinfo/routes.php:98 GET /api/archimate/export/organization/{organizationUuid} -> lib/Controller/SettingsController.php:1685 exportOrgArchiMate -> lib/Service/ArchiMateService.php:302 -> lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications in GEMMA view copies; UI ArchiMateImportExport.vue:602 'Organization Export' with Modules/Deelnames/Gebruik checkboxes",
- "glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma' over src/ templates/ locales/glpi.pot returns nothing; no GEMMA plotting or per entity model export."
+ "topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma' over src/ templates/ locales/glpi.pot returns nothing; no GEMMA plotting or per entity model export. Export formats are src/Glpi/Search/Output/Csv.php:38 and src/Glpi/Search/Output/Pdf.php:43, no model file."
}
},
{
@@ -991,7 +1041,9 @@
"note": "There is an endpoint, but its comparison is broken (a missing key against a placeholder string) and no page calls it. The compare_archimate.py/.php scripts in the repo root are developer tools, not a user capability.",
"evidence": {
"stackiq": "appinfo/routes.php:107 POST /api/archimate/test-round-trip -> lib/Controller/SettingsController.php:2886 (@NoAdminRequired, any logged-in user) -> lib/Service/ArchiMateService.php:1496 testRoundTrip: reads $importResult['imported_count'] (:1528), a key no import path sets, and compares it to exportToArchiMate's 'exported_count' which is the literal string 'calculated_in_export_service' (:271), so it can never report success; it also imports a test model into the live register",
- "glpi": "source read at 11.0.9: there is no model import or export to round trip, grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing."
+ "topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: the merge guide checks the result inside Archi via its status log; the catalogue itself offers no round-trip check; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Archi_modellen_samenvoegen (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: there is no model import or export to round trip, grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing. Export formats are src/Glpi/Search/Output/Csv.php:38 and src/Glpi/Search/Output/Pdf.php:43, no model file."
}
},
{
@@ -1018,7 +1070,9 @@
"note": "The import runs as one blocking request with a spinner. The cancel endpoint calls a missing method and import progress is never recorded, so neither following nor cancelling works.",
"evidence": {
"stackiq": "appinfo/routes.php:103 POST /api/archimate/import/cancel -> lib/Service/SettingsService.php:5200 calls ArchiMateService::cancelArchiMateImport(), which does not exist in lib/Service/ArchiMateService.php (Error, not caught by catch(\\Exception)); routes.php:119-120 /api/progress/{operationId} read ProgressTracker, but the ArchiMate import never writes to it (only SbomImportService gets it, lib/AppInfo/Application.php:507); ArchiMateImportExport.vue:538 shows only a spinner, no cancel button",
- "glpi": "source read at 11.0.9: no model import exists (grep -ril 'archimate' src/ returns nothing), so there is no import to follow; the generic progress endpoint src/Glpi/Controller/ProgressController.php serves other long operations."
+ "topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no model import is documented; for export only \"Er verschijnt een venster met de melding dat de export gegenereerd wordt\"; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no model import exists (grep -ril 'archimate' src/ returns nothing), so there is no import to follow; the generic progress endpoint src/Glpi/Controller/ProgressController.php serves other long operations. The progress route is src/Glpi/Controller/ProgressController.php:50 /progress/check/{key}, used by the installer (src/Glpi/Controller/InstallController.php:57)."
}
},
{
@@ -1026,7 +1080,7 @@
"area": "architecture",
"name": "Read the definition of a GEMMA term in place while working in the catalogue.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "no",
@@ -1045,7 +1099,9 @@
"note": "You can open a standard's page and read its definition, but reference components and other GEMMA terms have no page and there is no inline definition where they appear.",
"evidence": {
"stackiq": "src/manifest.json StandaardDetail /standaarden/:id st-data widget shows all element fields (documentation, gemmaNotes) of a standard; FacetedCatalogIndexView.vue:150 shows reference components by name only",
- "glpi": "source read at 11.0.9: grep -ril 'gemma\\|glossary' over src/ templates/ locales/glpi.pot returns nothing; no reference term definitions ship in core."
+ "topdesk": "unknown: GEMMA is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/lexicon: lexicon of catalogue terms (Addendum, Referentiecomponent, Standaard, SaaS); terms in page text link to it (read 2026-09-26); https://www.softwarecatalogus.nl/node/13683: \"Alle referentiecomponenten ... de toelichting bij de referentiecomponenten\" (read 2026-09-26). Reached on: Lexicon; Alle referentiecomponenten.",
+ "glpi": "source read at 11.0.9: grep -ril 'gemma\\|glossary' over src/ templates/ locales/glpi.pot returns nothing; no reference term definitions ship in core. The knowledge base (src/KnowbaseItem.php:57) is the only place definitions could be written by hand."
}
},
{
@@ -1053,7 +1109,7 @@
"area": "architecture",
"name": "Map applications to business capabilities or functions and see the map.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
"bluedolphin": "yes",
"glpi": "no",
@@ -1074,7 +1130,9 @@
"sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | docs, intelligence competitor_features#27420 'Business Capability Mapping' (2026-04-12): Map applications to business capabilities and processes",
"bluedolphin": "docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
"stackiq": "module.referenceComponents / usage.usedForReferenceComponents in lib/Settings/softwarecatalogus_register.json hold the application-to-reference-component mapping; lib/Service/ArchiMateExportService.php:2734 draws it only into exported view copies",
- "glpi": "source read at 11.0.9: grep -rli 'business capabilit\\|business process' over src/ and locales/glpi.pot returns nothing; 'Capacity' in src/Glpi/Asset/Capacity.php is a feature toggle for custom assets, not a business capability."
+ "topdesk": "unknown: no capability or function map is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"de pakketten die getoond worden in het pakketoverzicht te plotten op een GEMMA architectuurkaart ... [Toon kaart]\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: view \"RD02 Bedrijfsfuncties ruimtelijk domein met referentiecomponenten\" with the municipality's packages plotted (read 2026-09-26). Mapping runs through fixed GEMMA reference components and business functions, not the organisation's own capability model. Reached on: Mijn softwarecatalogus > Pakketten > kaart kiezen > Toon kaart.",
+ "glpi": "source read at 11.0.9: grep -rli 'business capabilit\\|business process' over src/ and locales/glpi.pot returns nothing; 'Capacity' in src/Glpi/Asset/Capacity.php is a feature toggle for custom assets, not a business capability. src/Glpi/Asset/Capacity.php:39 is the custom asset capacity class."
}
},
{
@@ -1101,6 +1159,8 @@
"sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model.",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models.",
"stackiq": "src/manifest.json has no page for the view or element schema beyond Standaarden; no diagram editor in src/views or src/components",
+ "topdesk": "unknown: no architecture modelling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: the docs send users to Archi or other tools for modelling; drawing inside the catalogue is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30890 (read 2026-09-26)",
"glpi": "source read at 11.0.9: the impact graph is an editable diagram, src/Impact.php:1160 add asset, add relation and add group tools, groups stored in install/mysql/glpi-empty.sql:1264 glpi_impactcompounds and node positions in install/mysql/glpi-empty.sql:1276 glpi_impactitems; it draws dependency graphs only, with no architecture notation or views. Reached on: Appliance > Impact analysis tab, graph edit mode."
}
},
@@ -1127,7 +1187,9 @@
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27464 'Process Mapping' (2026-04-12): Map processes, applications, data, and technology",
"stackiq": "no process schema in lib/Settings/softwarecatalogus_register.json (20 schemas listed under components.schemas); no process page in src/manifest.json",
- "glpi": "source read at 11.0.9: grep -rli 'business process' over src/ and locales/glpi.pot returns nothing; no process itemtype to link to applications."
+ "topdesk": "unknown: no process modelling linked to applications is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no process modelling is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'business process' over src/ and locales/glpi.pot returns nothing; no process itemtype to link to applications. Appliance tabs (src/Appliance.php:98 onwards) link no process."
}
},
{
@@ -1135,7 +1197,7 @@
"area": "architecture",
"name": "Model a future-state landscape and compare it with today's.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
@@ -1153,6 +1215,8 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27419 'IT Transformation' (2026-04-12): Plan and execute cloud migrations and modernization | Rated partial because transformation planning.",
"stackiq": "searched src/manifest.json and the register for scenario/future-state/toekomst: nothing; usage.status 'Planned' and plannedReplacement (register) are per-usage fields, not a comparable landscape",
+ "topdesk": "unknown: Long-Term Planning scenarios are for maintenance planning and the module \"will reach end of life ... November 2026\"; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"geplande harmonisaties ... met een status gepland met bijbehorende datum. Zo kan ook het uiteindelijke doel-landschap in 1 overzicht inzichtelijk worden gemaakt\" (read 2026-09-26). No side-by-side comparison of today and target. Reached on: Mijn softwarecatalogus (samenwerking) > Pakketten > status Gepland.",
"glpi": "source read at 11.0.9: grep -rli 'future state\\|what-if\\|scenario' over src/*.php returns nothing; the impact graph (src/Impact.php:49) shows only the current relations, with no plateau or target landscape."
}
},
@@ -1161,7 +1225,7 @@
"area": "architecture",
"name": "Find reference components that no application in your landscape covers.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "yes",
"glpi": "no",
@@ -1179,6 +1243,8 @@
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
"stackiq": "grep for uncovered/gap/coverage in lib and src found nothing; lib/Service/FacetService.php counts modules per reference component but never lists components with zero coverage",
+ "topdesk": "unknown: GEMMA reference components are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tile \"Pakketten met meer mogelijkheden: U heeft in uw pakketoverzicht pakketten die geschikt zijn voor referentiecomponenten waarbij u nog geen pakket heeft opgevoerd\" (read 2026-09-26). It lists uncovered components only where an owned package could fill them. Reached on: Dashboard tile Pakketten met meer mogelijkheden.",
"glpi": "source read at 11.0.9: no reference component model to compare against, grep -ril 'gemma\\|reference component' over src/ locales/glpi.pot returns nothing; appliances are typed only by the free Appliance type dropdown (install/mysql/glpi-empty.sql:8941)."
}
},
@@ -1205,6 +1271,8 @@
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48970 'AI-powered diagramming' (2026-07-23): AI assists diagram generation. | docs, intelligence competitor_features#27461 'AI-Powered Diagramming' (2026-04-12): Auto-generate BPMN diagrams with built-in AI",
"stackiq": "no diagram generation in lib/Service or src; no AI integration for diagrams",
+ "topdesk": "unknown: the AI features cover tickets and knowledge, not diagrams; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no assistant is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'openai\\|llm\\|mistral\\|chatgpt\\|artificial intelligence' over src/ templates/ returns nothing; diagrams are drawn by hand in the impact graph (src/Impact.php:1160)."
}
},
@@ -1231,8 +1299,9 @@
"featureConfidence": "high",
"note": "The GEMMA standards imported with the AMEF model are browsable on their own page with a detail view that lists compliance claims.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48840 'Standards support declaration' (2026-07-23): Suppliers declare which standards (StUF, ZGW/Zaakgericht APIs, etc.) a product supports. | docs, intelligence competitor_features#27556 'Standards Mapping' (2026-04-12): Map software to Forum Standaardisatie standards",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle standaarden: Dit overzicht is een opsomming van alle standaarden waaraan pakketten mogelijk moeten voldoen. Alle standaarden hebben een toelichting en indien aanwezig een toelichting op het compliancy-instrument\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle standaarden.",
"stackiq": "src/manifest.json page Standaarden /standaarden (index on @resolve:amef_register schema element, filter gemmaType=standaard, columns name/gemmaThema/gemmaStatus/url) and StandaardDetail /standaarden/:id with compliance claims per standard; menu entry Standards (order 50)",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"glpi": "source read at 11.0.9: no standards itemtype, grep -ril 'standaard\\|forum standaardisatie' src/ locales/glpi.pot returns nothing and the word standard in src/Appliance.php occurs only in addStandardTab (src/Appliance.php:100)."
}
},
@@ -1241,7 +1310,7 @@
"area": "compliance",
"name": "Attach a test report or other evidence to a compliance claim.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "partial",
@@ -1260,6 +1329,8 @@
"note": "Evidence can be attached as a file, a URL or a Nextcloud Files link on the compliance claim's page.",
"evidence": {
"stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.evidence (file, pdf/jpeg/png/doc, 10 MB), compliancy.url, compliancy.evidenceReference; src/manifest.json KompliantieDetail cm-files widget type integration integrationId files 'Evidence documents'",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Door de vakje achter de standaard aan te vinken voor Ondersteuning(gepland) en Compliancy, wordt de optie om een testrapport of auditrapport op te voeren geopend\" (read 2026-09-26). Reached on: Supplier login > productversie > Voeg extra standaarden toe.",
"glpi": "source read at 11.0.9: any document can be attached to an appliance through the Documents tab, src/Appliance.php:100 Document_Item tab and src/Document_Item.php:46, stored in install/mysql/glpi-empty.sql:2585 glpi_documents; there is no compliance claim to attach it to. Reached on: Management > Appliances > Documents tab."
}
},
@@ -1268,7 +1339,7 @@
"area": "compliance",
"name": "Tell a verified compliance claim apart from one the supplier only asserts.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "no",
@@ -1287,6 +1358,8 @@
"note": "The matrix separates claims with evidence from claims without, but 'verified' only means evidence is attached: no one reviews or approves the evidence, so a supplier-uploaded document counts as verified.",
"evidence": {
"stackiq": "src/utils/complianceMatrix.js:9-17 cell state verified = compliancy record with evidence (hasEvidence :107 checks evidence/evidenceReference/url), claimed = link without evidence; rendered by src/views/ComplianceMatrixView.vue",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C8: \"Gepubliceerde testrapporten voor een aantal standaarden die in de compliancy-monitor staan, worden sinds eind 2016 door VNG Realisatie gecontroleerd en daarna op status goedgekeurd of afgekeurd gezet\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketversies: facet \"Standaard met testrapport: Toon alleen pakketversies met compliancy aangetoond in een testrapport\" (read 2026-09-26). Reached on: Alle pakketversies > filter Standaard met testrapport; Compliancy monitor.",
"glpi": "source read at 11.0.9: no compliance claim model, grep -rli 'complian' over src/Appliance.php src/Software.php returns nothing; nothing to mark verified or claimed (src/Appliance.php:46 fields are inventory and management fields only)."
}
},
@@ -1295,10 +1368,10 @@
"area": "compliance",
"name": "See applications against chosen standards in one matrix, cell by cell.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1313,7 +1386,10 @@
"featureConfidence": "high",
"note": "A filter-first matrix of applications against chosen standard versions (or BIO measures), cell by cell with verified/claimed/none.",
"evidence": {
- "stackiq": "src/manifest.json ComplianceMatrix /compliance-matrix custom page -> src/customComponents.js ComplianceMatrixView -> src/views/ComplianceMatrixView.vue (modules x selected standard versions or BIO measures, src/utils/complianceMatrix.js:270 columns)"
+ "stackiq": "src/manifest.json ComplianceMatrix /compliance-matrix custom page -> src/customComponents.js ComplianceMatrixView -> src/views/ComplianceMatrixView.vue (modules x selected standard versions or BIO measures, src/utils/complianceMatrix.js:270 columns)",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/compliancy_monitor: per standard (e.g. \"Betalen en invorderen services 1.0\") a table of Leverancier, Pakketversie, Compliancy \"Ok\" or \"Niet ok\" (read 2026-09-26). Fixed per standard, not a matrix of chosen applications against chosen standards. Reached on: Homepage > Compliancy monitor.",
+ "glpi": "source read at 11.0.9: there are no standards in core (grep -rli 'standaard\\|forum standaardisatie' src/ locales/glpi.pot returns nothing), so no application by standard matrix; search output (src/Glpi/Search/Output/Spreadsheet.php) only tabulates item fields. The spreadsheet output is src/Glpi/Search/Output/Csv.php:38 and siblings."
}
},
{
@@ -1324,7 +1400,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1339,7 +1415,10 @@
"featureConfidence": "medium",
"note": "One action updates every module's standards from its compliance records, but only a Nextcloud admin can run it and it stops at 1000 compliance records.",
"evidence": {
- "stackiq": "appinfo/routes.php:275 POST /api/bulk-sync-standards -> lib/Controller/SettingsController.php:3598 (isAdmin check) -> lib/Service/ModuleComplianceService.php:527 bulkSyncModuleStandards (reads up to 1000 compliancy records and updates module standards); UI src/views/settings/sections/StatisticsOverview.vue:79 button -> src/modals/BulkSyncDialog.vue:321"
+ "stackiq": "appinfo/routes.php:275 POST /api/bulk-sync-standards -> lib/Controller/SettingsController.php:3598 (isAdmin check) -> lib/Service/ModuleComplianceService.php:527 bulkSyncModuleStandards (reads up to 1000 compliancy records and updates module standards); UI src/views/settings/sections/StatisticsOverview.vue:79 button -> src/modals/BulkSyncDialog.vue:321",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: only per-version copying is described (\"opvoer van een nieuwe versies mogelijk als kopie van een op te geven vorige versie\"); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no standards model exists (see comp-standards-register); massive actions (src/MassiveAction.php:666 Update) update item fields only."
}
},
{
@@ -1350,7 +1429,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1365,7 +1444,10 @@
"featureConfidence": "medium",
"note": "The page exists and shows the theme, but the level column is wired to a key that does not exist (bbnNiveau vs bbnLevel; level only shows on the detail page), and the BIO measures are not shipped, so someone has to type them in.",
"evidence": {
- "stackiq": "src/manifest.json BioMaatregelen /bio-maatregelen index (columns code,name,thema,bioVersion,bbnNiveau) and BioMaatregelDetail; register property is bbnLevel (lib/Settings/softwarecatalogus_register.json bioMeasure), so the bbnNiveau column is empty; no BIO catalogue is seeded (only 6 demo objects in lib/Settings/stackiq_mock_register.json)"
+ "stackiq": "src/manifest.json BioMaatregelen /bio-maatregelen index (columns code,name,thema,bioVersion,bbnNiveau) and BioMaatregelDetail; register property is bbnLevel (lib/Settings/softwarecatalogus_register.json bioMeasure), so the bbnNiveau column is empty; no BIO catalogue is seeded (only 6 demo objects in lib/Settings/stackiq_mock_register.json)",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: BIO measures are not in the catalogue docs; BBN views live on GEMMA Online per the news page; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/nieuws (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'iso 27001\\|27002' and grep -rwi 'bio' over src/ locales/glpi.pot return nothing; no security measure catalogue ships (menus at src/Html.php:1295 onwards list none)."
}
},
{
@@ -1376,7 +1458,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1391,7 +1473,10 @@
"featureConfidence": "medium",
"note": "You can record that an application meets a BIO measure, but there is no way to record that it does not meet one: the absence of a claim is the only negative, which cannot be told apart from 'not assessed'. The md-compliance column key 'bioMaatregel' also differs from the property bioMeasure.",
"evidence": {
- "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.bioMeasure links a module to a BIO measure; src/manifest.json ModuleDetail md-compliance lists claims incl. bioMaatregel column, BioMaatregelDetail bm-compliance lists modules per measure; compliancy has no status/met-not-met field"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.bioMeasure links a module to a BIO measure; src/manifest.json ModuleDetail md-compliance lists claims incl. bioMaatregel column, BioMaatregelDetail bm-compliance lists modules per measure; compliancy has no status/met-not-met field",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no BIO assessment per application is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no measure catalogue and no assessment itemtype; grep -rli 'iso 27001\\|27002' over src/ locales/glpi.pot returns nothing and Appliance tabs (src/Appliance.php:98 onwards) hold no assessment."
}
},
{
@@ -1402,7 +1487,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1417,7 +1502,10 @@
"featureConfidence": "low",
"note": "DPIA status, date, next review and document link are fields on the application and shown and filterable on the Applications pages. The scheduled 'dpia-review-overdue' notification is only a register declaration.",
"evidence": {
- "stackiq": "lib/Settings/softwarecatalogus_register.json module.dpiaStatus (enum not required/required/executed), dpiaDate, dpiaNextAssessment, dpiaDocumentRef; src/manifest.json ModuleDetail md-data includes the DPIA fields; Modules /modules quick filter 'Without DPIA (BBN2+)'"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json module.dpiaStatus (enum not required/required/executed), dpiaDate, dpiaNextAssessment, dpiaDocumentRef; src/manifest.json ModuleDetail md-data includes the DPIA fields; Modules /modules quick filter 'Without DPIA (BBN2+)'",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no DPIA field is described; the VWO addendum is a supplier-level processing agreement; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/leveranciers (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'dpia\\|impact assessment\\|gdpr' over src/ returns nothing, locales/glpi.pot:12792 'gdpr-tools' is only an icon name. The GDPR records plugin yild/gdprropa read at tag 1.0.3 has 'PIA required' and 'PIA status' (inc/record.class.php:459, :468) but declares GLPI 10 only, setup.php:56 max 10.99.99, so it does not run on 11.0.9."
}
},
{
@@ -1425,10 +1513,10 @@
"area": "compliance",
"name": "Check an application against the Forum Standaardisatie comply-or-explain list.",
"origin": "competitor",
- "vng-softwarecatalogus": "yes",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1441,8 +1529,10 @@
"providerHow": "read-from-code",
"note": "There is no list or check for the Forum Standaardisatie comply-or-explain list; only GEMMA standards imported with the model.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27556 'Standards Mapping' (2026-04-12): Map software to Forum Standaardisatie standards",
- "stackiq": "grep for forum standaardisatie / pas toe of leg uit / comply-or-explain in lib and src: no hits; standards come only from the GEMMA AMEF import (element gemmaType=standaard)"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/inkoopondersteuning%20standaarden: \"De verplichte standaarden zijn: ... de open standaarden die onder het pas-toe-of-leg-uit regime van de overheid binnen het werkingsgebied vallen\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: package version shows \"Verplichte standaarden ... Ondersteuning Compliancy Testrapport\" (read 2026-09-26). Comply-or-explain standards are mixed into the mandatory set, not shown as their own list. Reached on: Package page > Standaarden; Inkoopondersteuning.",
+ "stackiq": "grep for forum standaardisatie / pas toe of leg uit / comply-or-explain in lib and src: no hits; standards come only from the GEMMA AMEF import (element gemmaType=standaard)",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'standaard\\|forum standaardisatie\\|comply' over src/ locales/glpi.pot returns nothing relevant; no comply or explain list in core (Setup menu src/Html.php:1330 onwards)."
}
},
{
@@ -1450,10 +1540,10 @@
"area": "compliance",
"name": "Score the correctness and completeness of the register against a rule set.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1466,7 +1556,10 @@
"providerHow": "read-from-code",
"note": "No rule-based score of register correctness or completeness exists on any page.",
"evidence": {
- "stackiq": "grep for completeness/health score/quality score in lib and src: no hits; lib/Command/ReferencesAuditCommand.php:34 (occ stackiq:references:audit) only audits cross-app uuid references, it is not a scored rule set"
+ "stackiq": "grep for completeness/health score/quality score in lib and src: no hits; lib/Command/ReferencesAuditCommand.php:34 (occ stackiq:references:audit) only audits cross-app uuid references, it is not a scored rule set",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C7: automatic checks and \"Te corrigeren fouten ... Bijvoorbeeld over het ontbreken van pakketversies, of tegenstrijdigheid in de status van een pakketversie en vermelde datum distributie\" (read 2026-09-26); https://www.softwarecatalogus.nl/voortgang-verbeteren: star criteria for completeness (read 2026-09-26). Reached on: Supplier dashboard Te corrigeren fouten; Voortgang sterren.",
+ "glpi": "source read at 11.0.9: grep -ril 'completeness' over src/ templates/ locales/glpi.pot returns nothing and no rule set scores register quality; the rules engine (src/Glpi/Rules/, src/RuleCollection.php) assigns and imports data, it does not score it. The rules engine base is src/RuleCollection.php:48."
}
},
{
@@ -1477,7 +1570,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "partial",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1491,7 +1584,10 @@
"note": "Nothing sends questionnaires to suppliers or stores their answers.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders. | Rated partial because questionnaires collect portfolio data.",
- "stackiq": "grep for questionnaire/vragenlijst in lib and src: no hits; no questionnaire schema in lib/Settings/softwarecatalogus_register.json"
+ "stackiq": "grep for questionnaire/vragenlijst in lib and src: no hits; no questionnaire schema in lib/Settings/softwarecatalogus_register.json",
+ "topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no questionnaire to suppliers is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: native forms (src/Glpi/Form/Form.php:92) are filled by logged in or helpdesk users and only produce tickets, changes or problems (src/Glpi/Form/Destination/FormDestinationTicket.php:47); nothing sends a questionnaire to a supplier or stores answers on an appliance."
}
},
{
@@ -1502,7 +1598,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1517,8 +1613,10 @@
"featureConfidence": "medium",
"note": "A supplier in aanbod-beheerder creates modules and services on the index pages and publishes them by setting publicationDate in the form. The dedicated publish endpoint (PUT /api/publication/...) is not called by any page (src/utils/openDataProjection.js has no importer).",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48838 'Supplier product offering (aanbod) registration' (2026-07-23): ICT suppliers publish their product offering for the municipal market with global functionality descriptions. | docs, intelligence competitor_features#27555 'Vendor Registration' (2026-04-12): ICT providers register their software offerings",
- "stackiq": "src/manifest.json:592 Modules and :647 Diensten are FacetedCatalogIndexView over schema module/catalogService (CnIndexPage, showAdd default true); lib/Settings/softwarecatalogus_register.json:6779 module has provider + publicationDate (visible on form) and public read when publicationDate <= now or registeredBy Supplier"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Deze handleiding is bedoeld voor de leveranciers en legt uit hoe de leveranciers hun productportfolio kunnen aanvullen en beheren ... voeg pakket toe\" (read 2026-09-26). Reached on: Supplier login > Productportfolio.",
+ "stackiq": "src/manifest.json:592 Modules and :647 Diensten are FacetedCatalogIndexView over schema module/catalogService (CnIndexPage, showAdd default true); lib/Settings/softwarecatalogus_register.json:6779 module has provider + publicationDate (visible on form) and public read when publicationDate <= now or registeredBy Supplier",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: suppliers are records kept by the buying organisation, install/mysql/glpi-empty.sql:7067 glpi_suppliers, with no supplier login or offering page; profiles (src/Profile.php) cover internal users and the self-service helpdesk only."
}
},
{
@@ -1529,7 +1627,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1544,8 +1642,10 @@
"featureConfidence": "medium",
"note": "Live facet counts on reference component and standard narrow the module and service lists. Scope is whatever the RBAC read rules let the viewer see (published entries are public).",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27553 'ICT Market Orientation' (2026-04-12): Find and compare software from registered ICT providers",
- "stackiq": "lib/Service/FacetService.php:109 DIMENSIONS referenceComponent, standard, applicationService, domain for schemas module and catalogService (:102); src/views/FacetedCatalogIndexView.vue:108 CnFacetSidebar narrows CnIndexPage; route GET /api/facets/{schema} called from src/services/facets.js"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Ik ben op zoek naar een nieuw pakket voor referentiecomponent voor BAG-administratie\" and standards filters combine (read 2026-09-26); https://www.softwarecatalogus.nl/pakketten: facets Referentiecomponent and Standaard (read 2026-09-26). Reached on: Alle pakketten > filters.",
+ "stackiq": "lib/Service/FacetService.php:109 DIMENSIONS referenceComponent, standard, applicationService, domain for schemas module and catalogService (:102); src/views/FacetedCatalogIndexView.vue:108 CnFacetSidebar narrows CnIndexPage; route GET /api/facets/{schema} called from src/services/facets.js",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: search covers only the organisation's own records (src/Glpi/Search/SearchEngine.php); there is no market wide catalogue and no reference component or standard to filter on (grep -ril 'gemma\\|reference component' src/ returns nothing). The marketplace (src/Glpi/Marketplace/) lists GLPI plugins, not software for a task. The search engine is src/Glpi/Search/SearchEngine.php:101; the marketplace is src/Glpi/Marketplace/Controller.php:64."
}
},
{
@@ -1553,10 +1653,10 @@
"area": "market",
"name": "Browse all organisations that offer applications or services, with search and filters.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1569,7 +1669,10 @@
"providerHow": "read-from-code",
"note": "The Organisations index lists organisations with search, a type facet and a status filter. There is no filter for 'offers at least one product'; type Supplier is the proxy.",
"evidence": {
- "stackiq": "src/manifest.json:386 Organisaties type:index over schema organization with status filter and OrganisatieCard; register :2022 organization.type is facetable (Municipality/Supplier/Collaboration/Community); public read of Active suppliers in organization authorization (:2467)"
+ "stackiq": "src/manifest.json:386 Organisaties type:index over schema organization with status filter and OrganisatieCard; register :2022 organization.type is facetable (Municipality/Supplier/Collaboration/Community); public read of Active suppliers in organization authorization (:2467)",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/leveranciers: \"Leveranciers ... Zoek in leveranciers ... 354 resultaten gevonden\", filter \"Met ondertekend addendum\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle leveranciers.",
+ "glpi": "source read at 11.0.9: src/Supplier.php:46 Supplier list under Management (src/Html.php:1298) with search, filters and a supplier type (install/mysql/glpi-empty.sql:7072 suppliertypes_id), but it holds only the suppliers this organisation entered, not all organisations offering to government. Reached on: Management > Suppliers (front/supplier.php)."
}
},
{
@@ -1580,7 +1683,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1593,8 +1696,10 @@
"providerHow": "read-from-code",
"note": "Nothing lets an organisation find or contact other organisations using the same product.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27557 'Contact & Collaboration' (2026-04-12): Connect with municipalities using similar products",
- "stackiq": "Looked in src/components, src/views and lib/Controller for any contact or messaging between organisations sharing a module: none. Usage read rules (register :3137) hide other organisations' usages from municipalities."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle gemeenten ... inclusief contactgegevens van gemeenten ... U kunt contact onderhouden met deze gemeenten\" (read 2026-09-26). Reached on: Inlogmenu > Alle gemeenten.",
+ "stackiq": "Looked in src/components, src/views and lib/Controller for any contact or messaging between organisations sharing a module: none. Usage read rules (register :3137) hide other organisations' usages from municipalities.",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: each GLPI instance holds one organisation's data (entities are internal subdivisions, src/Entity.php), so there is no view of other organisations using the same product; grep -rli 'peer' src/*.php matches only relation and network code such as src/CommonDBConnexity.php, no peer organisation feature."
}
},
{
@@ -1605,7 +1710,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1620,8 +1725,10 @@
"featureConfidence": "medium",
"note": "A supplier can register a future version with status 'in development' and planned dates, which reads as a crude release plan. There is no roadmap view or declared roadmap; the overlay marks maintenance-and-supplier-roadmap as 'soon'.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48839 'Product roadmap / planning declaration' (2026-07-23): Suppliers declare product planning and release roadmap per product.",
- "stackiq": "register :7651 moduleVersion with status enum in development/in use/end of support/withdrawn and dateInDevelopment/dateInUse/dateEndSupport, read public; src/manifest.json:915 Moduleversies index + ModuleversieDetail"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle pakketversies en planningen ... gelijk zichtbaar de planning van de diverse pakketversies\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketversies: facet \"Status planning ... Filter op in ontwikkeling en zie de distributie planningsdata\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle pakketversies en planningen.",
+ "stackiq": "register :7651 moduleVersion with status enum in development/in use/end of support/withdrawn and dateInDevelopment/dateInUse/dateEndSupport, read public; src/manifest.json:915 Moduleversies index + ModuleversieDetail",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: suppliers (install/mysql/glpi-empty.sql:7067 glpi_suppliers) carry address and contact fields only, and software versions (install/mysql/glpi-empty.sql:6900) carry no planned release date; grep -rli 'roadmap' src/*.php returns nothing."
}
},
{
@@ -1632,7 +1739,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1647,7 +1754,10 @@
"featureConfidence": "high",
"note": "Logged-in users write a rated review from the application page. Services have no detail page, so only applications can be reviewed there.",
"evidence": {
- "stackiq": "src/manifest.json:514 ModuleDetail bodyWidget ReviewsPanel; src/components/reviews/ReviewsPanel.vue:63 opens SubmitReviewModal; POST /api/reviews -> lib/Service/ReviewService.php:232 stamps author and forces status pending; rating 1..10 in software-review schema (:3961)"
+ "stackiq": "src/manifest.json:514 ModuleDetail bodyWidget ReviewsPanel; src/components/reviews/ReviewsPanel.vue:63 opens SubmitReviewModal; POST /api/reviews -> lib/Service/ReviewService.php:232 stamps author and forces status pending; rating 1..10 in software-review schema (:3961)",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no reviews are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no product review model; satisfaction surveys rate ticket handling only (src/CommonITILSatisfaction.php) and knowledge base comments (src/KnowbaseItem_Comment.php) carry no rating. Ticket satisfaction is src/CommonITILSatisfaction.php:43 and knowledge base comments src/KnowbaseItem_Comment.php:43."
}
},
{
@@ -1658,7 +1768,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1673,7 +1783,10 @@
"featureConfidence": "high",
"note": "The application page shows the approved-only average and count. Services have no detail page, so the aggregate is not shown for them.",
"evidence": {
- "stackiq": "lib/Service/ReviewAggregateService.php:51 approved-only average + count; GET /api/reviews/aggregate (PublicPage) called from src/utils/reviewAggregate.js imported by src/components/reviews/ReviewsPanel.vue"
+ "stackiq": "lib/Service/ReviewAggregateService.php:51 approved-only average + count; GET /api/reviews/aggregate (PublicPage) called from src/utils/reviewAggregate.js imported by src/components/reviews/ReviewsPanel.vue",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no ratings are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: with no product reviews there is no average rating; the only averages are ticket satisfaction statistics (src/CommonITILSatisfaction.php). Ticket satisfaction is src/CommonITILSatisfaction.php:43."
}
},
{
@@ -1684,7 +1797,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1697,7 +1810,10 @@
"providerHow": "read-from-code",
"note": "Each product can point at its own contact person of the supplier through the form. The application page's data widget names the old Dutch keys, so the product's contact person (and its descriptions) do not show there; the same stale keys are on SuiteDetail (src/manifest.json:683).",
"evidence": {
- "stackiq": "register :6856 module.contactPerson -> contactPerson with x-relation-filter organization = @object.provider; catalogService and suite also carry contactPerson; src/manifest.json:500 ModuleDetail md-data include lists 'contactpersoon', 'beschrijvingKort', 'beschrijvingLang', which are not module properties (renamed to contactPerson/shortDescription/longDescription)"
+ "stackiq": "register :6856 module.contactPerson -> contactPerson with x-relation-filter organization = @object.provider; catalogService and suite also carry contactPerson; src/manifest.json:500 ModuleDetail md-data include lists 'contactpersoon', 'beschrijvingKort', 'beschrijvingLang', which are not module properties (renamed to contactPerson/shortDescription/longDescription)",
+ "topdesk": "unknown: supplier contacts are registered per supplier (\"Registering a supplier contact\"); contacts per product are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: the docs name one contact per supplier (\"Bij elke leverancier is een contactpersoon opgevoerd\"); whether a product can carry its own is not stated; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30402 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: contacts link to a supplier as a whole, src/Contact_Supplier.php:39 (install/mysql/glpi-empty.sql:1429 glpi_contacts_suppliers), not to a product; per application there is only the free text contact field on an appliance (src/Appliance.php:214) and the user or technician in charge. Reached on: Management > Suppliers > Contacts tab; Appliance contact field."
}
},
{
@@ -1705,10 +1821,10 @@
"area": "market",
"name": "Keep one record per supplier that every product and contract points to.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "yes",
"stackiq": "yes",
"built": {
@@ -1722,8 +1838,10 @@
"note": "One organisation record is the supplier; products reference it and the detail page lists them. A contract reaches the supplier only through its service, not by its own field.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because Provider fact sheet.",
- "topdesk": "docs, intelligence competitor_features#48932 'Contract & vendor management' (2026-07-23): Track supplier contracts and operational agreements.",
- "stackiq": "register :2022 organization (one record, type Supplier); module.provider (:6921) and catalogService.provider (:3762) are $ref organization; catalogContract points at service (+usage), register :3252; OrganisatieDetail src/manifest.json:403 lists the supplier's services and applications"
+ "topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier ... The Supplier Card has been created\" and \"Registering a supplier contact\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Create a new preliminary contract or preliminary supplier contract\" (read 2026-09-26). Reached on: Supporting Files > New > Supplier.",
+ "stackiq": "register :2022 organization (one record, type Supplier); module.provider (:6921) and catalogService.provider (:3762) are $ref organization; catalogContract points at service (+usage), register :3252; OrganisatieDetail src/manifest.json:403 lists the supplier's services and applications",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"De verbinding met de leveranciersgegevens garandeert juiste schrijfwijzes van leveranciers- en pakketnamen en juiste versienummering\" (read 2026-09-26); https://www.softwarecatalogus.nl/leveranciers: one record per supplier with contact and addenda (read 2026-09-26). There are no contracts to point to it. Reached on: Alle leveranciers > supplier page.",
+ "glpi": "source read at 11.0.9: one Supplier record (src/Supplier.php:46, install/mysql/glpi-empty.sql:7067) is referenced by contracts through install/mysql/glpi-empty.sql:1550 glpi_contracts_suppliers and by the financial record of any item through install/mysql/glpi-empty.sql:3263 glpi_infocoms.suppliers_id. Reached on: Management > Suppliers."
}
},
{
@@ -1731,10 +1849,10 @@
"area": "lifecycle",
"name": "See the lifecycle phase of each application in use: planned, in use or being phased out.",
"origin": "own-code",
- "vng-softwarecatalogus": "no",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "partial",
"stackiq": "yes",
"built": {
@@ -1749,10 +1867,11 @@
"featureConfidence": "high",
"note": "Pick an organisation and its applications in use are grouped by derived lifecycle phase. The usage records themselves cannot be created or edited on any stackiq page (see life-planned-replacement).",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: A1: \"Bij de oude versie kan de status gewijzigd worden in uit-te-faseren / uitgefaseerd\" (read 2026-09-26); https://www.softwarecatalogus.nl/voortgang-verbeteren: \"pakketversies hebben de status Gepland óf Uit te faseren\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30355: \"Vul onder Planning bij Status in gebruik in\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Planning Status.",
"sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
- "topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | Rated partial because replacement timelines on assets.",
- "stackiq": "src/manifest.json LifecycleRoadmap /portfolio-roadmap custom page -> src/views/LifecycleRoadmapView.vue:55 groups the selected organisation's usages by phase, derived from usage dates by src/utils/lifecyclePhase.js derivePhase (:408); usage.status enum Acquisition/Planned/In production/To be phased out/Phased out in lib/Settings/softwarecatalogus_register.json"
+ "topdesk": "https://docs.topdesk.com/en/managing-disruptions-in-your-asset-management-process.html: built-in \"operational/impacted status for assets\" (read 2026-09-26); lifecycle phases need a self-defined drop-down field (https://docs.topdesk.com/en/creating-new-fields.html). No planned, in use, phase-out model ships. Reached on: Asset card > General widget.",
+ "stackiq": "src/manifest.json LifecycleRoadmap /portfolio-roadmap custom page -> src/views/LifecycleRoadmapView.vue:55 groups the selected organisation's usages by phase, derived from usage dates by src/utils/lifecyclePhase.js derivePhase (:408); usage.status enum Acquisition/Planned/In production/To be phased out/Phased out in lib/Settings/softwarecatalogus_register.json",
+ "glpi": "source read at 11.0.9: appliances carry a status, install/mysql/glpi-empty.sql:8950 glpi_appliances.states_id and src/Appliance.php:350 search option Status, whose values are an admin defined tree dropdown src/State.php:45 (install/mysql/glpi-empty.sql:7027 glpi_states), so phases such as planned, in use and being phased out are set up and filtered on. Reached on: Management > Appliances, Status field; Setup > Dropdowns > Statuses of items."
}
},
{
@@ -1760,10 +1879,10 @@
"area": "lifecycle",
"name": "See per organisation which applications are replaced when, on a roadmap.",
"origin": "own-code",
- "vng-softwarecatalogus": "no",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -1778,9 +1897,11 @@
"featureConfidence": "high",
"note": "Per organisation it shows which applications are phased out or replaced and when; it is a grouped list ordered by urgency rather than a timeline chart.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"de uit te faseren applicaties van die status worden voorzien inclusief datum. Zo ontstaat inzicht in het totale huidige- en doel-landschap in 1 overzicht\" (read 2026-09-26). Dates per status, no roadmap view described. Reached on: Mijn softwarecatalogus > Pakketten > Planning.",
"sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
- "stackiq": "src/views/LifecycleRoadmapView.vue:28 organisation select, :55 phase groups, :96-110 phase-out date, planned replacement and link to the replacing module (:400 plannedReplacement, :423 plannedReplacementDate), ordered by nearest urgency (:428)"
+ "stackiq": "src/views/LifecycleRoadmapView.vue:28 organisation select, :55 phase groups, :96-110 phase-out date, planned replacement and link to the replacing module (:400 plannedReplacement, :423 plannedReplacementDate), ordered by nearest urgency (:428)",
+ "topdesk": "unknown: no replacement roadmap is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: replacements can be planned as projects linked to the appliance, src/Appliance.php:108 Item_Project tab (src/Item_Project.php:45) and src/Project.php:50 Project with Kanban; the Gantt view is the separate gantt plugin (src/Project.php:599 checks isActivated('gantt')). No per organisation application roadmap view exists. Reached on: Tools > Projects, Appliance > Projects tab."
}
},
{
@@ -1788,10 +1909,10 @@
"area": "lifecycle",
"name": "Find applications that overlap because they fulfil the same reference component.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1805,7 +1926,10 @@
"note": "Nothing finds applications in your landscape that fulfil the same reference component; the Reports card promises 'overlapping' software but the report does not compute it.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | Rated partial because rationalisation through capability map.",
- "stackiq": "grep for overlap/redundant in lib and src finds only code comments and the Reports card description (src/manifest.json:1031 'Overlapping and ageing software'); lib/Service/PortfolioReportService.php computes TIME quadrants, EOL exposure, cloud share and cost, no grouping by reference component; the /modules facet counts modules per reference component across the whole catalogue, not your landscape"
+ "stackiq": "grep for overlap/redundant in lib and src finds only code comments and the Reports card description (src/manifest.json:1031 'Overlapping and ageing software'); lib/Service/PortfolioReportService.php computes TIME quadrants, EOL exposure, cloud share and cost, no grouping by reference component; the /modules facet counts modules per reference component across the whole catalogue, not your landscape",
+ "topdesk": "unknown: no functional classification to detect overlap is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tile \"Referentiecomponenten met meerdere pakketten: Deze tegel signaleert dat er meer dan 1 pakket(versie) bij eenzelfde referentiecomponent in productie is\" (read 2026-09-26). Reached on: Dashboard tile Referentiecomponenten met meerdere pakketten.",
+ "glpi": "source read at 11.0.9: no reference component model to detect overlap on, grep -rli 'reference component\\|gemma' over src/ locales/glpi.pot returns nothing; appliances only carry a free type dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id)."
}
},
{
@@ -1813,10 +1937,10 @@
"area": "lifecycle",
"name": "Open a report of overlapping and ageing software for rationalisation.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1830,7 +1954,10 @@
"note": "The report covers ageing software (EOL exposure) with TIME quadrants, cost and a CSV export, but not overlap, even though its card says 'overlapping and ageing'.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R). | docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
- "stackiq": "appinfo/routes.php:303 GET /api/portfolio-report -> lib/Controller/PortfolioReportController.php -> lib/Service/PortfolioReportService.php + PortfolioReportDerivation.php; UI src/views/organisaties/PortfolioReport.vue (TIME chart :112, quadrant summary :126 with EOL exposure/cloud/cost, rows :176, CSV export :50)"
+ "stackiq": "appinfo/routes.php:303 GET /api/portfolio-report -> lib/Controller/PortfolioReportController.php -> lib/Service/PortfolioReportService.php + PortfolioReportDerivation.php; UI src/views/organisaties/PortfolioReport.vue (TIME chart :112, quadrant summary :126 with EOL exposure/cloud/cost, rows :176, CSV export :50)",
+ "topdesk": "unknown: no rationalisation report is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Referentiecomponenten met meerdere pakketten ... per referentiecomponent aan welke pakketversies daaraan gekoppeld zijn\" (read 2026-09-26). Overlap only, ageing not covered. Reached on: Dashboard tile.",
+ "glpi": "source read at 11.0.9: the built in report list src/Report.php:77 to src/Report.php:111 holds default, by contract, by year, financial, network, loan and status reports; none covers overlapping or ageing software."
}
},
{
@@ -1838,10 +1965,10 @@
"area": "lifecycle",
"name": "Record which version of an application your organisation currently runs.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -1856,7 +1983,10 @@
"featureConfidence": "low",
"note": "The version an organisation runs is a field on its usage and drives the EOL badges, but no stackiq page lets the organisation set or change it.",
"evidence": {
- "stackiq": "lib/Settings/softwarecatalogus_register.json usage.moduleVersion ($ref moduleVersion); read by src/views/LifecycleRoadmapView.vue:397 for EOL state; ModuleversieDetail mv-related shows related usages; no usage create/edit page in src/manifest.json"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json usage.moduleVersion ($ref moduleVersion); read by src/views/LifecycleRoadmapView.vue:397 for EOL state; ModuleversieDetail mv-related shows related usages; no usage create/edit page in src/manifest.json",
+ "topdesk": "unknown: versions in use are only possible as a self-defined field; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Pakketversie - selecteer de versie die in gebruik is\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen.",
+ "glpi": "source read at 11.0.9: src/Item_SoftwareVersion.php:39 records which software version is installed on which item (install/mysql/glpi-empty.sql:1064 glpi_items_softwareversions with date_install at :1074), filled by hand or by native inventory, and listed on the Software Installations tab (src/Software.php:129). Reached on: Assets > Software > Installations tab."
}
},
{
@@ -1864,10 +1994,10 @@
"area": "lifecycle",
"name": "Get notified when a supplier publishes a new version of an application you use.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1882,7 +2012,10 @@
"featureConfidence": "medium",
"note": "The only rule is a register declaration, and it addresses the version's own managers and catalogue admins, not the organisations that use the application, so even if OpenRegister dispatches it a user of the application is not told.",
"evidence": {
- "stackiq": "lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications module-version-published (trigger created, recipients object-acl manage + group software-catalog-admins); no notification code in lib (no INotificationManager use)"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications module-version-published (trigger created, recipients object-acl manage + group software-catalog-admins); no notification code in lib (no INotificationManager use)",
+ "topdesk": "unknown: no supplier version feed is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/suggesties_overnemen: \"Wanneer een leverancier een pakketversie registreert kan deze een suggestie versturen naar de gemeenten en samenwerkingen die dit pakket afnemen\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C2: \"Via de notificatiefunctie krijgt u een signaal zodra het versienummer is toegevoegd\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Suggesties; Inbox.",
+ "glpi": "source read at 11.0.9: GLPI has no feed of supplier releases; software versions appear only when entered or inventoried (src/SoftwareVersion.php:42), and notification events for software are licence expiry only (src/NotificationTargetSoftwareLicense.php)."
}
},
{
@@ -1893,7 +2026,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1907,7 +2040,10 @@
"note": "You could register a database as its own 'System software' module and feed its EOL, but nothing ties it to the applications that depend on it; SBOM components carry no lifecycle.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
- "stackiq": "lib/Settings/softwarecatalogus_register.json sbomComponent has name/version/purl/licenses/type/hashes/bomRef/vexCveIds, no lifecycle or EOL field; the EOL feed (lib/Service/EolSyncService.php:290) only stamps versions of modules with eolProductSlug; no relation from an application to the platform it runs on"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json sbomComponent has name/version/purl/licenses/type/hashes/bomRef/vexCveIds, no lifecycle or EOL field; the EOL feed (lib/Service/EolSyncService.php:290) only stamps versions of modules with eolProductSlug; no relation from an application to the platform it runs on",
+ "topdesk": "unknown: no technology lifecycle is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: technologies per version are recorded (\"Pakketversie is beschikbaar voor één of meerdere technologien; databases, OS, SAAS\") but no lifecycle for them is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: underlying technology is held as items (database instances src/DatabaseInstance.php, operating systems, software) and each can carry a financial record with warranty and decommission date, install/mysql/glpi-empty.sql:3282 glpi_infocoms.decommission_date; there is no end of support date or lifecycle feed (grep -i 'end_of_support' install/mysql/glpi-empty.sql returns nothing). Reached on: any item > Management tab (Infocom)."
}
},
{
@@ -1918,7 +2054,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -1932,7 +2068,10 @@
"note": "Strategic goals are not modelled.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#27466 'Strategy Alignment' (2026-04-12): Connect architecture to strategic objectives",
- "stackiq": "no goal/strategy schema among the 20 in lib/Settings/softwarecatalogus_register.json; grep for strateg/doel in src/manifest.json: none"
+ "stackiq": "no goal/strategy schema among the 20 in lib/Settings/softwarecatalogus_register.json; grep for strateg/doel in src/manifest.json: none",
+ "topdesk": "unknown: no strategic goals are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no strategic goals are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -i 'strategic\\|goal\\|objective' over src/Appliance.php and src/Project.php returns nothing; no goal itemtype exists and the Appliance tabs (src/Appliance.php:98 onwards) link items, contracts, documents, tickets and projects only."
}
},
{
@@ -1943,8 +2082,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "yes",
"stackiq": "no",
"built": {
"state": "specified",
@@ -1958,7 +2097,10 @@
"featureConfidence": "high",
"note": "Listed as 'soon' in the feature overlay; nothing is built.",
"evidence": {
- "stackiq": "openspec/features.overlay.json maintenance-and-supplier-roadmap status 'soon'; no maintenance schema in lib/Settings/softwarecatalogus_register.json and no page in src/manifest.json"
+ "stackiq": "openspec/features.overlay.json maintenance-and-supplier-roadmap status 'soon'; no maintenance schema in lib/Settings/softwarecatalogus_register.json and no page in src/manifest.json",
+ "topdesk": "https://docs.topdesk.com/en/operations-management.html: \"In TOPdesk you can easily schedule operational activities in the user-friendly planner. If you wish to schedule a recurring activity, you can use a series\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: assets can be linked to \"Operational Activity\" cards (read 2026-09-26). Reached on: Modules > Operations Management > Planner.",
+ "vng-softwarecatalogus": "unknown: no maintenance announcements are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no maintenance window on an item ('Maintenance mode' in locales/glpi.pot:7534 is GLPI's own downtime switch); planned work is a change linked to the appliance, src/Appliance.php:107 Change_Item tab, with planned tasks carrying begin and end (install/mysql/glpi-empty.sql:792 glpi_changetasks, :799 begin, :800 end) shown in the planning. Reached on: Appliance > Changes tab; Assistance > Planning."
}
},
{
@@ -1969,8 +2111,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "yes",
"stackiq": "partial",
"built": {
"state": "built",
@@ -1984,7 +2126,10 @@
"featureConfidence": "high",
"note": "A daily job moves Active contracts past their end date to Expired on its own. There is no 'expiring' state in the enum, so the middle step of the row does not exist.",
"evidence": {
- "stackiq": "lib/Service/ContractStatusService.php:77 shouldExpire and :114 expirePastContracts set Active -> Expired when endDate < now; lib/BackgroundJob/ContractStatusJob.php:57 daily, registered in appinfo/info.xml:99"
+ "stackiq": "lib/Service/ContractStatusService.php:77 shouldExpire and :114 expirePastContracts set Active -> Expired when endDate < now; lib/BackgroundJob/ContractStatusJob.php:57 daily, registered in appinfo/info.xml:99",
+ "topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Status: Configurable drop-down showing the contract's lifecycle status, e.g. draft, active ... Reminder date\" (read 2026-09-26); https://docs.topdesk.com/en/terminating-a-contract.html: \"The contract will terminate once the end date passes\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM.",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: contract status is a manual dropdown (install/mysql/glpi-empty.sql:1512 glpi_contracts.states_id); expiry is computed, src/Contract.php:654 virtual 'Expiration' column from begin date, duration and renewal, and src/Contract.php:1092 cronContract sends end and notice alerts, but the status itself never moves by itself. Reached on: Management > Contracts list, Expiration column."
}
},
{
@@ -1995,8 +2140,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "yes",
"stackiq": "yes",
"built": {
"state": "built",
@@ -2011,7 +2156,10 @@
"featureConfidence": "high",
"note": "An expired contract can be raised for renewal as a decidiq decision and the outcome shows on the contract's approval panel. It needs the decidiq app installed; without it the panel hides the action.",
"evidence": {
- "stackiq": "src/components/contracts/ContractApprovalPanel.vue:183 canSubmitRenewal for status Expired; POST /api/contracts/{uuid}/approval/renewal -> ContractApprovalService.php:254 with decisionType contract-renewal; lib/EventListener/DecisionConcludedListener.php projects the outcome (approvalState, status Active) via DECISION_CONCLUDED_EVENTS registered in lib/AppInfo/Application.php:830"
+ "stackiq": "src/components/contracts/ContractApprovalPanel.vue:183 canSubmitRenewal for status Expired; POST /api/contracts/{uuid}/approval/renewal -> ContractApprovalService.php:254 with decisionType contract-renewal; lib/EventListener/DecisionConcludedListener.php projects the outcome (approvalState, status Active) via DECISION_CONCLUDED_EVENTS registered in lib/AppInfo/Application.php:830",
+ "topdesk": "https://docs.topdesk.com/en/extending-a-contract.html: \"Under Create , select Extend contract ... The contract is now a preliminary contract ... Click Validate Contract\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Sequence Number ... goes up by 1 each time the contract is extended ... so you can trace the contract's extension history\" (read 2026-09-26). Reached on: Contract card > Create > Extend contract.",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: src/Contract.php:60 to :62 renewal kinds never, tacit and express, with the renewal computation in the alert cron (src/Contract.php:1293); there is no renewal decision record or outcome, only the contract's renewal setting and an optional approval through a change. Reached on: Management > Contracts, Renewal field."
}
},
{
@@ -2023,7 +2171,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "no",
"built": {
"state": "none",
@@ -2037,8 +2185,10 @@
"featureConfidence": "medium",
"note": "The application page has no contracts list, and a contract links to a usage and a service rather than the application, so there is no path from an application to its contracts in the UI.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets. | Rated yes because contracts tracked against assets.",
- "stackiq": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it"
+ "glpi": "source read at 11.0.9: src/Appliance.php:99 and src/Software.php:131 add the Contract_Item tab (src/Contract_Item.php:43, install/mysql/glpi-empty.sql:1536 glpi_contracts_items) listing every contract of the application. Reached on: Management > Appliances > Contracts tab.",
+ "stackiq": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it",
+ "topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: assets link to \"Service cards\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"On the Services tab, link the services that apply to this contract\" (read 2026-09-26). Contract to asset runs through the service. Reached on: Contract > Services tab > Service > Links > Assets.",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
}
},
{
@@ -2050,7 +2200,7 @@
"sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "yes",
"built": {
"state": "built",
@@ -2065,8 +2215,10 @@
"note": "The portfolio report sums annualised contract cost per organisation and TIME quadrant, and the license posture page per vendor. The Dashboard only counts contracts.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS cost.",
- "glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts | docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets.",
- "stackiq": "lib/Service/PortfolioReportDerivation.php:163 annualisedCost (Monthly x12, Annually x1, One-off separate); lib/Service/PortfolioReportService.php:337 sumContractCost per quadrant; src/views/organisaties/PortfolioReport.vue:167 and :248 show annualised cost; src/utils/contractCost.js:111 totalAnnualisedCost used by src/views/LicensePostureView.vue per vendor"
+ "glpi": "source read at 11.0.9: contract costs have a period and a budget, install/mysql/glpi-empty.sql:1458 glpi_contractcosts with begin_date, end_date, cost and budgets_id; the contract list sums them in the 'Total cost' column (src/Contract.php:773) and a budget with a period shows spend per entity and type (src/Budget.php:537 showValuesByEntity). Reached on: Management > Contracts (Total cost column); Management > Budgets.",
+ "stackiq": "lib/Service/PortfolioReportDerivation.php:163 annualisedCost (Monthly x12, Annually x1, One-off separate); lib/Service/PortfolioReportService.php:337 sumContractCost per quadrant; src/views/organisaties/PortfolioReport.vue:167 and :248 show annualised cost; src/utils/contractCost.js:111 totalAnnualisedCost used by src/views/LicensePostureView.vue per vendor",
+ "topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Costs (Services) ... Total internal cost, based on the service levels linked\" (read 2026-09-26); https://docs.topdesk.com/en/obtain-insights-with-asset-type-report.html: \"do you need an overview of the total costs of new assets? Use the Asset Type Report\" (read 2026-09-26). Reached on: Contract card > Financial; Asset Type Report.",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
}
},
{
@@ -2074,7 +2226,7 @@
"area": "contracts",
"name": "Record the licence model of an application, such as open source, per user or per organisation.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
@@ -2092,8 +2244,10 @@
"featureConfidence": "medium",
"note": "An application records open versus closed source and which open-source licence. There is no licence metric such as per user, per organisation or per seat.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48901 'License management' (2026-07-23): Track license entitlements, compliance and expirations.",
- "stackiq": "register :6937 module.licentietype enum Closed source/Open source and module.licence (five open-source licence names); catalogContract.contractType enum SLA/Licence/Maintenance (:3341)"
+ "glpi": "source read at 11.0.9: each licence has a type, install/mysql/glpi-empty.sql:6775 glpi_softwarelicenses.softwarelicensetypes_id, an admin editable dropdown seeded with types such as OEM (install/empty_data.php:9294). Reached on: Management > Licenses (front/softwarelicense.php), Type field.",
+ "stackiq": "register :6937 module.licentietype enum Closed source/Open source and module.licence (five open-source licence names); catalogContract.contractType enum SLA/Licence/Maintenance (:3341)",
+ "topdesk": "unknown: licence cards hold number, code, purchase and expiration date; a licence model is only possible as a self-defined field; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/nieuws: \"is er de leverancier Open Source Pakketten aangemaakt. Onder deze leverancier staat nu een aantal veelgebruikte open source pakketten geregistreerd\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: Archi listed under supplier \"Open Source pakketten\", version \"Open source\" (read 2026-09-26). Other licence models are not recorded. Reached on: Alle pakketten > Leverancier Open Source pakketten."
}
},
{
@@ -2104,7 +2258,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -2117,7 +2271,10 @@
"providerHow": "read-from-code",
"note": "The page shows the open-source share of the running portfolio with per-vendor and per-organisation breakdowns, computed at read time.",
"evidence": {
- "stackiq": "src/views/LicensePostureView.vue:11 open-source vs closed-source share weighted by in-production usage, :64 per-vendor rollup, per-organisation open-source-first report; derived in src/utils/licensePosture.js"
+ "stackiq": "src/views/LicensePostureView.vue:11 open-source vs closed-source share weighted by in-production usage, :64 per-vendor rollup, per-organisation open-source-first report; derived in src/utils/licensePosture.js",
+ "topdesk": "unknown: no portfolio licence posture is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: licences can be listed and filtered by type in search (install/mysql/glpi-empty.sql:6775 softwarelicensetypes_id), but the dashboard's per type charts cover asset types and Software only (src/Glpi/Dashboard/Grid.php:1452), not licences, and no portfolio share view exists. Reached on: Management > Licenses, filtered by type."
}
},
{
@@ -2129,7 +2286,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "no",
"built": {
"state": "none",
@@ -2143,8 +2300,10 @@
"featureConfidence": "high",
"note": "No field records licences bought or in use. The overlay lists license-and-seat-tracking as 'soon'.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48901 'License management' (2026-07-23): Track license entitlements, compliance and expirations. | docs, intelligence competitor_features#3270 'License Management' (2026-03-28): Track software licenses, compliance, and expiration",
- "stackiq": "grep for seat/licence count across lib/, src/ and the register finds no seat or quantity field on catalogContract (:3252), module or usage"
+ "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:6774 glpi_softwarelicenses.number is the bought quantity; src/SoftwareLicense.php:158 computeValidityIndicator compares it with assigned items (Item_SoftwareLicense::countForLicense) and flags over use in red (src/SoftwareLicense.php:1030), with allow_overquota at install/mysql/glpi-empty.sql:6797. Reached on: Assets > Software > Licenses tab.",
+ "stackiq": "grep for seat/licence count across lib/, src/ and the register finds no seat or quantity field on catalogContract (:3252), module or usage",
+ "topdesk": "https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"add fields to fill the number of licences you have purchased and still have left ... the Relationship grid widget on the software cards will display details about the licences\" (read 2026-09-26). Reached on: Asset Management > software card > Relationship grid.",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
}
},
{
@@ -2155,8 +2314,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "partial",
"stackiq": "no",
"built": {
"state": "none",
@@ -2168,7 +2327,10 @@
"providerHow": "read-from-code",
"note": "Without seat or consumption data there is nothing to compute an effective licence position from.",
"evidence": {
- "stackiq": "No entitlement or consumption fields exist (see ctr-seat-count); no service computes a licence position in lib/Service/"
+ "stackiq": "No entitlement or consumption fields exist (see ctr-seat-count); no service computes a licence position in lib/Service/",
+ "topdesk": "https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"Knowing which software tools are used by whom ... the legal implications of using a tool without being licensed\" (read 2026-09-26). Entitlement against linked users, no measured consumption. Reached on: Asset Management > licence cards.",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: entitlement is compared with licence assignments (src/SoftwareLicense.php:158 computeValidityIndicator), while measured installations are counted separately (src/Item_SoftwareVersion.php:39); core has no computed effective licence position report reconciling the two for an audit. Reached on: Assets > Software > Licenses and Installations tabs."
}
},
{
@@ -2180,7 +2342,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "no",
"built": {
"state": "none",
@@ -2192,8 +2354,10 @@
"providerHow": "read-from-code",
"note": "Contracts carry a cost and a period, but there is no budget to charge them against.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145790 'C-reporting-1 A budget the case costs are charged against, with a period.': glpi: Budgets (Management, Budgets, front/budget.php) Lane findings: D-glpi-37. | Rated yes because budgets, source-read 2026-09-14.",
- "stackiq": "grep for budget across lib/, src/ and lib/Settings finds no budget schema or field; catalogContract has cost + costPeriod only (register :3363)"
+ "glpi": "source read at 11.0.9: src/Budget.php:46 Budget with a period and value (install/mysql/glpi-empty.sql:306 begin_date, :307 end_date, :308 value); contract costs (install/mysql/glpi-empty.sql:1466 budgets_id) and financial records (src/Infocom.php:599 budgets_id check) are charged to it. Reached on: Management > Budgets.",
+ "stackiq": "grep for budget across lib/, src/ and lib/Settings finds no budget schema or field; catalogContract has cost + costPeriod only (register :3363)",
+ "topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Budget holder: Cost-accounting owner of the contract\" and \"Applicable to ... Budget holder\" (read 2026-09-26). No budget with a period is described. Reached on: Contract card > Financial.",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
}
},
{
@@ -2204,7 +2368,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "partial",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -2217,8 +2381,10 @@
"providerHow": "read-from-code",
"note": "No purchase value, useful life or depreciation is recorded or computed.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts | Rated partial because TCO tracking.",
- "stackiq": "grep for depreciation/afschrijving finds nothing in lib/, src/ or the register"
+ "glpi": "source read at 11.0.9: the financial record of any item, licences included (src/SoftwareLicense.php:245 Infocom tab), carries depreciation type, duration and coefficient (install/mysql/glpi-empty.sql:3269 sink_time, :3270 sink_type, :3271 sink_coeff); src/Infocom.php:872 Linear and degressive types and src/Infocom.php:1085 linearAmortise compute the table. Reached on: Management > Licenses > Management tab.",
+ "stackiq": "grep for depreciation/afschrijving finds nothing in lib/, src/ or the register",
+ "topdesk": "unknown: depreciation is not mentioned (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
}
},
{
@@ -2229,8 +2395,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "yes",
+ "topdesk": "partial",
"stackiq": "yes",
"built": {
"state": "built",
@@ -2245,7 +2411,10 @@
"featureConfidence": "medium",
"note": "The contract page has a Documents files panel for the signed contract, plus a document reference field.",
"evidence": {
- "stackiq": "src/manifest.json:567 ContractDetail ct-files integration 'files' (Documents panel); catalogContract.documentReference text field (register :3252)"
+ "stackiq": "src/manifest.json:567 ContractDetail ct-files integration 'files' (Documents panel); catalogContract.documentReference text field (register :3252)",
+ "topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"You can view the contracts in a variety of formats, including PDF\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Archive Number (Free text) Reference to a physical or external archived copy of the contract document\" (read 2026-09-26). Reached on: Contract card.",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: src/Contract.php:126 adds the Documents tab (Document_Item) to every contract, storing the signed file in install/mysql/glpi-empty.sql:2585 glpi_documents. Reached on: Management > Contracts > Documents tab."
}
},
{
@@ -2256,7 +2425,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -2270,7 +2439,10 @@
"note": "The portfolio report shows each application in use with its cloud model and annualised cost, which lets you pick out SaaS spend. There is no SaaS subscription list and nothing discovers purchases made outside IT.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates",
- "stackiq": "usage.cloudDienstverleningsmodel (register :3050) plus contract cost; lib/Service/PortfolioReportService.php:302 per-usage annualised cost and cloud-transition share; src/views/organisaties/PortfolioReport.vue:166 cloudTransitionLabel per row"
+ "stackiq": "usage.cloudDienstverleningsmodel (register :3050) plus contract cost; lib/Service/PortfolioReportService.php:302 per-usage annualised cost and cloud-transition share; src/views/organisaties/PortfolioReport.vue:166 cloudTransitionLabel per row",
+ "topdesk": "unknown: no SaaS spend tracking is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -i 'saas' over src/ returns nothing; spend is only what is entered on contracts and financial records (install/mysql/glpi-empty.sql:1458 glpi_contractcosts), with no discovery of subscriptions bought outside IT."
}
},
{
@@ -2278,10 +2450,10 @@
"area": "security",
"name": "Register a known vulnerability with its CVE code and severity score.",
"origin": "own-code",
- "vng-softwarecatalogus": "no",
+ "vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -2294,8 +2466,10 @@
"providerHow": "read-from-code",
"note": "A vulnerability is registered with CVE code and CVSS score, and a severity band is derived from the score.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
- "stackiq": "src/views/KwetsbaarhedenView.vue:378 reportVulnerability opens the generic ObjectModal for 'vulnerability'; register.json:1619 vulnerability schema with cveCode (pattern CVE-yyyy-n, :1679) and cvssScore 0-10"
+ "vng-softwarecatalogus": "unknown: no vulnerability register is described; the docs do not state its absence either (the IBD-foto export only hands CPE identifiers to the IBD); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Hoe%20maak%20je%20een%20ICT-foto%20voor%20de%20IBD%3F (read 2026-09-26)",
+ "stackiq": "src/views/KwetsbaarhedenView.vue:378 reportVulnerability opens the generic ObjectModal for 'vulnerability'; register.json:1619 vulnerability schema with cveCode (pattern CVE-yyyy-n, :1679) and cvssScore 0-10",
+ "topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'cve\\|vulnerab\\|cvss' over src/ templates/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74 (a PHP version warning) and a session comment at src/Session.php:1085; no vulnerability itemtype exists."
}
},
{
@@ -2306,7 +2480,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -2319,7 +2493,10 @@
"providerHow": "read-from-code",
"note": "A vulnerability links to applications, not to specific versions. Per-version affectedness only shows as a computed match against a version's imported SBOM.",
"evidence": {
- "stackiq": "register.json:1701 vulnerability.modules links to module (applications), not moduleVersion; version level only via read-time SBOM match (src/utils/sbomVulnerabilityMatch.js, sbomComponent.vexCveIds register.json:8024) on the ModuleversieDetail Components tab"
+ "stackiq": "register.json:1701 vulnerability.modules links to module (applications), not moduleVersion; version level only via read-time SBOM match (src/utils/sbomVulnerabilityMatch.js, sbomComponent.vexCveIds register.json:8024) on the ModuleversieDetail Components tab",
+ "topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no vulnerability model (see src/Glpi/System/Requirement/PhpSupportedVersion.php:74 as the only 'vulnerabilities' hit), so nothing links to software versions (install/mysql/glpi-empty.sql:6900)."
}
},
{
@@ -2330,7 +2507,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -2343,7 +2520,10 @@
"providerHow": "read-from-code",
"note": "An SBOM in CycloneDX JSON or SPDX 2.x JSON can be uploaded for a version. XML and tag-value formats are not accepted.",
"evidence": {
- "stackiq": "src/components/sbom/SbomComponentsPanel.vue:53-90 upload control (.json) -> POST /api/moduleversies/{uuid}/sbom (appinfo/routes.php:92) -> lib/Controller/SbomController.php:129 importSbom -> lib/Service/SbomParserService.php:77 parse (CycloneDX JSON) and :127 parseSpdx (SPDX 2.x JSON)"
+ "stackiq": "src/components/sbom/SbomComponentsPanel.vue:53-90 upload control (.json) -> POST /api/moduleversies/{uuid}/sbom (appinfo/routes.php:92) -> lib/Controller/SbomController.php:129 importSbom -> lib/Service/SbomParserService.php:77 parse (CycloneDX JSON) and :127 parseSpdx (SPDX 2.x JSON)",
+ "topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -ril 'sbom\\|cyclonedx\\|spdx' over src/ templates/ locales/glpi.pot returns nothing; inventory import (src/Glpi/Inventory/) takes glpi-agent JSON only. Inventory import is src/Glpi/Inventory/Inventory.php:106."
}
},
{
@@ -2354,7 +2534,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -2367,7 +2547,10 @@
"providerHow": "read-from-code",
"note": "Matching is deliberately local, against vulnerabilities typed into the catalogue. No public CVE feed is read.",
"evidence": {
- "stackiq": "src/utils/sbomVulnerabilityMatch.js header: 'no HTTP request to an external advisory feed is ever made'; lib/Service/EolSyncService.php syncs endoflife.date support dates, not CVEs"
+ "stackiq": "src/utils/sbomVulnerabilityMatch.js header: 'no HTTP request to an external advisory feed is ever made'; lib/Service/EolSyncService.php syncs endoflife.date support dates, not CVEs",
+ "topdesk": "unknown: no CVE matching is described; the roadmap card https://tip.topdesk.com/c/186-automated-asset-scanning-tool (under consideration) mentions monitoring \"security vulnerabilities\" as a future idea; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: the catalogue does not match CVEs itself; its \"IBD-foto\" export lists supplier, product and CPE so the IBD can do so; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Hoe%20maak%20je%20een%20ICT-foto%20voor%20de%20IBD%3F (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'cve' over src/ templates/ finds no feed matching (only src/Glpi/System/Requirement/PhpSupportedVersion.php:74 text); no pluginsGLPI cve repository exists (git ls-remote https://github.com/pluginsGLPI/cve: repository not found)."
}
},
{
@@ -2378,7 +2561,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -2392,7 +2575,10 @@
"note": "Only individual vulnerabilities get a severity band. No application gets a combined score from its vulnerabilities and support status.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks | Rated partial because technology risk.",
- "stackiq": "src/utils/vulnerabilitySeverity.js derives a severity band per vulnerability from CVSS; no per-application risk score in lib/ or src/ (searched risk)"
+ "stackiq": "src/utils/vulnerabilitySeverity.js derives a severity band per vulnerability from CVSS; no per-application risk score in lib/ or src/ (searched risk)",
+ "topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: with no vulnerability data (only hit src/Glpi/System/Requirement/PhpSupportedVersion.php:74) and no support status field on software (install/mysql/glpi-empty.sql:6856 glpi_softwares), no risk score is computed; grep -i 'risk' over src/Appliance.php src/Software.php returns nothing."
}
},
{
@@ -2403,7 +2589,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -2416,7 +2602,10 @@
"providerHow": "read-from-code",
"note": "The exposure row shows which version is deployed, but no record says which version fixes the vulnerability, so patch status cannot be seen.",
"evidence": {
- "stackiq": "register.json:1619 vulnerability has no fixed-in version field; src/utils/vulnerabilityExposure.js computeExposure carries the deployed moduleVersion per usage but nothing compares it to a fix"
+ "stackiq": "register.json:1619 vulnerability has no fixed-in version field; src/utils/vulnerabilityExposure.js computeExposure carries the deployed moduleVersion per usage but nothing compares it to a fix",
+ "topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: installed versions are known (src/Item_SoftwareVersion.php:39) but no vulnerability or fixed in version exists to compare against (grep -rli 'cve' src/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74)."
}
},
{
@@ -2427,7 +2616,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -2440,7 +2629,10 @@
"providerHow": "read-from-code",
"note": "All vulnerabilities are listed with severity filters and each opens in the record form. The separate KwetsbaarheidDetail page is not what a row opens.",
"evidence": {
- "stackiq": "src/manifest.json:969 Kwetsbaarheden custom page -> src/views/KwetsbaarhedenView.vue table with severity tabs; row click openDetail (:417) opens the record in the generic ObjectModal"
+ "stackiq": "src/manifest.json:969 Kwetsbaarheden custom page -> src/views/KwetsbaarhedenView.vue table with severity tabs; row click openDetail (:417) opens the record in the generic ObjectModal",
+ "topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no vulnerability itemtype and no such entry in any menu (src/Html.php:1295 to :1334 list Management, Tools, Administration and Setup types)."
}
},
{
@@ -2451,8 +2643,8 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "yes",
"stackiq": "yes",
"built": {
"state": "built",
@@ -2464,8 +2656,10 @@
"providerHow": "read-from-code",
"note": "Organisations are created on the index with their type. The required contactsUid is a Nextcloud Contacts UID the form asks for as text, which is awkward but does not block the capability.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27555 'Vendor Registration' (2026-04-12): ICT providers register their software offerings | docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
- "stackiq": "src/manifest.json:386 Organisaties type:index over schema organization (Add form); register :2022 organization.type enum Municipality/Supplier/Collaboration/Community, required contactsUid + type"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Als leverancier kunt u zich aanmelden door de volgende gegevens te sturen naar softwarecatalogus@vng.nl\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C4 roles for gemeente and samenwerking accounts (read 2026-09-26); organisation types gemeente, samenwerking, leverancier. Reached on: Registration via VNG helpdesk.",
+ "stackiq": "src/manifest.json:386 Organisaties type:index over schema organization (Add form); register :2022 organization.type enum Municipality/Supplier/Collaboration/Community, required contactsUid + type",
+ "topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier ... In the Tasks block, specify whether first or second line incidents, or services or changes, may be assigned to the supplier\" (read 2026-09-26); branches are registered as Branch cards (https://docs.topdesk.com/en/drop-down-lists-settings.html \"the Person and Branch cards\"). Reached on: Supporting Files > New > Supplier / Branch.",
+ "glpi": "source read at 11.0.9: external organisations are suppliers with a type dropdown (src/Supplier.php:46, install/mysql/glpi-empty.sql:7072 suppliertypes_id); the organisation's own units are entities (src/Entity.php:58). There is no generic organisation register covering municipalities or cooperations. Reached on: Management > Suppliers; Administration > Entities."
}
},
{
@@ -2473,10 +2667,10 @@
"area": "organisations",
"name": "Review a self-registered organisation in a queue before it becomes active.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -2491,7 +2685,10 @@
"featureConfidence": "high",
"note": "An admin reviews pending self-registrations and approves or rejects them. Approval sets registrationStatus and publication, but leaves the separate status field at Draft, which is what user provisioning waits for (see org-status).",
"evidence": {
- "stackiq": "src/views/settings/StackiqSettings.vue:92 ModerationQueue (type organisation) -> src/utils/adminApi.js -> GET /api/moderation/pending, POST /api/moderation/{uuid}/approve|reject; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; lib/Service/ModerationService.php:230 approval sets registrationStatus active and stamps publicationDate (:173)"
+ "stackiq": "src/views/settings/StackiqSettings.vue:92 ModerationQueue (type organisation) -> src/utils/adminApi.js -> GET /api/moderation/pending, POST /api/moderation/{uuid}/approve|reject; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; lib/Service/ModerationService.php:230 approval sets registrationStatus active and stamps publicationDate (:173)",
+ "topdesk": "unknown: no review queue for organisations is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Om te kunnen deelnemen aan de softwarecatalogus controleren wij of de leverancier voldoet aan de richtlijnen van de softwarecatalogus\" (read 2026-09-26). Manual review by e-mail, no queue described.",
+ "glpi": "source read at 11.0.9: suppliers are created by staff (src/Supplier.php:75 sets is_active on a new record) and there is no self registration or approval queue for organisations; grep -i 'moderat' over src/Supplier.php src/Entity.php returns nothing."
}
},
{
@@ -2502,7 +2699,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -2515,7 +2712,10 @@
"providerHow": "read-from-code",
"note": "No working path moves an organisation between Draft, Active and Inactive: the field is hidden on the form and locked on the detail page, the status dialog is orphaned, and the Nextcloud dashboard widget still uses the old Dutch values so it lists nothing and would write an invalid value.",
"evidence": {
- "stackiq": "register organization.status enum Draft/Active/Inactive is visible:false (:2022); src/manifest.json:403 OrganisatieDetail overrides status editable:false; src/modals/object/ChangeOrganisatieStatusDialog.vue:211 is never opened (no setDialog('changeOrganisatieStatus') in src); src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters status 'concept' and :129 writes 'actief', neither an enum value"
+ "stackiq": "register organization.status enum Draft/Active/Inactive is visible:false (:2022); src/manifest.json:403 OrganisatieDetail overrides status editable:false; src/modals/object/ChangeOrganisatieStatusDialog.vue:211 is never opened (no setDialog('changeOrganisatieStatus') in src); src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters status 'concept' and :129 writes 'actief', neither an enum value",
+ "topdesk": "unknown: cards can be archived; concept, active, inactive states for organisations are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: suppliers carry a \"heeft geldig convenant\" flag and may be removed, but no concept, active, inactive status is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/leveranciers (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: a supplier is active or inactive, src/Supplier.php:365 is_active search option (install/mysql/glpi-empty.sql:7087 glpi_suppliers.is_active); there is no concept state. Reached on: Management > Suppliers, Active field."
}
},
{
@@ -2526,8 +2726,8 @@
"vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "yes",
+ "topdesk": "partial",
"stackiq": "yes",
"built": {
"state": "built",
@@ -2539,8 +2739,10 @@
"providerHow": "read-from-code",
"note": "Contact persons are listed on the organisation with their function and roles. The Contactpersonen index page exists but has no menu entry.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27557 'Contact & Collaboration' (2026-04-12): Connect with municipalities using similar products",
- "stackiq": "src/manifest.json:418 OrganisatieDetail org-contactpersonen object-list (role, roles) with rowRoute ContactpersoonDetail; register :1788 contactPerson (contactsUid, role, organization, roles enum of catalogue roles)"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30402: \"Bij elke leverancier is een contactpersoon opgevoerd. Deze persoon is verantwoordelijk voor de inhoud\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E4 contact details of municipalities (read 2026-09-26). One contact, no roles. Reached on: Supplier page header.",
+ "stackiq": "src/manifest.json:418 OrganisatieDetail org-contactpersonen object-list (role, roles) with rowRoute ContactpersoonDetail; register :1788 contactPerson (contactsUid, role, organization, roles enum of catalogue roles)",
+ "topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier contact ... The Supplier card where the contact person is active must be registered first\" (read 2026-09-26). Roles per contact are not described. Reached on: Supporting Files > New > Supplier Contact.",
+ "glpi": "source read at 11.0.9: contacts (src/Contact.php:45, install/mysql/glpi-empty.sql:1390 glpi_contacts) carry a contact type and a title (:1402 contacttypes_id, :1405 usertitles_id) and are linked to suppliers through src/Contact_Supplier.php:39. Reached on: Management > Contacts; Supplier > Contacts tab."
}
},
{
@@ -2548,11 +2750,11 @@
"area": "organisations",
"name": "Give a colleague access to your organisation's part of the catalogue.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "yes",
+ "topdesk": "partial",
"stackiq": "yes",
"built": {
"state": "built",
@@ -2565,7 +2767,10 @@
"providerHow": "read-from-code",
"note": "A beheerder of the organisation grants an existing Nextcloud user access to it from the header switcher; membership is stored by OpenRegister. It adds existing users; it does not send an invitation to a new person.",
"evidence": {
- "stackiq": "src/components/organisations/OrganisationSwitcher.vue:48 'Manage members' (isBeheerder) opens src/modals/GrantOrganisationAccessModal.vue; POST /api/organisations/{uuid}/members -> lib/Controller/OrganisationMembersController.php:108 authorizeBeheerder then OpenRegister joinOrganisation (:123)"
+ "stackiq": "src/components/organisations/OrganisationSwitcher.vue:48 'Manage members' (isBeheerder) opens src/modals/GrantOrganisationAccessModal.vue; POST /api/organisations/{uuid}/members -> lib/Controller/OrganisationMembersController.php:108 authorizeBeheerder then OpenRegister joinOrganisation (:123)",
+ "topdesk": "https://docs.topdesk.com/en/step-2, operator-import-with-a-linked-person.html: \"Create new operators via import\" (read 2026-09-26); permissions via permission groups (https://docs.topdesk.com/en/automated-actions.html). Administrators create accounts; no invitation flow. Reached on: Supporting Files > Operators.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/gebruikersbeheer: \"Beheerders van gemeenten, samenwerkingen of leveranciers kunnen voor collega's een account aanmaken ... ontvangt deze nieuwe gebruiker een e-mail met daarin de inloginstructies\" (read 2026-09-26). Reached on: Menu > Gebruikersbeheer > Gebruiker toevoegen.",
+ "glpi": "source read at 11.0.9: an administrator gives a user a profile on an entity, install/mysql/glpi-empty.sql:5917 glpi_profiles_users with profiles_id and entities_id, set on the user's Authorizations tab or automatically by authorisation rules (src/RuleRight.php:297 profiles_id action, :273 entities_id action). There is no emailed invitation link. Reached on: Administration > Users > Authorizations tab."
}
},
{
@@ -2573,10 +2778,10 @@
"area": "organisations",
"name": "Act for more than one organisation with one account and switch between them.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -2590,7 +2795,10 @@
"providerHow": "read-from-code",
"note": "A user who belongs to several organisations switches the active one from the header; OpenRegister holds the memberships.",
"evidence": {
- "stackiq": "src/components/organisations/OrganisationSwitcher.vue:197 POST /apps/openregister/api/organisations/{uuid}/set-active; mounted in src/App.vue:55"
+ "stackiq": "src/components/organisations/OrganisationSwitcher.vue:197 POST /apps/openregister/api/organisations/{uuid}/set-active; mounted in src/App.vue:55",
+ "topdesk": "unknown: one account acting for several organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C4: \"Een account kan ook beide rollen gekregen hebben. In het inlogmenu kan dan van rol gewisseld worden ... Gecombineerde rollen kunnen alleen door VNG Realisatie aangemaakt worden\" (read 2026-09-26). Reached on: Inlogmenu > rol wisselen.",
+ "glpi": "source read at 11.0.9: one user can hold several profile and entity pairs (install/mysql/glpi-empty.sql:5917 glpi_profiles_users) and switch between them in the session, src/Session.php:461 changeActiveEntities and src/Session.php:592 changeProfile. Reached on: user menu, entity and profile selector."
}
},
{
@@ -2601,7 +2809,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -2614,7 +2822,10 @@
"providerHow": "read-from-code",
"note": "An admin can merge a municipality into another and its usages, contacts and contracts follow. A supplier takeover leaves the source's applications and services pointing at the tombstoned supplier, because module and service provider fields are not in the relation map.",
"evidence": {
- "stackiq": "src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail; POST /api/organisaties/{uuid}/merge -> lib/Controller/MergeController.php:142 isAdmin; lib/Service/MergeOrganisatieService.php:111 re-points usage.consumer/participants, contactPerson.organization, connection.provider and @self.organisation of catalogContract/compliancy; module.provider and catalogService.provider are not re-pointed"
+ "stackiq": "src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail; POST /api/organisaties/{uuid}/merge -> lib/Controller/MergeController.php:142 isAdmin; lib/Service/MergeOrganisatieService.php:111 re-points usage.consumer/participants, contactPerson.organization, connection.provider and @self.organisation of catalogContract/compliancy; module.provider and catalogService.provider are not re-pointed",
+ "topdesk": "unknown: merging organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no merge of organisations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: entities cannot be merged, src/Entity.php:202 forbids the dropdown merge action for Entity; records can be moved into another entity with src/Transfer.php:50 Transfer (massive action add_transfer_list, src/MassiveAction.php:598), keeping or cleaning linked items per transfer options. Reached on: Administration > Entities; list Actions > Add to transfer list."
}
},
{
@@ -2625,7 +2836,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "partial",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -2638,8 +2849,10 @@
"providerHow": "read-from-code",
"note": "The merge panel shows per-type counts of what would be re-pointed before the admin confirms. It inherits the merge's blind spot: module and service provider links are not counted because they are not moved.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#146004 'C-configuration-95 The product shows what an import or a migration will change before it writes.': glpi: Form export and import (Form/ExportController.php, Form/Import/Step1IndexController.php through Step4ExecuteController.php) Lane findings: D-glpi-11. | Rated partial because import previews before writing; not for merges, source-read 2026-09-14.",
- "stackiq": "src/components/organisations/OrganisationMergePanel.vue:324 organisatieStore.dryRunMerge shows dryRunCounts before execute; POST /api/organisaties/{uuid}/merge/dry-run -> lib/Service/MergeOrganisatieService.php:160 dryRun"
+ "glpi": "source read at 11.0.9: with no merge (src/Entity.php:202 forbids merge for Entity) there is nothing to preview; the transfer (src/Transfer.php:50) runs directly without a what would change report.",
+ "stackiq": "src/components/organisations/OrganisationMergePanel.vue:324 organisatieStore.dryRunMerge shows dryRunCounts before execute; POST /api/organisaties/{uuid}/merge/dry-run -> lib/Service/MergeOrganisatieService.php:160 dryRun",
+ "topdesk": "unknown: merging organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no merge of organisations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -2647,11 +2860,11 @@
"area": "organisations",
"name": "Map catalogue roles such as administrator, buyer and civil servant onto user groups.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "partial",
"built": {
"state": "built",
@@ -2663,8 +2876,10 @@
"providerHow": "read-from-code",
"note": "An admin configures which groups count as generic users, organisation admins and super users. The catalogue roles themselves map to fixed, hard-coded group names and by organisation type, so an admin cannot map e.g. 'buyer' onto a group of their choice.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141837 '11.19 User, role and department administration in the app': `/front/user.form.php`, `/front/profile.form.php` (`src/Profile.php`, `src/ProfileRight.php:46`), `/front/group.form.php`, and the three-way user x profile x entity grant `src/Profile_User.php:320` with a recursive flag | Rated yes because user, profile and entity administration, source-read 2026-09-14.",
- "stackiq": "src/views/settings/StackiqSettings.vue:80 UserGroupsConfiguration -> GET/POST /api/user-groups/config (src/store/modules/settings.js:830); lib/Controller/SettingsController.php:3379; lib/Service/Stackiq/GroupHandler.php:103 generic groups, :167 fixed role groups (aanbod-beheerder, gebruik-beheerder, ...), group choice by organisation type (:471)"
+ "glpi": "source read at 11.0.9: roles are profiles with per right settings (src/Profile.php:55), mapped onto groups and directory attributes by authorisation rules, src/RuleRight.php:236 group criterion and src/RuleRight.php:297 profile action. Reached on: Administration > Profiles; Administration > Rules > Authorizations assignment rules.",
+ "stackiq": "src/views/settings/StackiqSettings.vue:80 UserGroupsConfiguration -> GET/POST /api/user-groups/config (src/store/modules/settings.js:830); lib/Controller/SettingsController.php:3379; lib/Service/Stackiq/GroupHandler.php:103 generic groups, :167 fixed role groups (aanbod-beheerder, gebruik-beheerder, ...), group choice by organisation type (:471)",
+ "topdesk": "https://docs.topdesk.com/en/automated-actions.html: \"Assign these permissions via Supporting Files > Permission Groups > [Permission Group]\" (read 2026-09-26); https://docs.topdesk.com/en/details-about-certain-permissions.html: permission tables per module (read 2026-09-26). Reached on: Supporting Files > Permission Groups.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C4 roles gemeentebeheerder, raadpleger, samenwerkingsbeheerder; \"Er is géén rol voor het raadplegen van een samenwerking\" (read 2026-09-26). Fixed roles, no mapping onto groups. Reached on: Gebruikersbeheer."
}
},
{
@@ -2688,9 +2903,10 @@
"providerHow": "read-from-code",
"note": "Stackiq does nothing for single sign-on. A Nextcloud admin can add an identity provider app, but that is the platform, not a stackiq page.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48908 'LDAP / SSO' (2026-07-23): Directory authentication and SSO.",
- "topdesk": "docs, intelligence competitor_features#48935 'SSO integration' (2026-07-23): SAML / SSO authentication.",
- "stackiq": "No OIDC/SAML code in lib/ or src/; stackiq creates local Nextcloud users with a password (lib/Service/Stackiq/ContactPersonHandler.php:292)"
+ "glpi": "source read at 11.0.9: src/Auth.php:106 EXTERNAL (web server provided identity, for example a SAML or OIDC module in front of GLPI), src/Auth.php:107 CAS with phpCAS::client at src/Auth.php:557, and src/Auth.php:108 X509 certificates, next to LDAP at src/Auth.php:105. Reached on: Setup > Authentication > Other authentication methods.",
+ "topdesk": "https://docs.topdesk.com/en/automatic-login-methods.html: \"Single Sign-on via SAML requirements TOPdesk uses OpenSAML 3 for authentication. You can connect all common IdP solutions which support SAML 2.0\" (read 2026-09-26). Reached on: Settings > Login Settings.",
+ "stackiq": "No OIDC/SAML code in lib/ or src/; stackiq creates local Nextcloud users with a password (lib/Service/Stackiq/ContactPersonHandler.php:292)",
+ "vng-softwarecatalogus": "unknown: login is by username and password (\"Vul uw GEMMA Softwarecatalogus-gebruikersnaam in\"); no identity provider sign-in is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/user/login (read 2026-09-26)"
}
},
{
@@ -2702,7 +2918,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "no",
"built": {
"state": "none",
@@ -2714,8 +2930,10 @@
"providerHow": "read-from-code",
"note": "Stackiq has no directory sync for users or groups. Nextcloud's LDAP app could do it platform-wide, outside stackiq.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48908 'LDAP / SSO' (2026-07-23): Directory authentication and SSO. | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141776 '5.11 Contact import and change subscriptions from registries': LDAP import and periodic re-sync of users and groups (`src/AuthLDAP.php`, `/front/ldap.import.php`, `/front/ldap.group.import.php`) with `src/RuleRight.php` mapping directory attributes to profiles; nothing subscribes to",
- "stackiq": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/"
+ "glpi": "source read at 11.0.9: src/AuthLDAP.php:59 LDAP directories with user import and group import (src/AuthLDAP.php:2816 ldapImportGroup), and the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users (alias ldap:sync at :80). Reached on: Administration > Users > LDAP directory link; Setup > Authentication > LDAP directories.",
+ "stackiq": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/",
+ "topdesk": "https://docs.topdesk.com/en/manual-login-with-ldap.html: \"This is also required if you want to import persons from your AD via Supporting files import\" (read 2026-09-26); https://tip.topdesk.com/c/242-support-scim-when-importing-users-from-entra-id-to-topdesk: roadmap card in column \"Launched\", \"Support SCIM when importing users from Entra ID to TOPdesk\" (read 2026-09-26). Reached on: Settings > Import settings > Supporting Files imports.",
+ "vng-softwarecatalogus": "unknown: no directory sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -2723,11 +2941,11 @@
"area": "organisations",
"name": "Change your own password and see your own account details.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
"stackiq": "partial",
"built": {
"state": "built",
@@ -2739,7 +2957,10 @@
"providerHow": "read-from-code",
"note": "A user can change their own password from their contact row in the organisation card, which is hard to find. There is no 'my account' page in stackiq; /api/me feeds only the organisation switcher. Nextcloud's personal settings do both natively.",
"evidence": {
- "stackiq": "src/components/ContactpersonenList.vue:115 'Change Password' opens src/dialogs/ChangePasswordDialog.vue -> POST /api/contactpersonen/change-password -> lib/Controller/ContactpersonenController.php:718, self-reset allowed at :753; GET /api/me (:1578) used only by src/App.vue and OrganisationSwitcher"
+ "stackiq": "src/components/ContactpersonenList.vue:115 'Change Password' opens src/dialogs/ChangePasswordDialog.vue -> POST /api/contactpersonen/change-password -> lib/Controller/ContactpersonenController.php:718, self-reset allowed at :753; GET /api/me (:1578) used only by src/App.vue and OrganisationSwitcher",
+ "topdesk": "https://docs.topdesk.com/en/editing-your-personal-profile.html: \"Click on Personal Profile . In the General and Private section, you can edit your personal information. In the Change password section, you can change your password\" (read 2026-09-26). Reached on: Profile picture > Personal Profile.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/wachtwoord-vergeten: \"Op het inlogscherm ... staat een link om een nieuw wachtwoord aan te vragen\" (read 2026-09-26). Reset by mail; viewing own account details is not described. Reached on: Inloggen > Vraag een nieuw wachtwoord aan.",
+ "glpi": "source read at 11.0.9: front/preference.php renders the user's own form through src/User.php:3105 showMyForm (template pages/admin/user/user.html.twig), whose preference variant shows a 'Change password' button to front/updatepassword.php at templates/pages/admin/user/user.html.twig:277 to :279; the new password form is templates/password_form.html.twig:79."
}
},
{
@@ -2763,8 +2984,10 @@
"providerHow": "read-from-code",
"note": "The mails are sent from templates, but the admin template editor's Save button does not call the backend and reports success anyway, so an administrator cannot edit a template from the UI. The transport defaults to 'null', which sends nothing until configured.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141830 '11.12 E-mail template library': `src/NotificationTemplate.php` with per-language bodies (`src/NotificationTemplateTranslation.php`), bound to events and delivery modes by `src/Notification_NotificationTemplate.php`, at `/front/notificationtemplate.php` | Rated yes because notification templates, source-read 2026-09-14.",
- "stackiq": "lib/Service/SymfonyEmailService.php:466 registration, :553 activation, :641 user creation mails from templates; src/views/settings/sections/EmailConfiguration.vue:902 saveTemplate is a stub that logs 'not yet implemented in the backend' and still shows success; backend POST /api/email/templates/{templateName} (lib/Controller/SettingsController.php:2194) has no caller in src/; lib/Settings/connections.json email adapter reports the 'null' transport as simulated"
+ "glpi": "source read at 11.0.9: src/NotificationTargetUser.php:44 user events passwordexpires, passwordforget and passwordinit; their text lives in admin editable templates, src/NotificationTemplate.php:47 and translations src/NotificationTemplateTranslation.php:42, seeded at install/empty_data.php:3212 (passwordinit) and :5640. Reached on: Setup > Notifications > Notification templates.",
+ "stackiq": "lib/Service/SymfonyEmailService.php:466 registration, :553 activation, :641 user creation mails from templates; src/views/settings/sections/EmailConfiguration.vue:902 saveTemplate is a stub that logs 'not yet implemented in the backend' and still shows success; backend POST /api/email/templates/{templateName} (lib/Controller/SettingsController.php:2194) has no caller in src/; lib/Settings/connections.json email adapter reports the 'null' transport as simulated",
+ "topdesk": "unknown: email designs are editable for automated actions, but account activation mails are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: new users receive a login mail, but administrator-editable templates are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersbeheer (read 2026-09-26)"
}
},
{
@@ -2775,7 +2998,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -2790,7 +3013,10 @@
"featureConfidence": "high",
"note": "The dedicated publish/withdraw endpoint is complete and guarded but no page calls it, and the old modal publish buttons are dead code. The only UI path is typing a publication or depublication date into the generic edit form.",
"evidence": {
- "stackiq": "lib/Controller/PublicationController.php:87 publish/depublish (routes.php:208-209, PUT/DELETE /api/publication/{objectType}/{uuid}) with an IDOR guard; lib/Service/PublicationService.php:51 publishable types catalogService, module, connection, organization. No src/ caller of /api/publication (only a comment in src/utils/openDataProjection.js). The publish buttons in src/modals/object/ViewObject.vue:4854 are unreachable: Modals.vue renders ViewObject only for modal 'viewOrganisatie'/'viewContactpersoon', which nothing sets. Workaround: publicationDate/depublicationDate are visible, editable fields on module/catalogService/organization/connection (lib/Settings/softwarecatalogus_register.json:6777 schema)."
+ "stackiq": "lib/Controller/PublicationController.php:87 publish/depublish (routes.php:208-209, PUT/DELETE /api/publication/{objectType}/{uuid}) with an IDOR guard; lib/Service/PublicationService.php:51 publishable types catalogService, module, connection, organization. No src/ caller of /api/publication (only a comment in src/utils/openDataProjection.js). The publish buttons in src/modals/object/ViewObject.vue:4854 are unreachable: Modals.vue renders ViewObject only for modal 'viewOrganisatie'/'viewContactpersoon', which nothing sets. Workaround: publicationDate/depublicationDate are visible, editable fields on module/catalogService/organization/connection (lib/Settings/softwarecatalogus_register.json:6777 schema).",
+ "topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: supplier data is public by default and municipal data is never public; publishing or withdrawing one entry is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'open data\\|opendata' over src/ locales/glpi.pot returns nothing; items have no publish state, the closest is is_helpdesk_visible (install/mysql/glpi-empty.sql:8956 on glpi_appliances), which only shows the item to helpdesk users of the same instance."
}
},
{
@@ -2798,10 +3024,10 @@
"area": "sharing",
"name": "Publish usage as open data without exposing personal contact details.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -2816,7 +3042,10 @@
"featureConfidence": "high",
"note": "Usage (gebruik) is not published as open data at all: anonymous callers get an empty envelope and the usage schema has no public read rule. The PII-stripping projection exists only as an unused, unit-tested JS util.",
"evidence": {
- "stackiq": "src/utils/openDataProjection.js:36 STRIPPED_FIELDS (PII projection) is imported by nothing in src/ and has no PHP counterpart (grep 'projection' in lib/ finds none). Usage schema read rule lib/Settings/softwarecatalogus_register.json:3150 has no public group; lib/Controller/GebruikController.php:102 returns an empty result to anonymous callers."
+ "stackiq": "src/utils/openDataProjection.js:36 STRIPPED_FIELDS (PII projection) is imported by nothing in src/ and has no PHP counterpart (grep 'projection' in lib/ finds none). Usage schema read rule lib/Settings/softwarecatalogus_register.json:3150 has no public group; lib/Controller/GebruikController.php:102 returns an empty result to anonymous callers.",
+ "topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Beschikbare%20downloads: public CSV downloads of packages, versions and compliance (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: \"Ingevuld door (28) Aantal gemeenten met een versie van het pakket in productie\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C5 contact details \"alleen als contactgegevens voor andere ingelogde gebruikers\" (read 2026-09-26). Reached on: Beschikbare downloads; package page.",
+ "glpi": "source read at 11.0.9: no open data publication exists (grep -rli 'open data' src/ returns nothing); anonymisation settings cover ticket actors only (install/mysql/glpi-empty.sql:2824 anonymize_support_agents on entities)."
}
},
{
@@ -2827,7 +3056,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -2842,7 +3071,10 @@
"featureConfidence": "high",
"note": "The announce hop is a real call into OpenCatalogi, but it is off by default, can only be switched on with occ, has no announce button, and needs OpenCatalogi installed.",
"evidence": {
- "stackiq": "lib/Service/Federation/FederationService.php:215 announce() calls OpenCatalogi BroadcastService->broadcast(directory URL); only caller is lib/BackgroundJob/FederationSyncJob.php:73. Off by default: lib/Service/Federation/FederationConfig.php:56 federation_enabled=false; lib/Settings/connections.json lists federation as switch-only via occ. isAvailable() is class_exists('OCA\\\\OpenCatalogi\\\\Service\\\\DirectoryService') (FederationService.php:95)."
+ "stackiq": "lib/Service/Federation/FederationService.php:215 announce() calls OpenCatalogi BroadcastService->broadcast(directory URL); only caller is lib/BackgroundJob/FederationSyncJob.php:73. Off by default: lib/Service/Federation/FederationConfig.php:56 federation_enabled=false; lib/Settings/connections.json lists federation as switch-only via occ. isAvailable() is class_exists('OCA\\\\OpenCatalogi\\\\Service\\\\DirectoryService') (FederationService.php:95).",
+ "topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'federat\\|activitypub' over src/ returns nothing; every instance is standalone and the only outbound registration is the plugin marketplace client (src/Glpi/Marketplace/). The marketplace client is src/Glpi/Marketplace/Controller.php:64."
}
},
{
@@ -2853,7 +3085,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -2868,7 +3100,10 @@
"featureConfidence": "high",
"note": "The pull does not fetch the peer: the peer URL is passed as a parameter OpenCatalogi ignores, so what gets mirrored is the local directory listing. Provenance is stamped on mirrors but no page displays it. Federation is also off by default.",
"evidence": {
- "stackiq": "lib/Service/Federation/FederationService.php:434 fetchPeerCatalog() calls OpenCatalogi DirectoryService->getDirectory(['url' => $peerUrl]); OpenCatalogi's getDirectory (opencatalogi lib/Service/DirectoryService.php:2409, also on origin/development) reads only filters/limit/offset/include-federated and ignores 'url', so it returns this instance's own directory listings, not the peer's published entries. Provenance marking itself is built: lib/Service/Federation/FederationMerger.php:239 stamps _source.instance. Mirrors are written into the organization schema (FederationService.php:56 PEER_MIRROR_TYPE). No src/ code reads _source, so no page shows where an entry came from."
+ "stackiq": "lib/Service/Federation/FederationService.php:434 fetchPeerCatalog() calls OpenCatalogi DirectoryService->getDirectory(['url' => $peerUrl]); OpenCatalogi's getDirectory (opencatalogi lib/Service/DirectoryService.php:2409, also on origin/development) reads only filters/limit/offset/include-federated and ignores 'url', so it returns this instance's own directory listings, not the peer's published entries. Provenance marking itself is built: lib/Service/Federation/FederationMerger.php:239 stamps _source.instance. Mirrors are written into the organization schema (FederationService.php:56 PEER_MIRROR_TYPE). No src/ code reads _source, so no page shows where an entry came from.",
+ "topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'federat' over src/ returns nothing; data enters only through the UI, the APIs (src/Glpi/Api/APIRest.php:60, src/Glpi/Api/HL/Router.php) and inventory, never from peer catalogues."
}
},
{
@@ -2879,7 +3114,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -2894,7 +3129,10 @@
"featureConfidence": "high",
"note": "Adding and removing peers works end to end, but only for a Nextcloud admin in the admin settings, and the peers are only used by a pull that currently fetches the wrong data (see share-federation-pull).",
"evidence": {
- "stackiq": "lib/Controller/FederationController.php:86 addPeer / removePeer (routes.php:246-247), #[AuthorizedAdminSetting(StackiqAdmin)]; lib/Service/Federation/FederationService.php:157/191 with an SSRF host guard; UI src/views/settings/sections/FederationSettings.vue:283 (POST) and :307 (DELETE), mounted from src/views/settings/StackiqSettings.vue:114."
+ "stackiq": "lib/Controller/FederationController.php:86 addPeer / removePeer (routes.php:246-247), #[AuthorizedAdminSetting(StackiqAdmin)]; lib/Service/Federation/FederationService.php:157/191 with an SSRF host guard; UI src/views/settings/sections/FederationSettings.vue:283 (POST) and :307 (DELETE), mounted from src/views/settings/StackiqSettings.vue:114.",
+ "topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'federat' over src/ returns nothing; there is no peer list in the Setup menu (src/Html.php:1330 onwards)."
}
},
{
@@ -2920,9 +3158,10 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48867 'REST & GraphQL API' (2026-07-23): Programmatic access to the workspace graph.",
"bluedolphin": "docs, intelligence competitor_features#48972 'REST API' (2026-07-23): Programmatic integration with other systems.",
- "glpi": "docs, intelligence competitor_features#48907 'REST API (HLAPI 2.x)' (2026-07-23): High-level REST API expanding object coverage in GLPI 11.",
- "topdesk": "docs, intelligence competitor_features#48933 'REST API' (2026-07-23): Open REST API for integrations.",
- "stackiq": "Every catalogue entity is an OpenRegister object (src/manifest.json pages read register @resolve:voorzieningen_register), so OpenRegister's /apps/openregister/api/objects/{register}/{schema} CRUD applies, gated by the schema authorization rules (lib/Settings/softwarecatalogus_register.json:6777 module and others). Stackiq adds its own routed endpoints in appinfo/routes.php (e.g. :202 /api/aanbod, :255-261 /api/aangeboden-gebruik, :298 /api/gebruik, :303 /api/portfolio-report)."
+ "glpi": "source read at 11.0.9: legacy REST API src/Glpi/Api/APIRest.php:60 (documented in apirest.md) and the v2 high level API, src/Glpi/Api/HL/Controller/AssetController.php:149 /Assets with GET list (:2825), GET item (:2839) and POST create (:2988), Appliance and Software included (src/Glpi/Api/HL/Controller/AssetController.php:39, :133). Reached on: /apirest.php and /api.php/v2.",
+ "topdesk": "https://docs.topdesk.com/en/required-knowledge.html: \"basic knowledge of REST API requests (see developers.topdesk.com )\" (read 2026-09-26); https://docs.topdesk.com/en/details-about-certain-permissions.html: \"API access > REST API : this permission is necessary for operator cards that are used for accessing the TOPdesk API\" (read 2026-09-26). Reached on: developers.topdesk.com.",
+ "stackiq": "Every catalogue entity is an OpenRegister object (src/manifest.json pages read register @resolve:voorzieningen_register), so OpenRegister's /apps/openregister/api/objects/{register}/{schema} CRUD applies, gated by the schema authorization rules (lib/Settings/softwarecatalogus_register.json:6777 module and others). Stackiq adds its own routed endpoints in appinfo/routes.php (e.g. :202 /api/aanbod, :255-261 /api/aangeboden-gebruik, :298 /api/gebruik, :303 /api/portfolio-report).",
+ "vng-softwarecatalogus": "unknown: https://www.softwarecatalogus.nl/api answers only \"Services Endpoint api has been setup successfully.\" and no API is documented; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api (read 2026-09-26)"
}
},
{
@@ -2934,7 +3173,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "partial",
"built": {
"state": "built",
@@ -2947,8 +3186,10 @@
"providerHow": "read-from-code",
"note": "The generated OpenAPI file is empty. What exists is hand-written: two JSON doc endpoints and markdown pages. OpenRegister may generate an OAS per register, but stackiq does not surface it.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141846 '12.18 OpenAPI documentation': auto-generated from route attributes: `src/Glpi/Api/HL/OpenAPIGenerator.php` with `src/Glpi/Api/HL/Doc/`, versioned per route (`#[RouteVersion]`, router at `src/Glpi/Api/HL/Router.php:98`); the legacy API is documented i | Rated yes because OpenAPI generator, source-read 2026-09-14.",
- "stackiq": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261). The views docs endpoint is login-only; the aangeboden-gebruik docs endpoint is @PublicPage (AangebodenGebruikController.php:860), so anyone can read it (corrected 2026-09-26). Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint."
+ "glpi": "source read at 11.0.9: src/Glpi/Api/HL/Controller/CoreController.php:322 route /doc serves a Swagger UI 'GLPI API Documentation' (:329 to :331) over the spec built by src/Glpi/Api/HL/OpenAPIGenerator.php. Reached on: /api.php/doc.",
+ "stackiq": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261). The views docs endpoint is login-only; the aangeboden-gebruik docs endpoint is @PublicPage (AangebodenGebruikController.php:860), so anyone can read it (corrected 2026-09-26). Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint.",
+ "topdesk": "https://developers.topdesk.com/: TOPdesk API reference site, linked from the docs as \"TOPdesk API documentation\" (read 2026-09-26); https://docs.topdesk.com/en/generate-a-document.html: \"see FreeMarker and the TOPdesk API documentation\" (read 2026-09-26). Reached on: developers.topdesk.com.",
+ "vng-softwarecatalogus": "unknown: no API documentation for the current catalogue was found; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)"
}
},
{
@@ -2960,7 +3201,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "partial",
"built": {
"state": "built",
@@ -2974,9 +3215,10 @@
"featureConfidence": "medium",
"note": "A full ArchiMate export exists but is only reached from admin settings. The one export on a user page is the portfolio report CSV, and the catalogue list pages offer no export.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27550 'Application Landscape Mapping' (2026-04-12): Map and export municipality application landscape",
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141818 '10.3 Export list results to CSV or XLSX': `src/Glpi/Search/Output/Csv.php`, `Xlsx.php`, `Ods.php` and `Pdf.php`, mapped at `src/Glpi/Search/SearchEngine.php:108-130` | Rated yes because CSV, XLSX, ODS, PDF export, source-read 2026-09-14.",
- "stackiq": "ArchiMate export lib/Controller/SettingsController.php:1615 (POST /api/archimate/export) and :1685 per-organisation export (GET /api/archimate/export/organization/{uuid}), called only from src/views/settings/sections/ArchiMateImportExport.vue (admin settings, StackiqSettings.vue:86). CSV export of the portfolio report: lib/Controller/PortfolioReportController.php:105, button src/views/organisaties/PortfolioReport.vue:567. No index page opts into the library's CSV/Excel export (no allowExport in src/manifest.json)."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"De publieke informatie is ook beschikbaar als download van exportbestanden ... Mijn pakketten, Mijn koppelingen: Knop [Exporteren]\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Exporteren; Beschikbare downloads.",
+ "glpi": "source read at 11.0.9: every search list exports to CSV, PDF, ODS and XLSX through src/Glpi/Search/Output/Csv.php, Pdf.php, Ods.php and Xlsx.php, plus impact CSV (front/impactcsv.php) and the APIs (src/Glpi/Api/HL/Controller/AssetController.php:2825). Reached on: any list, Export menu.",
+ "stackiq": "ArchiMate export lib/Controller/SettingsController.php:1615 (POST /api/archimate/export) and :1685 per-organisation export (GET /api/archimate/export/organization/{uuid}), called only from src/views/settings/sections/ArchiMateImportExport.vue (admin settings, StackiqSettings.vue:86). CSV export of the portfolio report: lib/Controller/PortfolioReportController.php:105, button src/views/organisaties/PortfolioReport.vue:567. No index page opts into the library's CSV/Excel export (no allowExport in src/manifest.json).",
+ "topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: tile actions \"Export to .CSV Export to Excel\" (read 2026-09-26); https://docs.topdesk.com/en/create-odata-reports-for-asset-management.html: \"generate reports by using the TOPdesk OData feed ... Microsoft Power BI, or Microsoft Excel\" (read 2026-09-26). Reached on: Asset dashboard; OData feed."
}
},
{
@@ -2984,10 +3226,10 @@
"area": "sharing",
"name": "Exchange application data with the organisation's service management tool.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
"bluedolphin": "yes",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "yes",
"stackiq": "no",
"built": {
@@ -3002,8 +3244,10 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48866 'Out-of-the-box integrations (ServiceNow, Signavio, SAP)' (2026-07-23): Pre-built connectors sync CMDB, process and ERP data.",
"bluedolphin": "docs, intelligence competitor_features#48973 'TOPdesk integration' (2026-07-23): Connector to TOPdesk asset/service data. | docs, intelligence competitor_features#27465 'TOPdesk Integration' (2026-04-12): Available on TOPdesk Marketplace for IT landscape insights",
- "topdesk": "docs, intelligence competitor_features#48934 'Marketplace integrations (Lansweeper, ValueBlue)' (2026-07-23): Pre-built connectors incl. Lansweeper discovery and ValueBlue EA. | docs, intelligence competitor_features#27391 'Marketplace Integrations' (2026-04-12): TOPdesk Marketplace with third-party integrations including Lansweeper, BlueDolphin",
- "stackiq": "No ITSM connector: lib/Settings/connections.json lists only email, federation and eol-feed; grep for topdesk/servicenow/itsm in lib/ and src/ finds nothing."
+ "topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: \"Go to Links > Assets . Click Link asset\" (read 2026-09-26) on calls and changes; TOPdesk is itself the service management tool. Reached on: Call card > Links > Assets.",
+ "stackiq": "No ITSM connector: lib/Settings/connections.json lists only email, federation and eol-feed; grep for topdesk/servicenow/itsm in lib/ and src/ finds nothing.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"Met de exportfunctie kunt u de gegevens in andere tools synchroon houden ... We verwachten in 2019 een pilot met Topdesk ... Een import vanuit die tools naar de Softwarecatalogus ... is vooralsnog niet voorhanden\" (read 2026-09-26); https://www.softwarecatalogus.nl/RID%20de%20Liemers: RID de Liemers signals updates through its TOPdesk change process by hand (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: GLPI is itself the service management tool, so application records are used directly by tickets, problems and changes, src/Appliance.php:105 onwards Item_Ticket, Item_Problem and Change_Item tabs; the menu src/Html.php:1283 Assistance holds Ticket, Problem and Change. Reached on: Appliance > Tickets, Problems, Changes tabs."
}
},
{
@@ -3015,7 +3259,7 @@
"sap-leanix": "no",
"bluedolphin": "no",
"glpi": "yes",
- "topdesk": "partial",
+ "topdesk": "yes",
"stackiq": "yes",
"built": {
"state": "built",
@@ -3029,9 +3273,10 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
"bluedolphin": "docs, intelligence competitor_features#27467 'SaaS Platform' (2026-04-12): Cloud-native SaaS, no installation required",
- "glpi": "docs, intelligence competitor_features#48912 '100% open source (GPL)' (2026-07-23): Fully GPL; no license fees, broad device coverage.",
- "topdesk": "docs, intelligence competitor_features#26346 'SaaS Platform' (2026-04-10): Cloud-hosted SaaS platform with automatic updates | Rated partial because offered as SaaS; on-premises not in the reading.",
- "stackiq": "appinfo/info.xml: a Nextcloud app (id stackiq, EUPL-1.2) installed on the customer's own Nextcloud with OpenRegister; stackiq-compose.yaml at repo root for a local stack."
+ "glpi": "source read at 11.0.9: GPL 3 source distributed for installation on own servers (LICENSE, INSTALL.md, install/mysql/glpi-empty.sql schema and the web installer src/Glpi/Controller/InstallController.php). The version is src/autoload/constants.php:43 GLPI_VERSION 11.0.9, the installer controller src/Glpi/Controller/InstallController.php:57, the licence LICENSE:1 GNU GPL version 3.",
+ "topdesk": "https://docs.topdesk.com/VA2026R3/index.html: \"TOPdesk Virtual Appliance documentation\", releases VA 2023 R2 to VA 2026 R3 (read 2026-09-26); https://tip.topdesk.com/c/255-va-release-q4-2026: roadmap card in column \"Planned\", \"VA Release Q4 2026\" in section \"On premise - VA releases\" (read 2026-09-26). Reached on: Virtual Appliance.",
+ "stackiq": "appinfo/info.xml: a Nextcloud app (id stackiq, EUPL-1.2) installed on the customer's own Nextcloud with OpenRegister; stackiq-compose.yaml at repo root for a local stack.",
+ "vng-softwarecatalogus": "unknown: the catalogue is run by VNG Realisatie; self-hosting is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3039,11 +3284,11 @@
"area": "insight",
"name": "Search the catalogue and narrow the results with facets such as reference component and supplier.",
"origin": "own-code",
- "vng-softwarecatalogus": "partial",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -3057,9 +3302,10 @@
"featureConfidence": "low",
"note": "Search plus reference-component, standard, application-service and domain facets work. Supplier is not offered as a facet, which is half of the row's example.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#27553 'ICT Market Orientation' (2026-04-12): Find and compare software from registered ICT providers",
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141806 '9.2 Advanced search with per-case-type fields': the search engine is strong, with ~160 ticket search options (`src/Ticket.php:2670`), nested criteria groups, `AND`/`OR`/`AND NOT`/`OR NOT` (`src/Glpi/Search/SearchEngine.php:551-564`), cross-itemtype meta-criteria, but | Rated yes because search engine with nested criteria, source-read 2026-09-14.",
- "stackiq": "lib/Service/FacetService.php:109 DIMENSIONS = referenceComponent, standard, applicationService, domain (GET /api/facets/{schema}, routes.php:195); src/views/FacetedCatalogIndexView.vue renders CnFacetSidebar with these plus search, on the Applications and Services pages. Supplier is only a column (src/manifest.json Modules config columns 'provider'), not a facet, although the module schema marks provider facetable."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Aan de linkerkant staan zogenaamde filter mogelijkheden. Deze werken ook in combinatie ... Achter de te zetten filters staat een getal\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketversies: facets Leverancier, Standaard, Referentiecomponent, Status planning, Domein, Doelgroep, Bedrijfsfunctie (read 2026-09-26). Reached on: Alle pakketten / Alle pakketversies.",
+ "glpi": "source read at 11.0.9: every list has a criteria builder, src/Glpi/Search/Input/QueryBuilder.php:72 showGenericSearch, over all search options, for example manufacturer on appliances (src/Appliance.php:229 region, glpi_manufacturers) and status (src/Appliance.php:350); there are no counted facets and no reference component to filter on. Reached on: Management > Appliances, search criteria.",
+ "stackiq": "lib/Service/FacetService.php:109 DIMENSIONS = referenceComponent, standard, applicationService, domain (GET /api/facets/{schema}, routes.php:195); src/views/FacetedCatalogIndexView.vue renders CnFacetSidebar with these plus search, on the Applications and Services pages. Supplier is only a column (src/manifest.json Modules config columns 'provider'), not a facet, although the module schema marks provider facetable.",
+ "topdesk": "https://docs.topdesk.com/en/the-asset-management-module-page.html: \"Asset overview : view all your assets in a filterable list\" (read 2026-09-26). Facets with counts are not described. Reached on: Asset Management > Asset overview."
}
},
{
@@ -3071,7 +3317,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "yes",
"built": {
"state": "built",
@@ -3083,8 +3329,10 @@
"providerHow": "read-from-code",
"note": "A user can save the facet and search selection as a named view and reopen it. Storage is OpenRegister's views API. It covers only those two pages.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141807 '9.3 Personal saved searches': `src/SavedSearch.php:52`, `is_private` default 1, personal ordering (`:824`) and a default per itemtype (`src/SavedSearch_User.php:94-115`), at `/front/savedsearch.php` | Rated yes because saved searches, source-read 2026-09-14.",
- "stackiq": "src/views/FacetedCatalogIndexView.vue:68 Saved views menu (save current filters, list, apply); src/store/modules/facets.js:404 saveCurrentAsView POSTs to OpenRegister /apps/openregister/api/views (:61), fetchSavedViews :361 reads them back."
+ "glpi": "source read at 11.0.9: src/SavedSearch.php:52 SavedSearch, private or shared, listed under Tools > Saved searches (src/Html.php:1309) with optional alerts (front/savedsearch_alert.form.php). Reached on: Tools > Saved searches (front/savedsearch.php).",
+ "stackiq": "src/views/FacetedCatalogIndexView.vue:68 Saved views menu (save current filters, list, apply); src/store/modules/facets.js:404 saveCurrentAsView POSTs to OpenRegister /apps/openregister/api/views (:61), fetchSavedViews :361 reads them back.",
+ "topdesk": "https://tip.topdesk.com/c/83-share-saved-overviews-with-operators-and-operator-groups: roadmap card in column \"Launched\", \"User is able to share saved overviews with operators and operator groups - Rename the saved overview\" (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: only VNG-defined \"Marktscans-voorgedefinieerde filters\" are described; users saving their own view is not; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Marktscans (read 2026-09-26)"
}
},
{
@@ -3092,7 +3340,7 @@
"area": "insight",
"name": "Open a dashboard with counts of organisations, applications and contracts.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
@@ -3109,9 +3357,10 @@
"note": "The dashboard shows counts of organisations, applications, services and contracts. The counts are computed by OpenRegister through the library stat widget.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports. | docs, intelligence competitor_features#27424 'Dashboards & Reports' (2026-04-12): Real-time dashboards for CIO-level reporting",
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141816 '10.1 Configurable KPI dashboards (count, gauge, chart)': `src/Glpi/Dashboard/Grid.php:67` with 20 widget types: pie, donut, half pie/donut, bars, lines, areas, stacked and horizontal variants, big number, multiple numbers, summary numbers, markdown, search result, article list",
- "topdesk": "docs, intelligence competitor_features#48936 'Reporting & dashboards' (2026-07-23): Operational reporting and dashboards.",
- "stackiq": "src/manifest.json:72 Dashboard page with stat widgets kpi-organisations, kpi-modules, kpi-services, kpi-contracts (source metric count on organization/module/catalogService/catalogContract) plus catalog-panels."
+ "glpi": "source read at 11.0.9: src/Glpi/Dashboard/Grid.php:1400 adds a 'Number of %s' card for every menu itemtype, so suppliers, appliances, software and contracts are counted (menu types src/Html.php:1298 to :1300); dashboards are stored by src/Glpi/Dashboard/Dashboard.php:66 and shown on the central page (src/Central.php:135). Reached on: Home > Dashboard; Assets > Dashboard.",
+ "topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: \"open the Asset dashboard to see statistics and visualised information regarding your registered assets\" (read 2026-09-26); https://docs.topdesk.com/en/reporting.html: \"Introducing the Reporting Hub\" (read 2026-09-26). Reached on: Asset Management > Asset dashboard.",
+ "stackiq": "src/manifest.json:72 Dashboard page with stat widgets kpi-organisations, kpi-modules, kpi-services, kpi-contracts (source metric count on organization/module/catalogService/catalogContract) plus catalog-panels.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tiles for logged-in municipalities (read 2026-09-26); https://www.softwarecatalogus.nl/: \"Voortgang gemeenten Aantal gemeenten per voortgangscategorie ... Aantal ingelogde gemeenten in 2026: 69\" (read 2026-09-26). No contracts. Reached on: Dashboard; homepage."
}
},
{
@@ -3122,7 +3371,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -3135,7 +3384,10 @@
"providerHow": "read-from-code",
"note": "The widget is registered and loads, but it filters on a status value the data no longer holds, so it always lists nothing. Its accept button would write an invalid status.",
"evidence": {
- "stackiq": "lib/Dashboard/ConceptOrganisatiesWidget.php registered at lib/AppInfo/Application.php:760; src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters organisations on status === 'concept', but the status enum is Draft/Active/Inactive/merged (lib/Settings/softwarecatalogus_register.json:2321) after lib/Repair/RenameDutchCatalogValues.php:76 renamed 'Concept' to 'Draft'. Accept writes status 'actief' (:129), which is not in the enum either."
+ "stackiq": "lib/Dashboard/ConceptOrganisatiesWidget.php registered at lib/AppInfo/Application.php:760; src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters organisations on status === 'concept', but the status enum is Draft/Active/Inactive/merged (lib/Settings/softwarecatalogus_register.json:2321) after lib/Repair/RenameDutchCatalogValues.php:76 renamed 'Concept' to 'Draft'. Accept writes status 'actief' (:129), which is not in the enum either.",
+ "topdesk": "unknown: not a Nextcloud app; no such widget applies; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: the catalogue is not a Nextcloud app; no such widget applies; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: GLPI is not a Nextcloud app and has no concept organisation state (suppliers only have is_active, install/mysql/glpi-empty.sql:7087), so no such widget exists in its own dashboards (src/Glpi/Dashboard/Grid.php:67)."
}
},
{
@@ -3143,11 +3395,11 @@
"area": "insight",
"name": "Pick a ready-made report from a list and open it.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "yes",
"built": {
"state": "built",
@@ -3159,8 +3411,10 @@
"providerHow": "read-from-code",
"note": "The report picker exists and opens a working report. The list holds exactly one report.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145791 'C-reporting-2 A canned report the product ships, run without building it.': glpi: Reports (Tools, Reports, front/report.default.php, report.dynamic.php, report.year.php, report.state.php, report.reservation.php, report.contract.php) Lane findings: D-glpi-35. | Rated yes because canned reports, source-read 2026-09-14.",
- "stackiq": "src/manifest.json:1021 Reports page (type reports) with one card, Portfolio rationalization, routing to src/manifest.json PortfolioReport /portfolio-report (PortfolioReportView, GET /api/portfolio-report routes.php:303)."
+ "glpi": "source read at 11.0.9: src/Report.php:52 Report builds a pick list of ready made reports, src/Report.php:77 default, :81 by contract, :85 by year, :87 financial information, :110 status, chosen from 'Select the report you want to generate' (src/Report.php:143). Reached on: Tools > Reports (front/report.php).",
+ "stackiq": "src/manifest.json:1021 Reports page (type reports) with one card, Portfolio rationalization, routing to src/manifest.json PortfolioReport /portfolio-report (PortfolioReportView, GET /api/portfolio-report routes.php:303).",
+ "topdesk": "https://docs.topdesk.com/en/reporting.html: \"Introducing the Reporting Hub ... So far, you could find dashboards and reports in different places\" (read 2026-09-26); https://tip.topdesk.com/c/20-reporting-hub: roadmap card in column \"Launched\", \"Reporting Hub\" (read 2026-09-26). Reached on: TOPdesk menu > Reporting Hub.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/rapportages: \"Regelmatig worden er rapportages gemaakt over het gebruik van de Softwarecatalogus\" (read 2026-09-26); compliancy monitor and digital accessibility monitor pages. Reached on: Rapportages; Compliancy monitor."
}
},
{
@@ -3172,7 +3426,7 @@
"sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "no",
"built": {
"state": "none",
@@ -3187,8 +3441,10 @@
"note": "Users cannot build their own report. The one fixed portfolio report can be exported as CSV, but it is not configurable.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141816 '10.1 Configurable KPI dashboards (count, gauge, chart)': `src/Glpi/Dashboard/Grid.php:67` with 20 widget types: pie, donut, half pie/donut, bars, lines, areas, stacked and horizontal variants, big number, multiple numbers, summary numbers, markdown, search result, article list",
- "stackiq": "No report builder in src/ or lib/. The only report is the fixed Gartner TIME portfolio report (lib/Controller/PortfolioReportController.php, CSV at :105). The overlay lists portfolio-reporting as status 'soon'."
+ "glpi": "source read at 11.0.9: any itemtype list takes arbitrary criteria (src/Glpi/Search/Input/QueryBuilder.php:72), selectable columns, and exports to CSV, PDF, ODS or XLSX (src/Glpi/Search/Output/Xlsx.php); the result can be saved (src/SavedSearch.php:52) and charted on a dashboard (src/Glpi/Dashboard/Grid.php:67). Reached on: any list with criteria, column selection and export.",
+ "stackiq": "No report builder in src/ or lib/. The only report is the fixed Gartner TIME portfolio report (lib/Controller/PortfolioReportController.php, CSV at :105). The overlay lists portfolio-reporting as status 'soon'.",
+ "topdesk": "https://docs.topdesk.com/en/reporting.html: \"The Report Wizard is not available for the Asset Management module. Further reporting can be done with the Asset Type Report or the OData feed\" (read 2026-09-26). Reached on: Asset Type Report; OData.",
+ "vng-softwarecatalogus": "unknown: only CSV exports for use in a spreadsheet are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)"
}
},
{
@@ -3196,11 +3452,11 @@
"area": "insight",
"name": "Export a filtered list to a spreadsheet.",
"origin": "competitor",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "yes",
"stackiq": "partial",
"built": {
"state": "built",
@@ -3214,8 +3470,10 @@
"featureConfidence": "low",
"note": "One fixed report exports to CSV for a selected organisation. The filtered catalogue lists cannot be exported.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141818 '10.3 Export list results to CSV or XLSX': `src/Glpi/Search/Output/Csv.php`, `Xlsx.php`, `Ods.php` and `Pdf.php`, mapped at `src/Glpi/Search/SearchEngine.php:108-130` | Rated yes because source-read 2026-09-14.",
- "stackiq": "Portfolio report CSV: lib/Controller/PortfolioReportController.php:105 (DataDownloadResponse text/csv), button src/views/organisaties/PortfolioReport.vue:567. No index page sets the library's allowExport (grep allowExport/exportable in src/manifest.json and the register finds nothing), so Applications, Contracts and the other lists have no export."
+ "glpi": "source read at 11.0.9: src/Glpi/Search/Output/Csv.php, Ods.php, Xlsx.php and Pdf.php export the filtered list; the output format selector is rendered by src/Html.php:4219 Dropdown::showOutputFormat. Reached on: any filtered list, Export.",
+ "stackiq": "Portfolio report CSV: lib/Controller/PortfolioReportController.php:105 (DataDownloadResponse text/csv), button src/views/organisaties/PortfolioReport.vue:567. No index page sets the library's allowExport (grep allowExport/exportable in src/manifest.json and the register finds nothing), so Applications, Contracts and the other lists have no export.",
+ "topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: \"Export to .CSV Export to Excel\" (read 2026-09-26). Reached on: Asset dashboard tile menu.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: \"Export to CSV\" on the filtered package-version list (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Ook beschikbaar via knop [Export to csv] op pagina Alle pakketten\" (read 2026-09-26). Reached on: Alle pakketversies > Export to CSV."
}
},
{
@@ -3226,8 +3484,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "yes",
"stackiq": "no",
"built": {
"state": "none",
@@ -3239,7 +3497,10 @@
"providerHow": "read-from-code",
"note": "Reports cannot be scheduled or sent to people.",
"evidence": {
- "stackiq": "No scheduled report or report mail job: lib/BackgroundJob/ holds only ContractStatusJob, EolSyncJob, FederationSyncJob and OrganizationContactSyncJob; grep for report scheduling in lib/ and src/ finds nothing."
+ "stackiq": "No scheduled report or report mail job: lib/BackgroundJob/ holds only ContractStatusJob, EolSyncJob, FederationSyncJob and OrganizationContactSyncJob; grep for report scheduling in lib/ and src/ finds nothing.",
+ "topdesk": "https://docs.topdesk.com/en/details-about-certain-permissions.html: \"Reports & Selections > Schedule reports with my own authorizations : the operator can schedule reports to be regularly saved or sent to contact persons\" (read 2026-09-26). Reached on: Reports & Selections.",
+ "vng-softwarecatalogus": "unknown: no scheduled reports are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: saved search alerts, src/SavedSearch_Alert.php:45 with count conditions (src/SavedSearch_Alert.php:53 to :58) and a frequency, run by src/SavedSearch_Alert.php:307 cronSavedSearchesAlerts and sent through the notification system to configured recipients; they notify on a result count rather than sending the report itself. Reached on: Tools > Saved searches > Alerts tab."
}
},
{
@@ -3251,7 +3512,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "partial",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -3265,8 +3526,10 @@
"featureConfidence": "medium",
"note": "Cost is reported per vendor and, within the portfolio report, for one organisation at a time. There is no cross-organisation or per-domain cost report.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#3271 'Financial Management' (2026-03-28): TCO tracking with procurement and contracts",
- "stackiq": "src/views/LicensePostureView.vue:84 per-vendor rollup with annual cost from contracts (src/utils/licensePosture.js perVendorRollup); src/views/organisaties/PortfolioReport.vue:143 annualised and one-off cost per TIME quadrant for one selected organisation (lib/Service/PortfolioReportService.php via GET /api/portfolio-report)."
+ "glpi": "source read at 11.0.9: src/Budget.php:537 showValuesByEntity shows spend per entity and item type for a budget, and src/Report.php:89 'Other financial and administrative information (licenses, cartridges, consumables)' (front/report.infocom.conso.php); there is no cost per domain or reference component view. Reached on: Management > Budgets > budget tabs; Tools > Reports.",
+ "stackiq": "src/views/LicensePostureView.vue:84 per-vendor rollup with annual cost from contracts (src/utils/licensePosture.js perVendorRollup); src/views/organisaties/PortfolioReport.vue:143 annualised and one-off cost per TIME quadrant for one selected organisation (lib/Service/PortfolioReportService.php via GET /api/portfolio-report).",
+ "topdesk": "https://docs.topdesk.com/en/obtain-insights-with-asset-type-report.html: \"do you need an overview of the total costs of new assets?\" (read 2026-09-26); call cost fields in https://docs.topdesk.com/en/fields-for-call-management-reports.html. Reached on: Asset Type Report.",
+ "vng-softwarecatalogus": "unknown: costs are not recorded; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3277,8 +3540,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "no",
+ "topdesk": "partial",
"stackiq": "yes",
"built": {
"state": "built",
@@ -3290,7 +3553,10 @@
"providerHow": "read-from-code",
"note": "The page lists features with their status. Note that the overlay feeding it is a self-description and may be stale in the app's favour.",
"evidence": {
- "stackiq": "src/manifest.json:1048 FeaturesRoadmap page (type roadmap, line 1050), footer menu entry FeaturesRoadmapMenu; content from openspec/features.overlay.json statuses stable/beta/soon."
+ "stackiq": "src/manifest.json:1048 FeaturesRoadmap page (type roadmap, line 1050), footer menu entry FeaturesRoadmapMenu; content from openspec/features.overlay.json statuses stable/beta/soon.",
+ "topdesk": "https://docs.topdesk.com/en/topdesk-labs.html: \"As a SaaS user, you can turn on the labs features you are curious about through Functional Settings > Labs\" (read 2026-09-26); https://docs.topdesk.com/en/ai-features.html: \"On your settings page, you can find an overview of all the AI features currently available in your environment\" (read 2026-09-26). Coming-soon items live on the external roadmap, not in the app. Reached on: Functional Settings > Labs.",
+ "vng-softwarecatalogus": "unknown: FAQ E14 points to a homepage block \"Binnenkort in de Softwarecatalogus\", but today's homepage shows no such block; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/ (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'coming soon' over src/ templates/ returns no in app feature status page; src/Glpi/Features/ holds item traits (for example src/Glpi/Features/Kanban.php), not feature flags. src/Glpi/Features/Kanban.php:45 is a trait, typical of that directory."
}
},
{
@@ -3314,8 +3580,10 @@
"providerHow": "read-from-code",
"note": "A progress API exists but no page reads it. Admins see a sync status and final import results, not the progress of a running job.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145875 'C-configuration-20 A long running administrative operation reports its progress.': glpi: Progress on a long operation (src/Glpi/Controller/ProgressController.php, Traits/AsyncOperationProgressControllerTrait.php) Lane findings: D-glpi-29. | Rated yes because source-read 2026-09-14.",
- "stackiq": "lib/Controller/SettingsController.php:1289 getProgress and :1360 streamProgress (routes.php:119-120) serve lib/Service/ProgressTracker.php, used only by lib/Service/MergeOrganisatieService.php; no src/ caller of /api/progress. The admin ArchiMate import shows a spinner then the final objects-processed count (src/views/settings/sections/ArchiMateImportExport.vue:103). Organisation sync shows a status block with last sync time and organisations to process (src/views/settings/sections/OrganizationSynchronization.vue:211)."
+ "glpi": "source read at 11.0.9: massive actions over many records show a progress bar, src/MassiveAction.php:1294 displayProgressBar; the LDAP synchronisation command shows one per user batch, src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:382; long web operations report through src/Glpi/Controller/ProgressController.php:50 /progress/check/{key}. Inventory imports run per agent request without a progress view. Reached on: massive action screen; CLI ldap:sync.",
+ "stackiq": "lib/Controller/SettingsController.php:1289 getProgress and :1360 streamProgress (routes.php:119-120) serve lib/Service/ProgressTracker.php, used only by lib/Service/MergeOrganisatieService.php; no src/ caller of /api/progress. The admin ArchiMate import shows a spinner then the final objects-processed count (src/views/settings/sections/ArchiMateImportExport.vue:103). Organisation sync shows a status block with last sync time and organisations to process (src/views/settings/sections/OrganizationSynchronization.vue:211).",
+ "topdesk": "unknown: import errors can be downloaded as logs; following progress of a running import is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no progress display for sync or import is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3339,9 +3607,10 @@
"providerHow": "read-from-code",
"note": "There is no knowledge base. Files can be attached to an application, but that is not searchable articles.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48909 'Knowledge base' (2026-07-23): Built-in KB with FAQ publishing.",
- "topdesk": "docs, intelligence competitor_features#48931 'Knowledge base' (2026-07-23): Knowledge management and published articles.",
- "stackiq": "No knowledge-article schema among the register's schemas (sector, suite, catalogService, vulnerability, contactPerson, organization, usage, catalogContract, connection, software-review, element, view, model, property-definition, relation, module, compliancy, bioMeasure, moduleVersion, sbomComponent in lib/Settings/softwarecatalogus_register.json); ModuleDetail only has a Documentation files panel."
+ "glpi": "source read at 11.0.9: src/KnowbaseItem.php:57 knowledge base articles with categories and visibility, linked to items through src/KnowbaseItem_Item.php:45 and shown on the appliance Knowledge base tab (src/Appliance.php:104); menu src/Html.php:1307. Reached on: Tools > Knowledge base (front/knowbaseitem.php).",
+ "topdesk": "https://docs.topdesk.com/en/knowledge-management.html: \"The Knowledge Base is set up and managed by your organization's knowledge managers. Every operator is able to use information from the Knowledge Base\" (read 2026-09-26). Reached on: Modules > Knowledge Management.",
+ "stackiq": "No knowledge-article schema among the register's schemas (sector, suite, catalogService, vulnerability, contactPerson, organization, usage, catalogContract, connection, software-review, element, view, model, property-definition, relation, module, compliancy, bioMeasure, moduleVersion, sbomComponent in lib/Settings/softwarecatalogus_register.json); ModuleDetail only has a Documentation files panel.",
+ "vng-softwarecatalogus": "unknown: the FAQ and manuals are site help, no knowledge base about applications is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3353,7 +3622,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "no",
"built": {
"state": "none",
@@ -3365,8 +3634,10 @@
"providerHow": "read-from-code",
"note": "Stackiq is a catalogue, and nothing discovers installed software.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48899 'Native inventory (GLPI Agent)' (2026-07-23): Built-in agent (ex-FusionInventory) discovers hardware/software automatically. | docs, intelligence competitor_features#3269 'Inventory' (2026-03-28): Automatic inventory discovery with FusionInventory agent",
- "stackiq": "No discovery agent or agent-ingest endpoint in lib/ or appinfo/routes.php. The nearest capability is SBOM import per module version (lib/Controller/SbomController.php:129), which records components of a known release, not installed software."
+ "glpi": "source read at 11.0.9: native inventory receives glpi-agent submissions at src/Glpi/Controller/InventoryController.php:61 /Inventory (legacy :62 /front/inventory.php), processed by src/Glpi/Inventory/Inventory.php:106 with src/Glpi/Inventory/Asset/Software.php creating software and installations. The agent is the separate glpi-project/glpi-agent repository. Reached on: Administration > Inventory; Assets > Software.",
+ "stackiq": "No discovery agent or agent-ingest endpoint in lib/ or appinfo/routes.php. The nearest capability is SBOM import per module version (lib/Controller/SbomController.php:129), which records components of a known release, not installed software.",
+ "topdesk": "https://docs.topdesk.com/en/taking-inventory-with-configuration-management.html: \"TOPsis will scan the workstations in your network and import the data into TOPdesk\" (read 2026-09-26) (old Configuration Management); https://docs.topdesk.com/en/migration-status.html: \"For network scanning purposes, we advise you to use other solutions that are available via the TOPdesk Marketplace: Lansweeper integration Microsoft Endpoint Manager integration\" (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3378,7 +3649,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "no",
"built": {
"state": "none",
@@ -3390,8 +3661,10 @@
"providerHow": "read-from-code",
"note": "No device discovery.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48911 'Network / SNMP discovery' (2026-07-23): SNMP network equipment inventory.",
- "stackiq": "No network scanning code in lib/ or routes (appinfo/routes.php)."
+ "glpi": "source read at 11.0.9: src/Glpi/Inventory/Request.php:97 NETDISCOVERY_ACTION calls src/Glpi/Inventory/Request.php:237 networkDiscovery, importing devices found by the agent's network discovery; scheduling discovery tasks from the server goes through the HANDLE_NETDISCOVERY_TASK hook (src/Glpi/Inventory/Request.php:448), which the separate glpiinventory plugin implements. Reached on: Administration > Inventory; Assets > Network devices.",
+ "stackiq": "No network scanning code in lib/ or routes (appinfo/routes.php).",
+ "topdesk": "https://docs.topdesk.com/en/creating-a-new-import.html: \"Connecting to Lansweeper as Asset Management import source\" (read 2026-09-26); https://tip.topdesk.com/c/186-automated-asset-scanning-tool: roadmap card in column \"Under consideration\", \"The asset discovery tool constantly monitors the entire network for new devices\" (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3402,7 +3675,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -3416,7 +3689,10 @@
"note": "No discovery of unregistered SaaS use.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model.",
- "stackiq": "No SaaS or SSO-log discovery code in lib/; lib/Settings/connections.json has no such source."
+ "stackiq": "No SaaS or SSO-log discovery code in lib/; lib/Settings/connections.json has no such source.",
+ "topdesk": "unknown: SaaS discovery is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: inventory handlers under src/Glpi/Inventory/Asset/ (Software.php, Process.php, VirtualMachine.php and others) read what the agent sees on devices; grep -i 'saas' over src/ returns nothing, so cloud subscriptions nobody registered are not discovered. The software handler is src/Glpi/Inventory/Asset/Software.php:56."
}
},
{
@@ -3440,9 +3716,10 @@
"providerHow": "read-from-code",
"note": "Only software is registered, not hardware.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#3266 'IT Asset Management' (2026-03-28): Track hardware, software, and network assets",
- "topdesk": "docs, intelligence competitor_features#27388 'Asset Management' (2026-04-12): Track hardware and software assets, locations, and assignments",
- "stackiq": "No hardware schema in lib/Settings/softwarecatalogus_register.json (schemas are software, organisation, contract and GEMMA model types only)."
+ "glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:208 asset_types lists Computer, Monitor, NetworkEquipment and the other hardware types managed next to software, under the Assets menu. Reached on: Assets > Computers, Monitors, Network devices.",
+ "topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"Think of a router that provides a computer with access to your network, or a printer\" (read 2026-09-26); any asset type via templates. Reached on: Asset Management.",
+ "stackiq": "No hardware schema in lib/Settings/softwarecatalogus_register.json (schemas are software, organisation, contract and GEMMA model types only).",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3466,9 +3743,9 @@
"providerHow": "read-from-code",
"note": "The landscape and its relations are recorded as catalogue objects, not as a CMDB with CI classes. Connections (koppelingen) have no index or detail page of their own.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
- "glpi": "docs, intelligence competitor_features#48902 'CMDB & configuration relations' (2026-07-23): CI relationships and impact analysis.",
- "topdesk": "docs, intelligence competitor_features#48926 'Asset Management / CMDB' (2026-07-23): Register assets, users, relations and replacement timelines in one overview. | docs, intelligence competitor_features#27387 'CMDB / Configuration Management' (2026-04-12): Configuration database for registering IT objects like laptops, software, infrastructure",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"Dubbel beheer (én in de Softwarecatalogus én in de CMDB) ... Een CMDB die separaat wordt bijgehouden\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/19703: \"Zolang de CMDB niet gekoppeld is aan de Softwarecatalogus\" (read 2026-09-26). The docs treat the CMDB as a separate tool.",
+ "glpi": "source read at 11.0.9: configuration items are the asset types (src/autoload/CFG_GLPI.php:208) plus appliances, with relations recorded as appliance membership (src/Appliance_Item.php:45), impact relations (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) and network port links. Reached on: Assets menu; item > Impact analysis tab.",
+ "topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"You register these functionalities as custom link types, and these link types are shown in the graphical overview of assets\" (read 2026-09-26). Reached on: Asset card > Relationships widget.",
"stackiq": "Applications (module lib/Settings/softwarecatalogus_register.json:6777), versions (moduleVersion :7649), suites (suite :1135) and application-to-application connections (connection :3563) with relations; ModuleDetail and SuiteDetail show a Related panel. No manifest page has register+schema 'connection' or 'usage', so connections are not listed or created on their own page."
}
},
@@ -3480,7 +3757,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3493,7 +3770,10 @@
"providerHow": "read-from-code",
"note": "An admin can merge duplicate organisations with a dry run. Nothing deduplicates applications or reconciles records arriving from several sources.",
"evidence": {
- "stackiq": "Organisation merge: src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail, calling /api/organisaties/{uuid}/merge/dry-run and /merge (src/store/modules/organisatie.js:486/524, lib/Controller/MergeController.php:106, admin-only body guard). Federation mirrors are reconciled per peer by lib/Service/Federation/FederationMerger.php."
+ "stackiq": "Organisation merge: src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail, calling /api/organisaties/{uuid}/merge/dry-run and /merge (src/store/modules/organisatie.js:486/524, lib/Controller/MergeController.php:106, admin-only body guard). Federation mirrors are reconciled per peer by lib/Service/Federation/FederationMerger.php.",
+ "topdesk": "unknown: deduplication across sources is not described; https://tip.topdesk.com/c/239-ai-cmdb-monitoring- (duplicates) is under consideration; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: src/RuleImportAsset.php:46 import and link rules decide whether an incoming inventory record matches an existing asset (by serial, UUID, MAC and similar) or creates one; src/RuleDictionnarySoftware.php:44 normalises software names and publishers from different sources; duplicates can be merged afterwards (src/Software.php:1011). Reached on: Administration > Rules > Rules for import and link equipments; Dictionaries."
}
},
{
@@ -3517,9 +3797,10 @@
"providerHow": "read-from-code",
"note": "No ticketing.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48903 'ITIL helpdesk / ticketing' (2026-07-23): Full incident/request ticketing with the assets module.",
- "topdesk": "docs, intelligence competitor_features#48927 'Incident / ticket management' (2026-07-23): Core ITSM incident and request handling.",
- "stackiq": "No incident or request schema or endpoint in lib/Settings/softwarecatalogus_register.json or appinfo/routes.php."
+ "glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:301 ticket_types includes Appliance (line 305), so tickets link to an application through src/Item_Ticket.php:41, shown on the appliance Tickets tab (src/Appliance.php:105). Reached on: Assistance > Tickets; Appliance > Tickets tab.",
+ "topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: \"On Call, Change (Activity) ... cards, you can link multiple assets\" (read 2026-09-26). Reached on: Call card > Links > Assets.",
+ "stackiq": "No incident or request schema or endpoint in lib/Settings/softwarecatalogus_register.json or appinfo/routes.php.",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3543,9 +3824,10 @@
"providerHow": "read-from-code",
"note": "Contracts go through an approval, but changes to an application do not.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#3277 'Change Management' (2026-03-28): ITIL change management with approval workflows",
- "topdesk": "docs, intelligence competitor_features#48929 'Change management' (2026-07-23): Structured change workflows with action sequences.",
- "stackiq": "No change-request workflow for applications. The only approval flow is for contracts: src/components/contracts/ContractApprovalPanel.vue on ContractDetail via /api/contracts/{uuid}/approval (routes.php:35-37), delegated to decidiq."
+ "glpi": "source read at 11.0.9: changes link to the appliance (src/Appliance.php:107 Change_Item tab) and go through approvals, src/ChangeValidation.php:39 ChangeValidation extends CommonITILValidation. Reached on: Assistance > Changes; Appliance > Changes tab.",
+ "topdesk": "https://docs.topdesk.com/en/requesting-a-change.html: \"A Preliminary Request for Change can only be dealt with as a Request for Change after it is authorized\" (read 2026-09-26). Reached on: Modules > Change Management.",
+ "stackiq": "No change-request workflow for applications. The only approval flow is for contracts: src/components/contracts/ContractApprovalPanel.vue on ContractDetail via /api/contracts/{uuid}/approval (routes.php:35-37), delegated to decidiq.",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3569,9 +3851,10 @@
"providerHow": "read-from-code",
"note": "A contract can be typed as SLA, but no service level targets are recorded or tracked.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48904 'SLA management' (2026-07-23): SLA targets and escalation rules.",
- "topdesk": "docs, intelligence competitor_features#48930 'SLA management' (2026-07-23): Service-level target tracking and reporting.",
- "stackiq": "catalogContract.contractType enum includes 'SLA' (lib/Settings/softwarecatalogus_register.json:3344) as a label only; no service-level target, measurement or breach fields in any schema."
+ "glpi": "source read at 11.0.9: src/SLM.php:42 service level management with src/SLA.php:44 SLA and OLA targets on tickets (install/mysql/glpi-empty.sql:7304 glpi_tickets.slas_id_ttr), assigned by business rules (src/RuleCommonITILObject.php:73) that can key on the linked appliance (src/RuleCommonITILObject.php:305 assign_appliance). Reached on: Setup > Service levels.",
+ "topdesk": "https://docs.topdesk.com/en/track-when-you-respond-to-calls, response-times.html: \"you register and track how quickly your operators need to respond ... you need a Contract Management and SLM license\" (read 2026-09-26). Reached on: Contract Management and SLM.",
+ "stackiq": "catalogContract.contractType enum includes 'SLA' (lib/Settings/softwarecatalogus_register.json:3344) as a label only; no service-level target, measurement or breach fields in any schema.",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
}
},
{
@@ -3582,7 +3865,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "yes",
"stackiq": "no",
"built": {
@@ -3595,8 +3878,10 @@
"providerHow": "read-from-code",
"note": "End users cannot request software.",
"evidence": {
- "topdesk": "docs, intelligence competitor_features#48928 'Self-service portal' (2026-07-23): End-user portal for requests and knowledge, reduces direct support load.",
- "stackiq": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls."
+ "topdesk": "https://docs.topdesk.com/en/mobile-access-to-the-self-service-portal.html: \"The SSP layout is suited to be displayed in a mobile interface\" (read 2026-09-26); https://tip.topdesk.com/c/86-webshop-is-connected-with-asset-management: roadmap card in column \"Building\", \"End-user can order items which are in Asset Management\" (read 2026-09-26); pricing lists \"Self-Service Portal\" and \"Webshop\". Reached on: Self-Service Portal.",
+ "stackiq": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls.",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: the 11.0 service catalog src/Glpi/Form/ServiceCatalog/ServiceCatalog.php:45 lists native forms for self service users (menu src/Html.php:1283), and a form question can offer software items to pick, src/Glpi/Form/QuestionType/QuestionTypeItem.php:180 Software::class, creating a ticket from the answer. Reached on: Self service > Service catalog."
}
},
{
@@ -3607,7 +3892,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "yes",
"stackiq": "no",
"built": {
@@ -3620,8 +3905,10 @@
"providerHow": "read-from-code",
"note": "There is no native mobile app.",
"evidence": {
- "topdesk": "docs, intelligence competitor_features#48937 'Mobile app' (2026-07-23): Native mobile operator app.",
- "stackiq": "No mobile app or mobile-specific surface in the repo; the app is the Nextcloud web UI (src/manifest.json)."
+ "topdesk": "https://docs.topdesk.com/en/installing-the-topdesk-mobile-store-application.html: \"Scan the QR code to download the app from the Play store\" (read 2026-09-26). Reached on: TOPdesk Mobile app.",
+ "stackiq": "No mobile app or mobile-specific surface in the repo; the app is the Nextcloud web UI (src/manifest.json).",
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'android\\|ios app\\|mobile app' over src/ templates/ returns nothing; the repository ships only the responsive web interface (templates/) and APIs (src/Glpi/Api/HL/Controller/CoreController.php:322 docs), no native mobile client."
}
},
{
@@ -3632,8 +3919,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -3647,7 +3934,10 @@
"featureConfidence": "medium",
"note": "The sync runs on a schedule and its last run time is shown, but only an admin can see and configure it, which is the rule for partial.",
"evidence": {
- "stackiq": "lib/BackgroundJob/OrganizationContactSyncJob.php:75 TimedJob every 300 s calling performScheduledSync; admin section src/views/settings/sections/CronjobConfiguration.vue:56 shows each job's interval and an enable switch; src/views/settings/sections/OrganizationSynchronization.vue:211 shows Last Sync from app config last_sync_time (lib/Service/OrganizationSyncService.php:1609, written by recordSyncTime :1674)."
+ "stackiq": "lib/BackgroundJob/OrganizationContactSyncJob.php:75 TimedJob every 300 s calling performScheduledSync; admin section src/views/settings/sections/CronjobConfiguration.vue:56 shows each job's interval and an enable switch; src/views/settings/sections/OrganizationSynchronization.vue:211 shows Last Sync from app config last_sync_time (lib/Service/OrganizationSyncService.php:1609, written by recordSyncTime :1674).",
+ "topdesk": "https://docs.topdesk.com/en/events-that-trigger-actions.html: \"when tracking imports/Exchange exports via system events ... on a schedule\" (read 2026-09-26); https://tip.topdesk.com/c/116-support-for-importing-persons-and-operators-directly-from-local-active-directory: roadmap card in column \"Launched\", person import from AD (read 2026-09-26). Reached on: Settings > Import settings.",
+ "vng-softwarecatalogus": "unknown: only \"De kaart wordt dagelijks bijgewerkt\" is stated; no organisation or contact sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/17042 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: automatic actions are scheduled and show their last run, src/CronTask.php:59 with install/mysql/glpi-empty.sql:1610 glpi_crontasks.lastrun, but LDAP user and group synchronisation is not one of them (grep -i ldap over the cron seed in install/empty_data.php:438 finds none); it is the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users, which must be scheduled by the system cron. Organisation (supplier) records have no sync at all. Reached on: Setup > Automatic actions; CLI bin/console ldap:sync."
}
}
],
@@ -3660,7 +3950,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
"bluedolphin": "partial",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3675,10 +3965,12 @@
"featureConfidence": "high",
"note": "The usage schema models this separation properly, but no stackiq page creates or edits a usage: the ObjectModal accepts type 'usage' (src/modals/Modals.vue:38) yet nothing opens it. Usages are only read by the roadmap, compliance matrix and vulnerability views.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: municipality adds the supplier's package and version to its own landscape (\"om het pakket toe te voegen aan je omgeving\") (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E1 \"Leveranciers onderhouden de gegevens van hun producten ... Gemeenten en Samenwerkingen onderhouden de gegevens van het eigen applicatieportfolio\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten.",
"sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers.",
"bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository.",
- "stackiq": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/"
+ "stackiq": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/",
+ "topdesk": "unknown: one organisation per environment; a separate usage record is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: use is recorded as installations separate from the software product, src/Item_SoftwareVersion.php:39 (install/mysql/glpi-empty.sql:1064 glpi_items_softwareversions) per device, and licence assignments per item or user; there is no usage record of a module by an organisation as such. Reached on: Assets > Software > Installations tab."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend create usage (gebruik) records through /api/aangeboden-gebruik or the OpenRegister objects API, and is that frontend part of what stackiq ships?"
},
@@ -3690,7 +3982,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
"built": {
@@ -3703,7 +3995,10 @@
"providerHow": "read-from-code",
"note": "There is no importer for the previous VNG Softwarecatalogus's registrations. The repair steps only rename stackiq's own earlier data, and the ArchiMate import brings in the GEMMA model, not organisations' entries.",
"evidence": {
- "stackiq": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets"
+ "stackiq": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets",
+ "topdesk": "unknown: no import from the VNG Softwarecatalogus is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: this is the previous catalogue itself; no import of an earlier registration is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: data from earlier GLPI versions is carried over by src/Update.php:172 doUpdates with the chain in install/migrations/ (update_0.85.x_to_0.90.0.php up to the 11.0 steps); data from another catalogue needs the separate datainjection plugin (pluginsGLPI/datainjection tag 2.15.11, inc/backendcsv.class.php). Reached on: web installer update; plugin Data injection."
},
"pendingQuestion": "Is the data from the previous VNG Softwarecatalogus meant to be brought over by a one-off migration outside this repo (for example an OpenRegister register import of an export file)?"
},
@@ -3715,8 +4010,8 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
"bluedolphin": "partial",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -3730,10 +4025,12 @@
"featureConfidence": "medium",
"note": "The connection model with direction and standard is complete, and the demo data ships six, but no stackiq page creates or edits one.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48842 'Application-to-application connection registry (koppelingen)' (2026-07-23): Records interfaces/connections between registered applications.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Selecteer vervolgens de betreffende pakketversie. De richting van het berichtenverkeer ... Selecteer vervolgens de betreffende standaard en versie\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > toevoegen.",
"sap-leanix": "docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | Rated partial because ArchiMate flow relations.",
- "stackiq": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it"
+ "stackiq": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it",
+ "topdesk": "https://docs.topdesk.com/en/hierarchy-of-relationships.html: \"When assets are linked with a link type , one of the assets often supplies a certain feature to another asset. The supplying asset therefore is the parent asset\" (read 2026-09-26). Direction via parent and child; no standard per relation. Reached on: Asset card > Relationships widget.",
+ "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1247 glpi_impactrelations stores a directed link from a source item to an impacted item with a name, added via src/Impact.php:1161 'Add relation'; there is no field for the standard or protocol used. Reached on: Appliance > Impact analysis tab, Add relation."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend register koppelingen through the OpenRegister objects API, and does it count as part of stackiq?"
},
@@ -3742,10 +4039,10 @@
"area": "connections",
"name": "Record that your organisation actually runs a given connection, not only that it exists.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3760,7 +4057,10 @@
"featureConfidence": "medium",
"note": "The model records which connections a usage runs, but neither usages nor connections have a page.",
"evidence": {
- "stackiq": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller"
+ "stackiq": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller",
+ "topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Geef bij status in productie of gepland aan\"; connections are registered in the organisation's own landscape (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen.",
+ "glpi": "source read at 11.0.9: an impact relation (install/mysql/glpi-empty.sql:1247) is a single fact in one instance; there is no separate usage record saying the organisation runs it, and grep -n 'usage' src/ImpactRelation.php returns nothing."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend let an organisation record the connections it runs, through /api/koppelingen-gebruik or the objects API?"
},
@@ -3769,10 +4069,10 @@
"area": "connections",
"name": "See which connections you run together with other organisations.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3787,7 +4087,10 @@
"featureConfidence": "medium",
"note": "Shared usage (with the connections it carries) is answerable through the API, but no stackiq page shows it.",
"evidence": {
- "stackiq": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/"
+ "stackiq": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/",
+ "topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: A10: \"Een Samenwerking geeft aan welke gemeenten gebruik maken van een betreffende koppeling. Die gemeentenamen worden getoond\" (read 2026-09-26). Reached on: Alle koppelingen.",
+ "glpi": "source read at 11.0.9: relations live inside one instance (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) and entities are subdivisions of one organisation (src/Entity.php:58); no cross organisation sharing of connections exists (grep -rli 'federat' src/ returns nothing)."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend show shared connections from /api/aangeboden-gebruik/deelnemers?"
},
@@ -3799,7 +4102,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3814,8 +4117,10 @@
"featureConfidence": "high",
"note": "The mapping is stored and can be filtered on, but no stackiq screen writes it: the module field is hideOnForm and the usage schema has no index or edit page; writes come through ArchiMate import, the OpenRegister objects API or the external VNG frontend.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48835 'Reference component mapping (referentiecomponenten)' (2026-07-23): Maps each registered software product onto GEMMA reference components/domains so functionality is comparable across suppliers. | docs, intelligence competitor_features#27551 'Reference Component Linking' (2026-04-12): Link software to GEMMA reference components",
- "stackiq": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Referentiecomponenten aangegeven door leverancier ... Toegevoegde referentiecomponenten\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen.",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules",
+ "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'gemma\\|reference component' over src/ locales/glpi.pot returns nothing; the only classification of an appliance is its type dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id)."
},
"pendingQuestion": "Does the Modules page's CnIndexPage create/edit dialog in nextcloud-vue 2.55.1 render module.referenceComponents (hideOnForm:true, items.$ref element in the AMEF register) as a working multiselect of reference components? nextcloud-vue's fieldsFromSchema (src/utils/schema.js:529) does not check hideOnForm."
},
@@ -3827,7 +4132,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3842,8 +4147,10 @@
"featureConfidence": "medium",
"note": "No stackiq page renders a GEMMA view. The enriched view data is served for an external frontend, and the org export draws applications into view copies that open in Archi.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48836 'Municipal application landscape registration' (2026-07-23): Municipalities register which software packages they use; auto-plotted on the GEMMA reference component map. | Rated yes because landscape auto-plotted on the reference component map.",
- "stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"de pakketten die getoond worden in het pakketoverzicht te plotten op een GEMMA architectuurkaart ... [Toon kaart]\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Toon kaart.",
+ "stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export",
+ "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'gemma\\|archimate' over src/ templates/ locales/glpi.pot returns nothing; the only diagram is the impact graph (src/Impact.php:252 displayGraphView)."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend render /api/views/{id} with include_gebruik, and is that frontend in scope for stackiq's column?"
},
@@ -3855,7 +4162,7 @@
"vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3870,8 +4177,10 @@
"featureConfidence": "high",
"note": "The API separates shared usage from own usage and names the source organisation, but nothing in stackiq draws it; in the ArchiMate export shared applications get the same style as own ones, so they are not drawn differently.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48844 'Municipal cooperation / shared-service management' (2026-07-23): Manages gemeente-samenwerking (shared service centres) registering a joint landscape.",
- "stackiq": "lib/Service/ViewService.php:1187 getDeelnamesGebruikData + :924 tags shared usage with _type='deelnames' and _sourceOrganization; lib/Service/ArchiMateExportService.php:3005 org export gives every nested application the same green fillColor, deelnames only get their own folder (:3086)"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: cooperation packages: \"kies bij Organisaties welke gemeenten ... de betreffende applicatie gebruiken ... Het pakket verschijnt dan ook alleen op de lijst en kaart van de samenwerking en niet bij de gemeenten\" (read 2026-09-26). Drawing shared apart from own is not described. Reached on: Samenwerking > Pakketten > Organisaties.",
+ "stackiq": "lib/Service/ViewService.php:1187 getDeelnamesGebruikData + :924 tags shared usage with _type='deelnames' and _sourceOrganization; lib/Service/ArchiMateExportService.php:3005 org export gives every nested application the same green fillColor, deelnames only get their own folder (:3086)",
+ "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no GEMMA views (grep -rli 'gemma' src/ returns nothing) and no partner sharing; the impact graph (src/Impact.php:1559 makeDataForCytoscape) draws one instance's items only."
},
"pendingQuestion": "Does the external VNG frontend draw deelnames nodes differently from own usage on a GEMMA view?"
},
@@ -3883,7 +4192,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -3898,7 +4207,10 @@
"featureConfidence": "low",
"note": "A pure API row: the views endpoint is routed, authorised for logged-in users and returns the imported GEMMA views; elements come through OpenRegister's generic objects API.",
"evidence": {
- "stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/docs, /api/views/{viewId} -> lib/Controller/ViewController.php:82,218 (@NoAdminRequired) -> lib/Service/ViewService.php:108,166 read views from the AMEF register; GEMMA elements are element objects in the AMEF register, readable through the OpenRegister objects API"
+ "stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/docs, /api/views/{viewId} -> lib/Controller/ViewController.php:82,218 (@NoAdminRequired) -> lib/Service/ViewService.php:108,166 read views from the AMEF register; GEMMA elements are element objects in the AMEF register, readable through the OpenRegister objects API",
+ "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no API over GEMMA in the catalogue is documented; GEMMA overviews are copied from GEMMA Online tables; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: the v2 API controllers (src/Glpi/Api/HL/Controller/, for example AssetController.php:149 /Assets) expose GLPI itemtypes only; grep -rli 'gemma' src/ returns nothing."
},
"pendingQuestion": "Is the view API reachable without a Nextcloud login (no #[PublicPage] on ViewController), and does the row require public access?"
},
@@ -3910,7 +4222,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3925,8 +4237,10 @@
"featureConfidence": "high",
"note": "A compliance record can be created on the Compliance index, but the standard-version relation points at element objects that live in the AMEF register while the page works on the voorzieningen register, so the version picker may not resolve; the free-text standardGemma field is the fallback. Not offered from the application page itself.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48840 'Standards support declaration' (2026-07-23): Suppliers declare which standards (StUF, ZGW/Zaakgericht APIs, etc.) a product supports.",
- "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.standardVersion ($ref element, queryParams gemmaType=standaardversie) + compliancy.module + compliancy.standardGemma (string); src/manifest.json Komplianties /komplianties index on the voorzieningen register; ModuleDetail md-compliance object-list has allowCreate:false; module.standardVersions is hideOnForm"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"via de optie Voeg extra standaarden toe de gewenste standaard te selecteren ... Ondersteuning(gepland) en Compliancy\" (read 2026-09-26). Reached on: Supplier login > productversie > standaarden.",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.standardVersion ($ref element, queryParams gemmaType=standaardversie) + compliancy.module + compliancy.standardGemma (string); src/manifest.json Komplianties /komplianties index on the voorzieningen register; ModuleDetail md-compliance object-list has allowCreate:false; module.standardVersions is hideOnForm",
+ "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no standards model (grep -rli 'standaard' src/ locales/glpi.pot returns nothing); software versions (install/mysql/glpi-empty.sql:6900) carry no supported standard."
},
"pendingQuestion": "On /komplianties, does the create form's standardVersion select (items $ref element, which lives only in the AMEF register) list standard versions, or does it resolve against the voorzieningen register and come back empty/404 as the Standaarden page did before its register fix?"
},
@@ -3938,7 +4252,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3953,7 +4267,10 @@
"featureConfidence": "high",
"note": "The accept/decline logic is complete and authorised, but nothing in src/ calls it, so only the external VNG frontend or a script can use it. There is also no stackiq page for usage (gebruik) records at all.",
"evidence": {
- "stackiq": "lib/Controller/AanbodController.php:200 acceptAanbod and :303 denyAanbod, lib/Service/AanbodService.php:289 checks the active organisation is aanbieder or afnemer then re-owns the object; routes appinfo/routes.php PUT /api/aanbod/{uuid}/accept, DELETE /api/aanbod/{uuid}/deny; also /api/aangeboden-gebruik/{id}/set-self and /deny"
+ "stackiq": "lib/Controller/AanbodController.php:200 acceptAanbod and :303 denyAanbod, lib/Service/AanbodService.php:289 checks the active organisation is aanbieder or afnemer then re-owns the object; routes appinfo/routes.php PUT /api/aanbod/{uuid}/accept, DELETE /api/aanbod/{uuid}/deny; also /api/aangeboden-gebruik/{id}/set-self and /deny",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: suppliers see \"Mijn gemeenten\" (who registered their packages) but accepting or declining a usage is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: suppliers have no login or role (install/mysql/glpi-empty.sql:7067 glpi_suppliers is a plain record; profiles in src/Profile.php:55 are for users), so no supplier can accept or decline a claimed usage."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend (not in this repo) call PUT /api/aanbod/{uuid}/accept and /api/aangeboden-gebruik/{id}/set-self, and is that frontend part of what we ship?"
},
@@ -3965,7 +4282,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -3980,8 +4297,10 @@
"featureConfidence": "high",
"note": "The shared-usage enrichment on GEMMA views exists server-side but no stackiq page renders it, so a user cannot see peers' software per reference component in this app.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48837 'Cross-municipality software comparison' (2026-07-23): Municipalities compare used software and connections with peer gemeenten; core network-effect value. | docs, intelligence competitor_features#27552 'Municipality Comparison' (2026-04-12): Compare application landscapes between municipalities",
- "stackiq": "lib/Controller/ViewController.php (routes GET /api/views, /api/views/{viewId}) enriches GEMMA views with shared usage (deelnames); src/store/modules/view.js:89 calls it but no component imports that store"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle gemeenten helpt bijvoorbeeld in het verkrijgen van inzicht welke gemeenten dezelfde pakketten gebruiken ... Ook met betrekking tot een bepaald beleidsthema, referentiecomponent of standaard\" (read 2026-09-26). Reached on: Inlogmenu > Alle gemeenten / Alle pakketoverzichten.",
+ "stackiq": "lib/Controller/ViewController.php (routes GET /api/views, /api/views/{viewId}) enriches GEMMA views with shared usage (deelnames); src/store/modules/view.js:89 calls it but no component imports that store",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no reference components (grep -rli 'reference component' src/ returns nothing) and no data from comparable organisations, since each instance is standalone (src/Entity.php:58 entities are internal)."
},
"pendingQuestion": "Does the external VNG frontend render /api/views with the deelnames enrichment, and does that count as a stackiq page?"
},
@@ -3993,7 +4312,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4008,8 +4327,10 @@
"featureConfidence": "medium",
"note": "There is no usage page and no 'used by' list on the application page. A supplier may see usages of its own product through the generic related panel, other roles see only their own usages; the per-product usage endpoints have no caller in src/.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48837 'Cross-municipality software comparison' (2026-07-23): Municipalities compare used software and connections with peer gemeenten; core network-effect value.",
- "stackiq": "register :2656 usage (consumer, module); usage read rule lets aanbod-beheerder read usages where provider = own organisation (:3137); ModuleDetail md-related widget src/manifest.json:491; GET /api/koppelingen-gebruik/{uuid} and /api/gebruik in lib/Controller/AangebodenGebruikController.php, lib/Controller/GebruikController.php"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Marktscans: \"kunnen ingelogde gemeenten of samenwerkingen zien bij welke collega-gemeenten betreffende pakketversie in het applicatielandschap staat (klik daarvoor op het getal boven Ingevuld door)\" (read 2026-09-26). Reached on: Package page > Ingevuld door.",
+ "stackiq": "register :2656 usage (consumer, module); usage read rule lets aanbod-beheerder read usages where provider = own organisation (:3137); ModuleDetail md-related widget src/manifest.json:491; GET /api/koppelingen-gebruik/{uuid} and /api/gebruik in lib/Controller/AangebodenGebruikController.php, lib/Controller/GebruikController.php",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: within one instance the version Summary tab shows installations per entity, src/Item_SoftwareVersion.php:850 showForVersionByEntity, and the installation list carries the entity column (src/Item_SoftwareVersion.php:484); organisations outside the instance are not visible. Reached on: Assets > Software > version > Summary tab."
},
"pendingQuestion": "Does the generic 'related' widget on ModuleDetail list usage objects that point at the module (inverse relation), and for which roles?"
},
@@ -4021,7 +4342,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4036,7 +4357,10 @@
"featureConfidence": "high",
"note": "The ReviewsPanel path holds reviews as pending and an admin approves them in settings. But the generic Reviews index /reviews shows pending reviews to every catalogue group and its Add form writes software-review through OpenRegister directly, where status (enum incl. approved) is a visible form field, so moderation can be bypassed.",
"evidence": {
- "stackiq": "lib/Service/ReviewService.php:232 forces pending; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; src/views/settings/StackiqSettings.vue:98 ModerationQueue type=software-review via src/utils/adminApi.js; lib/Settings/register.d/catalog-ratings.json public read only matches status approved but every catalogue group reads all reviews and may create them"
+ "stackiq": "lib/Service/ReviewService.php:232 forces pending; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; src/views/settings/StackiqSettings.vue:98 ModerationQueue type=software-review via src/utils/adminApi.js; lib/Settings/register.d/catalog-ratings.json public read only matches status approved but every catalogue group reads all reviews and may create them",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no reviews are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: there are no product reviews (see mkt-reviews); the only moderation is knowledge base publication by rights on src/KnowbaseItem.php:57, unrelated to reviews."
},
"pendingQuestion": "Does the installed OpenRegister let a catalogue user create a software-review with status=approved through /reviews (the generic create), bypassing ReviewService?"
},
@@ -4045,10 +4369,10 @@
"area": "market",
"name": "Keep your application landscape and connections hidden from suppliers.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4062,7 +4386,10 @@
"providerHow": "read-from-code",
"note": "The register declares organisation-scoped reads, so a supplier sees only usages of its own products and published connections. This rests on the installed OpenRegister executing the declared match rules.",
"evidence": {
- "stackiq": "register usage authorization (:3137) reads scoped to _organisation or consumer; aanbod-beheerder also reads usages where provider = own organisation; connection read (:3855) public when published and by provider; openspec/specs/vendor-visibility-rbac"
+ "stackiq": "register usage authorization (:3137) reads scoped to _organisation or consumer; aanbod-beheerder also reads usages where provider = own organisation; connection read (:3855) public when published and by provider; openspec/specs/vendor-visibility-rbac",
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E2: \"Leveranciers kunnen alleen hun eigen applicatieversies die in gebruik zijn bij gemeenten en samenwerkingen zien ... overigens ziet de leverancier geen status-informatie. Die is vertrouwelijk\" (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: suppliers are records without accounts (install/mysql/glpi-empty.sql:7067 glpi_suppliers) and all data is visible only through the profiles and entities assigned to users (install/mysql/glpi-empty.sql:5917 glpi_profiles_users), so a supplier sees nothing unless given an account. Reached on: Administration > Profiles."
},
"pendingQuestion": "Does the installed OpenRegister enforce the declared authorization.read match rules (e.g. {group: aanbod-beheerder, match: {provider: $organisation}}) on usage and connection reads?"
},
@@ -4071,11 +4398,11 @@
"area": "market",
"name": "Use the catalogue free of charge as a municipality or supplier.",
"origin": "competitor",
- "vng-softwarecatalogus": "yes",
+ "vng-softwarecatalogus": "unknown",
"sap-leanix": "no",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "no",
"stackiq": "partial",
"built": {
"state": "built",
@@ -4088,10 +4415,11 @@
"providerHow": "read-from-code",
"note": "The software is free and published entries are publicly readable, but the repo ships no hosted public catalogue; the public-facing frontend is the external VNG one.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
+ "vng-softwarecatalogus": "unknown: public browsing is open (\"Iedereen kan de softwarecatalogus raadplegen\", FAQ E6) but no page states the use is free of charge; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden (read 2026-09-26)",
"sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
- "glpi": "docs, intelligence competitor_features#48912 '100% open source (GPL)' (2026-07-23): Fully GPL; no license fees, broad device coverage.",
- "stackiq": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; catalogService and organization carry public read rules for published entries; module's public read also admits every object with registeredBy Supplier, a rule with no publication-date or status condition (lib/Settings/softwarecatalogus_register.json:7322-7327, corrected 2026-09-26); public intake POST /api/intake/register"
+ "glpi": "source read at 11.0.9: LICENSE:1 GNU General Public License version 3, so any municipality or supplier can run it without licence fees; there is no free hosted public service, the paid cloud is GLPI Network by Teclib. Reached on: self hosted install.",
+ "stackiq": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; catalogService and organization carry public read rules for published entries; module's public read also admits every object with registeredBy Supplier, a rule with no publication-date or status condition (lib/Settings/softwarecatalogus_register.json:7322-7327, corrected 2026-09-26); public intake POST /api/intake/register",
+ "topdesk": "https://www.topdesk.com/en/pricing/: \"Essential ... £51 Per agent/month\", \"Engaged ... £72\", \"Excellent ... £101\" (read 2026-09-26)"
},
"pendingQuestion": "Is a hosted, free-of-charge stackiq instance offered to municipalities and suppliers (the competitor offer is a public service, not software)?"
},
@@ -4100,11 +4428,11 @@
"area": "lifecycle",
"name": "Get a warning before an application or version falls out of support.",
"origin": "own-code",
- "vng-softwarecatalogus": "no",
+ "vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "partial",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -4118,9 +4446,11 @@
"featureConfidence": "high",
"note": "You see an 'approaching end of support' badge when you open the roadmap. A pushed warning rests only on a register declaration, and that rule addresses catalogue admins and the version's managers, not the organisations using the application.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "vng-softwarecatalogus": "unknown: suppliers set a status \"Einde ondersteuning\" and municipalities are notified of supplier changes, but an advance warning before support ends is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/pakketversies (read 2026-09-26)",
"sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
- "stackiq": "src/views/LifecycleRoadmapView.vue:73-86 EOL passed/approaching/withdrawn badges with EOL_WINDOW_DAYS=180 (:143); lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications eol-approaching (scheduled, dateEndSupport withinNext P180D, recipients software-catalog-admins + object-acl manage) is a declaration only; no notification code in lib (no INotificationManager use)"
+ "stackiq": "src/views/LifecycleRoadmapView.vue:73-86 EOL passed/approaching/withdrawn badges with EOL_WINDOW_DAYS=180 (:143); lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications eol-approaching (scheduled, dateEndSupport withinNext P180D, recipients software-catalog-admins + object-acl manage) is a declaration only; no notification code in lib (no INotificationManager use)",
+ "topdesk": "https://docs.topdesk.com/en/events-that-trigger-actions.html: \"…when a card date will be reached within a particular period of time\" (read 2026-09-26). Works on any date field, e.g. a self-defined end-of-support date; no built-in end-of-support. Reached on: Action Management > events.",
+ "glpi": "source read at 11.0.9: alerts exist for dates GLPI stores, licence expiry (src/NotificationTargetSoftwareLicense.php:46 'Alarms on expired licenses'), contract end and notice (src/NotificationTargetContract.php:47) and warranty expiry (src/Infocom.php:651 cronInfocom); no end of support date exists on an application or version (install/mysql/glpi-empty.sql:6900 glpi_softwareversions). Reached on: Setup > Notifications; Setup > Automatic actions."
},
"pendingQuestion": "Does the installed OpenRegister dispatch the scheduled x-openregister-notifications rule 'eol-approaching' on moduleVersion, and to whom?"
},
@@ -4132,7 +4462,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4148,7 +4478,10 @@
"note": "The matcher is complete, but it is off by default, only an admin can switch it on, each module needs an eolProductSlug, and the feed data only exists when integriq's endoflife.date source is provisioned.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | Rated partial because obsolescence tracking; source of dates not named.",
- "stackiq": "lib/BackgroundJob/EolSyncJob.php (registered appinfo/info.xml:101) + appinfo/routes.php:292-295 /api/eol-sync/* -> lib/Service/EolSyncService.php:145 run() reads eol_cycle objects via OpenRegister ObjectService (:328), stamps dateEndSupport on module versions via EolMatcherService; enabled defaults to false (lib/Service/SettingsService.php:7211); lib/Settings/connections.json eol-feed is a switch, off until enabled; the cycles are fetched by integriq's endoflife-date source"
+ "stackiq": "lib/BackgroundJob/EolSyncJob.php (registered appinfo/info.xml:101) + appinfo/routes.php:292-295 /api/eol-sync/* -> lib/Service/EolSyncService.php:145 run() reads eol_cycle objects via OpenRegister ObjectService (:328), stamps dateEndSupport on module versions via EolMatcherService; enabled defaults to false (lib/Service/SettingsService.php:7211); lib/Settings/connections.json eol-feed is a switch, off until enabled; the cycles are fetched by integriq's endoflife-date source",
+ "topdesk": "unknown: no end-of-life feed is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: end-of-support comes from supplier input; no public feed is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -i 'end_of_support\\|endoflife' over install/mysql/glpi-empty.sql and src/ returns nothing; no external lifecycle feed is read (the only outbound catalogues are the plugin marketplace, src/Glpi/Marketplace/). The marketplace client, the only outbound catalogue, is src/Glpi/Marketplace/Controller.php:64."
},
"pendingQuestion": "Is integriq's endoflife-date source (eol_product/eol_cycle register) provisioned on a default install, so that switching the sync on actually finds cycles?"
},
@@ -4157,10 +4490,10 @@
"area": "lifecycle",
"name": "Record which application is planned to replace another.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4175,7 +4508,10 @@
"featureConfidence": "high",
"note": "The planned replacement is stored per usage and displayed on the roadmap, but no stackiq page lets you record it.",
"evidence": {
- "stackiq": "lib/Settings/softwarecatalogus_register.json usage.plannedReplacement ($ref module) + plannedReplacementDate; read by src/views/LifecycleRoadmapView.vue:400; no usage page in src/manifest.json and navigationStore.setModal('usage') is never called (src/modals/Modals.vue:38 lists usage but nothing opens it)"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json usage.plannedReplacement ($ref module) + plannedReplacementDate; read by src/views/LifecycleRoadmapView.vue:400; no usage page in src/manifest.json and navigationStore.setModal('usage') is never called (src/modals/Modals.vue:38 lists usage but nothing opens it)",
+ "topdesk": "unknown: no replacement link is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"geplande harmonisaties ... status gepland met bijbehorende datum ... de uit te faseren applicaties van die status worden voorzien inclusief datum\" (read 2026-09-26). No explicit replaces link. Reached on: Mijn softwarecatalogus > Pakketten > Planning.",
+ "glpi": "source read at 11.0.9: a software can be flagged as an 'Upgrade from' another software, templates/pages/assets/software.html.twig:46 to :50 (is_update with softwares_id, install/mysql/glpi-empty.sql:6864 and :6865); this records succession after the fact, with no planned replacement link for appliances. Reached on: Assets > Software form, Upgrade from."
},
"pendingQuestion": "Is the external VNG Softwarecatalogus frontend (which writes usage objects) counted as part of stackiq for this row?"
},
@@ -4187,7 +4523,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4201,7 +4537,10 @@
"note": "The TIME classification is stored and reported per quadrant, but there is no page in stackiq where a user classifies an application.",
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
- "stackiq": "lib/Settings/softwarecatalogus_register.json usage.timeClassification enum Tolerate/Invest/Migrate/Eliminate + timeRationale + timeReviewDate; read by lib/Service/PortfolioReportService.php and rendered in src/views/organisaties/PortfolioReport.vue:112 quadrant chart; src/modals/object/ObjectModal.vue:178 has the enum select but is never opened for usage"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json usage.timeClassification enum Tolerate/Invest/Migrate/Eliminate + timeRationale + timeReviewDate; read by lib/Service/PortfolioReportService.php and rendered in src/views/organisaties/PortfolioReport.vue:112 quadrant chart; src/modals/object/ObjectModal.vue:178 has the enum select but is never opened for usage",
+ "topdesk": "unknown: no TIME classification is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no TIME classification is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'tolerate\\|eliminate' over src/ locales/glpi.pot returns nothing; a TIME class can only be held in a repurposed single choice dropdown such as the appliance status (install/mysql/glpi-empty.sql:8950 states_id, values from src/State.php:45) or type (install/mysql/glpi-empty.sql:8941). Reached on: Management > Appliances, Status or Type field."
},
"pendingQuestion": "Is the external VNG frontend or OpenRegister's generic object editor the intended place to set timeClassification, and does it count here?"
},
@@ -4210,7 +4549,7 @@
"area": "contracts",
"name": "Register a contract for a service with its number, type, term and cost.",
"origin": "own-code",
- "vng-softwarecatalogus": "no",
+ "vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
@@ -4228,9 +4567,9 @@
"featureConfidence": "high",
"note": "All the fields are on the contract form, but a contract requires a usage (gebruik) record and no stackiq page can create one, so on a fresh install the form cannot be completed without data from elsewhere (demo data, API, external frontend).",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
- "glpi": "docs, intelligence competitor_features#48905 'Financial & contract management' (2026-07-23): Purchase, contract, warranty and budget tracking against assets. | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145509 'C-parties-and-contacts-1 A contract is a record with its own term and costs, linked to the party it binds and the cases raised under it': glpi: Contracts (Management, Contracts, front/contract_item.php, contractcost.php, ticket_contract.php) Lane findings: D-glpi-49.",
- "topdesk": "docs, intelligence competitor_features#48932 'Contract & vendor management' (2026-07-23): Track supplier contracts and operational agreements.",
+ "vng-softwarecatalogus": "unknown: contracts are not described in the public docs; their absence is not stated either; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1483 glpi_contracts with name, num (contract number), contracttypes_id, begin_date, duration, notice and renewal, and costs in install/mysql/glpi-empty.sql:1458 glpi_contractcosts. Reached on: Management > Contracts.",
+ "topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Contract Number (mandatory) ... Type ... Start Date (mandatory) ... End Date (mandatory) ... Costs (Services)\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM > New.",
"stackiq": "src/manifest.json:527 Contracten type:index over catalogContract (contractNumber, contractType, startDate, endDate, cost, status); register :3252 catalogContract requires service AND usage; no manifest page has schema usage (grep src/manifest.json)"
},
"pendingQuestion": "Does the installed OpenRegister accept a catalogContract without the required usage (schema hardValidation false), and can the related-object picker create a usage inline?"
@@ -4240,11 +4579,11 @@
"area": "contracts",
"name": "Get warned before a contract expires.",
"origin": "own-code",
- "vng-softwarecatalogus": "no",
+ "vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
"stackiq": "no",
"built": {
"state": "specified",
@@ -4259,9 +4598,11 @@
"featureConfidence": "high",
"note": "The only expiry warning is a declared OpenRegister notification whose filter value 'Actief' never matches the English status 'Active', so even if OpenRegister dispatches it, no contract qualifies. No page shows contracts that are about to expire.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48846 'No lifecycle / contract / vulnerability tracking' (2026-07-23): GAP: registry only -- no EOL, contract, vulnerability or CMDB asset lifecycle management.",
+ "vng-softwarecatalogus": "unknown: contracts are not described in the public docs; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS renewal dates.",
- "stackiq": "lib/Settings/softwarecatalogus_register.json:3255 x-openregister-notifications contract-expiry filters status equals 'Actief' but the status enum is Active/Expired/In negotiation (:3428), and the subject uses {{contractNummer}}/{{eindDatum}} while fields are contractNumber/endDate; Contracten quick filter 'Expiring / expired' filters status Expired only (src/manifest.json:527)"
+ "stackiq": "lib/Settings/softwarecatalogus_register.json:3255 x-openregister-notifications contract-expiry filters status equals 'Actief' but the status enum is Active/Expired/In negotiation (:3428), and the subject uses {{contractNummer}}/{{eindDatum}} while fields are contractNumber/endDate; Contracten quick filter 'Expiring / expired' filters status Expired only (src/manifest.json:527)",
+ "topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"To prevent the accidental extension of unwanted contracts, TOPdesk warns you when contracts are about to expire\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Reminder date Date on which an operator should be reminded about the contract, e.g. ahead of expiry\" (read 2026-09-26). Reached on: Contract card > Reminder date.",
+ "glpi": "source read at 11.0.9: src/Contract.php:1092 cronContract computes end and notice dates and sends the events of src/NotificationTargetContract.php:47 (end of contract, notice, periodicity, periodicity notice); install/mysql/glpi-empty.sql:1508 glpi_contracts.alert sets which alerts apply. Reached on: Management > Contracts, Email alarms field; Setup > Notifications."
},
"pendingQuestion": "Does the installed OpenRegister dispatch scheduled x-openregister-notifications, and does it compare the filter value case/locale-insensitively (it cannot map 'Actief' to 'Active')?"
},
@@ -4273,8 +4614,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "no",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -4289,7 +4630,10 @@
"featureConfidence": "high",
"note": "The approval path through decidiq works and only an approved outcome sets Active. Nothing stops a user from creating or editing a contract with status Active directly in the generic form, so 'only after an approval' is not enforced.",
"evidence": {
- "stackiq": "lib/Service/ContractApprovalService.php:254 submitForApproval dispatches OCA\\Decidiq\\Event\\DecisionRequestedEvent (fail-closed), :412 projectOutcome sets status Active only on approved; src/manifest.json:579 ContractApprovalPanel on ContractDetail; but register :3428 status enum incl. Active is an editable form field and approvalState (register.d/contracts-to-decidesk.json) is not readOnly; the declared x-openregister-lifecycle uses Dutch states 'In onderhandeling'/'Actief' that match no enum value"
+ "stackiq": "lib/Service/ContractApprovalService.php:254 submitForApproval dispatches OCA\\Decidiq\\Event\\DecisionRequestedEvent (fail-closed), :412 projectOutcome sets status Active only on approved; src/manifest.json:579 ContractApprovalPanel on ContractDetail; but register :3428 status enum incl. Active is an editable form field and approvalState (register.d/contracts-to-decidesk.json) is not readOnly; the declared x-openregister-lifecycle uses Dutch states 'In onderhandeling'/'Actief' that match no enum value",
+ "topdesk": "https://docs.topdesk.com/en/registering-and-validating-contracts.html: \"Create a new Preliminary Contract card ... Validate the contract. You have created an active contract\" (read 2026-09-26). A validation step, no recorded approval decision. Reached on: Contract card > Validate Contract.",
+ "vng-softwarecatalogus": "unknown: contracts are not described in the public docs; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -n 'alidation' src/Contract.php returns nothing and no ContractValidation class exists; approvals exist only for ITIL objects (src/ChangeValidation.php:39), and the contract status is a free dropdown (install/mysql/glpi-empty.sql:1512 states_id)."
},
"pendingQuestion": "Does the installed OpenRegister enforce x-openregister-lifecycle transitions on catalogContract.status, given its states are Dutch ('Actief') and the enum is English ('Active')?"
},
@@ -4301,7 +4645,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4314,7 +4658,10 @@
"providerHow": "read-from-code",
"note": "The list shows how many in-production usages are exposed to each vulnerability. The per-organisation exposure lives on a detail tab the list does not open, so a user sees the count but not reliably who is exposed.",
"evidence": {
- "stackiq": "src/utils/vulnerabilityExposure.js:54 in-production join vulnerability.modules -> usage.module -> usage.consumer; count shown in the list (src/views/KwetsbaarhedenView.vue:111); per-organisation rows in VulnerabilityExposurePanel on KwetsbaarheidDetail tab (src/manifest.json:997), but a list row opens the edit modal, not the detail page (KwetsbaarhedenView.vue:417)"
+ "stackiq": "src/utils/vulnerabilityExposure.js:54 in-production join vulnerability.modules -> usage.module -> usage.consumer; count shown in the list (src/views/KwetsbaarhedenView.vue:111); per-organisation rows in VulnerabilityExposurePanel on KwetsbaarheidDetail tab (src/manifest.json:997), but a list row opens the edit modal, not the detail page (KwetsbaarhedenView.vue:417)",
+ "topdesk": "unknown: vulnerabilities are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no vulnerability functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no vulnerability data exists (grep -rli 'cve' src/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74), so exposure cannot be derived even though installations per entity are known (src/Item_SoftwareVersion.php:850)."
},
"pendingQuestion": "Is KwetsbaarheidDetail reachable from any page, for example by clicking a vulnerability in ModuleDetail's Related panel?"
},
@@ -4326,7 +4673,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4341,7 +4688,10 @@
"featureConfidence": "high",
"note": "The alert is declared, not code in stackiq, and it goes to catalogue admins and the record's managers, not to the organisations that use the affected software.",
"evidence": {
- "stackiq": "register.json:1622 x-openregister-notifications 'vulnerability-reported' on vulnerability, trigger created, channels nc-notification + email, recipients group software-catalog-admins and object-acl manage (a declaration only)"
+ "stackiq": "register.json:1622 x-openregister-notifications 'vulnerability-reported' on vulnerability, trigger created, channels nc-notification + email, recipients group software-catalog-admins and object-acl manage (a declaration only)",
+ "topdesk": "unknown: vulnerabilities are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no vulnerability functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no vulnerability events among notification targets; software notifications are licence expiry only (src/NotificationTargetSoftwareLicense.php:46)."
},
"pendingQuestion": "Does the installed OpenRegister dispatch the x-openregister-notifications 'vulnerability-reported' rule on the vulnerability schema, and can recipients be the consumers of the affected modules?"
},
@@ -4350,10 +4700,10 @@
"area": "organisations",
"name": "Let a new organisation sign itself up without an account.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4368,7 +4718,10 @@
"featureConfidence": "high",
"note": "The anonymous sign-up endpoint is complete and lands in moderation, but stackiq has no sign-up form. The schema also grants 'public' create on organization, so an anonymous generic OpenRegister create could skip the intake's pending stamp.",
"evidence": {
- "stackiq": "lib/Controller/IntakeController.php:74 PublicPage + AnonRateLimit(5/h) on POST /api/intake/register; lib/Service/IntakeService.php:146 forces registrationStatus pending, publicationDate null; no caller in src/. Separately, organization authorization.create includes 'public' (register :2467)"
+ "stackiq": "lib/Controller/IntakeController.php:74 PublicPage + AnonRateLimit(5/h) on POST /api/intake/register; lib/Service/IntakeService.php:146 forces registrationStatus pending, publicationDate null; no caller in src/. Separately, organization authorization.create includes 'public' (register :2467)",
+ "topdesk": "unknown: organisations signing themselves up is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Als leverancier kunt u zich aanmelden door de volgende gegevens te sturen naar softwarecatalogus@vng.nl\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-gemeente-aanmelden: cooperations without an account \"vraag deze dan aan door een mail te sturen\" (read 2026-09-26). Sign-up by e-mail, no online form.",
+ "glpi": "source read at 11.0.9: suppliers are created by staff only (src/Supplier.php:75 sets is_active on add from the staff form) and there is no public sign up page among front/ pages (front/lostpassword.php and front/initpassword.php are the only anonymous account pages)."
},
"pendingQuestion": "Does the external VNG frontend post to /api/intake/register, and does OpenRegister's generic public create on organization let an anonymous caller set registrationStatus/status/publicationDate directly?"
},
@@ -4380,8 +4733,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "no",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -4395,7 +4748,10 @@
"featureConfidence": "high",
"note": "Conversion and role-based group assignment exist, manual and automatic on create for active organisations. Both read an email field the contact schema no longer has, so a contact created through the current form (contactsUid only) fails with 'No email address found' unless it carries legacy data.",
"evidence": {
- "stackiq": "lib/Controller/ContactpersonenController.php:393 convertToUser -> lib/Service/Stackiq/ContactPersonHandler.php:292 createUserAccount reads objectData['email'] (:299); automatic path lib/EventListener/StackiqEventListener.php -> lib/Service/ContactpersoonService.php:128 also reads contactData['email']; contactPerson schema (:1788) declares no email (identity moved to Nextcloud Contacts via contactsUid); UI: src/components/ContactpersonenList.vue:97 'Convert to User' inside OrganisatieCard"
+ "stackiq": "lib/Controller/ContactpersonenController.php:393 convertToUser -> lib/Service/Stackiq/ContactPersonHandler.php:292 createUserAccount reads objectData['email'] (:299); automatic path lib/EventListener/StackiqEventListener.php -> lib/Service/ContactpersoonService.php:128 also reads contactData['email']; contactPerson schema (:1788) declares no email (identity moved to Nextcloud Contacts via contactsUid); UI: src/components/ContactpersonenList.vue:97 'Convert to User' inside OrganisatieCard",
+ "topdesk": "https://docs.topdesk.com/en/step-2, operator-import-with-a-linked-person.html: \"To create operators with a person card linked via the Supporting Files import\" (read 2026-09-26); https://docs.topdesk.com/en/assigning-or-editing-self-service-portal-login-data.html: \"select the TOPdesk field Has access to Self-Service Portal and map it\" (read 2026-09-26). Reached on: Supporting Files imports.",
+ "vng-softwarecatalogus": "unknown: no conversion of contact persons into accounts is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersbeheer (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: contacts (src/Contact.php:45) and users are separate itemtypes with no conversion action; user accounts come from manual creation, LDAP import (src/AuthLDAP.php:59) or authorisation rules (src/RuleRight.php:297 profile action)."
},
"pendingQuestion": "Does a contactPerson created via the current form reach createUserAccount with an email (e.g. resolved from Nextcloud Contacts by contactsUid somewhere I did not find), or does conversion fail for every post-migration contact?"
},
@@ -4407,7 +4763,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4422,8 +4778,10 @@
"featureConfidence": "medium",
"note": "A cooperation can be registered with its participant organisations. The landscape it shares is only exposed through the deelnemers API and the unrendered view enrichment; no page shows it, and there is no usage page to record it.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48844 'Municipal cooperation / shared-service management' (2026-07-23): Manages gemeente-samenwerking (shared service centres) registering a joint landscape.",
- "stackiq": "register organization.type 'Collaboration' + participants/deelnames (:2236); usage.participants (:2718); shared landscape endpoint GET /api/aangeboden-gebruik/deelnemers (lib/Controller/AangebodenGebruikController.php) has no caller in src/"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"Handleiding beheer gemeente-samenwerking ... Samenwerkingsverbanden die als doel hebben om de applicatielandschappen van de aangesloten gemeenten te harmoniseren\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30355: cooperation selects the member municipalities per package (read 2026-09-26). Reached on: Samenwerking account > Pakketten.",
+ "stackiq": "register organization.type 'Collaboration' + participants/deelnames (:2236); usage.participants (:2718); shared landscape endpoint GET /api/aangeboden-gebruik/deelnemers (lib/Controller/AangebodenGebruikController.php) has no caller in src/",
+ "topdesk": "unknown: cooperations of organisations are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: entities form a tree (src/Entity.php:58 extends CommonTreeDropdown) and records flagged recursive are shared with all child entities (src/Appliance.php:325 is_recursive), so a parent entity can hold a landscape shared by several subordinate units; there is no cooperation of independent organisations. Reached on: Administration > Entities; Appliance Child entities field."
},
"pendingQuestion": "Does the external VNG frontend show a cooperation's shared landscape from /api/aangeboden-gebruik/deelnemers?"
},
@@ -4432,11 +4790,11 @@
"area": "organisations",
"name": "Keep each organisation's records visible only to that organisation unless published.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "specified",
@@ -4449,8 +4807,10 @@
"providerHow": "read-from-code",
"note": "Organisation-scoped reads are declared per schema and the custom endpoints add their own guards. Whether generic pages are actually segregated depends on OpenRegister executing those match rules.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48910 'Multi-entity (tenant) segregation' (2026-07-23): Hierarchical entities for multi-org / multi-department isolation.",
- "stackiq": "register authorization.read rules with {match: {_organisation: $organisation}} on catalogContract (:3474), contactPerson (:1788), usage (:3137), connection (:3855); public reads only for published entries; lib/Controller/ContactpersonenController.php:293 org guard on the custom endpoint"
+ "glpi": "source read at 11.0.9: every query on entity scoped items is restricted to the user's active entities, src/DbUtils.php:920 getEntitiesRestrictCriteria; records carry entities_id and is_recursive (install/mysql/glpi-empty.sql:8937 and :8938 on glpi_appliances), so an entity's records stay invisible to other entities unless shared down the tree. Reached on: entity selector in the header.",
+ "stackiq": "register authorization.read rules with {match: {_organisation: $organisation}} on catalogContract (:3474), contactPerson (:1788), usage (:3137), connection (:3855); public reads only for published entries; lib/Controller/ContactpersonenController.php:293 org guard on the custom endpoint",
+ "topdesk": "https://docs.topdesk.com/en/details-about-certain-permissions.html: \"To restrict access to specific data, link the operator to branch, operator, or category filters\" (read 2026-09-26). Reached on: Operator card > filters.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E6: \"Alle gegevens ingevoerd door de gemeenten en samenwerkingen zijn alleen zichtbaar voor gemeentelijke raadplegers en beheerders\"; E2 \"Ingelogde gemeenten en samenwerkingsverbanden kunnen de applicatielandschappen en koppelingen van collega-gemeenten ... bekijken\" (read 2026-09-26)"
},
"pendingQuestion": "Does the installed OpenRegister evaluate authorization.read match rules with $organisation on the generic object list and detail endpoints the stackiq pages use?"
},
@@ -4459,10 +4819,10 @@
"area": "organisations",
"name": "Make the first user of an organisation its administrator and manager of later users.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4477,7 +4837,10 @@
"featureConfidence": "medium",
"note": "The first user of an organisation becomes its admin and later users get that admin as manager. It rides on the contact-to-account path, which reads an email field the current contact schema lacks, so it only fires for contacts that carry one.",
"evidence": {
- "stackiq": "lib/Service/Stackiq/ContactPersonHandler.php:646 first contact of an organisation gets the organisation-admin groups; lib/Service/Stackiq/HierarchyHandler.php:79 ensureOrganizationBeheerder and :130 setupManagerRelationships make later users report to the primary beheerder"
+ "stackiq": "lib/Service/Stackiq/ContactPersonHandler.php:646 first contact of an organisation gets the organisation-admin groups; lib/Service/Stackiq/HierarchyHandler.php:79 ensureOrganizationBeheerder and :130 setupManagerRelationships make later users report to the primary beheerder",
+ "topdesk": "unknown: first-user administrator rules are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/17042: \"Vanuit de gemeente is minimaal één gebruiker aangewezen als beheerder. Deze gebruiker kan nieuwe accounts aanmaken voor collega's\" (read 2026-09-26). Reached on: Gebruikersbeheer.",
+ "glpi": "source read at 11.0.9: an administrator can delegate user management per entity with a profile holding user rights, and GLPI stops a delegate from granting a profile stronger than their own, src/Profile.php:744 currentUserHaveMoreRightThan and src/Profile.php:679 getUnderActiveProfileRestrictCriteria; nothing makes the first user of an organisation its administrator automatically. Reached on: Administration > Users > Authorizations tab."
},
"pendingQuestion": "Same as org-contact-to-account: does conversion get an email for a post-migration contact?"
},
@@ -4489,7 +4852,7 @@
"vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4504,8 +4867,10 @@
"featureConfidence": "medium",
"note": "Anonymous browsing rests on RBAC read rules declared in the register and executed by OpenRegister; stackiq ships no public page, and the browsing surface is the external VNG Softwarecatalogus frontend, which is not in this repo. Note the module rule also exposes every registeredBy=Supplier module regardless of publication date.",
"evidence": {
- "vng-softwarecatalogus": "docs, intelligence competitor_features#48845 'Public open-access catalog' (2026-07-23): Catalog is publicly browsable; free to use for municipalities and suppliers.",
- "stackiq": "lib/Settings/softwarecatalogus_register.json:7307 module authorization.read grants group public on publicationDate<=$now (and, separately, on registeredBy=Supplier); lib/Settings/softwarecatalogus_register.json:1559 catalogService same; suite read is plain 'public' (lib/Settings/softwarecatalogus_register.json:1270). No stackiq route is #[PublicPage] except intake/review aggregate/gebruik (lib/Controller/GebruikController.php:102 returns an empty envelope to anonymous callers). The app's pages are all behind Nextcloud login (appinfo/routes.php:313 SPA catch-all)."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E6: \"Iedereen kan de softwarecatalogus raadplegen ... De gegevens ingevoerd door de leveranciers zijn openbaar\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketten: package list readable without login (read 2026-09-26). Reached on: Alle pakketten.",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json:7307 module authorization.read grants group public on publicationDate<=$now (and, separately, on registeredBy=Supplier); lib/Settings/softwarecatalogus_register.json:1559 catalogService same; suite read is plain 'public' (lib/Settings/softwarecatalogus_register.json:1270). No stackiq route is #[PublicPage] except intake/review aggregate/gebruik (lib/Controller/GebruikController.php:102 returns an empty envelope to anonymous callers). The app's pages are all behind Nextcloud login (appinfo/routes.php:313 SPA catch-all).",
+ "topdesk": "unknown: the Self-Service Portal requires a login per the SSP login settings; public browsing of assets is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: the only anonymous content is the public FAQ, gated by use_public_faq (src/KnowbaseItem.php:131, src/Document.php:717); asset, appliance and software lists all require a session (src/Glpi/Controller/GenericListController.php checks canView)."
},
"pendingQuestion": "Does the installed OpenRegister honour the {group: public, match: {publicationDate: {$lte: $now}}} read rule on module/catalogService for an anonymous GET /apps/openregister/api/objects, and which public frontend (the external VNG Softwarecatalogus site) is the intended browse surface?"
},
@@ -4530,8 +4895,10 @@
"providerHow": "read-from-code",
"note": "There is no dedicated developer-facing public API: public access to the offering is whatever OpenRegister executes from the declared read rules, and stackiq's own offering endpoint requires login.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141847 '12.19 Public data API with certificates or API keys': the API is fully authenticated, never public: user tokens plus optional app tokens with IP allow-listing (`apirest.md:62-67`, `src/APIClient.php:42`) and OAuth2 with scopes (`src/Glpi/OAuth/`). No anonymous public datase | Rated no because API is always authenticated, source-read 2026-09-14.",
- "stackiq": "Anonymous read of the supplier offering depends on declared rules: lib/Settings/softwarecatalogus_register.json:7307 module read includes public on publicationDate<=$now and on registeredBy=Supplier; lib/Settings/softwarecatalogus_register.json:1559 catalogService public on publicationDate. Stackiq's own offering endpoint lib/Controller/AanbodController.php (routes.php:202) is authenticated-only (@NoAdminRequired + in-body guard). Rate limit only on GebruikController (#[AnonRateLimit])."
+ "glpi": "source read at 11.0.9: the v2 API routes without authentication are only the index, documentation and getting started pages, src/Glpi/Api/HL/Controller/CoreController.php:301, :322, :397, :407; all data routes require OAuth or session auth, and there is no supplier offering to expose.",
+ "stackiq": "Anonymous read of the supplier offering depends on declared rules: lib/Settings/softwarecatalogus_register.json:7307 module read includes public on publicationDate<=$now and on registeredBy=Supplier; lib/Settings/softwarecatalogus_register.json:1559 catalogService public on publicationDate. Stackiq's own offering endpoint lib/Controller/AanbodController.php (routes.php:202) is authenticated-only (@NoAdminRequired + in-body guard). Rate limit only on GebruikController (#[AnonRateLimit]).",
+ "topdesk": "unknown: the REST API requires an operator or API account; a public API is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no public API is documented; public data is offered as CSV downloads; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)"
},
"pendingQuestion": "Does the installed OpenRegister execute the module/catalogService public read rules for anonymous API callers, and is any API key or rate limit applied to that public surface?"
},
@@ -4543,7 +4910,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4556,7 +4923,10 @@
"providerHow": "read-from-code",
"note": "The contribution is declarative and read-only, and it covers only an organisation's own records for portal subjects. It shows nothing publicly, and the create/accept actions are deferred per its own docblock.",
"evidence": {
- "stackiq": "lib/Portal/PortalContributionProvider.php:130 getContribution() declares read-only, organisation-scoped collections (catalogService, usage, catalogContract, compliancy) for the vendor-org and participant-org audiences. Portaliq discovers it by FQCN from the Stackiq in appinfo/info.xml (portaliq lib/Contribution/PortalProviderLocator.php:49/77). No info.xml dependency; inert without portaliq."
+ "stackiq": "lib/Portal/PortalContributionProvider.php:130 getContribution() declares read-only, organisation-scoped collections (catalogService, usage, catalogContract, compliancy) for the vendor-org and participant-org audiences. Portaliq discovers it by FQCN from the Stackiq in appinfo/info.xml (portaliq lib/Contribution/PortalProviderLocator.php:49/77). No info.xml dependency; inert without portaliq.",
+ "topdesk": "unknown: no shared external portal is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no external portal integration is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: no embeddable widget or external portal integration for catalogue content; the self service interface (src/Glpi/Form/ServiceCatalog/ServiceCatalog.php:45) is GLPI's own helpdesk portal and grep -rli 'iframe embed\\|oembed' over src/ returns nothing."
},
"pendingQuestion": "Does the installed portaliq render stackiq's contribution (its PortalProviderLocator iterating installed apps), and is that portal live for any stackiq customer?"
},
@@ -4568,8 +4938,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "no",
+ "topdesk": "no",
"stackiq": "partial",
"built": {
"state": "none",
@@ -4581,7 +4951,10 @@
"providerHow": "read-from-code",
"note": "Stackiq has nothing of its own here. An AI client could only reach catalogue objects through OpenRegister's generic MCP server, if it covers the voorzieningen register.",
"evidence": {
- "stackiq": "No MCP, tool-provider, TaskProcessing or ContextChat code in stackiq lib/ or src/ (grep 'mcp|ToolProvider|assistant|TaskProcessing|ContextChat' in lib/ finds nothing). OpenRegister ships a generic MCP endpoint (openregister appinfo/routes.php:1969 /api/mcp/v1/discover and the JSON-RPC endpoint) over all registers."
+ "stackiq": "No MCP, tool-provider, TaskProcessing or ContextChat code in stackiq lib/ or src/ (grep 'mcp|ToolProvider|assistant|TaskProcessing|ContextChat' in lib/ finds nothing). OpenRegister ships a generic MCP endpoint (openregister appinfo/routes.php:1969 /api/mcp/v1/discover and the JSON-RPC endpoint) over all registers.",
+ "topdesk": "https://tip.topdesk.com/c/200-ai-mcp-based-service-: roadmap card in column \"Building\", \"Model Context Protocol (MCP-based service) allows secure, controlled connectivity between your TOPdesk environment and LLM-powered assistants\" (read 2026-09-26); the shipped TOPdesk Robin works inside tickets (https://docs.topdesk.com/en/td-robin-for-operators.html).",
+ "vng-softwarecatalogus": "unknown: no assistant or tool interface is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'mcp\\|model context\\|openai\\|llm' over src/ returns nothing; AI tool access would go through the generic v2 API (src/Glpi/Api/HL/Controller/AssetController.php:149) with no tool interface of its own."
},
"pendingQuestion": "Does OpenRegister's MCP server expose the voorzieningen register's objects (module, catalogService, organization) for read and write to an AI client with a stackiq user's rights?"
},
@@ -4593,8 +4966,8 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown",
+ "glpi": "yes",
+ "topdesk": "yes",
"stackiq": "partial",
"built": {
"state": "none",
@@ -4606,7 +4979,10 @@
"providerHow": "read-from-code",
"note": "Change notification to another system is possible only through OpenRegister machinery: its webhooks UI, or a flow authored on stackiq's Flows page. Stackiq itself sends nothing.",
"evidence": {
- "stackiq": "Stackiq has no webhook code. The Flows page (src/manifest.json:1057, settings-section menu entry FlowsMenu) authors OpenRegister's native flows scoped to app stackiq; OpenRegister's flow event catalogue has object.created/object.updated (openregister lib/Service/Flow/EventCatalogService.php:53-54), and OpenRegister has its own webhooks admin (openregister appinfo/routes.php:1909)."
+ "stackiq": "Stackiq has no webhook code. The Flows page (src/manifest.json:1057, settings-section menu entry FlowsMenu) authors OpenRegister's native flows scoped to app stackiq; OpenRegister's flow event catalogue has object.created/object.updated (openregister lib/Service/Flow/EventCatalogService.php:53-54), and OpenRegister has its own webhooks admin (openregister appinfo/routes.php:1909).",
+ "topdesk": "https://docs.topdesk.com/en/let-your-topdesk-talk-to-other-applications.html: \"Send a request from TOPdesk to another program ... This way you can create an integration with almost any software that has an API\" (read 2026-09-26) triggered by card events (https://docs.topdesk.com/en/events-that-trigger-actions.html). Reached on: Action Management > action sequences.",
+ "vng-softwarecatalogus": "unknown: notifications go to people by mail and inbox, no system webhooks are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: src/Webhook.php:64 Webhook sends HTTP calls on new, update and delete events (src/Webhook.php:311 getDefaultEventsList) for management itemtypes including Appliance, Budget, Contact and others (src/Webhook.php:398). Reached on: Setup > Webhooks (src/Html.php:1331)."
},
"pendingQuestion": "Can a flow created on stackiq's Flows page be triggered by object.updated on a catalogue schema and make an outbound HTTP call to an external system?"
},
@@ -4633,9 +5009,10 @@
"featureConfidence": "high",
"note": "Per-record history is shown on 11 detail pages, backed by OpenRegister's audit trail. There is no catalogue-wide view of who changed what, and the overlay itself lists audit-trail-view as 'soon'.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141820 '10.5 Audit or event log viewer with filters and export': two logs, both searchable and exportable through the search engine: `src/Log.php:48` field-level object history (Historical tab, `src/Ticket.php:887`) and `src/Glpi/Event.php:63` the system/event log at `/front/logs.php` | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141852 '13.9 Audit trail including reads and views': writes are covered thoroughly: `src/Log.php:48` field-level history on every object, `src/Glpi/Event.php:63` the system log including logins (`src/Auth.php:1149-1163`), `src/RuleMatchedLog.php` for rule decisions. Reads | Rated yes because field-level history, source-read 2026-09-14.",
- "topdesk": "docs, intelligence competitor_features#26345 'Audit Trail' (2026-04-10): Complete audit trail of all service management actions",
- "stackiq": "src/manifest.json:436 (and 10 more detail pages: ContactpersoonDetail, ModuleDetail, ContractDetail, SuiteDetail, StandaardDetail, BioMaatregelDetail, ReviewDetail, KompliantieDetail, ModuleversieDetail, KwetsbaarheidDetail) declare a sidebar tab History with widget type audit, which reads OpenRegister's audit trail for that one object."
+ "glpi": "source read at 11.0.9: src/Appliance.php:58 dohistory is true and src/Appliance.php:112 adds the Historical tab (src/Log.php:48 Log), recording who changed which field and when. Reached on: Management > Appliances > Historical tab.",
+ "topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: \"History widget : shows both present and past changes that have been made to an asset\" (read 2026-09-26); https://docs.topdesk.com/en/cards-in-call-management.html: \"Audit trail tab Previous events while processing this call\" (read 2026-09-26). Reached on: Asset card > History widget.",
+ "stackiq": "src/manifest.json:436 (and 10 more detail pages: ContactpersoonDetail, ModuleDetail, ContractDetail, SuiteDetail, StandaardDetail, BioMaatregelDetail, ReviewDetail, KompliantieDetail, ModuleversieDetail, KwetsbaarheidDetail) declare a sidebar tab History with widget type audit, which reads OpenRegister's audit trail for that one object.",
+ "vng-softwarecatalogus": "unknown: only a \"Laatst gewijzigd\" date on supplier pages and a mutation date in exports are shown; who changed what is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)"
},
"pendingQuestion": "Is OpenRegister's audit trail enabled for the voorzieningen register on a default install, so the History tab shows entries?"
},
@@ -4647,7 +5024,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "partial",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
"built": {
@@ -4662,7 +5039,10 @@
"note": "Five custom pages subscribe to collection events and refetch on a change. Whether the event ever arrives depends on OpenRegister and the push transport, which this repo cannot show.",
"evidence": {
"bluedolphin": "docs, intelligence competitor_features#48969 'Real-time collaboration' (2026-07-23): Multiple stakeholders collaborate on models. | Rated partial because real-time collaboration on models.",
- "stackiq": "src/composables/useLiveCollections.js:40 subscribes via the library's useObjectSubscription; used in src/views/KwetsbaarhedenView.vue:197, LicensePostureView.vue:209, LifecycleRoadmapView.vue:184, ComplianceMatrixView.vue:326, PortfolioReport.vue:323. The standard index pages (Contracts, Organisations and others) rely on whatever the library's CnIndexPage does."
+ "stackiq": "src/composables/useLiveCollections.js:40 subscribes via the library's useObjectSubscription; used in src/views/KwetsbaarhedenView.vue:197, LicensePostureView.vue:209, LifecycleRoadmapView.vue:184, ComplianceMatrixView.vue:326, PortfolioReport.vue:323. The standard index pages (Contracts, Organisations and others) rely on whatever the library's CnIndexPage does.",
+ "topdesk": "unknown: live list updates are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: no live list updates are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'websocket\\|EventSource' over src/ finds only src/Glpi/Api/HL/Controller/NotificationController.php:303 'websocket: Not used by GLPI core'; lists refresh on reload only."
},
"pendingQuestion": "Does the installed OpenRegister publish or-collection-{register}-{schema} events over a transport (notify_push or SSE) that the nc-vue liveUpdatesPlugin receives, so these pages update without a reload?"
},
@@ -4671,11 +5051,11 @@
"area": "insight",
"name": "Receive in-app notifications about changes that concern you.",
"origin": "own-code",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "partial",
- "topdesk": "unknown",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "specified",
@@ -4689,8 +5069,10 @@
"featureConfidence": "high",
"note": "Every notification rests on a declaration OpenRegister must execute. At least one rule (contract expiry) filters on a stale Dutch status value and would never fire, and its subject template uses fields (contractNummer, eindDatum) the schema no longer has.",
"evidence": {
- "glpi": "source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#141783 '6.8 In-app notifications (bell)': `MODE_AJAX` is a wired delivery mode (`src/Notification_NotificationTemplate.php:55-59`, `getModes()` at `:381-398`, implementation `src/NotificationAjax.php`), rendering as a browser toast rather than a persistent inbox | Rated partial because toast delivery, not an inbox, source-read 2026-09-14.",
- "stackiq": "Only declarations: x-openregister-notifications on vulnerability (lib/Settings/softwarecatalogus_register.json:1622), usage (:2662), catalogContract (:3253), software-review (:3962), module (:6781), moduleVersion (:7652). Stackiq has no INotifier or notification code of its own (grep in lib/). The contract-expiry rule filters status equals 'Actief' (lib/Settings/softwarecatalogus_register.json:3255) while the enum is Active/Expired/In negotiation, so it can never match."
+ "glpi": "source read at 11.0.9: besides mail there is a browser notification mode, src/NotificationAjax.php:42 and src/Notification_NotificationTemplate.php:56 MODE_AJAX, but it only carries events that notification targets define (tickets, changes, contracts, licences, saved search alerts and similar); changes to an appliance raise no notification event. Reached on: Setup > Notifications > Browser followups configuration.",
+ "stackiq": "Only declarations: x-openregister-notifications on vulnerability (lib/Settings/softwarecatalogus_register.json:1622), usage (:2662), catalogContract (:3253), software-review (:3962), module (:6781), moduleVersion (:7652). Stackiq has no INotifier or notification code of its own (grep in lib/). The contract-expiry rule filters status equals 'Actief' (lib/Settings/softwarecatalogus_register.json:3255) while the enum is Active/Expired/In negotiation, so it can never match.",
+ "topdesk": "https://docs.topdesk.com/en/topdesk-mobile.html: \"change your notification settings\" in the mobile app (read 2026-09-26); https://docs.topdesk.com/en/action-management.html: \"specific mobile alerts for operators\" (read 2026-09-26). Mostly email and mobile alerts, no in-app inbox described. Reached on: TOPdesk Mobile; Action Management.",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Gemeenten, samenwerkingen, en leveranciers hebben nu rechtsboven bij het inlogmenu een inbox-symbool met daarbij het aantal nieuwe berichten\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E17 \"De softwarecatalogus bevat een notificatievoorziening en een inbox voor gemeenten en samenwerkingen\" (read 2026-09-26). Reached on: Inlogmenu > Inbox."
},
"pendingQuestion": "Does the installed OpenRegister dispatch the x-openregister-notifications rules on vulnerability, software-review, moduleVersion and the scheduled rules on catalogContract/usage/module, as Nextcloud notifications to the listed recipients?"
},
@@ -4703,7 +5085,7 @@
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
- "topdesk": "yes",
+ "topdesk": "partial",
"stackiq": "partial",
"built": {
"state": "built",
@@ -4715,9 +5097,10 @@
"providerHow": "read-from-code",
"note": "The store installs configuration sets and flows, not code plugins, and it depends on a registry being configured.",
"evidence": {
- "glpi": "docs, intelligence competitor_features#48906 'Plugin ecosystem' (2026-07-23): Large plugin marketplace (FormCreator, GenericObject, etc.). | source read of GLPI by the procest lane on 2026-09-14, intelligence competitor_features#145919 'C-configuration-48 An extension is found, installed, updated and removed from inside the product.': glpi: Marketplace (Setup, Plugins, front/marketplace.php, marketplace.download.php, front/plugin.php) Lane findings: D-glpi-45.",
- "topdesk": "docs, intelligence competitor_features#27391 'Marketplace Integrations' (2026-04-12): TOPdesk Marketplace with third-party integrations including Lansweeper, BlueDolphin",
- "stackiq": "src/manifest.json:225 Store page (type store, footer menu StoreMenu) over the OpenRegister store plane, with store.types openregister.configset and openregister.flows; its own note says that with no registry configured it shows only the app's built-in items."
+ "glpi": "source read at 11.0.9: src/Glpi/Marketplace/View.php:53 marketplace view at front/marketplace.php (src/Glpi/Marketplace/View.php:103) and src/Glpi/Marketplace/Controller.php:64 download and install of plugins; src/Glpi/Marketplace/View.php:185 notes that a registration, at least a free one, is required. Reached on: Setup > Plugins > Marketplace.",
+ "topdesk": "https://marketplace.topdesk.com/: \"Showing all 133 results\" of integrations (read 2026-09-26); https://docs.topdesk.com/en/exporting-and-importing.html: \"import an action sequence example from the TOPdesk Marketplace\" (read 2026-09-26). Integrations and action-sequence templates, not installable plugins. Reached on: TOPdesk Marketplace.",
+ "stackiq": "src/manifest.json:225 Store page (type store, footer menu StoreMenu) over the OpenRegister store plane, with store.types openregister.configset and openregister.flows; its own note says that with no registry configured it shows only the app's built-in items.",
+ "vng-softwarecatalogus": "unknown: no plugins are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
},
"pendingQuestion": "Is a store registry configured on a default install, and are any stackiq configuration sets published to it?"
}
From cca6e68453b94279ad4de3af5a1f5765589eb3e6 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:17:05 +0200
Subject: [PATCH 20/45] chore(parity): apply r-glpi errata, land-demo-data no
to partial
---
openspec/parity/capabilities.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index bd7d02a32..324cf2d25 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -568,7 +568,7 @@
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "no",
+ "glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
"built": {
@@ -584,7 +584,7 @@
"stackiq": "src/manifest.json:3 setup wizard step load-demo-data (:24); lib/Controller/SetupController.php:202 runAction load-demo-data (AuthorizedAdminSetting); lib/Service/DemoDataService.php:202 install() imports lib/Settings/stackiq_mock_register.json (120 objects, 6 per schema) through OpenRegister ConfigurationService::importFromApp",
"topdesk": "unknown: no example data set is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the catalogue is one hosted service; no loadable example data set is described (a \"VNG Realisatie Demo\" supplier appears in the live data); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
- "glpi": "source read at 11.0.9: grep -ril 'demo data\\|sample data' over src/ templates/ locales/glpi.pot returns nothing and src/Glpi/Console/ has no demo loader; example data exists only as test fixtures under tests/, not shipped as a feature."
+ "glpi": "source read at 11.0.9: on a clean install dashboards render placeholder figures from src/Glpi/Dashboard/FakeProvider.php:65 FakeProvider, with the banner 'You are viewing demonstration data.' and a 'Disable demonstration' button (src/Glpi/Dashboard/Grid.php:427, :428, :448); CHANGELOG.md 11.0.0 lists it. No example records (applications, contracts, suppliers) are loaded; the console entry point src/Glpi/Console/Application.php:66 has no demo data command. Reached on: Home > Dashboard on a fresh install."
}
},
{
From ca32289bd40a139501e5a765d1f13ee9fe82d1c0 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:19:50 +0200
Subject: [PATCH 21/45] chore(parity): record the GLPI 11.0.9 lab drive on 26
cells
---
openspec/parity/capabilities.json | 121 +++++++++++++++++-------------
1 file changed, 68 insertions(+), 53 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index 324cf2d25..d1b800b3d 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -179,9 +179,9 @@
"note": "An application with supplier and description can be registered on the Modules page, but the module schema has no status field, and the per-organisation usage that carries a status has no page to create it on. The Modules list also cannot open ModuleDetail: its standalone CnIndexPage (FacetedCatalogIndexView.vue:108-117) binds no @view/@row-click, so the View action is inert.",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"klik dan op de knop + achter de beschrijving van het pakket om het pakket toe te voegen aan je omgeving ... Pakketversie ... Referentiecomponenten ... Vul onder Planning bij Status in gebruik in\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus: \"Wanneer Gemeenten en samenwerkingen hun applicatielandschap hebben ingevoerd, wordt deze automatisch geplot op de GEMMA referentiecomponentenkaart\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Voeg pakket toe.",
- "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | docs, intelligence competitor_features#27422 'Fact Sheets & Data Model' (2026-04-12): Flexible data model for applications, processes, IT components",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Applications are software systems or programs that process or analyze business data'; application fact sheet with description and lifecycle, supplier via 'provider -> IT component -> application relation' (https://help.sap.com/docs/leanix/ea/provider-modeling-guidelines) (read 2026-09-26). Reached on: Inventory > Application fact sheet.",
"bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository. | docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
- "glpi": "source read at 11.0.9: src/Appliance.php:46 class Appliance is GLPI's application itemtype; install/mysql/glpi-empty.sql:8935 glpi_appliances carries name, comment (description), manufacturers_id and states_id (status); src/Appliance.php:350 search option Status; supplier through the Management tab Infocom (install/mysql/glpi-empty.sql:3263 glpi_infocoms.suppliers_id) and Contract_Item (src/Appliance.php:99); menu src/Html.php:1300 lists Appliance under Management, served by src/Glpi/Kernel/Listener/RequestListener/LegacyItemtypeRouteListener.php:100. Reached on: Management > Appliances (front/appliance.php).",
+ "glpi": "source read at 11.0.9: src/Appliance.php:46 class Appliance is GLPI's application itemtype; install/mysql/glpi-empty.sql:8935 glpi_appliances carries name, comment (description), manufacturers_id and states_id (status); src/Appliance.php:350 search option Status; supplier through the Management tab Infocom (install/mysql/glpi-empty.sql:3263 glpi_infocoms.suppliers_id) and Contract_Item (src/Appliance.php:99); menu src/Html.php:1300 lists Appliance under Management, served by src/Glpi/Kernel/Listener/RequestListener/LegacyItemtypeRouteListener.php:100. Reached on: Management > Appliances (front/appliance.php). Driven on the lab at 11.0.9 (2026-09-26): created the appliance \"Zaaksysteem lab\" with a description through /front/appliance.form.php; it appears in the Appliances list and CSV export.",
"topdesk": "https://docs.topdesk.com/en/migrating-objects-to-asset-management.html: \"In the new Asset Management you design your own template for each type of asset you have\" (read 2026-09-26); https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"Create a new template for software cards\" (read 2026-09-26). Applications are a self-designed asset type, no application model ships. Reached on: Modules > Asset Management > Template Designer / Asset overview > New.",
"stackiq": "src/manifest.json:592 Modules page (FacetedCatalogIndexView, schema module) with the library CnIndexPage create form at src/views/FacetedCatalogIndexView.vue:108; lib/Settings/softwarecatalogus_register.json:6777 module schema has name, shortDescription/longDescription and provider (Supplier) but NO status property; status lives on usage (register.json:2654, enum Acquisition..In production) which has no page"
}
@@ -192,7 +192,7 @@
"name": "Break an application into modules and see which module belongs to which product.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -209,7 +209,7 @@
"featureConfidence": "low",
"note": "Stackiq's 'module' is the whole application, so there is no breakdown of one application into modules. The nearest thing is a suite (product) listing its applications, which answers 'which module belongs to which product' but not the decomposition.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated partial because fact sheets separate Application from IT Component.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Applications often consist of multiple entities or modules within a common ecosystem or platform', modeled as parent/child hierarchy, e.g. Adobe Photoshop as child of Adobe Creative Cloud (read 2026-09-26). Reached on: Application fact sheet > parent/child relations.",
"stackiq": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')",
"topdesk": "unknown: assets can be linked parent to child, but no application module concept is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the docs model a pakket and its pakketversies only, no module level is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
@@ -222,7 +222,7 @@
"name": "Record the released versions of a module, with the date each came into use.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -242,7 +242,8 @@
"glpi": "source read at 11.0.9: src/SoftwareVersion.php:42 SoftwareVersion child of Software, table install/mysql/glpi-empty.sql:6900 glpi_softwareversions with name, states_id, operatingsystems_id but no release or in-use date; the only date is per installation, install/mysql/glpi-empty.sql:1074 glpi_items_softwareversions.date_install. Reached on: Assets > Software > Versions tab (front/softwareversion.form.php).",
"stackiq": "src/manifest.json:915 Moduleversies type:index (columns version, module, dateInUse, status) + :937 ModuleversieDetail; register.json:7649 moduleVersion schema with dateInUse (register.json:7746), dateInDevelopment, dateEndSupport, dateWithdrawn",
"topdesk": "unknown: no version records per application or module are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Titel is de naam van uw productversie ... Status geeft aan of uw product in ontwikkeling, in productie, of teruggetrokken is ... startdata van ontwikkeling, test en distributie\" (read 2026-09-26). Versions are recorded per package (pakketversie), not per module. Reached on: Supplier login > Productportfolio > product > plus (versie toevoegen)."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Titel is de naam van uw productversie ... Status geeft aan of uw product in ontwikkeling, in productie, of teruggetrokken is ... startdata van ontwikkeling, test en distributie\" (read 2026-09-26). Versions are recorded per package (pakketversie), not per module. Reached on: Supplier login > Productportfolio > product > plus (versie toevoegen).",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'if versioning is relevant ... you can capture it in the Release field of the application fact sheets'; each fact sheet carries lifecycle phase dates, but the guide says 'versioning for applications doesn't add significant value' (read 2026-09-26). Reached on: Application fact sheet > Name and Description > Release."
}
},
{
@@ -251,7 +252,7 @@
"name": "Bundle several existing applications into one suite that is offered as a single product.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -271,6 +272,7 @@
"stackiq": "src/dialogs/SuiteWizardDialog.vue:183 onSubmit saves a suite via objectStore.saveObject('suite') with applications[] (src/utils/suiteWizard.js:44 requires at least one); mounted by src/views/suites/SuitesIndexView.vue:46 on manifest page Suites (src/manifest.json:666)",
"topdesk": "unknown: no suite bundling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no bundling of packages into a suite is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Adobe Creative Cloud is a suite that bundles various applications ... It is modeled as the parent entity'; a platform fact sheet can group applications. Modeled for the buyer's own inventory, not as a product offered to others (read 2026-09-26). Reached on: Application fact sheet hierarchy, Platform fact sheet.",
"glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:562 appliance_types contains Appliance and Software, so an Appliance can bundle existing appliances and software through src/Appliance_Item.php:45 (table install/mysql/glpi-empty.sql:8979 glpi_appliances_items). There is no notion of offering the bundle as a product to others. Reached on: Management > Appliances > Items tab."
}
},
@@ -280,7 +282,7 @@
"name": "Register a service a supplier delivers on top of applications, such as hosting or support.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "yes",
@@ -300,6 +302,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: facet \"Ondersteunde technologie: On-premise, Dienst - Software as a Service (SAAS)\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30355: \"Onder het tabblad Technologie selecteer je de onderliggende technieken van het pakket. Veelal Saas of on-premise\" (read 2026-09-26). Hosting as SaaS is a property of a package version, no separate service record (hosting, support) is documented. Reached on: Alle pakketversies > filter Ondersteunde technologie.",
"stackiq": "src/manifest.json:647 Diensten page (FacetedCatalogIndexView, schema catalogService) with the CnIndexPage create form; register.json:1324 catalogService with provider (required), modules[] (register.json:1419) and type enum Functional/Application/Technical management, Implementation support, Training, Licence reseller (register.json:1459)",
"topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"Services you offer may rely on services of external suppliers. These services are called underpinning services. TOPdesk allows you to link your services to supplier services\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: \"On Call, Change (Activity), Operational Activity, Knowledge Item, Problem, and Service cards, you can link multiple assets in one go\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM > Service card > Links > Assets.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/it-component-modeling-guidelines: IT component subtype 'Service : Services refer to the provisioning of services related to IT components (usually provided by a 3rd party) ... Examples: Maintenance/Support Service ... Hosting Service'; linked to providers (read 2026-09-26). Reached on: Inventory > IT Component fact sheet, subtype Service.",
"glpi": "source read at 11.0.9: no supplier service itemtype; services are held as contracts, src/ContractType.php:37 admin dropdown of contract types (for example hosting or support), install/mysql/glpi-empty.sql:1550 glpi_contracts_suppliers ties the contract to a Supplier and install/mysql/glpi-empty.sql:1536 glpi_contracts_items ties it to the Appliance or Software it covers. Reached on: Management > Contracts (front/contract.php), Suppliers tab."
}
},
@@ -309,7 +312,7 @@
"name": "Tag applications with the government sectors they are meant for.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -327,6 +330,7 @@
"stackiq": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395",
"topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: facets \"Domein\" (Bestuur, Fysieke leefomgeving, Sociaal domein, ...) and \"Doelgroep\" (Gemeente, Generiek, Inwoners en ondernemers, Ketenpartners) (read 2026-09-26). Domains are municipal policy domains, the catalogue serves municipalities only, not other government sectors. Reached on: Alle pakketversies > filters Domein, Doelgroep.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/tags-and-custom-fields: tags and tag groups for 'quick, high-level classification', filterable and usable as reporting views; no predefined government sector list is documented (read 2026-09-26). Reached on: Fact sheet > Tags.",
"glpi": "source read at 11.0.9: no government sector concept, grep -i 'sector' over src/*.php and locales/glpi.pot hits only menu sectorization (src/Html.php:1019); the nearest holder is the single-valued Appliance type dropdown install/mysql/glpi-empty.sql:8941 appliancetypes_id, or an admin custom dropdown (install/mysql/glpi-empty.sql:10113 glpi_dropdowns_dropdowndefinitions) used as a field of a custom asset. Multi-valued tagging needs the separate tag plugin (github.com/pluginsGLPI/tag, not read). Reached on: Management > Appliances, Appliance type field."
}
},
@@ -336,7 +340,7 @@
"name": "Name the business owner and the technical owner responsible for an application.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -353,11 +357,11 @@
"featureConfidence": "low",
"note": "One contact person per application can be set, but there is no separate business owner and technical owner. ModuleDetail's data widget includes 'contactpersoon', a key the schema no longer has, so the contact may not show there.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | Rated partial because surveys go to application owners, so ownership is modelled.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/subscription-roles: 'Define roles that map to your organization's positions, such as application owner', with subscription types 'Responsible, Accountable, Observer' per fact sheet (read 2026-09-26). Reached on: Fact sheet > Subscriptions; Administration > Subscription Roles.",
"stackiq": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')",
"topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: \"Assignment widget : assigns locations and persons to the asset\" (read 2026-09-26). No separate business and technical owner roles are described. Reached on: Asset card > Assignment widget.",
"vng-softwarecatalogus": "unknown: the landscape entry fields listed (pakketversie, referentiecomponenten, technologie, status) include no business or technical owner; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30355 (read 2026-09-26)",
- "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:8935 glpi_appliances holds users_id and users_id_tech; src/Appliance.php:186 search option User and src/Appliance.php:195 Group (business side), src/Appliance.php:240 'Technician in charge' and the 'Group in charge' option a few lines below (technical side). Reached on: Management > Appliances, form fields User, Group, Technician in charge, Group in charge."
+ "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:8935 glpi_appliances holds users_id and users_id_tech; src/Appliance.php:186 search option User and src/Appliance.php:195 Group (business side), src/Appliance.php:240 'Technician in charge' and the 'Group in charge' option a few lines below (technical side). Reached on: Management > Appliances, form fields User, Group, Technician in charge, Group in charge. Driven on the lab at 11.0.9 (2026-09-26): the saved appliance holds users_id and users_id_tech (glpi_appliances row 1), shown as User and Technician in charge."
}
},
{
@@ -382,8 +386,8 @@
"providerHow": "read-from-code",
"note": "Stackiq offers no way to add fields. Editing the schema in OpenRegister's own admin UI is possible there, but that is an OpenRegister feature, not a stackiq page.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because flexible fact sheet data model.",
- "glpi": "source read at 11.0.9: native custom fields exist only for admin defined custom asset types, src/Glpi/Asset/CustomFieldDefinition.php:52 child of AssetDefinition (install/mysql/glpi-empty.sql:10159 glpi_assets_customfielddefinitions keyed on assets_assetdefinitions_id), set up under Setup > Asset definitions (src/Html.php:1330). The core Appliance and Software types take no custom fields in core; that needs the fields plugin, read at pluginsGLPI/fields tag 1.24.5, inc/container.class.php:91 containers with a list of itemtypes. Reached on: Setup > Asset definitions > Custom fields; or plugin Fields.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/fact-sheet-fields: 'Adding a Custom Field ... To add a custom field, follow these steps'; https://help.sap.com/docs/leanix/ea/tags-and-custom-fields: custom fields as text, dates, numbers, set in the meta model configuration by an admin (read 2026-09-26). Reached on: Administration > Meta Model Configuration > Fact Sheet Fields.",
+ "glpi": "source read at 11.0.9: native custom fields exist only for admin defined custom asset types, src/Glpi/Asset/CustomFieldDefinition.php:52 child of AssetDefinition (install/mysql/glpi-empty.sql:10159 glpi_assets_customfielddefinitions keyed on assets_assetdefinitions_id), set up under Setup > Asset definitions (src/Html.php:1330). The core Appliance and Software types take no custom fields in core; that needs the fields plugin, read at pluginsGLPI/fields tag 1.24.5, inc/container.class.php:91 containers with a list of itemtypes. Reached on: Setup > Asset definitions > Custom fields; or plugin Fields. Driven on the lab at 11.0.9 (2026-09-26): Setup > Asset definitions (/front/asset/assetdefinition.php) is where custom asset types and their fields are defined; appliances themselves take no custom fields in core.",
"stackiq": "Looked in src/manifest.json, src/views, lib/Controller: no field-definition or schema-extension UI in stackiq; the data model is fixed in lib/Settings/softwarecatalogus_register.json",
"topdesk": "https://docs.topdesk.com/en/creating-new-fields.html: \"Whether it is a contact person, a purchase price, or a reminder date ... Use fields in a fieldset or dataset widget to register any useful information about an asset\" (read 2026-09-26). Reached on: Asset Management > Template Designer > Fields.",
"vng-softwarecatalogus": "unknown: no user-defined fields are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
@@ -395,7 +399,7 @@
"name": "Import an existing application list in bulk from a spreadsheet or file.",
"origin": "competitor",
"vng-softwarecatalogus": "no",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "yes",
"glpi": "partial",
"topdesk": "yes",
@@ -410,7 +414,7 @@
"providerHow": "read-from-code",
"note": "The generic index page offers a file import (CSV per schema, or a register-wide JSON/Excel) that OpenRegister executes. Nothing stackiq-specific maps a spreadsheet's supplier names to organisation references, so relation columns must already hold identifiers.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#27428 'EAM Automation' (2026-04-12): Automated data collection from ServiceNow, Jira, cloud providers | Rated partial because automated collection from ServiceNow, Jira and cloud.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/importing-fact-sheet-data-through-excel-file and https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: 'using the import option, you can update multiple fact sheets in bulk' via Excel export and import (read 2026-09-26). Reached on: Inventory > Import (Excel).",
"bluedolphin": "docs, intelligence competitor_features#48971 'Data import (Excel)' (2026-07-23): Bulk import of application/portfolio data.",
"stackiq": "Library CnIndexPage (@conduction/nextcloud-vue 2.55.1, package-lock) showMassImport default true (CnIndexPage.vue:1599) and self-mode handleMassImport (selfModeActions.js:168) POSTs to /apps/openregister/api/registers/{register}/import with the schema for CSV (selfModeIO.js:82); rendered on the Modules page's CnIndexPage (src/views/FacetedCatalogIndexView.vue:108)",
"topdesk": "https://docs.topdesk.com/en/generate-import-file.html: \"Importing assets speeds up this task ... export an asset template to XLSX format\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-new-import.html: \"You can use a file (CSV or XLSX), connect with an MS SQL database or import from Microsoft Intune , or Lansweeper\" (read 2026-09-26). Reached on: Settings > Import settings > Asset Management imports.",
@@ -442,7 +446,7 @@
"note": "The application page shows versions and compliance claims, and usages only as untyped entries in the generic Related panel. Contracts are not shown. The page cannot be opened from the Applications list itself, and its data widget asks for three field names the schema no longer has, so the descriptions do not render.",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakket/archi: package page shows versions with status and start dates, \"Pakket geschikt voor (GEMMA 2) Ingevuld door (28)\", and per version the mandatory and recommended standards with support, compliancy and testrapport (read 2026-09-26). No contracts on the page. Reached on: Alle pakketten > package name.",
- "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because fact sheet is the per-application page.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines and https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: the application fact sheet holds lifecycle, relations to IT components, organizations, interfaces, cost on relations, and a Relations Explorer on one fact sheet (read 2026-09-26). Reached on: Inventory > Application fact sheet.",
"stackiq": "src/manifest.json:491 ModuleDetail: md-versions (:504), md-compliance (:503), md-related generic Related panel (:502); no contract widget (catalogContract links to service/usage, register.json:3250, not to module); md-data include lists stale keys beschrijvingKort/beschrijvingLang/contactpersoon (:500)",
"topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: twelve widgets incl. \"History\", \"Relationships\", \"Relationship grid\", \"Documents\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: assets linked to calls, changes, services (read 2026-09-26). Versions and compliance are not part of it. Reached on: Asset card.",
"glpi": "source read at 11.0.9: src/Appliance.php:98 onwards defineTabs puts Items, Contracts, Documents, Management (Infocom), Certificates, Domains, Knowledge base, Tickets, Problems, Changes and Impact on the one appliance page; versions sit on the separate Software page (src/SoftwareVersion.php:42), and no compliance tab exists (grep -i 'complian' src/Appliance.php returns nothing). Reached on: Management > Appliances > appliance form tabs."
@@ -454,7 +458,7 @@
"name": "Select many catalogue entries at once and publish, lock or delete them together.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -474,7 +478,8 @@
"stackiq": "Library CnIndexPage mass delete/copy/export (showMassDelete default true, CnIndexPage.vue:1617; selfModeActions.js:63 handleMassDelete) on index pages; stackiq's MassPublishObjects/MassLockObjects dialogs (src/dialogs/Dialogs.vue:8-14) are only opened from src/modals/object/ViewObject.vue:4865, and ViewObject is only mounted for modals 'viewOrganisatie'/'viewContactpersoon' (src/modals/Modals.vue:7,19) which nothing in src/ sets",
"topdesk": "https://docs.topdesk.com/en/editing-assets-in-bulk.html: \"select multiple assets by ticking their boxes ... You can use bulk edit for updating up to 500 assets\" (read 2026-09-26); editable are assignments, drop-down, date, number, text and checkbox fields. Bulk publish or delete is not described. Reached on: Asset Management > Asset overview > select > bulk edit.",
"vng-softwarecatalogus": "unknown: no multi-select publish, lock or delete is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "glpi": "source read at 11.0.9: every search list offers massive actions, src/MassiveAction.php:666 Update (any field, for example status), src/MassiveAction.php:698 Put in trashbin, src/MassiveAction.php:652 Delete permanently, src/MassiveAction.php:656 Restore. There is no publish state; locking applies to inventory fields only. Reached on: any list, for example Management > Appliances, Actions button."
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: 'switch to table view in the inventory, you can perform inline editing across multiple fact sheets'; https://help.sap.com/docs/leanix/ea/archiving-deleting-and-recovering-fact-sheets: 'Archiving Fact Sheets in Bulk' through an Excel action column. No publish or lock action is documented (read 2026-09-26). Reached on: Inventory > Table view; Excel import with action column.",
+ "glpi": "source read at 11.0.9: every search list offers massive actions, src/MassiveAction.php:666 Update (any field, for example status), src/MassiveAction.php:698 Put in trashbin, src/MassiveAction.php:652 Delete permanently, src/MassiveAction.php:656 Restore. There is no publish state; locking applies to inventory fields only. Reached on: any list, for example Management > Appliances, Actions button. Driven on the lab at 11.0.9 (2026-09-26): the Appliances list carries the massive actions control."
}
},
{
@@ -501,6 +506,7 @@
"stackiq": "src/components/organisations/OrganisationMergePanel.vue:46 (admin-only controls) mounted as OrganisatieDetail bodyWidget org-merge (src/manifest.json:430); lib/Controller/MergeController.php:106 execute with isAdmin check at :142; generic src/modals/object/MergeObject.vue only mounted for modal 'mergeOrganisatie' which nothing sets",
"topdesk": "https://docs.topdesk.com/en/migration-status.html: \"You cannot merge the two cards into one card\" (read 2026-09-26); https://tip.topdesk.com/c/239-ai-cmdb-monitoring-: roadmap card in column \"Under consideration\", \"AI can continuously scan your configuration database for duplicate records ... and surfaces them for review\" (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no merge of entries is described; the news page only mentions a pseudo-supplier \"Open Source Pakketten\" created against duplicate spellings; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/nieuws (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea (all 663 EA pages grepped for merge); duplicates are handled by archiving (https://help.sap.com/docs/leanix/ea/archiving-deleting-and-recovering-fact-sheets 'removing outdated or duplicate fact sheets'), no merge of two fact sheets is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/Software.php:109 'Merging' tab on a recursive software, src/Software.php:926 showMergeCandidates lists same named software, src/Software.php:997 massive action Merge, src/Software.php:1011 private function merge moves versions and licences into the kept entry; dropdowns get Replace, src/CommonDropdown.php:680. Reached on: Assets > Software > Merging tab."
}
},
@@ -525,7 +531,7 @@
"providerHow": "read-from-code",
"note": "Nothing asks owners to confirm or correct their entries.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48865 'Survey campaigns for data collection' (2026-07-23): Crowd-sources data quality via targeted surveys to app owners. | docs, intelligence competitor_features#27423 'Survey-Based Data Collection' (2026-04-12): Crowdsource architecture data from application owners",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/reviewing-responses: 'Review and approve survey responses before they are saved to fact sheets'; https://help.sap.com/docs/leanix/ea/application-modernization-collect-data: 'Create a new survey to get key information from application or business owners' (read 2026-09-26). Reached on: Surveys.",
"bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders.",
"stackiq": "No survey, attestation or owner-confirmation code in lib/ or src/ (searched survey/enquete/confirm entry)",
"topdesk": "unknown: Survey Management runs general surveys (and \"will reach end of life ... November 2026\"), not confirmation of entries by owners; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -539,7 +545,7 @@
"name": "See how complete and up to date each application's entry is, as a score.",
"origin": "competitor",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -557,6 +563,7 @@
"stackiq": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)",
"topdesk": "unknown: the only readiness score described is the AI readiness score for the knowledge base; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/voortgang-verbeteren: \"Met het aantal sterren (*) wordt een indicatie van volledigheid van ingevulde gegevens aangegeven\", criteria include referentiecomponenten filled, statuses, koppelingen and \"Datum laatste wijziging is recenter dan 3 maanden geleden\" (read 2026-09-26). Scored per organisation, not per application entry. Reached on: Homepage block Voortgang gemeenten; organisation page header.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/fact-sheet-completeness: 'The fact sheet completion score measures how much of the required data has been filled out for a fact sheet ... You can view the fact sheet completion score in the fact sheet's header' (read 2026-09-26). Reached on: Fact sheet header > completion score.",
"glpi": "source read at 11.0.9: grep -ril 'completeness' over src/ templates/ locales/glpi.pot returns nothing; no score of how filled in an item is exists in core. The item form tabs (src/Appliance.php:98 onwards) show no score."
}
},
@@ -584,7 +591,8 @@
"stackiq": "src/manifest.json:3 setup wizard step load-demo-data (:24); lib/Controller/SetupController.php:202 runAction load-demo-data (AuthorizedAdminSetting); lib/Service/DemoDataService.php:202 install() imports lib/Settings/stackiq_mock_register.json (120 objects, 6 per schema) through OpenRegister ConfigurationService::importFromApp",
"topdesk": "unknown: no example data set is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the catalogue is one hosted service; no loadable example data set is described (a \"VNG Realisatie Demo\" supplier appears in the live data); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
- "glpi": "source read at 11.0.9: on a clean install dashboards render placeholder figures from src/Glpi/Dashboard/FakeProvider.php:65 FakeProvider, with the banner 'You are viewing demonstration data.' and a 'Disable demonstration' button (src/Glpi/Dashboard/Grid.php:427, :428, :448); CHANGELOG.md 11.0.0 lists it. No example records (applications, contracts, suppliers) are loaded; the console entry point src/Glpi/Console/Application.php:66 has no demo data command. Reached on: Home > Dashboard on a fresh install."
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; demo and sandbox workspaces are mentioned (https://help.sap.com/docs/leanix/ea/automations 'Demo and sandbox workspaces allow up to 10,000 automations per month') but loading an example data set into a workspace is not described (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: on a clean install dashboards render placeholder figures from src/Glpi/Dashboard/FakeProvider.php:65 FakeProvider, with the banner 'You are viewing demonstration data.' and a 'Disable demonstration' button (src/Glpi/Dashboard/Grid.php:427, :428, :448); CHANGELOG.md 11.0.0 lists it. No example records (applications, contracts, suppliers) are loaded; the console entry point src/Glpi/Console/Application.php:66 has no demo data command. Reached on: Home > Dashboard on a fresh install. Driven on the lab at 11.0.9 (2026-09-26): glpi_configs.is_demo_dashboards is 1 on the fresh install, so the dashboard cards come from FakeProvider until an administrator disables the demonstration."
}
},
{
@@ -611,6 +619,7 @@
"stackiq": "src/dialogs/SuiteWizardDialog.vue (3 steps) is the only wizard, opened from src/views/suites/SuitesIndexView.vue:46; applications, services and connections use the bare CnIndexPage form (FacetedCatalogIndexView.vue:108) or nothing",
"topdesk": "unknown: wizards exist for imports and migration, not for adding an application; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the manuals describe forms (\"Hierna opent een formulier\"), no step-by-step wizard; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30355 (read 2026-09-26)",
+ "sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/creating-fact-sheets describes creating a fact sheet in the inventory with reference catalog suggestions and duplicate hints, not a step by step wizard; wizards are documented only for KPI and integration mapping configuration (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'wizard' over src/ templates/ locales/glpi.pot returns nothing for item creation; appliances are added through the plain form only (install/mysql/glpi-empty.sql:8935 glpi_appliances has no is_template column)."
}
},
@@ -620,7 +629,7 @@
"name": "See the third-party components a module version is built from.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -638,6 +647,7 @@
"stackiq": "src/components/sbom/SbomComponentsPanel.vue lists sbomComponent rows (name/version/purl/licenses) as the ModuleversieDetail 'Components' sidebar tab (src/manifest.json:961); register.json:7920 sbomComponent schema",
"topdesk": "unknown: no software components per version are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no third-party component list per version is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/uploading-sboms-from-fact-sheets: 'Upload SBOM files directly from a microservice fact sheet'; https://help.sap.com/docs/leanix/ea/tech-stack-discovery-from-sboms: 'the system automatically analyzes the SBOM components and builds a structured view of your technology stack'. Part of SAP LeanIX Technology Risk and Compliance (read 2026-09-26). Reached on: Microservice fact sheet > SBOM (Technology Risk and Compliance).",
"glpi": "source read at 11.0.9: grep -ril 'sbom\\|cyclonedx\\|spdx' over src/ templates/ locales/glpi.pot returns nothing; software versions carry no component list (install/mysql/glpi-empty.sql:6900 glpi_softwareversions)."
}
},
@@ -647,7 +657,7 @@
"name": "Record whether an application runs on premises, as SaaS or at a hosting party.",
"origin": "competitor",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -664,7 +674,7 @@
"featureConfidence": "medium",
"note": "The application form records on-premises, IaaS, PaaS or SaaS plus hosting location and jurisdiction. There is no field naming the hosting party itself.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | Rated partial because SaaS is tracked as a class of application.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/applications-in-reference-catalog lists application fields 'Hosting Type' and 'Hosting Description'; https://help.sap.com/docs/leanix/ea/configuring-kpis filters applications on 'Hosting Type = \"Cloud\"'; IT component subtypes SaaS, IaaS, PaaS, Hardware (read 2026-09-26). Reached on: Application fact sheet > Hosting Type.",
"stackiq": "register.json:6869 module.cloudDienstverleningsmodel enum On-premises, IaaS, PaaS, SaaS; register.json:6906 hostingLocation and hostingJurisdiction; usage.cloudDienstverleningsmodel (register.json:3050); on ModuleDetail md-data include (src/manifest.json:500)",
"topdesk": "unknown: only possible as a self-defined field; no hosting model is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Indien een leverancier zowel SaaS als On premise ondersteunt, kan je aangeven welke van deze twee varianten gebruikt wordt binnen de gemeente\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen > tabblad Technologie.",
@@ -677,7 +687,7 @@
"name": "Record a connection from an application to a national provision such as a basisregistratie.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -697,6 +707,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"De richting van het berichtenverkeer, de landelijke voorziening waarmee gekoppeld is/wordt, in dit geval GGK\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus: \"kunnen koppelingen tussen applicaties onderling en met Landelijke Voorzieningen vastgelegd worden\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > koppeling toevoegen.",
"stackiq": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection",
"topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Modeling External Applications ... applications of business partners, service providers, authorities', linked 'through an interface to analyze dependencies'. Generic external application modeling, no catalogue of national provisions such as basisregistraties (read 2026-09-26). Reached on: Application fact sheet (external) + Interface fact sheet.",
"glpi": "source read at 11.0.9: no national provision concept (grep -ril 'basisregistratie' src/ locales/glpi.pot returns nothing); a provision can be held as another Appliance and linked through an impact relation, install/mysql/glpi-empty.sql:1247 glpi_impactrelations (source item, impacted item, name), with Appliance enabled for impact at src/autoload/CFG_GLPI.php:649. Reached on: Appliance > Impact analysis tab, Add relation."
}
},
@@ -706,7 +717,7 @@
"name": "Browse all connections in the catalogue in one list and open each one.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -726,7 +737,8 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle koppelingen ... staan de koppelingen van alle gemeenten en samenwerkingsverbanden ... Door te klikken op het icoontje rechts van een koppeling, krijg je nog enige detail informatie\" (read 2026-09-26). Reached on: Inlogmenu > Alle koppelingen (logged-in municipal users).",
"stackiq": "No manifest page with schema connection (src/manifest.json and src/manifest.d/*.json); the Integrations page (src/manifest.d/connection-registry.json:23) lists integriq app_connection, explicitly not stackiq's connection schema (its _note)",
"topdesk": "unknown: relations are shown per asset and in a graphical overview; a list of all relations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "glpi": "source read at 11.0.9: src/ImpactRelation.php:39 ImpactRelation has only prepareInputForAdd and getIDFromInput (src/ImpactRelation.php:47, :107), no search options and no list page; relations are only seen per item in the Impact analysis tab (src/Impact.php:91)."
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines: 'Interfaces are connections between applications that illustrate how data exchange occurs', each a fact sheet listed in the inventory by fact sheet type (read 2026-09-26). Reached on: Inventory > filter fact sheet type Interface.",
+ "glpi": "source read at 11.0.9: src/ImpactRelation.php:39 ImpactRelation has only prepareInputForAdd and getIDFromInput (src/ImpactRelation.php:47, :107), no search options and no list page; relations are only seen per item in the Impact analysis tab (src/Impact.php:91). Driven on the lab at 11.0.9 (2026-09-26): /front/impactrelation.php opens by URL only (no menu entry) as a generic list whose only criterion and column is ID, so relations cannot be browsed by endpoint; rating unchanged."
}
},
{
@@ -735,7 +747,7 @@
"name": "See every connection an application has, from that application's own page.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -755,7 +767,8 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Mijn pakketoverzicht ... Onder het eerste tabblad zitten de pakketten en onder het tweede tabblad de koppelingen\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: \"Door op een applicatienaam in het Models venster te klikken, zie je in de Visualiser alle koppelingen tussen die applicatie met andere applicaties\" (in Archi after export) (read 2026-09-26). No per-application connection view inside the catalogue is described. Reached on: Mijn softwarecatalogus > Koppelingen.",
"stackiq": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"Links between assets are created and managed via the Relationships widget. For current relationships with other assets, the widget shows the template's icon, the Asset ID\" (read 2026-09-26). Generic asset relations, not interfaces. Reached on: Asset card > Relationships widget.",
- "glpi": "source read at 11.0.9: src/Impact.php:91 getTabNameForItem adds the 'Impact analysis' tab (src/Impact.php:80) to every impact enabled itemtype, Appliance and Software included (src/autoload/CFG_GLPI.php:649 and :663), with a list view src/Impact.php:270 displayListView of every related item in both directions. Reached on: Management > Appliances > Impact analysis tab."
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/circle-map-report: the Interface Circle Map 'helps you track changes and updates in application dependencies', and https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: relations incl. interfaces shown on the fact sheet and in the Relations Explorer (read 2026-09-26). Reached on: Application fact sheet > Relations (Provided and Consumed Interfaces).",
+ "glpi": "source read at 11.0.9: src/Impact.php:91 getTabNameForItem adds the 'Impact analysis' tab (src/Impact.php:80) to every impact enabled itemtype, Appliance and Software included (src/autoload/CFG_GLPI.php:649 and :663), with a list view src/Impact.php:270 displayListView of every related item in both directions. Reached on: Management > Appliances > Impact analysis tab. Driven on the lab at 11.0.9 (2026-09-26): the appliance page carries an Impact analysis tab with Add assets for every impact enabled item type."
}
},
{
@@ -781,9 +794,9 @@
"featureConfidence": "low",
"note": "No page draws connections. The ArchiMate export can be opened in Archi, but it carries GEMMA views and usages, not the catalogue's connections.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model. | docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/data-flow: data flow diagrams help 'understand how applications are connected, identify dependencies, and trace data movement between systems' (read 2026-09-26). Reached on: Diagrams > Data Flow Diagram.",
"bluedolphin": "docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models. | docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
- "glpi": "source read at 11.0.9: src/Impact.php:252 displayGraphView and src/Impact.php:1559 makeDataForCytoscape draw the relation network, with editing tools add asset, add relation, add group at src/Impact.php:1160. Reached on: Appliance > Impact analysis tab, graph view.",
+ "glpi": "source read at 11.0.9: src/Impact.php:252 displayGraphView and src/Impact.php:1559 makeDataForCytoscape draw the relation network, with editing tools add asset, add relation, add group at src/Impact.php:1160. Reached on: Appliance > Impact analysis tab, graph view. Driven on the lab at 11.0.9 (2026-09-26): the Impact analysis tab renders the graph editor with Add assets, Edit group and Edit edge tools.",
"stackiq": "No diagram rendering in src/ (no graph library; src/store/modules/view.js GET /api/views has no importer outside itself); lib/Service/ArchiMateExportService.php exports GEMMA views as ArchiMate XML without koppeling objects (no 'koppeling' in lib/Service/ArchiMate*)",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"After you define the relationship between assets, you can use the graphical overview to see a visual representation of their relationship\" (read 2026-09-26). Reached on: Asset card > graphical overview.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30890: \"Tekenen van een view met koppelingen ... Een koppeling is gemodelleerd als een Archimate flow relatie\" (read 2026-09-26). Diagrams are drawn in Archi after an AMEFF export, not in the catalogue."
@@ -795,7 +808,7 @@
"name": "Before changing or retiring an application, see what depends on it.",
"origin": "competitor",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "yes",
"glpi": "yes",
"topdesk": "partial",
@@ -814,7 +827,8 @@
"glpi": "source read at 11.0.9: src/Impact.php:49 class Impact 'Impact analysis', src/Impact.php:713 bfs walks the graph by direction and src/Impact.php:612 buildListData lists what is impacted, with ongoing tickets, problems and changes on impacted items (src/Impact.php:313). Reached on: Tools > Impact analysis (src/Html.php:1309) and the item's Impact analysis tab.",
"topdesk": "https://docs.topdesk.com/en/managing-disruptions-in-your-asset-management-process.html: \"you want to know how far the reach of the disruption is ... the operational/impacted status for assets ... Status impacts are also only shown in the graphical overview when a link type is used\" (read 2026-09-26). Disruption impact, not a pre-change dependency analysis. Reached on: Asset card > General widget > Determine status automatically.",
"stackiq": "src/manifest.json:502 ModuleDetail md-related (library CnRelatedObjectsWidget: /used lists every object that references this module: usages, connections, suites, services, vulnerabilities); no dependency or impact computation in lib/ or src/",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Pakketversies die niet meer in gebruik zijn, kunnen verwijderd worden waarbij feedback gegeven wordt over de koppelingen die ook automatisch verwijderd zullen worden\" (read 2026-09-26). Only on delete, no dependency analysis."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Pakketversies die niet meer in gebruik zijn, kunnen verwijderd worden waarbij feedback gegeven wordt over de koppelingen die ook automatisch verwijderd zullen worden\" (read 2026-09-26). Only on delete, no dependency analysis.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/meta-model: 'These relations are the basis for all the reports and allow you to analyze impact of changes, dependencies, risks, redundancies'; https://help.sap.com/docs/leanix/ea/data-flow: 'directional interface mapping, dependency analysis' (read 2026-09-26). Reached on: Reports and Data Flow Diagrams."
}
},
{
@@ -823,7 +837,7 @@
"name": "Filter connections by type, such as an API, a file exchange or a message.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -841,6 +855,7 @@
"stackiq": "register.json:3563 connection.type enum (file transfer, digikoppeling, message que, webservices, api, ...) exists, but no connection list page to filter",
"topdesk": "unknown: custom link types exist, but filtering relations by type is not described; https://tip.topdesk.com/c/90-graphical-overview-improvements is still under consideration; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: connections carry a standard and \"het soort overdracht\" (upload naar portaal, webservices), but the docs do not name a type filter on the connection list; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines: interface subtypes 'Logical interface, API, MCP server' and 'You can capture data flow directions, type of transfer, and frequency with the interface fact sheet'; subtypes and fields are filterable in the inventory (read 2026-09-26). Reached on: Inventory > Interface > filter by subtype or transfer type.",
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1247 glpi_impactrelations has only a free name besides the two endpoints, no connection type (API, file, message), so there is nothing to filter on; the graph settings (src/Impact.php:1167 impact_settings) cover depth and direction."
}
},
@@ -1672,7 +1687,7 @@
"stackiq": "src/manifest.json:386 Organisaties type:index over schema organization with status filter and OrganisatieCard; register :2022 organization.type is facetable (Municipality/Supplier/Collaboration/Community); public read of Active suppliers in organization authorization (:2467)",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/leveranciers: \"Leveranciers ... Zoek in leveranciers ... 354 resultaten gevonden\", filter \"Met ondertekend addendum\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle leveranciers.",
- "glpi": "source read at 11.0.9: src/Supplier.php:46 Supplier list under Management (src/Html.php:1298) with search, filters and a supplier type (install/mysql/glpi-empty.sql:7072 suppliertypes_id), but it holds only the suppliers this organisation entered, not all organisations offering to government. Reached on: Management > Suppliers (front/supplier.php)."
+ "glpi": "source read at 11.0.9: src/Supplier.php:46 Supplier list under Management (src/Html.php:1298) with search, filters and a supplier type (install/mysql/glpi-empty.sql:7072 suppliertypes_id), but it holds only the suppliers this organisation entered, not all organisations offering to government. Reached on: Management > Suppliers (front/supplier.php). Driven on the lab at 11.0.9 (2026-09-26): created supplier \"Lab Leverancier BV\" through /front/supplier.form.php; it appears in the Suppliers list."
}
},
{
@@ -2185,7 +2200,7 @@
"featureConfidence": "medium",
"note": "The application page has no contracts list, and a contract links to a usage and a service rather than the application, so there is no path from an application to its contracts in the UI.",
"evidence": {
- "glpi": "source read at 11.0.9: src/Appliance.php:99 and src/Software.php:131 add the Contract_Item tab (src/Contract_Item.php:43, install/mysql/glpi-empty.sql:1536 glpi_contracts_items) listing every contract of the application. Reached on: Management > Appliances > Contracts tab.",
+ "glpi": "source read at 11.0.9: src/Appliance.php:99 and src/Software.php:131 add the Contract_Item tab (src/Contract_Item.php:43, install/mysql/glpi-empty.sql:1536 glpi_contracts_items) listing every contract of the application. Reached on: Management > Appliances > Contracts tab. Driven on the lab at 11.0.9 (2026-09-26): after linking the contract, the appliance Contracts tab showed \"Lab contract, 2025-01-01, 12 months -> 2025-12-31\".",
"stackiq": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: assets link to \"Service cards\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"On the Services tab, link the services that apply to this contract\" (read 2026-09-26). Contract to asset runs through the service. Reached on: Contract > Services tab > Service > Links > Assets.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
@@ -2354,7 +2369,7 @@
"providerHow": "read-from-code",
"note": "Contracts carry a cost and a period, but there is no budget to charge them against.",
"evidence": {
- "glpi": "source read at 11.0.9: src/Budget.php:46 Budget with a period and value (install/mysql/glpi-empty.sql:306 begin_date, :307 end_date, :308 value); contract costs (install/mysql/glpi-empty.sql:1466 budgets_id) and financial records (src/Infocom.php:599 budgets_id check) are charged to it. Reached on: Management > Budgets.",
+ "glpi": "source read at 11.0.9: src/Budget.php:46 Budget with a period and value (install/mysql/glpi-empty.sql:306 begin_date, :307 end_date, :308 value); contract costs (install/mysql/glpi-empty.sql:1466 budgets_id) and financial records (src/Infocom.php:599 budgets_id check) are charged to it. Reached on: Management > Budgets. Driven on the lab at 11.0.9 (2026-09-26): /front/budget.php lists budgets with type, start date, end date and value.",
"stackiq": "grep for budget across lib/, src/ and lib/Settings finds no budget schema or field; catalogContract has cost + costPeriod only (register :3363)",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Budget holder: Cost-accounting owner of the contract\" and \"Applicable to ... Budget holder\" (read 2026-09-26). No budget with a period is described. Reached on: Contract card > Financial.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
@@ -2930,7 +2945,7 @@
"providerHow": "read-from-code",
"note": "Stackiq has no directory sync for users or groups. Nextcloud's LDAP app could do it platform-wide, outside stackiq.",
"evidence": {
- "glpi": "source read at 11.0.9: src/AuthLDAP.php:59 LDAP directories with user import and group import (src/AuthLDAP.php:2816 ldapImportGroup), and the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users (alias ldap:sync at :80). Reached on: Administration > Users > LDAP directory link; Setup > Authentication > LDAP directories.",
+ "glpi": "source read at 11.0.9: src/AuthLDAP.php:59 LDAP directories with user import and group import (src/AuthLDAP.php:2816 ldapImportGroup), and the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users (alias ldap:sync at :80). Reached on: Administration > Users > LDAP directory link; Setup > Authentication > LDAP directories. Driven on the lab at 11.0.9 (2026-09-26): /front/ldap.php offers \"Bulk import users from a LDAP directory\" and \"Synchronizing already imported users\".",
"stackiq": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/",
"topdesk": "https://docs.topdesk.com/en/manual-login-with-ldap.html: \"This is also required if you want to import persons from your AD via Supporting files import\" (read 2026-09-26); https://tip.topdesk.com/c/242-support-scim-when-importing-users-from-entra-id-to-topdesk: roadmap card in column \"Launched\", \"Support SCIM when importing users from Entra ID to TOPdesk\" (read 2026-09-26). Reached on: Settings > Import settings > Supporting Files imports.",
"vng-softwarecatalogus": "unknown: no directory sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
@@ -3158,7 +3173,7 @@
"evidence": {
"sap-leanix": "docs, intelligence competitor_features#48867 'REST & GraphQL API' (2026-07-23): Programmatic access to the workspace graph.",
"bluedolphin": "docs, intelligence competitor_features#48972 'REST API' (2026-07-23): Programmatic integration with other systems.",
- "glpi": "source read at 11.0.9: legacy REST API src/Glpi/Api/APIRest.php:60 (documented in apirest.md) and the v2 high level API, src/Glpi/Api/HL/Controller/AssetController.php:149 /Assets with GET list (:2825), GET item (:2839) and POST create (:2988), Appliance and Software included (src/Glpi/Api/HL/Controller/AssetController.php:39, :133). Reached on: /apirest.php and /api.php/v2.",
+ "glpi": "source read at 11.0.9: legacy REST API src/Glpi/Api/APIRest.php:60 (documented in apirest.md) and the v2 high level API, src/Glpi/Api/HL/Controller/AssetController.php:149 /Assets with GET list (:2825), GET item (:2839) and POST create (:2988), Appliance and Software included (src/Glpi/Api/HL/Controller/AssetController.php:39, :133). Reached on: /apirest.php and /api.php/v2. Driven on the lab at 11.0.9 (2026-09-26): the legacy API answers \"There isn't an active API client matching your IP address\" until an administrator adds an API client, and the v2 API is off until enabled in Setup > General > API.",
"topdesk": "https://docs.topdesk.com/en/required-knowledge.html: \"basic knowledge of REST API requests (see developers.topdesk.com )\" (read 2026-09-26); https://docs.topdesk.com/en/details-about-certain-permissions.html: \"API access > REST API : this permission is necessary for operator cards that are used for accessing the TOPdesk API\" (read 2026-09-26). Reached on: developers.topdesk.com.",
"stackiq": "Every catalogue entity is an OpenRegister object (src/manifest.json pages read register @resolve:voorzieningen_register), so OpenRegister's /apps/openregister/api/objects/{register}/{schema} CRUD applies, gated by the schema authorization rules (lib/Settings/softwarecatalogus_register.json:6777 module and others). Stackiq adds its own routed endpoints in appinfo/routes.php (e.g. :202 /api/aanbod, :255-261 /api/aangeboden-gebruik, :298 /api/gebruik, :303 /api/portfolio-report).",
"vng-softwarecatalogus": "unknown: https://www.softwarecatalogus.nl/api answers only \"Services Endpoint api has been setup successfully.\" and no API is documented; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api (read 2026-09-26)"
@@ -3186,7 +3201,7 @@
"providerHow": "read-from-code",
"note": "The generated OpenAPI file is empty. What exists is hand-written: two JSON doc endpoints and markdown pages. OpenRegister may generate an OAS per register, but stackiq does not surface it.",
"evidence": {
- "glpi": "source read at 11.0.9: src/Glpi/Api/HL/Controller/CoreController.php:322 route /doc serves a Swagger UI 'GLPI API Documentation' (:329 to :331) over the spec built by src/Glpi/Api/HL/OpenAPIGenerator.php. Reached on: /api.php/doc.",
+ "glpi": "source read at 11.0.9: src/Glpi/Api/HL/Controller/CoreController.php:322 route /doc serves a Swagger UI 'GLPI API Documentation' (:329 to :331) over the spec built by src/Glpi/Api/HL/OpenAPIGenerator.php. Reached on: /api.php/doc. Driven on the lab at 11.0.9 (2026-09-26): on a fresh install /api.php/v2/doc answers 403 \"The High-Level API is disabled\"; after switching on enable_hlapi in Setup > General > API it serves the Swagger UI \"GLPI API Documentation\".",
"stackiq": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261). The views docs endpoint is login-only; the aangeboden-gebruik docs endpoint is @PublicPage (AangebodenGebruikController.php:860), so anyone can read it (corrected 2026-09-26). Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint.",
"topdesk": "https://developers.topdesk.com/: TOPdesk API reference site, linked from the docs as \"TOPdesk API documentation\" (read 2026-09-26); https://docs.topdesk.com/en/generate-a-document.html: \"see FreeMarker and the TOPdesk API documentation\" (read 2026-09-26). Reached on: developers.topdesk.com.",
"vng-softwarecatalogus": "unknown: no API documentation for the current catalogue was found; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)"
@@ -3216,7 +3231,7 @@
"note": "A full ArchiMate export exists but is only reached from admin settings. The one export on a user page is the portfolio report CSV, and the catalogue list pages offer no export.",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"De publieke informatie is ook beschikbaar als download van exportbestanden ... Mijn pakketten, Mijn koppelingen: Knop [Exporteren]\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Exporteren; Beschikbare downloads.",
- "glpi": "source read at 11.0.9: every search list exports to CSV, PDF, ODS and XLSX through src/Glpi/Search/Output/Csv.php, Pdf.php, Ods.php and Xlsx.php, plus impact CSV (front/impactcsv.php) and the APIs (src/Glpi/Api/HL/Controller/AssetController.php:2825). Reached on: any list, Export menu.",
+ "glpi": "source read at 11.0.9: every search list exports to CSV, PDF, ODS and XLSX through src/Glpi/Search/Output/Csv.php, Pdf.php, Ods.php and Xlsx.php, plus impact CSV (front/impactcsv.php) and the APIs (src/Glpi/Api/HL/Controller/AssetController.php:2825). Reached on: any list, Export menu. Driven on the lab at 11.0.9 (2026-09-26): the Appliances list exported to CSV (/front/report.dynamic.php display_type 3) with the created record.",
"stackiq": "ArchiMate export lib/Controller/SettingsController.php:1615 (POST /api/archimate/export) and :1685 per-organisation export (GET /api/archimate/export/organization/{uuid}), called only from src/views/settings/sections/ArchiMateImportExport.vue (admin settings, StackiqSettings.vue:86). CSV export of the portfolio report: lib/Controller/PortfolioReportController.php:105, button src/views/organisaties/PortfolioReport.vue:567. No index page opts into the library's CSV/Excel export (no allowExport in src/manifest.json).",
"topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: tile actions \"Export to .CSV Export to Excel\" (read 2026-09-26); https://docs.topdesk.com/en/create-odata-reports-for-asset-management.html: \"generate reports by using the TOPdesk OData feed ... Microsoft Power BI, or Microsoft Excel\" (read 2026-09-26). Reached on: Asset dashboard; OData feed."
}
@@ -3329,7 +3344,7 @@
"providerHow": "read-from-code",
"note": "A user can save the facet and search selection as a named view and reopen it. Storage is OpenRegister's views API. It covers only those two pages.",
"evidence": {
- "glpi": "source read at 11.0.9: src/SavedSearch.php:52 SavedSearch, private or shared, listed under Tools > Saved searches (src/Html.php:1309) with optional alerts (front/savedsearch_alert.form.php). Reached on: Tools > Saved searches (front/savedsearch.php).",
+ "glpi": "source read at 11.0.9: src/SavedSearch.php:52 SavedSearch, private or shared, listed under Tools > Saved searches (src/Html.php:1309) with optional alerts (front/savedsearch_alert.form.php). Reached on: Tools > Saved searches (front/savedsearch.php). Driven on the lab at 11.0.9 (2026-09-26): Tools > Saved searches (/front/savedsearch.php) lists saved searches with private or shared scope and a default flag.",
"stackiq": "src/views/FacetedCatalogIndexView.vue:68 Saved views menu (save current filters, list, apply); src/store/modules/facets.js:404 saveCurrentAsView POSTs to OpenRegister /apps/openregister/api/views (:61), fetchSavedViews :361 reads them back.",
"topdesk": "https://tip.topdesk.com/c/83-share-saved-overviews-with-operators-and-operator-groups: roadmap card in column \"Launched\", \"User is able to share saved overviews with operators and operator groups - Rename the saved overview\" (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: only VNG-defined \"Marktscans-voorgedefinieerde filters\" are described; users saving their own view is not; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Marktscans (read 2026-09-26)"
@@ -3411,7 +3426,7 @@
"providerHow": "read-from-code",
"note": "The report picker exists and opens a working report. The list holds exactly one report.",
"evidence": {
- "glpi": "source read at 11.0.9: src/Report.php:52 Report builds a pick list of ready made reports, src/Report.php:77 default, :81 by contract, :85 by year, :87 financial information, :110 status, chosen from 'Select the report you want to generate' (src/Report.php:143). Reached on: Tools > Reports (front/report.php).",
+ "glpi": "source read at 11.0.9: src/Report.php:52 Report builds a pick list of ready made reports, src/Report.php:77 default, :81 by contract, :85 by year, :87 financial information, :110 status, chosen from 'Select the report you want to generate' (src/Report.php:143). Reached on: Tools > Reports (front/report.php). Driven on the lab at 11.0.9 (2026-09-26): /front/report.php offers Default report, By contract, By year, Hardware financial and administrative information, Other financial and administrative information, Network report, Loan and Status.",
"stackiq": "src/manifest.json:1021 Reports page (type reports) with one card, Portfolio rationalization, routing to src/manifest.json PortfolioReport /portfolio-report (PortfolioReportView, GET /api/portfolio-report routes.php:303).",
"topdesk": "https://docs.topdesk.com/en/reporting.html: \"Introducing the Reporting Hub ... So far, you could find dashboards and reports in different places\" (read 2026-09-26); https://tip.topdesk.com/c/20-reporting-hub: roadmap card in column \"Launched\", \"Reporting Hub\" (read 2026-09-26). Reached on: TOPdesk menu > Reporting Hub.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/rapportages: \"Regelmatig worden er rapportages gemaakt over het gebruik van de Softwarecatalogus\" (read 2026-09-26); compliancy monitor and digital accessibility monitor pages. Reached on: Rapportages; Compliancy monitor."
@@ -3470,7 +3485,7 @@
"featureConfidence": "low",
"note": "One fixed report exports to CSV for a selected organisation. The filtered catalogue lists cannot be exported.",
"evidence": {
- "glpi": "source read at 11.0.9: src/Glpi/Search/Output/Csv.php, Ods.php, Xlsx.php and Pdf.php export the filtered list; the output format selector is rendered by src/Html.php:4219 Dropdown::showOutputFormat. Reached on: any filtered list, Export.",
+ "glpi": "source read at 11.0.9: src/Glpi/Search/Output/Csv.php, Ods.php, Xlsx.php and Pdf.php export the filtered list; the output format selector is rendered by src/Html.php:4219 Dropdown::showOutputFormat. Reached on: any filtered list, Export. Driven on the lab at 11.0.9 (2026-09-26): the filtered Appliances list exported to CSV with the created record.",
"stackiq": "Portfolio report CSV: lib/Controller/PortfolioReportController.php:105 (DataDownloadResponse text/csv), button src/views/organisaties/PortfolioReport.vue:567. No index page sets the library's allowExport (grep allowExport/exportable in src/manifest.json and the register finds nothing), so Applications, Contracts and the other lists have no export.",
"topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: \"Export to .CSV Export to Excel\" (read 2026-09-26). Reached on: Asset dashboard tile menu.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: \"Export to CSV\" on the filtered package-version list (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Ook beschikbaar via knop [Export to csv] op pagina Alle pakketten\" (read 2026-09-26). Reached on: Alle pakketversies > Export to CSV."
@@ -3607,7 +3622,7 @@
"providerHow": "read-from-code",
"note": "There is no knowledge base. Files can be attached to an application, but that is not searchable articles.",
"evidence": {
- "glpi": "source read at 11.0.9: src/KnowbaseItem.php:57 knowledge base articles with categories and visibility, linked to items through src/KnowbaseItem_Item.php:45 and shown on the appliance Knowledge base tab (src/Appliance.php:104); menu src/Html.php:1307. Reached on: Tools > Knowledge base (front/knowbaseitem.php).",
+ "glpi": "source read at 11.0.9: src/KnowbaseItem.php:57 knowledge base articles with categories and visibility, linked to items through src/KnowbaseItem_Item.php:45 and shown on the appliance Knowledge base tab (src/Appliance.php:104); menu src/Html.php:1307. Reached on: Tools > Knowledge base (front/knowbaseitem.php). Driven on the lab at 11.0.9 (2026-09-26): /front/knowbaseitem.php opens the knowledge base with Search and Browse.",
"topdesk": "https://docs.topdesk.com/en/knowledge-management.html: \"The Knowledge Base is set up and managed by your organization's knowledge managers. Every operator is able to use information from the Knowledge Base\" (read 2026-09-26). Reached on: Modules > Knowledge Management.",
"stackiq": "No knowledge-article schema among the register's schemas (sector, suite, catalogService, vulnerability, contactPerson, organization, usage, catalogContract, connection, software-review, element, view, model, property-definition, relation, module, compliancy, bioMeasure, moduleVersion, sbomComponent in lib/Settings/softwarecatalogus_register.json); ModuleDetail only has a Documentation files panel.",
"vng-softwarecatalogus": "unknown: the FAQ and manuals are site help, no knowledge base about applications is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
@@ -3797,7 +3812,7 @@
"providerHow": "read-from-code",
"note": "No ticketing.",
"evidence": {
- "glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:301 ticket_types includes Appliance (line 305), so tickets link to an application through src/Item_Ticket.php:41, shown on the appliance Tickets tab (src/Appliance.php:105). Reached on: Assistance > Tickets; Appliance > Tickets tab.",
+ "glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:301 ticket_types includes Appliance (line 305), so tickets link to an application through src/Item_Ticket.php:41, shown on the appliance Tickets tab (src/Appliance.php:105). Reached on: Assistance > Tickets; Appliance > Tickets tab. Driven on the lab at 11.0.9 (2026-09-26): the default Super-Admin profile lists Computer, Monitor, NetworkEquipment, Peripheral, Phone, Printer, Software, DCRoom, Rack, Enclosure and Database as associable to tickets, not Appliance, so an appliance shows no Tickets tab until an administrator adds it in the profile; rating kept.",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: \"On Call, Change (Activity) ... cards, you can link multiple assets\" (read 2026-09-26). Reached on: Call card > Links > Assets.",
"stackiq": "No incident or request schema or endpoint in lib/Settings/softwarecatalogus_register.json or appinfo/routes.php.",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
@@ -3881,7 +3896,7 @@
"topdesk": "https://docs.topdesk.com/en/mobile-access-to-the-self-service-portal.html: \"The SSP layout is suited to be displayed in a mobile interface\" (read 2026-09-26); https://tip.topdesk.com/c/86-webshop-is-connected-with-asset-management: roadmap card in column \"Building\", \"End-user can order items which are in Asset Management\" (read 2026-09-26); pricing lists \"Self-Service Portal\" and \"Webshop\". Reached on: Self-Service Portal.",
"stackiq": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls.",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "glpi": "source read at 11.0.9: the 11.0 service catalog src/Glpi/Form/ServiceCatalog/ServiceCatalog.php:45 lists native forms for self service users (menu src/Html.php:1283), and a form question can offer software items to pick, src/Glpi/Form/QuestionType/QuestionTypeItem.php:180 Software::class, creating a ticket from the answer. Reached on: Self service > Service catalog."
+ "glpi": "source read at 11.0.9: the 11.0 service catalog src/Glpi/Form/ServiceCatalog/ServiceCatalog.php:45 lists native forms for self service users (menu src/Html.php:1283), and a form question can offer software items to pick, src/Glpi/Form/QuestionType/QuestionTypeItem.php:180 Software::class, creating a ticket from the answer. Reached on: Self service > Service catalog. Driven on the lab at 11.0.9 (2026-09-26): /ServiceCatalog shows the service catalog with \"Report an issue\" and \"Request a service\"."
}
},
{
@@ -3937,7 +3952,7 @@
"stackiq": "lib/BackgroundJob/OrganizationContactSyncJob.php:75 TimedJob every 300 s calling performScheduledSync; admin section src/views/settings/sections/CronjobConfiguration.vue:56 shows each job's interval and an enable switch; src/views/settings/sections/OrganizationSynchronization.vue:211 shows Last Sync from app config last_sync_time (lib/Service/OrganizationSyncService.php:1609, written by recordSyncTime :1674).",
"topdesk": "https://docs.topdesk.com/en/events-that-trigger-actions.html: \"when tracking imports/Exchange exports via system events ... on a schedule\" (read 2026-09-26); https://tip.topdesk.com/c/116-support-for-importing-persons-and-operators-directly-from-local-active-directory: roadmap card in column \"Launched\", person import from AD (read 2026-09-26). Reached on: Settings > Import settings.",
"vng-softwarecatalogus": "unknown: only \"De kaart wordt dagelijks bijgewerkt\" is stated; no organisation or contact sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/17042 (read 2026-09-26)",
- "glpi": "source read at 11.0.9: automatic actions are scheduled and show their last run, src/CronTask.php:59 with install/mysql/glpi-empty.sql:1610 glpi_crontasks.lastrun, but LDAP user and group synchronisation is not one of them (grep -i ldap over the cron seed in install/empty_data.php:438 finds none); it is the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users, which must be scheduled by the system cron. Organisation (supplier) records have no sync at all. Reached on: Setup > Automatic actions; CLI bin/console ldap:sync."
+ "glpi": "source read at 11.0.9: automatic actions are scheduled and show their last run, src/CronTask.php:59 with install/mysql/glpi-empty.sql:1610 glpi_crontasks.lastrun, but LDAP user and group synchronisation is not one of them (grep -i ldap over the cron seed in install/empty_data.php:438 finds none); it is the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users, which must be scheduled by the system cron. Organisation (supplier) records have no sync at all. Reached on: Setup > Automatic actions; CLI bin/console ldap:sync. Driven on the lab at 11.0.9 (2026-09-26): /front/crontask.php lists automatic actions with run mode, frequency and last run."
}
}
],
@@ -4568,7 +4583,7 @@
"note": "All the fields are on the contract form, but a contract requires a usage (gebruik) record and no stackiq page can create one, so on a fresh install the form cannot be completed without data from elsewhere (demo data, API, external frontend).",
"evidence": {
"vng-softwarecatalogus": "unknown: contracts are not described in the public docs; their absence is not stated either; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
- "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1483 glpi_contracts with name, num (contract number), contracttypes_id, begin_date, duration, notice and renewal, and costs in install/mysql/glpi-empty.sql:1458 glpi_contractcosts. Reached on: Management > Contracts.",
+ "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1483 glpi_contracts with name, num (contract number), contracttypes_id, begin_date, duration, notice and renewal, and costs in install/mysql/glpi-empty.sql:1458 glpi_contractcosts. Reached on: Management > Contracts. Driven on the lab at 11.0.9 (2026-09-26): created \"Lab contract\" with number C-001, start date, 12 month duration and 1 month notice.",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Contract Number (mandatory) ... Type ... Start Date (mandatory) ... End Date (mandatory) ... Costs (Services)\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM > New.",
"stackiq": "src/manifest.json:527 Contracten type:index over catalogContract (contractNumber, contractType, startDate, endDate, cost, status); register :3252 catalogContract requires service AND usage; no manifest page has schema usage (grep src/manifest.json)"
},
@@ -4982,7 +4997,7 @@
"stackiq": "Stackiq has no webhook code. The Flows page (src/manifest.json:1057, settings-section menu entry FlowsMenu) authors OpenRegister's native flows scoped to app stackiq; OpenRegister's flow event catalogue has object.created/object.updated (openregister lib/Service/Flow/EventCatalogService.php:53-54), and OpenRegister has its own webhooks admin (openregister appinfo/routes.php:1909).",
"topdesk": "https://docs.topdesk.com/en/let-your-topdesk-talk-to-other-applications.html: \"Send a request from TOPdesk to another program ... This way you can create an integration with almost any software that has an API\" (read 2026-09-26) triggered by card events (https://docs.topdesk.com/en/events-that-trigger-actions.html). Reached on: Action Management > action sequences.",
"vng-softwarecatalogus": "unknown: notifications go to people by mail and inbox, no system webhooks are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "glpi": "source read at 11.0.9: src/Webhook.php:64 Webhook sends HTTP calls on new, update and delete events (src/Webhook.php:311 getDefaultEventsList) for management itemtypes including Appliance, Budget, Contact and others (src/Webhook.php:398). Reached on: Setup > Webhooks (src/Html.php:1331)."
+ "glpi": "source read at 11.0.9: src/Webhook.php:64 Webhook sends HTTP calls on new, update and delete events (src/Webhook.php:311 getDefaultEventsList) for management itemtypes including Appliance, Budget, Contact and others (src/Webhook.php:398). Reached on: Setup > Webhooks (src/Html.php:1331). Driven on the lab at 11.0.9 (2026-09-26): Setup > Webhooks (/front/webhook.php) lists webhooks with type, event and category."
},
"pendingQuestion": "Can a flow created on stackiq's Flows page be triggered by object.updated on a catalogue schema and make an outbound HTTP call to an external system?"
},
@@ -5009,7 +5024,7 @@
"featureConfidence": "high",
"note": "Per-record history is shown on 11 detail pages, backed by OpenRegister's audit trail. There is no catalogue-wide view of who changed what, and the overlay itself lists audit-trail-view as 'soon'.",
"evidence": {
- "glpi": "source read at 11.0.9: src/Appliance.php:58 dohistory is true and src/Appliance.php:112 adds the Historical tab (src/Log.php:48 Log), recording who changed which field and when. Reached on: Management > Appliances > Historical tab.",
+ "glpi": "source read at 11.0.9: src/Appliance.php:58 dohistory is true and src/Appliance.php:112 adds the Historical tab (src/Log.php:48 Log), recording who changed which field and when. Reached on: Management > Appliances > Historical tab. Driven on the lab at 11.0.9 (2026-09-26): the appliance Historical tab listed two entries, including the contract link made by glpi.",
"topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: \"History widget : shows both present and past changes that have been made to an asset\" (read 2026-09-26); https://docs.topdesk.com/en/cards-in-call-management.html: \"Audit trail tab Previous events while processing this call\" (read 2026-09-26). Reached on: Asset card > History widget.",
"stackiq": "src/manifest.json:436 (and 10 more detail pages: ContactpersoonDetail, ModuleDetail, ContractDetail, SuiteDetail, StandaardDetail, BioMaatregelDetail, ReviewDetail, KompliantieDetail, ModuleversieDetail, KwetsbaarheidDetail) declare a sidebar tab History with widget type audit, which reads OpenRegister's audit trail for that one object.",
"vng-softwarecatalogus": "unknown: only a \"Laatst gewijzigd\" date on supplier pages and a mutation date in exports are shown; who changed what is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)"
@@ -5097,7 +5112,7 @@
"providerHow": "read-from-code",
"note": "The store installs configuration sets and flows, not code plugins, and it depends on a registry being configured.",
"evidence": {
- "glpi": "source read at 11.0.9: src/Glpi/Marketplace/View.php:53 marketplace view at front/marketplace.php (src/Glpi/Marketplace/View.php:103) and src/Glpi/Marketplace/Controller.php:64 download and install of plugins; src/Glpi/Marketplace/View.php:185 notes that a registration, at least a free one, is required. Reached on: Setup > Plugins > Marketplace.",
+ "glpi": "source read at 11.0.9: src/Glpi/Marketplace/View.php:53 marketplace view at front/marketplace.php (src/Glpi/Marketplace/View.php:103) and src/Glpi/Marketplace/Controller.php:64 download and install of plugins; src/Glpi/Marketplace/View.php:185 notes that a registration, at least a free one, is required. Reached on: Setup > Plugins > Marketplace. Driven on the lab at 11.0.9 (2026-09-26): Setup > Plugins > Marketplace, Discover tab: \"A registration, at least a free one, is required to use marketplace\"; plugins can still be installed by hand from their repositories.",
"topdesk": "https://marketplace.topdesk.com/: \"Showing all 133 results\" of integrations (read 2026-09-26); https://docs.topdesk.com/en/exporting-and-importing.html: \"import an action sequence example from the TOPdesk Marketplace\" (read 2026-09-26). Integrations and action-sequence templates, not installable plugins. Reached on: TOPdesk Marketplace.",
"stackiq": "src/manifest.json:225 Store page (type store, footer menu StoreMenu) over the OpenRegister store plane, with store.types openregister.configset and openregister.flows; its own note says that with no registry configured it shows only the app's built-in items.",
"vng-softwarecatalogus": "unknown: no plugins are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
From 5c5232692906daf750d9fb52b374344429d315c2 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:23:03 +0200
Subject: [PATCH 22/45] chore(parity): glpi driven at 11.0.9, VNG and TOPdesk
read 2026-09-26, sources objects for three systems
---
openspec/parity/capabilities.json | 222 +++++++++++++++++++++++++-----
1 file changed, 190 insertions(+), 32 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index d1b800b3d..a7c5c91b7 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -18,9 +18,58 @@
"key": "vng-softwarecatalogus",
"name": "GEMMA Softwarecatalogus",
"vendor": "VNG Realisatie",
- "readOn": "2026-07-23",
+ "readOn": "2026-09-26",
"evidenceGrade": "docs-only",
- "unknownReason": "Not covered by the 20 intelligence rows for this system (a docs pass dated 2026-04-12 and 2026-07-23); the public site was not driven."
+ "unknownReason": "The live softwarecatalogus.nl manuals, FAQ, release letters and public pages do not describe these capabilities, and the successor repository is not evidence for the incumbent.",
+ "readNote": "Public documentation of the live softwarecatalogus.nl (the Drupal 7 build in production) read 2026-09-26. The successor build on github.com/VNG-Realisatie is Conduction's own work (stackiq), so nothing from that repository counts as evidence for this column; its PvE wensen are used only as the origin of demand rows.",
+ "sources": {
+ "docs": "https://www.softwarecatalogus.nl/handleidingen_voor_gemeenten",
+ "sourceRepo": null,
+ "featurePage": "https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus",
+ "featureRequests": "https://www.softwarecatalogus.nl/gebruikersonderzoek%202021",
+ "issueTracker": {
+ "url": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues",
+ "featureLabel": "PvE wens"
+ },
+ "roadmap": null,
+ "changelog": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1",
+ "apiReference": null,
+ "marketplace": null,
+ "pricing": null,
+ "accessibilityStatement": "https://www.toegankelijkheidsverklaring.nl/register/20209",
+ "securityDocs": null,
+ "demoInstance": null,
+ "community": null,
+ "reviews": null,
+ "videos": "https://www.youtube.com/channel/UCg0bWcCn9Shnt57-L7hSbow",
+ "caseStudies": "https://www.softwarecatalogus.nl/praktijkvoorbeelden%20softwarecatalogus",
+ "partnerDirectory": null,
+ "trainingCurriculum": null,
+ "jobPostings": null,
+ "tenders": [
+ "TenderNed 343458 Vernieuwen GEMMA Softwarecatalogus (VNG Realisatie, market consultation, 2024-07-17)",
+ "TenderNed 354602, 354933, 356544 Vernieuwing Softwarecatalogus (VNG Realisatie, 2024-10 to 2024-11)",
+ "TenderNed 401475 Vernieuwing Softwarecatalogus (VNG Realisatie, 2025-11-18)",
+ "TenderNed 264353 functioneel beheerder GEMMA Online en Softwarecatalogus (VNG Realisatie, 2022-06-14)",
+ "Requirement text naming the Softwarecatalogus as the place for supplier product information: TenderNed 418890 (Noordwijk), 417169 (Reimerswaal), 415897 (FUMO), 383984 (HLT Samen)",
+ "Requirements scoping a solution by GEMMA Softwarecatalogus reference components: TenderNed 241147, 229235, 227989, 226100 (Stein)"
+ ],
+ "nullReasons": {
+ "sourceRepo": "The live catalogue runs on Drupal 7 (per the nieuws page) and its source is not public. github.com/VNG-Realisatie/Softwarecatalogus holds the successor build, not the incumbent.",
+ "roadmap": "FAQ E14 points to a homepage block 'Binnenkort in de Softwarecatalogus', which is absent from today's homepage.",
+ "apiReference": "https://www.softwarecatalogus.nl/api returns only 'Services Endpoint api has been setup successfully.'; no API documentation for the incumbent exists. The API specification on vng-realisatie.github.io describes the successor.",
+ "marketplace": "No plugin or extension marketplace; the catalogue is a single hosted service.",
+ "pricing": "No price or fee page found; no page states the service is free either.",
+ "securityDocs": "Only a privacy statement (Privacyverklaring softwarecatalogus) exists; no security documentation found.",
+ "demoInstance": "No demo or sandbox; the public site is browseable without login but no demo login is offered.",
+ "community": "No forum for the incumbent; contact runs through softwarecatalogus@vng.nl.",
+ "reviews": "No third-party review listings found for a free public-sector catalogue.",
+ "partnerDirectory": "No implementation partners; the supplier list at /leveranciers is catalogue content, not a partner directory.",
+ "trainingCurriculum": "Only manuals and FAQ; no training programme found.",
+ "jobPostings": "vng.nl/artikelen/werken-bij-de-vng is linked from the footer but answered 403 to scripted reads."
+ },
+ "readHow": "curl with a browser user agent on 2026-09-26: every non-null URL returned HTTP 200 (docs, featurePage, featureRequests, changelog, caseStudies, videos, accessibilityStatement, issueTracker). The accessibility statement is status C, last updated 02-04-2026. gh api confirmed the GitHub repo (pushed 2026-02-26, 209 open issues) and its label 'PvE wens'. The GitHub issue tracker and label belong to the successor project, whose PvE wensen describe what the incumbent lacks. vng.nl pages answered 403; gemmaonline.nl answered a JavaScript challenge and was not read. Ruling 2026-09-26: the column rests on the live softwarecatalogus.nl (the old Drupal 7 build) only; the successor build on GitHub is our own work, so nothing from that repo counts as incumbent evidence."
+ }
},
{
"key": "sap-leanix",
@@ -42,17 +91,94 @@
"key": "glpi",
"name": "GLPI",
"vendor": "Teclib",
- "readOn": "2026-07-23",
- "evidenceGrade": "docs-only",
- "unknownReason": "Not covered by the GLPI rows read for this product (a docs pass dated 2026-07-23) or by the procest lane's source reading of 2026-09-14, which answered case-management questions."
+ "readOn": "2026-09-26",
+ "evidenceGrade": "driven",
+ "unknownReason": "No glpi cell is unknown after the source read at 11.0.9.",
+ "readVersion": "11.0.9 (tag 11.0.9, commit 2a44dd1527a1f70da48d6b484bcb7a8849a6e5fb; version/11.0.9 and src/autoload/constants.php:43 agree)",
+ "readNote": "Source read at tag 11.0.9 across all 173 rows (routes, itemtypes, schema, rights, templates, locales, tests), plugins pluginsGLPI/datainjection 2.15.11, pluginsGLPI/fields 1.24.5 and yild/gdprropa 1.0.3 read at their tags where a row depends on them. Then driven on a lab at 11.0.9 (glpi/glpi:11.0.9, market-intelligence stackiq/glpi) for 26 rows marked \"Driven on the lab at 11.0.9\"; the rest rest on the source read at the same version.",
+ "sources": {
+ "docs": "https://glpi-user-documentation.readthedocs.io/",
+ "sourceRepo": "https://github.com/glpi-project/glpi (tag 11.0.9, 2a44dd15)",
+ "featurePage": "https://glpi-project.org/features/",
+ "featureRequests": "https://github.com/glpi-project/roadmap/discussions",
+ "issueTracker": {
+ "url": "https://github.com/glpi-project/glpi/issues",
+ "featureLabel": "feature suggestion"
+ },
+ "roadmap": "https://glpi-project.org/roadmap/",
+ "changelog": "https://github.com/glpi-project/glpi/blob/11.0.9/CHANGELOG.md",
+ "apiReference": "https://github.com/glpi-project/glpi/blob/11.0.9/apirest.md",
+ "marketplace": "https://plugins.glpi-project.org/",
+ "pricing": "https://glpi-project.org/pricing/",
+ "accessibilityStatement": null,
+ "securityDocs": "https://www.glpi-project.org/en/security-policy/",
+ "demoInstance": null,
+ "community": "https://forum.glpi-project.org/",
+ "reviews": null,
+ "videos": "https://www.youtube.com/playlist?list=PLUMG2P30gRaHYVZwtqLdRIe2DtkDkNG_s",
+ "caseStudies": "https://glpi-project.org/customers/",
+ "partnerDirectory": "https://glpi-project.org/partners/",
+ "trainingCurriculum": "https://www.glpi-project.org/en/trainings/",
+ "jobPostings": null,
+ "tenders": [
+ "No TenderNed tender names GLPI (name, description and requirement text searched 2026-09-26)",
+ "portugal-base 7721/2025 Renovacao de Licencas de Software GLPI e Fortinet (ANQEP, 2025-03-26)",
+ "spain-placsp ES-PLACSP-19542624 official plugins for the GLPI instance used by INTEF (2026-04-22)"
+ ],
+ "nullReasons": {
+ "accessibilityStatement": "no statement found: https://glpi-project.org/accessibility/ and /accessibility-statement/ return 404 and the pricing and home pages link none.",
+ "demoInstance": "no public demo: https://glpi-project.org/demo/ returns 404; the pricing page offers only a 45 day GLPI Network trial behind registration (https://myaccount.glpi-network.cloud/register.php), which readers may not open.",
+ "reviews": "G2 (https://www.g2.com/products/glpi/reviews), Capterra, Gartner Peer Insights, TrustRadius, SourceForge and AlternativeTo all return 403 to curl and WebFetch, so none could be confirmed.",
+ "jobPostings": "the GLPI home page links https://www.welcometothejungle.com/fr/companies/teclib, which returns 403 to non-browser clients; https://www.teclib.com/en/careers/ redirects to the GLPI home page, so no job list was confirmed."
+ },
+ "readHow": "2026-09-26: curl -sIL with a browser user agent returned 200 for docs, sourceRepo, featurePage (title 'Discover GLPI features'), issueTracker, changelog and apiReference at tag 11.0.9, marketplace, pricing, securityDocs, community (title 'Forum GLPI-Project'), videos (playlist title 'GLPI Success Stories'), caseStudies, partnerDirectory, trainingCurriculum; WebFetch confirmed content of pricing (GLPI Network public cloud 19 EUR per user per month, private cloud 21 EUR, self hosted Basic 100 EUR to Enterprise 4,500 EUR per month), roadmap (community roadmap pointing to GitHub discussions), featureRequests (suggest.glpi-project.org 301 redirects to github.com/glpi-project/roadmap/discussions, 'Ideas and feature requests' category, 118 discussions listed through the GitHub GraphQL API), marketplace, customers, partners (searchable by country) and trainings (four courses, no certification). github.com/glpi-project/glpi/discussions returns 404, so the roadmap repository is the feature channel. featureLabel read from the GitHub labels API (labels 'feature suggestion' and 'enhancement'). Plugin repositories read at their release tags: github.com/pluginsGLPI/datainjection 2.15.11, github.com/pluginsGLPI/fields 1.24.5, github.com/yild/gdprropa 1.0.3 (declares GLPI 10 only)."
+ }
},
{
"key": "topdesk",
"name": "TOPdesk",
"vendor": "TOPdesk",
- "readOn": "2026-07-23",
+ "readOn": "2026-09-26",
"evidenceGrade": "docs-only",
- "unknownReason": "Not covered by the 50 intelligence rows for this system (docs passes dated 2026-04-10 to 2026-07-23); the product was not driven."
+ "unknownReason": "The public TOPdesk documentation, developer docs and roadmap do not cover these capabilities; releasenotes.topdesk.com (a JavaScript app) and community.topdesk.com/ideas (403) could not be read.",
+ "readNote": "Public TOPdesk documentation read 2026-09-26 through the docs.topdesk.com offline search index, with every cited URL re-fetched at HTTP 200; the public roadmap on tip.topdesk.com read from its embedded data. No trial, no login.",
+ "sources": {
+ "docs": "https://docs.topdesk.com/",
+ "sourceRepo": null,
+ "featurePage": "https://www.topdesk.com/en/features/",
+ "featureRequests": "https://tip.topdesk.com/",
+ "issueTracker": null,
+ "roadmap": "https://tip.topdesk.com/",
+ "changelog": "https://releasenotes.topdesk.com/",
+ "apiReference": "https://developers.topdesk.com/",
+ "marketplace": "https://marketplace.topdesk.com/",
+ "pricing": "https://www.topdesk.com/en/pricing/",
+ "accessibilityStatement": "https://www.topdesk.com/en/accessibility/",
+ "securityDocs": "https://docs.topdesk.com/en/security.html",
+ "demoInstance": null,
+ "community": "https://community.topdesk.com/",
+ "reviews": null,
+ "videos": "https://www.topdesk.com/en/demo/",
+ "caseStudies": "https://www.topdesk.com/en/customer-stories/",
+ "partnerDirectory": null,
+ "trainingCurriculum": null,
+ "jobPostings": "https://careers.topdesk.com/",
+ "tenders": [
+ "TenderNed 399078 Vrijwillige transparantie TOPdesk MGR (Rijk van Nijmegen, 2025-10-31)",
+ "TenderNed 402170 Service- en vastgoed management systeem (Velsen, 2025-11-21): requirements REQ6, REQ12, REQ15 name integration with OGD/TOPdesk",
+ "TenderNed 206168 and 219511 TOPdesk migration (Amsterdam, 2020 to 2021)",
+ "TenderNed 324002 and 237630 TOPdesk specialist hire (Zorginstituut Nederland)"
+ ],
+ "nullReasons": {
+ "sourceRepo": "TOPdesk is closed source.",
+ "issueTracker": "No public issue tracker; support runs through My TOPdesk (login). Public input goes through the roadmap portal tip.topdesk.com.",
+ "demoInstance": "No public demo instance; a community question about a trial (community.topdesk.com/q-a-129/topdesk-trial-version-personal-instance-974) shows trials run through sales.",
+ "reviews": "G2 (g2.com/products/topdesk/reviews) and Capterra answered 403 to scripted reads; not confirmed.",
+ "partnerDirectory": "www.topdesk.com/en/partners/ answered 404 and no partner directory is linked from the English site.",
+ "trainingCurriculum": "www.topdesk.com/en/training/ answered 404; only consultancy services are linked (www.topdesk.com/en/services/consultancy/)."
+ },
+ "readHow": "curl with a browser user agent on 2026-09-26, all non-null URLs HTTP 200. docs.topdesk.com was read through its full-text search index en/js/fuzzydata.js (1,532 sections, 987 pages); every docs page cited in the pack was re-fetched with HTTP 200. tip.topdesk.com (Productboard public roadmap, columns Under consideration, Planned, Building, Launched) was parsed from the page's embedded JSON, 185 cards. releasenotes.topdesk.com is a JavaScript app whose entries were not read. community.topdesk.com/ideas answered 403; the community has no ideas board, ideas go to tip.topdesk.com per docs.topdesk.com/en/product-updates.html. docs.topdesk.com also carries Virtual Appliance (on-premises) documentation per release."
+ }
}
],
"areas": [
@@ -880,7 +1006,7 @@
"providerHow": "read-from-code",
"note": "Stackiq has no record for an API an application exposes.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#27425 'API Management' (2026-04-12): Catalog and manage APIs across the application landscape",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines: interface subtype 'API ... APIs provide functionalities accessible to external applications ... Examples: Metrics API, Import API', related to the providing application (read 2026-09-26). Reached on: Inventory > Interface fact sheet, subtype API.",
"stackiq": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label",
"topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no register of APIs an application exposes is described; standards are declared instead; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -893,7 +1019,7 @@
"name": "Export the graph of what an application is linked to, for use elsewhere.",
"origin": "competitor",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
@@ -913,7 +1039,8 @@
"glpi": "source read at 11.0.9: front/impactcsv.php streams Glpi\\Csv\\ImpactCsvExport for an item, linked from the impact list view at src/Impact.php:393; the graph Download button src/Impact.php:1165 calls js/impact.js:2528 download, which writes PNG (js/impact.js:2539) or JPEG (js/impact.js:2546). Reached on: Appliance > Impact analysis tab, Download and CSV export.",
"stackiq": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*",
"topdesk": "unknown: exporting the relation graph is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: \"Pakketten én koppelingen worden in 1 model geëxporteerd ... AMEFF-export\" (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Mijn koppelingen: Knop [Exporteren] op tabblad Koppelingen\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten or Koppelingen > Exporteren > AMEFF-export."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: \"Pakketten én koppelingen worden in 1 model geëxporteerd ... AMEFF-export\" (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Mijn koppelingen: Knop [Exporteren] op tabblad Koppelingen\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten or Koppelingen > Exporteren > AMEFF-export.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams: diagrams export 'in the following formats: PDF, SVG, PNG, HTML embed code, and XML' and open in draw.io; https://help.sap.com/docs/leanix/ea/exporting-fact-sheet-data-as-excel-file exports fact sheet data. No export of an application's relation graph as data is documented as such (read 2026-09-26). Reached on: Diagrams > Export (XML, draw.io); Inventory > Export."
}
},
{
@@ -922,7 +1049,7 @@
"name": "Add and check the organisation's outside integrations from one integrations overview.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "partial",
@@ -940,6 +1067,7 @@
"stackiq": "src/manifest.d/connection-registry.json:23 Integrations page (register integriq, schema app_connection) with visibleIf appInstalled 'integriq' (:17) and permission admin (:15,:27); Add integration handler leaves for integriq (src/services/connectionRegistry.js:43); rows synced from lib/Settings/connections.json (email, federation, eol-feed); status worked out by integriq",
"topdesk": "https://docs.topdesk.com/en/connections.html: \"TOPdesk offers a storage space for usernames, passwords, and authentication tokens used in automated actions ... Better overview: Observe when specific credentials are applied\" (read 2026-09-26); https://docs.topdesk.com/en/using-the-automated-actions-overview.html: \"contains all asset actions, webhooks, scheduled actions ... The last execution status\" (read 2026-09-26). Reached on: Settings > Connections; Action Management > Automated Actions.",
"vng-softwarecatalogus": "unknown: no overview of the catalogue's own outside integrations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/discovering-ai-agents-using-api: 'Go to the Integrations section in the administration area. Choose Add Integration'; https://help.sap.com/docs/leanix/ea/collibra-data-catalog-integration: 'Administration > Integrations > Sync Log' to check each integration (read 2026-09-26). Reached on: Administration > Integrations (Add Integration, Sync Log).",
"glpi": "source read at 11.0.9: outside integrations are set up on separate Setup pages, not one overview: src/Html.php:1331 Webhook, src/Html.php:1333 OAuthClient and MailCollector, Auth (LDAP, SSO) on src/Html.php:1332; src/Webhook.php:64 Webhook and src/OAuthClient.php:45 OAuthClient each have their own list. Reached on: Setup > Webhooks, Setup > OAuth clients, Setup > Authentication."
}
},
@@ -970,6 +1098,7 @@
"stackiq": "appinfo/routes.php:96 POST /api/archimate/import -> lib/Controller/SettingsController.php:1490 importArchiMate (isAdmin check :1496) -> lib/Service/ArchiMateImportService.php (5961 lines); UI src/views/settings/sections/ArchiMateImportExport.vue:32 file input + :791 importArchiMateFile",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: only export to AMEFF is documented; importing an ArchiMate file into the catalogue is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea (all EA pages grepped for ArchiMate and exchange format); diagram import supports '.drawio, Lucidchart, .vsdx, PNG, SVG, JPEG' only (https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams), ArchiMate appears only as a shape template (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma\\|togaf' over src/ templates/ locales/glpi.pot returns nothing; no model import exists. Import paths in core are inventory (src/Glpi/Inventory/Inventory.php:106) and form import (src/Glpi/Controller/Form/Import/), neither for models."
}
},
@@ -1000,6 +1129,7 @@
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
"stackiq": "appinfo/routes.php:97 POST /api/archimate/export -> lib/Controller/SettingsController.php:1615 exportArchiMate (admin or org-admin via verifyOrgExportPermission :1735) -> lib/Service/ArchiMateService.php:232 exportToArchiMate (docblock: organization filter 'currently not implemented'); UI ArchiMateImportExport.vue:591 'Export Base' button",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; exports are PDF, SVG, PNG, HTML and draw.io XML (https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams); no ArchiMate exchange format export is documented, ArchiMate 3.2 is only a visual template (https://help.sap.com/docs/leanix/ea/styles-and-patterns) (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing; exports are CSV, PDF and spreadsheet search output (src/Glpi/Csv/) only. Export formats are src/Glpi/Search/Output/Csv.php:38 and src/Glpi/Search/Output/Pdf.php:43 and the spreadsheet siblings."
}
},
@@ -1029,6 +1159,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: export file named \"GEMMA_Softwarecatalogus__ameff_model\" (read 2026-09-26); https://www.softwarecatalogus.nl/Archi_modellen_samenvoegen: \"De export van de Softwarecatalogus bevat de GEMMA en alle pakketten en koppelingen van de gemeente\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: \"GEMMA views met daarop geplot de pakketten van de gemeente\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Exporteren > AMEFF-export.",
"stackiq": "appinfo/routes.php:98 GET /api/archimate/export/organization/{organizationUuid} -> lib/Controller/SettingsController.php:1685 exportOrgArchiMate -> lib/Service/ArchiMateService.php:302 -> lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications in GEMMA view copies; UI ArchiMateImportExport.vue:602 'Organization Export' with Modules/Deelnames/Gebruik checkboxes",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no GEMMA content and no ArchiMate file export are documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma' over src/ templates/ locales/glpi.pot returns nothing; no GEMMA plotting or per entity model export. Export formats are src/Glpi/Search/Output/Csv.php:38 and src/Glpi/Search/Output/Pdf.php:43, no model file."
}
},
@@ -1058,6 +1189,7 @@
"stackiq": "appinfo/routes.php:107 POST /api/archimate/test-round-trip -> lib/Controller/SettingsController.php:2886 (@NoAdminRequired, any logged-in user) -> lib/Service/ArchiMateService.php:1496 testRoundTrip: reads $importResult['imported_count'] (:1528), a key no import path sets, and compares it to exportToArchiMate's 'exported_count' which is the literal string 'calculated_in_export_service' (:271), so it can never report success; it also imports a test model into the live register",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the merge guide checks the result inside Archi via its status log; the catalogue itself offers no round-trip check; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Archi_modellen_samenvoegen (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no model file import and export pair (ArchiMate or similar) is documented, so no round trip check exists in the docs (read 2026-09-26)",
"glpi": "source read at 11.0.9: there is no model import or export to round trip, grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing. Export formats are src/Glpi/Search/Output/Csv.php:38 and src/Glpi/Search/Output/Pdf.php:43, no model file."
}
},
@@ -1067,7 +1199,7 @@
"name": "Follow a long model import while it runs, and cancel it if needed.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -1087,6 +1219,7 @@
"stackiq": "appinfo/routes.php:103 POST /api/archimate/import/cancel -> lib/Service/SettingsService.php:5200 calls ArchiMateService::cancelArchiMateImport(), which does not exist in lib/Service/ArchiMateService.php (Error, not caught by catch(\\Exception)); routes.php:119-120 /api/progress/{operationId} read ProgressTracker, but the ArchiMate import never writes to it (only SbomImportService gets it, lib/AppInfo/Application.php:507); ArchiMateImportExport.vue:538 shows only a spinner, no cancel button",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no model import is documented; for export only \"Er verschijnt een venster met de melding dat de export gegenereerd wordt\"; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools (read 2026-09-26)",
+ "sap-leanix": "https://updates.leanix.net/announcements/product-update-march-2026: 'The new asynchronous import process runs entirely in the background ... A real-time progress widget in the inventory side-panel keeps you informed of import status'. This is the Excel import, not a model import, and cancelling is not described (read 2026-09-26). Reached on: Inventory side panel > import progress widget.",
"glpi": "source read at 11.0.9: no model import exists (grep -ril 'archimate' src/ returns nothing), so there is no import to follow; the generic progress endpoint src/Glpi/Controller/ProgressController.php serves other long operations. The progress route is src/Glpi/Controller/ProgressController.php:50 /progress/check/{key}, used by the installer (src/Glpi/Controller/InstallController.php:57)."
}
},
@@ -1116,6 +1249,7 @@
"stackiq": "src/manifest.json StandaardDetail /standaarden/:id st-data widget shows all element fields (documentation, gemmaNotes) of a standard; FacetedCatalogIndexView.vue:150 shows reference components by name only",
"topdesk": "unknown: GEMMA is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/lexicon: lexicon of catalogue terms (Addendum, Referentiecomponent, Standaard, SaaS); terms in page text link to it (read 2026-09-26); https://www.softwarecatalogus.nl/node/13683: \"Alle referentiecomponenten ... de toelichting bij de referentiecomponenten\" (read 2026-09-26). Reached on: Lexicon; Alle referentiecomponenten.",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no GEMMA terms and no in-place glossary of reference architecture terms are documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'gemma\\|glossary' over src/ templates/ locales/glpi.pot returns nothing; no reference term definitions ship in core. The knowledge base (src/KnowbaseItem.php:57) is the only place definitions could be written by hand."
}
},
@@ -1142,7 +1276,7 @@
"featureConfidence": "medium",
"note": "The mapping to GEMMA reference components exists, but there is no map view in stackiq; you only see it as a facet list or in Archi after an admin export.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | docs, intelligence competitor_features#27420 'Business Capability Mapping' (2026-04-12): Map applications to business capabilities and processes",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/meta-model: 'A business capability is supported by an application'; https://help.sap.com/docs/leanix/ea/application-portfolio-assessment lists a 'Business capability map' (read 2026-09-26). Reached on: Reports > Landscape Report on Business Capabilities.",
"bluedolphin": "docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
"stackiq": "module.referenceComponents / usage.usedForReferenceComponents in lib/Settings/softwarecatalogus_register.json hold the application-to-reference-component mapping; lib/Service/ArchiMateExportService.php:2734 draws it only into exported view copies",
"topdesk": "unknown: no capability or function map is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -1171,7 +1305,7 @@
"providerHow": "read-from-code",
"note": "Models are imported and exported as ArchiMate files; nothing lets a user draw or edit a model inside stackiq.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48869 'Architecture diagrams / free-draw' (2026-07-23): Auto-generated and manual architecture diagrams from the data model.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams and https://help.sap.com/docs/leanix/ea/working-with-fact-sheets-in-diagrams: free draw and data flow diagrams edited in the diagram editor, with an ArchiMate 3.2 shape template (https://help.sap.com/docs/leanix/ea/styles-and-patterns) (read 2026-09-26). Reached on: Diagrams > New Diagram (diagram editor).",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models.",
"stackiq": "src/manifest.json has no page for the view or element schema beyond Standaarden; no diagram editor in src/views or src/components",
"topdesk": "unknown: no architecture modelling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -1185,7 +1319,7 @@
"name": "Model business processes and link them to the applications that support them.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
@@ -1204,6 +1338,7 @@
"stackiq": "no process schema in lib/Settings/softwarecatalogus_register.json (20 schemas listed under components.schemas); no process page in src/manifest.json",
"topdesk": "unknown: no process modelling linked to applications is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no process modelling is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/business-context-modeling-guidelines: business context subtype 'Process : Processes show the different steps and interactions', related to applications; SAP Signavio integration documented under Discovery and Integrations (read 2026-09-26). Reached on: Business Context fact sheet, subtype Process.",
"glpi": "source read at 11.0.9: grep -rli 'business process' over src/ and locales/glpi.pot returns nothing; no process itemtype to link to applications. Appliance tabs (src/Appliance.php:98 onwards) link no process."
}
},
@@ -1213,7 +1348,7 @@
"name": "Model a future-state landscape and compare it with today's.",
"origin": "competitor",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -1228,7 +1363,7 @@
"providerHow": "read-from-code",
"note": "Planned usage and planned replacements exist per record, but there is no future-state model and no comparison with today.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#27419 'IT Transformation' (2026-04-12): Plan and execute cloud migrations and modernization | Rated partial because transformation planning.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/sap-leanix-architecture-and-road-map-planning: 'plan your target architecture and monitor initiative progress', transformation templates and impacts; https://updates.leanix.net/announcements/plan-with-consistent-future-architecture-data-introducing-the-committed-future (2026-09-24): 'Understanding your architecture across the past, present, and future ... introducing the committed future'. In the Architecture and Road Map Planning add on (read 2026-09-26). Reached on: Architecture and Road Map Planning > Transformations, target architecture diagrams.",
"stackiq": "searched src/manifest.json and the register for scenario/future-state/toekomst: nothing; usage.status 'Planned' and plannedReplacement (register) are per-usage fields, not a comparable landscape",
"topdesk": "unknown: Long-Term Planning scenarios are for maintenance planning and the module \"will reach end of life ... November 2026\"; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"geplande harmonisaties ... met een status gepland met bijbehorende datum. Zo kan ook het uiteindelijke doel-landschap in 1 overzicht inzichtelijk worden gemaakt\" (read 2026-09-26). No side-by-side comparison of today and target. Reached on: Mijn softwarecatalogus (samenwerking) > Pakketten > status Gepland.",
@@ -1241,7 +1376,7 @@
"name": "Find reference components that no application in your landscape covers.",
"origin": "competitor",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
@@ -1260,6 +1395,7 @@
"stackiq": "grep for uncovered/gap/coverage in lib and src found nothing; lib/Service/FacetService.php counts modules per reference component but never lists components with zero coverage",
"topdesk": "unknown: GEMMA reference components are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tile \"Pakketten met meer mogelijkheden: U heeft in uw pakketoverzicht pakketten die geschikt zijn voor referentiecomponenten waarbij u nog geen pakket heeft opgevoerd\" (read 2026-09-26). It lists uncovered components only where an owned package could fill them. Reached on: Dashboard tile Pakketten met meer mogelijkheden.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/report-types: Matrix Report 'Displays relations between fact sheets in a two-dimensional matrix' for 'Coverage gap analysis'. Gaps are business capabilities without supporting applications; no reference architecture such as GEMMA is shipped (read 2026-09-26). Reached on: Reports > Matrix Report.",
"glpi": "source read at 11.0.9: no reference component model to compare against, grep -ril 'gemma\\|reference component' over src/ locales/glpi.pot returns nothing; appliances are typed only by the free Appliance type dropdown (install/mysql/glpi-empty.sql:8941)."
}
},
@@ -1269,7 +1405,7 @@
"name": "Have a diagram drafted for you by an assistant from a description.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
@@ -1288,6 +1424,7 @@
"stackiq": "no diagram generation in lib/Service or src; no AI integration for diagrams",
"topdesk": "unknown: the AI features cover tickets and knowledge, not diagrams; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no assistant is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://updates.leanix.net/announcements/build-and-edit-architecture-diagrams-with-ai-agents (2026-09-15): 'AI agents connected to your workspace via the MCP server can now create, populate, and edit diagrams ... You describe what you want to see, and the agent adds fact sheets to a canvas' (read 2026-09-26). Reached on: MCP server with an AI agent > diagrams.",
"glpi": "source read at 11.0.9: grep -rli 'openai\\|llm\\|mistral\\|chatgpt\\|artificial intelligence' over src/ templates/ returns nothing; diagrams are drawn by hand in the impact graph (src/Impact.php:1160)."
}
},
@@ -1297,7 +1434,7 @@
"name": "Browse a register of the standards applications are expected to support.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -1317,6 +1454,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle standaarden: Dit overzicht is een opsomming van alle standaarden waaraan pakketten mogelijk moeten voldoen. Alle standaarden hebben een toelichting en indien aanwezig een toelichting op het compliancy-instrument\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle standaarden.",
"stackiq": "src/manifest.json page Standaarden /standaarden (index on @resolve:amef_register schema element, filter gemmaType=standaard, columns name/gemmaThema/gemmaStatus/url) and StandaardDetail /standaarden/:id with compliance claims per standard; menu entry Standards (order 50)",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/technology-standards-management-capabilities: Technology Risk and Compliance helps 'establish technology standards' for frameworks and languages. These are technology standards for components, not interoperability standards an application must support (read 2026-09-26). Reached on: Technology Risk and Compliance > technology standards.",
"glpi": "source read at 11.0.9: no standards itemtype, grep -ril 'standaard\\|forum standaardisatie' src/ locales/glpi.pot returns nothing and the word standard in src/Appliance.php occurs only in addStandardTab (src/Appliance.php:100)."
}
},
@@ -1326,7 +1464,7 @@
"name": "Attach a test report or other evidence to a compliance claim.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -1346,6 +1484,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.evidence (file, pdf/jpeg/png/doc, 10 MB), compliancy.url, compliancy.evidenceReference; src/manifest.json KompliantieDetail cm-files widget type integration integrationId files 'Evidence documents'",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Door de vakje achter de standaard aan te vinken voor Ondersteuning(gepland) en Compliancy, wordt de optie om een testrapport of auditrapport op te voeren geopend\" (read 2026-09-26). Reached on: Supplier login > productversie > Voeg extra standaarden toe.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets: 'The Resources tab ... You can upload files up to 10 MB' and links on any fact sheet. Files attach to the fact sheet, not to a specific compliance claim (read 2026-09-26). Reached on: Fact sheet > Resources tab.",
"glpi": "source read at 11.0.9: any document can be attached to an appliance through the Documents tab, src/Appliance.php:100 Document_Item tab and src/Document_Item.php:46, stored in install/mysql/glpi-empty.sql:2585 glpi_documents; there is no compliance claim to attach it to. Reached on: Management > Appliances > Documents tab."
}
},
@@ -1375,6 +1514,7 @@
"stackiq": "src/utils/complianceMatrix.js:9-17 cell state verified = compliancy record with evidence (hasEvidence :107 checks evidence/evidenceReference/url), claimed = link without evidence; rendered by src/views/ComplianceMatrixView.vue",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C8: \"Gepubliceerde testrapporten voor een aantal standaarden die in de compliancy-monitor staan, worden sinds eind 2016 door VNG Realisatie gecontroleerd en daarna op status goedgekeurd of afgekeurd gezet\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketversies: facet \"Standaard met testrapport: Toon alleen pakketversies met compliancy aangetoond in een testrapport\" (read 2026-09-26). Reached on: Alle pakketversies > filter Standaard met testrapport; Compliancy monitor.",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; a quality seal approves fact sheet data as a whole (https://help.sap.com/docs/leanix/ea/updating-lifecycle-phase-and-approving-quality-seal) but no distinction between verified and supplier asserted compliance claims is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no compliance claim model, grep -rli 'complian' over src/Appliance.php src/Software.php returns nothing; nothing to mark verified or claimed (src/Appliance.php:46 fields are inventory and management fields only)."
}
},
@@ -1384,7 +1524,7 @@
"name": "See applications against chosen standards in one matrix, cell by cell.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -1404,6 +1544,7 @@
"stackiq": "src/manifest.json ComplianceMatrix /compliance-matrix custom page -> src/customComponents.js ComplianceMatrixView -> src/views/ComplianceMatrixView.vue (modules x selected standard versions or BIO measures, src/utils/complianceMatrix.js:270 columns)",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/compliancy_monitor: per standard (e.g. \"Betalen en invorderen services 1.0\") a table of Leverancier, Pakketversie, Compliancy \"Ok\" or \"Niet ok\" (read 2026-09-26). Fixed per standard, not a matrix of chosen applications against chosen standards. Reached on: Homepage > Compliancy monitor.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/meta-model-dora-extension: 'You can create a regulatory dictionary, categorize DORA requirements, and link DORA obligations directly to specific IT and business architecture elements'; https://help.sap.com/docs/leanix/ea/report-types: Matrix Report maps relations cell by cell. Regulation obligations, not interoperability standards (read 2026-09-26). Reached on: DORA extension + Reports > Matrix Report.",
"glpi": "source read at 11.0.9: there are no standards in core (grep -rli 'standaard\\|forum standaardisatie' src/ locales/glpi.pot returns nothing), so no application by standard matrix; search output (src/Glpi/Search/Output/Spreadsheet.php) only tabulates item fields. The spreadsheet output is src/Glpi/Search/Output/Csv.php:38 and siblings."
}
},
@@ -1433,6 +1574,7 @@
"stackiq": "appinfo/routes.php:275 POST /api/bulk-sync-standards -> lib/Controller/SettingsController.php:3598 (isAdmin check) -> lib/Service/ModuleComplianceService.php:527 bulkSyncModuleStandards (reads up to 1000 compliancy records and updates module standards); UI src/views/settings/sections/StatisticsOverview.vue:79 button -> src/modals/BulkSyncDialog.vue:321",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: only per-version copying is described (\"opvoer van een nieuwe versies mogelijk als kopie van een op te geven vorige versie\"); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no action that refreshes the standards set of many applications is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no standards model exists (see comp-standards-register); massive actions (src/MassiveAction.php:666 Update) update item fields only."
}
},
@@ -1462,6 +1604,7 @@
"stackiq": "src/manifest.json BioMaatregelen /bio-maatregelen index (columns code,name,thema,bioVersion,bbnNiveau) and BioMaatregelDetail; register property is bbnLevel (lib/Settings/softwarecatalogus_register.json bioMeasure), so the bbnNiveau column is empty; no BIO catalogue is seeded (only 6 demo objects in lib/Settings/stackiq_mock_register.json)",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: BIO measures are not in the catalogue docs; BBN views live on GEMMA Online per the news page; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/nieuws (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for BIO and Baseline Informatiebeveiliging, no hits; LeanIX documents DORA and GDPR content only (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'iso 27001\\|27002' and grep -rwi 'bio' over src/ locales/glpi.pot return nothing; no security measure catalogue ships (menus at src/Html.php:1295 onwards list none)."
}
},
@@ -1491,6 +1634,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.bioMeasure links a module to a BIO measure; src/manifest.json ModuleDetail md-compliance lists claims incl. bioMaatregel column, BioMaatregelDetail bm-compliance lists modules per measure; compliancy has no status/met-not-met field",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no BIO assessment per application is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for BIO, no hits; no BIO measure assessment per application is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no measure catalogue and no assessment itemtype; grep -rli 'iso 27001\\|27002' over src/ locales/glpi.pot returns nothing and Appliance tabs (src/Appliance.php:98 onwards) hold no assessment."
}
},
@@ -1520,6 +1664,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json module.dpiaStatus (enum not required/required/executed), dpiaDate, dpiaNextAssessment, dpiaDocumentRef; src/manifest.json ModuleDetail md-data includes the DPIA fields; Modules /modules quick filter 'Without DPIA (BBN2+)'",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no DPIA field is described; the VWO addendum is a supplier-level processing agreement; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/leveranciers (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for DPIA and data protection impact assessment, no hits; only data classification of data objects for GDPR is documented (https://help.sap.com/docs/leanix/ea/data-object-modeling-guidelines 'classified into personally identifiable data (e.g., to cater to GDPR use cases)') (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'dpia\\|impact assessment\\|gdpr' over src/ returns nothing, locales/glpi.pot:12792 'gdpr-tools' is only an icon name. The GDPR records plugin yild/gdprropa read at tag 1.0.3 has 'PIA required' and 'PIA status' (inc/record.class.php:459, :468) but declares GLPI 10 only, setup.php:56 max 10.99.99, so it does not run on 11.0.9."
}
},
@@ -1547,6 +1692,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/inkoopondersteuning%20standaarden: \"De verplichte standaarden zijn: ... de open standaarden die onder het pas-toe-of-leg-uit regime van de overheid binnen het werkingsgebied vallen\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: package version shows \"Verplichte standaarden ... Ondersteuning Compliancy Testrapport\" (read 2026-09-26). Comply-or-explain standards are mixed into the mandatory set, not shown as their own list. Reached on: Package page > Standaarden; Inkoopondersteuning.",
"stackiq": "grep for forum standaardisatie / pas toe of leg uit / comply-or-explain in lib and src: no hits; standards come only from the GEMMA AMEF import (element gemmaType=standaard)",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for Forum Standaardisatie and comply or explain, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'standaard\\|forum standaardisatie\\|comply' over src/ locales/glpi.pot returns nothing relevant; no comply or explain list in core (Setup menu src/Html.php:1330 onwards)."
}
},
@@ -1556,7 +1702,7 @@
"name": "Score the correctness and completeness of the register against a rule set.",
"origin": "competitor",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -1574,6 +1720,7 @@
"stackiq": "grep for completeness/health score/quality score in lib and src: no hits; lib/Command/ReferencesAuditCommand.php:34 (occ stackiq:references:audit) only audits cross-app uuid references, it is not a scored rule set",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C7: automatic checks and \"Te corrigeren fouten ... Bijvoorbeeld over het ontbreken van pakketversies, of tegenstrijdigheid in de status van een pakketversie en vermelde datum distributie\" (read 2026-09-26); https://www.softwarecatalogus.nl/voortgang-verbeteren: star criteria for completeness (read 2026-09-26). Reached on: Supplier dashboard Te corrigeren fouten; Voortgang sterren.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-portfolio-management-dashboard: 'Data Quality KPI ... Overall Completion of Applications ... Broken quality seal ... Missing Business Capability'; completion score weights set by admins (https://help.sap.com/docs/leanix/ea/fact-sheet-completeness) (read 2026-09-26). Reached on: Dashboards > Application Portfolio Management Dashboard > Data Quality KPIs.",
"glpi": "source read at 11.0.9: grep -ril 'completeness' over src/ templates/ locales/glpi.pot returns nothing and no rule set scores register quality; the rules engine (src/Glpi/Rules/, src/RuleCollection.php) assigns and imports data, it does not score it. The rules engine base is src/RuleCollection.php:48."
}
},
@@ -1583,7 +1730,7 @@
"name": "Send a compliance questionnaire to a supplier and keep the answers with the application.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown",
@@ -1602,6 +1749,7 @@
"stackiq": "grep for questionnaire/vragenlijst in lib and src: no hits; no questionnaire schema in lib/Settings/softwarecatalogus_register.json",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no questionnaire to suppliers is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/reviewing-responses: survey answers are reviewed and saved to the fact sheet; recipients are the users 'assigned to the fact sheet'. Sending to an outside supplier is not documented (read 2026-09-26). Reached on: Surveys.",
"glpi": "source read at 11.0.9: native forms (src/Glpi/Form/Form.php:92) are filled by logged in or helpdesk users and only produce tickets, changes or problems (src/Glpi/Form/Destination/FormDestinationTicket.php:47); nothing sends a questionnaire to a supplier or stores answers on an appliance."
}
},
@@ -1631,6 +1779,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Deze handleiding is bedoeld voor de leveranciers en legt uit hoe de leveranciers hun productportfolio kunnen aanvullen en beheren ... voeg pakket toe\" (read 2026-09-26). Reached on: Supplier login > Productportfolio.",
"stackiq": "src/manifest.json:592 Modules and :647 Diensten are FacetedCatalogIndexView over schema module/catalogService (CnIndexPage, showAdd default true); lib/Settings/softwarecatalogus_register.json:6779 module has provider + publicationDate (visible on form) and public read when publicationDate <= now or registeredBy Supplier",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; LeanIX is a customer's internal EA workspace, no supplier facing publication of offerings is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers are records kept by the buying organisation, install/mysql/glpi-empty.sql:7067 glpi_suppliers, with no supplier login or offering page; profiles (src/Profile.php) cover internal users and the self-service helpdesk only."
}
},
@@ -1660,6 +1809,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Ik ben op zoek naar een nieuw pakket voor referentiecomponent voor BAG-administratie\" and standards filters combine (read 2026-09-26); https://www.softwarecatalogus.nl/pakketten: facets Referentiecomponent and Standaard (read 2026-09-26). Reached on: Alle pakketten > filters.",
"stackiq": "lib/Service/FacetService.php:109 DIMENSIONS referenceComponent, standard, applicationService, domain for schemas module and catalogService (:102); src/views/FacetedCatalogIndexView.vue:108 CnFacetSidebar narrows CnIndexPage; route GET /api/facets/{schema} called from src/services/facets.js",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/applications-in-reference-catalog: the catalog 'covers SAP applications, SAP AI agents, and SaaS applications' and is used to link your own fact sheets; market search by reference component and standard is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: search covers only the organisation's own records (src/Glpi/Search/SearchEngine.php); there is no market wide catalogue and no reference component or standard to filter on (grep -ril 'gemma\\|reference component' src/ returns nothing). The marketplace (src/Glpi/Marketplace/) lists GLPI plugins, not software for a task. The search engine is src/Glpi/Search/SearchEngine.php:101; the marketplace is src/Glpi/Marketplace/Controller.php:64."
}
},
@@ -1687,6 +1837,7 @@
"stackiq": "src/manifest.json:386 Organisaties type:index over schema organization with status filter and OrganisatieCard; register :2022 organization.type is facetable (Municipality/Supplier/Collaboration/Community); public read of Active suppliers in organization authorization (:2467)",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/leveranciers: \"Leveranciers ... Zoek in leveranciers ... 354 resultaten gevonden\", filter \"Met ondertekend addendum\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle leveranciers.",
+ "sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/provider-modeling-guidelines: 'SAP LeanIX has a catalog of 9000 providers' added automatically with IT components; browsing that catalog as a directory with filters is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/Supplier.php:46 Supplier list under Management (src/Html.php:1298) with search, filters and a supplier type (install/mysql/glpi-empty.sql:7072 suppliertypes_id), but it holds only the suppliers this organisation entered, not all organisations offering to government. Reached on: Management > Suppliers (front/supplier.php). Driven on the lab at 11.0.9 (2026-09-26): created supplier \"Lab Leverancier BV\" through /front/supplier.form.php; it appears in the Suppliers list."
}
},
@@ -1714,6 +1865,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle gemeenten ... inclusief contactgegevens van gemeenten ... U kunt contact onderhouden met deze gemeenten\" (read 2026-09-26). Reached on: Inlogmenu > Alle gemeenten.",
"stackiq": "Looked in src/components, src/views and lib/Controller for any contact or messaging between organisations sharing a module: none. Usage read rules (register :3137) hide other organisations' usages from municipalities.",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; a vendor community exists (https://community.leanix.net/) but no in product way to find organisations using the same product is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: each GLPI instance holds one organisation's data (entities are internal subdivisions, src/Entity.php), so there is no view of other organisations using the same product; grep -rli 'peer' src/*.php matches only relation and network code such as src/CommonDBConnexity.php, no peer organisation feature."
}
},
@@ -1723,7 +1875,7 @@
"name": "Read a supplier's declared roadmap and planned releases for a product.",
"origin": "competitor",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -1743,6 +1895,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle pakketversies en planningen ... gelijk zichtbaar de planning van de diverse pakketversies\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketversies: facet \"Status planning ... Filter op in ontwikkeling en zie de distributie planningsdata\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle pakketversies en planningen.",
"stackiq": "register :7651 moduleVersion with status enum in development/in use/end of support/withdrawn and dateInDevelopment/dateInUse/dateEndSupport, read public; src/manifest.json:915 Moduleversies index + ModuleversieDetail",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/it-components-in-reference-catalog: 'The catalog provides standardized IT component data including lifecycle dates, vendor information ... You no longer need to track vendor lifecycle dates manually'. Vendor lifecycle and support dates, not planned releases; needs Technology Risk and Compliance (read 2026-09-26). Reached on: IT Component fact sheet linked to the reference catalog.",
"glpi": "source read at 11.0.9: suppliers (install/mysql/glpi-empty.sql:7067 glpi_suppliers) carry address and contact fields only, and software versions (install/mysql/glpi-empty.sql:6900) carry no planned release date; grep -rli 'roadmap' src/*.php returns nothing."
}
},
@@ -1772,6 +1925,7 @@
"stackiq": "src/manifest.json:514 ModuleDetail bodyWidget ReviewsPanel; src/components/reviews/ReviewsPanel.vue:63 opens SubmitReviewModal; POST /api/reviews -> lib/Service/ReviewService.php:232 stamps author and forces status pending; rating 1..10 in software-review schema (:3961)",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no reviews are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no user review of an application with a rating is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no product review model; satisfaction surveys rate ticket handling only (src/CommonITILSatisfaction.php) and knowledge base comments (src/KnowbaseItem_Comment.php) carry no rating. Ticket satisfaction is src/CommonITILSatisfaction.php:43 and knowledge base comments src/KnowbaseItem_Comment.php:43."
}
},
@@ -1801,6 +1955,7 @@
"stackiq": "lib/Service/ReviewAggregateService.php:51 approved-only average + count; GET /api/reviews/aggregate (PublicPage) called from src/utils/reviewAggregate.js imported by src/components/reviews/ReviewsPanel.vue",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no ratings are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no review ratings exist in the docs to aggregate (read 2026-09-26)",
"glpi": "source read at 11.0.9: with no product reviews there is no average rating; the only averages are ticket satisfaction statistics (src/CommonITILSatisfaction.php). Ticket satisfaction is src/CommonITILSatisfaction.php:43."
}
},
@@ -1828,6 +1983,7 @@
"stackiq": "register :6856 module.contactPerson -> contactPerson with x-relation-filter organization = @object.provider; catalogService and suite also carry contactPerson; src/manifest.json:500 ModuleDetail md-data include lists 'contactpersoon', 'beschrijvingKort', 'beschrijvingLang', which are not module properties (renamed to contactPerson/shortDescription/longDescription)",
"topdesk": "unknown: supplier contacts are registered per supplier (\"Registering a supplier contact\"); contacts per product are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the docs name one contact per supplier (\"Bij elke leverancier is een contactpersoon opgevoerd\"); whether a product can carry its own is not stated; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30402 (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; subscriptions name internal users per fact sheet, but supplier contact persons per product are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: contacts link to a supplier as a whole, src/Contact_Supplier.php:39 (install/mysql/glpi-empty.sql:1429 glpi_contacts_suppliers), not to a product; per application there is only the free text contact field on an appliance (src/Appliance.php:214) and the user or technician in charge. Reached on: Management > Suppliers > Contacts tab; Appliance contact field."
}
},
@@ -1852,7 +2008,7 @@
"providerHow": "read-from-code",
"note": "One organisation record is the supplier; products reference it and the detail page lists them. A contract reaches the supplier only through its service, not by its own field.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers. | Rated yes because Provider fact sheet.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/provider-modeling-guidelines: 'Providers are companies or entities that supply IT solutions, services, or technologies'; one provider fact sheet linked from IT components and contracts (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model) (read 2026-09-26). Reached on: Inventory > Provider fact sheet.",
"topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier ... The Supplier Card has been created\" and \"Registering a supplier contact\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Create a new preliminary contract or preliminary supplier contract\" (read 2026-09-26). Reached on: Supporting Files > New > Supplier.",
"stackiq": "register :2022 organization (one record, type Supplier); module.provider (:6921) and catalogService.provider (:3762) are $ref organization; catalogContract points at service (+usage), register :3252; OrganisatieDetail src/manifest.json:403 lists the supplier's services and applications",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"De verbinding met de leveranciersgegevens garandeert juiste schrijfwijzes van leveranciers- en pakketnamen en juiste versienummering\" (read 2026-09-26); https://www.softwarecatalogus.nl/leveranciers: one record per supplier with contact and addenda (read 2026-09-26). There are no contracts to point to it. Reached on: Alle leveranciers > supplier page.",
@@ -1883,7 +2039,7 @@
"note": "Pick an organisation and its applications in use are grouped by derived lifecycle phase. The usage records themselves cannot be created or edited on any stackiq page (see life-planned-replacement).",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: A1: \"Bij de oude versie kan de status gewijzigd worden in uit-te-faseren / uitgefaseerd\" (read 2026-09-26); https://www.softwarecatalogus.nl/voortgang-verbeteren: \"pakketversies hebben de status Gepland óf Uit te faseren\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30355: \"Vul onder Planning bij Status in gebruik in\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Planning Status.",
- "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/advanced-filter-options: 'The lifecycle filter enables filtering of fact sheets by their lifecycle state: plan, phase-in, active, phase-out, and end-of-life' (read 2026-09-26). Reached on: Application fact sheet > Lifecycle.",
"topdesk": "https://docs.topdesk.com/en/managing-disruptions-in-your-asset-management-process.html: built-in \"operational/impacted status for assets\" (read 2026-09-26); lifecycle phases need a self-defined drop-down field (https://docs.topdesk.com/en/creating-new-fields.html). No planned, in use, phase-out model ships. Reached on: Asset card > General widget.",
"stackiq": "src/manifest.json LifecycleRoadmap /portfolio-roadmap custom page -> src/views/LifecycleRoadmapView.vue:55 groups the selected organisation's usages by phase, derived from usage dates by src/utils/lifecyclePhase.js derivePhase (:408); usage.status enum Acquisition/Planned/In production/To be phased out/Phased out in lib/Settings/softwarecatalogus_register.json",
"glpi": "source read at 11.0.9: appliances carry a status, install/mysql/glpi-empty.sql:8950 glpi_appliances.states_id and src/Appliance.php:350 search option Status, whose values are an admin defined tree dropdown src/State.php:45 (install/mysql/glpi-empty.sql:7027 glpi_states), so phases such as planned, in use and being phased out are set up and filtered on. Reached on: Management > Appliances, Status field; Setup > Dropdowns > Statuses of items."
@@ -1913,7 +2069,7 @@
"note": "Per organisation it shows which applications are phased out or replaced and when; it is a grouped list ordered by urgency rather than a timeline chart.",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"de uit te faseren applicaties van die status worden voorzien inclusief datum. Zo ontstaat inzicht in het totale huidige- en doel-landschap in 1 overzicht\" (read 2026-09-26). Dates per status, no roadmap view described. Reached on: Mijn softwarecatalogus > Pakketten > Planning.",
- "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/report-types: 'Roadmap Report Visualizes fact sheets on a timeline to show the evolution of the IT landscape'; https://help.sap.com/docs/leanix/ea/application-rationalization-create-roadmap (read 2026-09-26). Reached on: Reports > Roadmap Report.",
"stackiq": "src/views/LifecycleRoadmapView.vue:28 organisation select, :55 phase groups, :96-110 phase-out date, planned replacement and link to the replacing module (:400 plannedReplacement, :423 plannedReplacementDate), ordered by nearest urgency (:428)",
"topdesk": "unknown: no replacement roadmap is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"glpi": "source read at 11.0.9: replacements can be planned as projects linked to the appliance, src/Appliance.php:108 Item_Project tab (src/Item_Project.php:45) and src/Project.php:50 Project with Kanban; the Gantt view is the separate gantt plugin (src/Project.php:599 checks isActivated('gantt')). No per organisation application roadmap view exists. Reached on: Tools > Projects, Appliance > Projects tab."
@@ -1940,7 +2096,7 @@
"providerHow": "read-from-code",
"note": "Nothing finds applications in your landscape that fulfil the same reference component; the Reports card promises 'overlapping' software but the report does not compute it.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48861 'Business capability modeling' (2026-07-23): Maps applications to a business capability map for portfolio rationalisation. | Rated partial because rationalisation through capability map.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-rationalization: 'Application rationalization reduces costs, eliminates redundancies', using applications mapped to business capabilities; overlap is found per customer capability, not per reference component (read 2026-09-26). Reached on: Reports > Landscape Report by Business Capability.",
"stackiq": "grep for overlap/redundant in lib and src finds only code comments and the Reports card description (src/manifest.json:1031 'Overlapping and ageing software'); lib/Service/PortfolioReportService.php computes TIME quadrants, EOL exposure, cloud share and cost, no grouping by reference component; the /modules facet counts modules per reference component across the whole catalogue, not your landscape",
"topdesk": "unknown: no functional classification to detect overlap is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tile \"Referentiecomponenten met meerdere pakketten: Deze tegel signaleert dat er meer dan 1 pakket(versie) bij eenzelfde referentiecomponent in productie is\" (read 2026-09-26). Reached on: Dashboard tile Referentiecomponenten met meerdere pakketten.",
@@ -1968,7 +2124,7 @@
"providerHow": "read-from-code",
"note": "The report covers ageing software (EOL exposure) with TIME quadrants, cost and a CSV export, but not overlap, even though its card says 'overlapping and ageing'.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R). | docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-rationalization-evaluate-data: 'Leverage automated TIME classification, application portfolio and landscape reports ... to streamline application rationalization' (read 2026-09-26). Reached on: Use case Application Rationalization > reports.",
"stackiq": "appinfo/routes.php:303 GET /api/portfolio-report -> lib/Controller/PortfolioReportController.php -> lib/Service/PortfolioReportService.php + PortfolioReportDerivation.php; UI src/views/organisaties/PortfolioReport.vue (TIME chart :112, quadrant summary :126 with EOL exposure/cloud/cost, rows :176, CSV export :50)",
"topdesk": "unknown: no rationalisation report is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Referentiecomponenten met meerdere pakketten ... per referentiecomponent aan welke pakketversies daaraan gekoppeld zijn\" (read 2026-09-26). Overlap only, ageing not covered. Reached on: Dashboard tile.",
@@ -1981,7 +2137,7 @@
"name": "Record which version of an application your organisation currently runs.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
@@ -2001,6 +2157,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json usage.moduleVersion ($ref moduleVersion); read by src/views/LifecycleRoadmapView.vue:397 for EOL state; ModuleversieDetail mv-related shows related usages; no usage create/edit page in src/manifest.json",
"topdesk": "unknown: versions in use are only possible as a self-defined field; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Pakketversie - selecteer de versie die in gebruik is\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: version can be captured 'in the Release field of the application fact sheets', which the guide says rarely adds value; IT components carry release per catalog item (https://help.sap.com/docs/leanix/ea/it-components-in-reference-catalog) (read 2026-09-26). Reached on: Application or IT Component fact sheet > Release.",
"glpi": "source read at 11.0.9: src/Item_SoftwareVersion.php:39 records which software version is installed on which item (install/mysql/glpi-empty.sql:1064 glpi_items_softwareversions with date_install at :1074), filled by hand or by native inventory, and listed on the Software Installations tab (src/Software.php:129). Reached on: Assets > Software > Installations tab."
}
},
@@ -2030,6 +2187,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications module-version-published (trigger created, recipients object-acl manage + group software-catalog-admins); no notification code in lib (no INotificationManager use)",
"topdesk": "unknown: no supplier version feed is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/suggesties_overnemen: \"Wanneer een leverancier een pakketversie registreert kan deze een suggestie versturen naar de gemeenten en samenwerkingen die dit pakket afnemen\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C2: \"Via de notificatiefunctie krijgt u een signaal zodra het versienummer is toegevoegd\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Suggesties; Inbox.",
+ "sap-leanix": "unknown: https://updates.leanix.net/announcements/work-with-complete-technology-version-coverage-without-raising-manual-requests (2026-09-17) says the catalog is 'kept current as new versions are released', with version concurrency management planned for Q4; a notification to users about a new version is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: GLPI has no feed of supplier releases; software versions appear only when entered or inventoried (src/SoftwareVersion.php:42), and notification events for software are licence expiry only (src/NotificationTargetSoftwareLicense.php)."
}
},
@@ -2054,7 +2212,7 @@
"providerHow": "read-from-code",
"note": "You could register a database as its own 'System software' module and feed its EOL, but nothing ties it to the applications that depend on it; SBOM components carry no lifecycle.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/obsolescence-risk-management: 'SAP LeanIX helps you gain an overview of your application landscape's obsolescence risk exposure' over the technology layer; lifecycle dates of IT components from the catalog in Technology Risk and Compliance (read 2026-09-26). Reached on: Use case Obsolescence Risk Management; IT Component lifecycle.",
"stackiq": "lib/Settings/softwarecatalogus_register.json sbomComponent has name/version/purl/licenses/type/hashes/bomRef/vexCveIds, no lifecycle or EOL field; the EOL feed (lib/Service/EolSyncService.php:290) only stamps versions of modules with eolProductSlug; no relation from an application to the platform it runs on",
"topdesk": "unknown: no technology lifecycle is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: technologies per version are recorded (\"Pakketversie is beschikbaar voor één of meerdere technologien; databases, OS, SAAS\") but no lifecycle for them is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
From 2540bded6e8a5a3f925191ce913e55fb80294fd3 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:25:17 +0200
Subject: [PATCH 23/45] feat(parity): 31 demand rows mined from tenders,
feature requests, roadmaps and changelogs, stackiq rated from code
---
openspec/parity/capabilities.json | 1320 +++++++++++++++++++++++++----
1 file changed, 1144 insertions(+), 176 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index a7c5c91b7..6a492a050 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -2225,7 +2225,7 @@
"name": "Link applications to the strategic goals they serve.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
@@ -2244,6 +2244,7 @@
"stackiq": "no goal/strategy schema among the 20 in lib/Settings/softwarecatalogus_register.json; grep for strateg/doel in src/manifest.json: none",
"topdesk": "unknown: no strategic goals are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no strategic goals are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/objective-modeling-guidelines: 'Objectives link to business capabilities and initiatives so progress can be tracked over time'. Applications reach objectives through capabilities and initiatives; a direct application to objective relation is not described (read 2026-09-26). Reached on: Objective fact sheet.",
"glpi": "source read at 11.0.9: grep -i 'strategic\\|goal\\|objective' over src/Appliance.php and src/Project.php returns nothing; no goal itemtype exists and the Appliance tabs (src/Appliance.php:98 onwards) link items, contracts, documents, tickets and projects only."
}
},
@@ -2273,6 +2274,7 @@
"stackiq": "openspec/features.overlay.json maintenance-and-supplier-roadmap status 'soon'; no maintenance schema in lib/Settings/softwarecatalogus_register.json and no page in src/manifest.json",
"topdesk": "https://docs.topdesk.com/en/operations-management.html: \"In TOPdesk you can easily schedule operational activities in the user-friendly planner. If you wish to schedule a recurring activity, you can use a series\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: assets can be linked to \"Operational Activity\" cards (read 2026-09-26). Reached on: Modules > Operations Management > Planner.",
"vng-softwarecatalogus": "unknown: no maintenance announcements are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; planned maintenance is documented only for LeanIX's own service status (https://help.sap.com/docs/leanix/ea/status-pages-and-status-emails), not for applications in the inventory (read 2026-09-26)",
"glpi": "source read at 11.0.9: no maintenance window on an item ('Maintenance mode' in locales/glpi.pot:7534 is GLPI's own downtime switch); planned work is a change linked to the appliance, src/Appliance.php:107 Change_Item tab, with planned tasks carrying begin and end (install/mysql/glpi-empty.sql:792 glpi_changetasks, :799 begin, :800 end) shown in the planning. Reached on: Appliance > Changes tab; Assistance > Planning."
}
},
@@ -2282,7 +2284,7 @@
"name": "See each contract's status move from active to expiring to expired on its own.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "yes",
@@ -2302,6 +2304,7 @@
"stackiq": "lib/Service/ContractStatusService.php:77 shouldExpire and :114 expirePastContracts set Active -> Expired when endDate < now; lib/BackgroundJob/ContractStatusJob.php:57 daily, registered in appinfo/info.xml:99",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Status: Configurable drop-down showing the contract's lifecycle status, e.g. draft, active ... Reminder date\" (read 2026-09-26); https://docs.topdesk.com/en/terminating-a-contract.html: \"The contract will terminate once the end date passes\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'The contract fact sheet uses lifecycle phases to represent the current state of a contract': Plan, Phase In, Contract Start Date (active), Contract Notice Period, Contract End Date (expired). Requires the contract extension (read 2026-09-26). Reached on: Contract fact sheet > Lifecycle.",
"glpi": "source read at 11.0.9: contract status is a manual dropdown (install/mysql/glpi-empty.sql:1512 glpi_contracts.states_id); expiry is computed, src/Contract.php:654 virtual 'Expiration' column from begin date, duration and renewal, and src/Contract.php:1092 cronContract sends end and notice alerts, but the status itself never moves by itself. Reached on: Management > Contracts list, Expiration column."
}
},
@@ -2311,7 +2314,7 @@
"name": "Raise a renewal of a contract as a decision and see its outcome on the contract.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "yes",
@@ -2332,6 +2335,7 @@
"stackiq": "src/components/contracts/ContractApprovalPanel.vue:183 canSubmitRenewal for status Expired; POST /api/contracts/{uuid}/approval/renewal -> ContractApprovalService.php:254 with decisionType contract-renewal; lib/EventListener/DecisionConcludedListener.php projects the outcome (approvalState, status Active) via DECISION_CONCLUDED_EVENTS registered in lib/AppInfo/Application.php:830",
"topdesk": "https://docs.topdesk.com/en/extending-a-contract.html: \"Under Create , select Extend contract ... The contract is now a preliminary contract ... Click Validate Contract\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Sequence Number ... goes up by 1 each time the contract is extended ... so you can trace the contract's extension history\" (read 2026-09-26). Reached on: Contract card > Create > Extend contract.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'Contract Renewal Status ... Backlog, In Review, In Progress, or Done', 'Contract Renewal Decision ... Renew, Terminate, or No Decision', 'Contract Renewal Comments' (read 2026-09-26). Reached on: Contract fact sheet > Contract Renewal.",
"glpi": "source read at 11.0.9: src/Contract.php:60 to :62 renewal kinds never, tacit and express, with the renewal computation in the alert cron (src/Contract.php:1293); there is no renewal decision record or outcome, only the contract's renewal setting and an optional approval through a change. Reached on: Management > Contracts, Renewal field."
}
},
@@ -2341,7 +2345,7 @@
"name": "See the contracts behind an application from that application's page.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -2361,7 +2365,8 @@
"glpi": "source read at 11.0.9: src/Appliance.php:99 and src/Software.php:131 add the Contract_Item tab (src/Contract_Item.php:43, install/mysql/glpi-empty.sql:1536 glpi_contracts_items) listing every contract of the application. Reached on: Management > Appliances > Contracts tab. Driven on the lab at 11.0.9 (2026-09-26): after linking the contract, the appliance Contracts tab showed \"Lab contract, 2025-01-01, 12 months -> 2025-12-31\".",
"stackiq": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: assets link to \"Service cards\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"On the Services tab, link the services that apply to this contract\" (read 2026-09-26). Contract to asset runs through the service. Reached on: Contract > Services tab > Service > Links > Assets.",
- "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: relation 'Attached to Contract - Application Many-to-Many Links the contract to the applications it licenses or supports' (read 2026-09-26). Reached on: Application fact sheet > Contracts relation."
}
},
{
@@ -2370,7 +2375,7 @@
"name": "See what the portfolio costs per year across its contracts.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -2387,7 +2392,7 @@
"featureConfidence": "high",
"note": "The portfolio report sums annualised contract cost per organisation and TIME quadrant, and the license posture page per vendor. The Dashboard only counts contracts.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS cost.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'Contract Licensing Cost ... Annual licensing fees', maintenance and support costs; https://help.sap.com/docs/leanix/ea/application-total-cost-of-ownership-extension: 'Gain clear visibility into costs on different levels' with reports and KPIs (read 2026-09-26). Reached on: Contract fact sheet + TCO extension reports.",
"glpi": "source read at 11.0.9: contract costs have a period and a budget, install/mysql/glpi-empty.sql:1458 glpi_contractcosts with begin_date, end_date, cost and budgets_id; the contract list sums them in the 'Total cost' column (src/Contract.php:773) and a budget with a period shows spend per entity and type (src/Budget.php:537 showValuesByEntity). Reached on: Management > Contracts (Total cost column); Management > Budgets.",
"stackiq": "lib/Service/PortfolioReportDerivation.php:163 annualisedCost (Monthly x12, Annually x1, One-off separate); lib/Service/PortfolioReportService.php:337 sumContractCost per quadrant; src/views/organisaties/PortfolioReport.vue:167 and :248 show annualised cost; src/utils/contractCost.js:111 totalAnnualisedCost used by src/views/LicensePostureView.vue per vendor",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Costs (Services) ... Total internal cost, based on the service levels linked\" (read 2026-09-26); https://docs.topdesk.com/en/obtain-insights-with-asset-type-report.html: \"do you need an overview of the total costs of new assets? Use the Asset Type Report\" (read 2026-09-26). Reached on: Contract card > Financial; Asset Type Report.",
@@ -2400,7 +2405,7 @@
"name": "Record the licence model of an application, such as open source, per user or per organisation.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
@@ -2420,7 +2425,8 @@
"glpi": "source read at 11.0.9: each licence has a type, install/mysql/glpi-empty.sql:6775 glpi_softwarelicenses.softwarelicensetypes_id, an admin editable dropdown seeded with types such as OEM (install/empty_data.php:9294). Reached on: Management > Licenses (front/softwarelicense.php), Type field.",
"stackiq": "register :6937 module.licentietype enum Closed source/Open source and module.licence (five open-source licence names); catalogContract.contractType enum SLA/Licence/Maintenance (:3341)",
"topdesk": "unknown: licence cards hold number, code, purchase and expiration date; a licence model is only possible as a self-defined field; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/nieuws: \"is er de leverancier Open Source Pakketten aangemaakt. Onder deze leverancier staat nu een aantal veelgebruikte open source pakketten geregistreerd\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: Archi listed under supplier \"Open Source pakketten\", version \"Open source\" (read 2026-09-26). Other licence models are not recorded. Reached on: Alle pakketten > Leverancier Open Source pakketten."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/nieuws: \"is er de leverancier Open Source Pakketten aangemaakt. Onder deze leverancier staat nu een aantal veelgebruikte open source pakketten geregistreerd\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: Archi listed under supplier \"Open Source pakketten\", version \"Open source\" (read 2026-09-26). Other licence models are not recorded. Reached on: Alle pakketten > Leverancier Open Source pakketten.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'Contract Pricing Type Single select Consumption Based, Yearly Commitment, or Perpetual Licenses'. No open source or per user licence model field on the application is documented (read 2026-09-26). Reached on: Contract fact sheet > Contract Pricing Type."
}
},
{
@@ -2447,6 +2453,7 @@
"stackiq": "src/views/LicensePostureView.vue:11 open-source vs closed-source share weighted by in-production usage, :64 per-vendor rollup, per-organisation open-source-first report; derived in src/utils/licensePosture.js",
"topdesk": "unknown: no portfolio licence posture is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; licence analysis exists only for SBOM components of self-built software (https://help.sap.com/docs/leanix/ea/sbom-explorer 'assess license risks by filtering for unpermitted licenses'), not a portfolio share of open source applications (read 2026-09-26)",
"glpi": "source read at 11.0.9: licences can be listed and filtered by type in search (install/mysql/glpi-empty.sql:6775 softwarelicensetypes_id), but the dashboard's per type charts cover asset types and Software only (src/Glpi/Dashboard/Grid.php:1452), not licences, and no portfolio share view exists. Reached on: Management > Licenses, filtered by type."
}
},
@@ -2476,7 +2483,8 @@
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:6774 glpi_softwarelicenses.number is the bought quantity; src/SoftwareLicense.php:158 computeValidityIndicator compares it with assigned items (Item_SoftwareLicense::countForLicense) and flags over use in red (src/SoftwareLicense.php:1030), with allow_overquota at install/mysql/glpi-empty.sql:6797. Reached on: Assets > Software > Licenses tab.",
"stackiq": "grep for seat/licence count across lib/, src/ and the register finds no seat or quantity field on catalogContract (:3252), module or usage",
"topdesk": "https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"add fields to fill the number of licences you have purchased and still have left ... the Relationship grid widget on the software cards will display details about the licences\" (read 2026-09-26). Reached on: Asset Management > software card > Relationship grid.",
- "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for seats and licence counts, no hits; the contract fact sheet has cost fields but no licence quantity (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model) (read 2026-09-26)"
}
},
{
@@ -2503,6 +2511,7 @@
"stackiq": "No entitlement or consumption fields exist (see ctr-seat-count); no service computes a licence position in lib/Service/",
"topdesk": "https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"Knowing which software tools are used by whom ... the legal implications of using a tool without being licensed\" (read 2026-09-26). Entitlement against linked users, no measured consumption. Reached on: Asset Management > licence cards.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no entitlement against consumption computation is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: entitlement is compared with licence assignments (src/SoftwareLicense.php:158 computeValidityIndicator), while measured installations are counted separately (src/Item_SoftwareVersion.php:39); core has no computed effective licence position report reconciling the two for an audit. Reached on: Assets > Software > Licenses and Installations tabs."
}
},
@@ -2530,7 +2539,8 @@
"glpi": "source read at 11.0.9: src/Budget.php:46 Budget with a period and value (install/mysql/glpi-empty.sql:306 begin_date, :307 end_date, :308 value); contract costs (install/mysql/glpi-empty.sql:1466 budgets_id) and financial records (src/Infocom.php:599 budgets_id check) are charged to it. Reached on: Management > Budgets. Driven on the lab at 11.0.9 (2026-09-26): /front/budget.php lists budgets with type, start date, end date and value.",
"stackiq": "grep for budget across lib/, src/ and lib/Settings finds no budget schema or field; catalogContract has cost + costPeriod only (register :3363)",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Budget holder: Cost-accounting owner of the contract\" and \"Applicable to ... Budget holder\" (read 2026-09-26). No budget with a period is described. Reached on: Contract card > Financial.",
- "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; the contract has a 'Contract Cost Center' string (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model) but charging costs against a budget with a period is not documented (read 2026-09-26)"
}
},
{
@@ -2557,7 +2567,8 @@
"glpi": "source read at 11.0.9: the financial record of any item, licences included (src/SoftwareLicense.php:245 Infocom tab), carries depreciation type, duration and coefficient (install/mysql/glpi-empty.sql:3269 sink_time, :3270 sink_type, :3271 sink_coeff); src/Infocom.php:872 Linear and degressive types and src/Infocom.php:1085 linearAmortise compute the table. Reached on: Management > Licenses > Management tab.",
"stackiq": "grep for depreciation/afschrijving finds nothing in lib/, src/ or the register",
"topdesk": "unknown: depreciation is not mentioned (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for depreciation and amortisation, no hits (read 2026-09-26)"
}
},
{
@@ -2566,7 +2577,7 @@
"name": "Keep the signed contract document with the contract record.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -2587,6 +2598,7 @@
"stackiq": "src/manifest.json:567 ContractDetail ct-files integration 'files' (Documents panel); catalogContract.documentReference text field (register :3252)",
"topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"You can view the contracts in a variety of formats, including PDF\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Archive Number (Free text) Reference to a physical or external archived copy of the contract document\" (read 2026-09-26). Reached on: Contract card.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets: 'Files : You can upload files up to 10 MB. Uploaded files are then visible in the Resources tab', which applies to the contract fact sheet of the contract extension (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model) (read 2026-09-26). Reached on: Contract fact sheet > Resources tab.",
"glpi": "source read at 11.0.9: src/Contract.php:126 adds the Documents tab (Document_Item) to every contract, storing the signed file in install/mysql/glpi-empty.sql:2585 glpi_documents. Reached on: Management > Contracts > Documents tab."
}
},
@@ -2596,7 +2608,7 @@
"name": "See SaaS subscriptions and their spend, including ones bought outside IT.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "yes",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -2611,7 +2623,7 @@
"providerHow": "read-from-code",
"note": "The portfolio report shows each application in use with its cloud model and annualised cost, which lets you pick out SaaS spend. There is no SaaS subscription list and nothing discovers purchases made outside IT.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model. | docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/saas-discovery: discovery helps 'Eliminate shadow IT and business-managed IT' but 'The SaaS discovery feature in SAP LeanIX does not provide insight into cost, adoptions, contracts, and other SaaS specifics'. Spend only through manually kept contract costs (read 2026-09-26). Reached on: SaaS Discovery inbox; Contract fact sheet costs.",
"stackiq": "usage.cloudDienstverleningsmodel (register :3050) plus contract cost; lib/Service/PortfolioReportService.php:302 per-usage annualised cost and cloud-transition share; src/views/organisaties/PortfolioReport.vue:166 cloudTransitionLabel per row",
"topdesk": "unknown: no SaaS spend tracking is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
@@ -2642,6 +2654,7 @@
"vng-softwarecatalogus": "unknown: no vulnerability register is described; the docs do not state its absence either (the IBD-foto export only hands CPE identifiers to the IBD); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Hoe%20maak%20je%20een%20ICT-foto%20voor%20de%20IBD%3F (read 2026-09-26)",
"stackiq": "src/views/KwetsbaarhedenView.vue:378 reportVulnerability opens the generic ObjectModal for 'vulnerability'; register.json:1619 vulnerability schema with cveCode (pattern CVE-yyyy-n, :1679) and cvssScore 0-10",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no vulnerability record with CVE code and score exists, vulnerabilities are handled by searching SBOM components (https://help.sap.com/docs/leanix/ea/searching-for-sbom-library-components-by-package-url 'after a CVE alert') (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'cve\\|vulnerab\\|cvss' over src/ templates/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74 (a PHP version warning) and a session comment at src/Session.php:1085; no vulnerability itemtype exists."
}
},
@@ -2669,6 +2682,7 @@
"stackiq": "register.json:1701 vulnerability.modules links to module (applications), not moduleVersion; version level only via read-time SBOM match (src/utils/sbomVulnerabilityMatch.js, sbomComponent.vexCveIds register.json:8024) on the ModuleversieDetail Components tab",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; a PURL search finds services using a given library version, but linking a vulnerability record to affected versions is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no vulnerability model (see src/Glpi/System/Requirement/PhpSupportedVersion.php:74 as the only 'vulnerabilities' hit), so nothing links to software versions (install/mysql/glpi-empty.sql:6900)."
}
},
@@ -2678,7 +2692,7 @@
"name": "Import a software bill of materials in CycloneDX or SPDX for a version.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -2696,6 +2710,7 @@
"stackiq": "src/components/sbom/SbomComponentsPanel.vue:53-90 upload control (.json) -> POST /api/moduleversies/{uuid}/sbom (appinfo/routes.php:92) -> lib/Controller/SbomController.php:129 importSbom -> lib/Service/SbomParserService.php:77 parse (CycloneDX JSON) and :127 parseSpdx (SPDX 2.x JSON)",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/uploading-sboms-from-fact-sheets: 'select a CycloneDX or SPDX file in JSON or XML format' on a microservice fact sheet; also through the Self-Built Software Discovery API. Technology Risk and Compliance product (read 2026-09-26). Reached on: Microservice fact sheet > SBOM > Upload SBOM.",
"glpi": "source read at 11.0.9: grep -ril 'sbom\\|cyclonedx\\|spdx' over src/ templates/ locales/glpi.pot returns nothing; inventory import (src/Glpi/Inventory/) takes glpi-agent JSON only. Inventory import is src/Glpi/Inventory/Inventory.php:106."
}
},
@@ -2705,7 +2720,7 @@
"name": "Match the catalogue automatically against a public CVE feed.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "no",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -2723,6 +2738,7 @@
"stackiq": "src/utils/sbomVulnerabilityMatch.js header: 'no HTTP request to an external advisory feed is ever made'; lib/Service/EolSyncService.php syncs endoflife.date support dates, not CVEs",
"topdesk": "unknown: no CVE matching is described; the roadmap card https://tip.topdesk.com/c/186-automated-asset-scanning-tool (under consideration) mentions monitoring \"security vulnerabilities\" as a future idea; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the catalogue does not match CVEs itself; its \"IBD-foto\" export lists supplier, product and CPE so the IBD can do so; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Hoe%20maak%20je%20een%20ICT-foto%20voor%20de%20IBD%3F (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/api-updates-sbom-async-processing: 'Switching to asynchronous processing will allow us to add additional post-processing mechanisms in the future, such as vulnerability checks. Though there's no established timeline for these enhancements' (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'cve' over src/ templates/ finds no feed matching (only src/Glpi/System/Requirement/PhpSupportedVersion.php:74 text); no pluginsGLPI cve repository exists (git ls-remote https://github.com/pluginsGLPI/cve: repository not found)."
}
},
@@ -2747,7 +2763,7 @@
"providerHow": "read-from-code",
"note": "Only individual vulnerabilities get a severity band. No application gets a combined score from its vulnerabilities and support status.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks | Rated partial because technology risk.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/technology-obsolescence-risk-statuses-and-views-in-reports: 'Learn how risk statuses are determined for IT components and applications', e.g. 'Unaddressed Risk ... when the internal end-of-life date or vendor-provided end-of-support date is in the past'. Based on support status, not vulnerabilities (read 2026-09-26). Reached on: Technology Risk and Compliance > obsolescence risk status on applications.",
"stackiq": "src/utils/vulnerabilitySeverity.js derives a severity band per vulnerability from CVSS; no per-application risk score in lib/ or src/ (searched risk)",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -2778,6 +2794,7 @@
"stackiq": "register.json:1619 vulnerability has no fixed-in version field; src/utils/vulnerabilityExposure.js computeExposure carries the deployed moduleVersion per usage but nothing compares it to a fix",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no per vulnerability patch status is documented, and vulnerability checks are a future item (https://help.sap.com/docs/leanix/ea/api-updates-sbom-async-processing) (read 2026-09-26)",
"glpi": "source read at 11.0.9: installed versions are known (src/Item_SoftwareVersion.php:39) but no vulnerability or fixed in version exists to compare against (grep -rli 'cve' src/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74)."
}
},
@@ -2805,6 +2822,7 @@
"stackiq": "src/manifest.json:969 Kwetsbaarheden custom page -> src/views/KwetsbaarhedenView.vue table with severity tabs; row click openDetail (:417) opens the record in the generic ObjectModal",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no vulnerability list exists, only the SBOM explorer of components (https://help.sap.com/docs/leanix/ea/sbom-explorer) (read 2026-09-26)",
"glpi": "source read at 11.0.9: no vulnerability itemtype and no such entry in any menu (src/Html.php:1295 to :1334 list Management, Tools, Administration and Setup types)."
}
},
@@ -2814,7 +2832,7 @@
"name": "Register an organisation, such as a municipality, supplier or cooperation, with its type.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "yes",
@@ -2832,6 +2850,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Als leverancier kunt u zich aanmelden door de volgende gegevens te sturen naar softwarecatalogus@vng.nl\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C4 roles for gemeente and samenwerking accounts (read 2026-09-26); organisation types gemeente, samenwerking, leverancier. Reached on: Registration via VNG helpdesk.",
"stackiq": "src/manifest.json:386 Organisaties type:index over schema organization (Add form); register :2022 organization.type enum Municipality/Supplier/Collaboration/Community, required contactsUid + type",
"topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier ... In the Tasks block, specify whether first or second line incidents, or services or changes, may be assigned to the supplier\" (read 2026-09-26); branches are registered as Branch cards (https://docs.topdesk.com/en/drop-down-lists-settings.html \"the Person and Branch cards\"). Reached on: Supporting Files > New > Supplier / Branch.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/organization-modeling-guidelines: organization subtypes 'Business Unit, Customer, Region, Legal Entity, Team' for 'your hierarchical business architecture'; suppliers are separate provider fact sheets. No municipality or cooperation types for outside organisations (read 2026-09-26). Reached on: Inventory > Organization fact sheet.",
"glpi": "source read at 11.0.9: external organisations are suppliers with a type dropdown (src/Supplier.php:46, install/mysql/glpi-empty.sql:7072 suppliertypes_id); the organisation's own units are entities (src/Entity.php:58). There is no generic organisation register covering municipalities or cooperations. Reached on: Management > Suppliers; Administration > Entities."
}
},
@@ -2861,6 +2880,7 @@
"stackiq": "src/views/settings/StackiqSettings.vue:92 ModerationQueue (type organisation) -> src/utils/adminApi.js -> GET /api/moderation/pending, POST /api/moderation/{uuid}/approve|reject; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; lib/Service/ModerationService.php:230 approval sets registrationStatus active and stamps publicationDate (:173)",
"topdesk": "unknown: no review queue for organisations is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Om te kunnen deelnemen aan de softwarecatalogus controleren wij of de leverancier voldoet aan de richtlijnen van de softwarecatalogus\" (read 2026-09-26). Manual review by e-mail, no queue described.",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; organisations do not self register, so no moderation queue is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers are created by staff (src/Supplier.php:75 sets is_active on a new record) and there is no self registration or approval queue for organisations; grep -i 'moderat' over src/Supplier.php src/Entity.php returns nothing."
}
},
@@ -2888,6 +2908,7 @@
"stackiq": "register organization.status enum Draft/Active/Inactive is visible:false (:2022); src/manifest.json:403 OrganisatieDetail overrides status editable:false; src/modals/object/ChangeOrganisatieStatusDialog.vue:211 is never opened (no setDialog('changeOrganisatieStatus') in src); src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters status 'concept' and :129 writes 'actief', neither an enum value",
"topdesk": "unknown: cards can be archived; concept, active, inactive states for organisations are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: suppliers carry a \"heeft geldig convenant\" flag and may be removed, but no concept, active, inactive status is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/leveranciers (read 2026-09-26)",
+ "sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/organization-modeling-guidelines does not describe concept, active and inactive states for organizations; only archiving of fact sheets in general (https://help.sap.com/docs/leanix/ea/archiving-deleting-and-recovering-fact-sheets) (read 2026-09-26)",
"glpi": "source read at 11.0.9: a supplier is active or inactive, src/Supplier.php:365 is_active search option (install/mysql/glpi-empty.sql:7087 glpi_suppliers.is_active); there is no concept state. Reached on: Management > Suppliers, Active field."
}
},
@@ -2897,7 +2918,7 @@
"name": "Keep the contact persons of an organisation with their roles.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -2915,6 +2936,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30402: \"Bij elke leverancier is een contactpersoon opgevoerd. Deze persoon is verantwoordelijk voor de inhoud\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E4 contact details of municipalities (read 2026-09-26). One contact, no roles. Reached on: Supplier page header.",
"stackiq": "src/manifest.json:418 OrganisatieDetail org-contactpersonen object-list (role, roles) with rowRoute ContactpersoonDetail; register :1788 contactPerson (contactsUid, role, organization, roles enum of catalogue roles)",
"topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier contact ... The Supplier card where the contact person is active must be registered first\" (read 2026-09-26). Roles per contact are not described. Reached on: Supporting Files > New > Supplier Contact.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/subscription-roles: users subscribe to any fact sheet, including organization fact sheets, with roles 'such as application owner, project manager'. Contacts must be workspace users; external contact persons are not documented (read 2026-09-26). Reached on: Organization fact sheet > Subscriptions.",
"glpi": "source read at 11.0.9: contacts (src/Contact.php:45, install/mysql/glpi-empty.sql:1390 glpi_contacts) carry a contact type and a title (:1402 contacttypes_id, :1405 usertitles_id) and are linked to suppliers through src/Contact_Supplier.php:39. Reached on: Management > Contacts; Supplier > Contacts tab."
}
},
@@ -2924,7 +2946,7 @@
"name": "Give a colleague access to your organisation's part of the catalogue.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -2943,6 +2965,7 @@
"stackiq": "src/components/organisations/OrganisationSwitcher.vue:48 'Manage members' (isBeheerder) opens src/modals/GrantOrganisationAccessModal.vue; POST /api/organisations/{uuid}/members -> lib/Controller/OrganisationMembersController.php:108 authorizeBeheerder then OpenRegister joinOrganisation (:123)",
"topdesk": "https://docs.topdesk.com/en/step-2, operator-import-with-a-linked-person.html: \"Create new operators via import\" (read 2026-09-26); permissions via permission groups (https://docs.topdesk.com/en/automated-actions.html). Administrators create accounts; no invitation flow. Reached on: Supporting Files > Operators.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/gebruikersbeheer: \"Beheerders van gemeenten, samenwerkingen of leveranciers kunnen voor collega's een account aanmaken ... ontvangt deze nieuwe gebruiker een e-mail met daarin de inloginstructies\" (read 2026-09-26). Reached on: Menu > Gebruikersbeheer > Gebruiker toevoegen.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/users-overview: 'Invited users who haven't yet accepted the invitation request. You can reinvite a user'; https://help.sap.com/docs/leanix/ea/virtual-workspaces-configuration: 'Set up virtual workspaces to manage access for custom user groups' (read 2026-09-26). Reached on: Administration > Users > Invite.",
"glpi": "source read at 11.0.9: an administrator gives a user a profile on an entity, install/mysql/glpi-empty.sql:5917 glpi_profiles_users with profiles_id and entities_id, set on the user's Authorizations tab or automatically by authorisation rules (src/RuleRight.php:297 profiles_id action, :273 entities_id action). There is no emailed invitation link. Reached on: Administration > Users > Authorizations tab."
}
},
@@ -2952,7 +2975,7 @@
"name": "Act for more than one organisation with one account and switch between them.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
@@ -2971,6 +2994,7 @@
"stackiq": "src/components/organisations/OrganisationSwitcher.vue:197 POST /apps/openregister/api/organisations/{uuid}/set-active; mounted in src/App.vue:55",
"topdesk": "unknown: one account acting for several organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C4: \"Een account kan ook beide rollen gekregen hebben. In het inlogmenu kan dan van rol gewisseld worden ... Gecombineerde rollen kunnen alleen door VNG Realisatie aangemaakt worden\" (read 2026-09-26). Reached on: Inlogmenu > rol wisselen.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/manage-workspace-access: 'Provide users with access to exactly their relevant workspaces ... direct URL, base URLs or the workspace chooser to access available workspaces' (read 2026-09-26). Reached on: Workspace chooser.",
"glpi": "source read at 11.0.9: one user can hold several profile and entity pairs (install/mysql/glpi-empty.sql:5917 glpi_profiles_users) and switch between them in the session, src/Session.php:461 changeActiveEntities and src/Session.php:592 changeProfile. Reached on: user menu, entity and profile selector."
}
},
@@ -2998,6 +3022,7 @@
"stackiq": "src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail; POST /api/organisaties/{uuid}/merge -> lib/Controller/MergeController.php:142 isAdmin; lib/Service/MergeOrganisatieService.php:111 re-points usage.consumer/participants, contactPerson.organization, connection.provider and @self.organisation of catalogContract/compliancy; module.provider and catalogService.provider are not re-pointed",
"topdesk": "unknown: merging organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no merge of organisations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for merge of fact sheets or organizations, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: entities cannot be merged, src/Entity.php:202 forbids the dropdown merge action for Entity; records can be moved into another entity with src/Transfer.php:50 Transfer (massive action add_transfer_list, src/MassiveAction.php:598), keeping or cleaning linked items per transfer options. Reached on: Administration > Entities; list Actions > Add to transfer list."
}
},
@@ -3025,7 +3050,8 @@
"glpi": "source read at 11.0.9: with no merge (src/Entity.php:202 forbids merge for Entity) there is nothing to preview; the transfer (src/Transfer.php:50) runs directly without a what would change report.",
"stackiq": "src/components/organisations/OrganisationMergePanel.vue:324 organisatieStore.dryRunMerge shows dryRunCounts before execute; POST /api/organisaties/{uuid}/merge/dry-run -> lib/Service/MergeOrganisatieService.php:160 dryRun",
"topdesk": "unknown: merging organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: no merge of organisations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: no merge of organisations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no merge, so no merge preview is documented (read 2026-09-26)"
}
},
{
@@ -3034,7 +3060,7 @@
"name": "Map catalogue roles such as administrator, buyer and civil servant onto user groups.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3052,7 +3078,8 @@
"glpi": "source read at 11.0.9: roles are profiles with per right settings (src/Profile.php:55), mapped onto groups and directory attributes by authorisation rules, src/RuleRight.php:236 group criterion and src/RuleRight.php:297 profile action. Reached on: Administration > Profiles; Administration > Rules > Authorizations assignment rules.",
"stackiq": "src/views/settings/StackiqSettings.vue:80 UserGroupsConfiguration -> GET/POST /api/user-groups/config (src/store/modules/settings.js:830); lib/Controller/SettingsController.php:3379; lib/Service/Stackiq/GroupHandler.php:103 generic groups, :167 fixed role groups (aanbod-beheerder, gebruik-beheerder, ...), group choice by organisation type (:471)",
"topdesk": "https://docs.topdesk.com/en/automated-actions.html: \"Assign these permissions via Supporting Files > Permission Groups > [Permission Group]\" (read 2026-09-26); https://docs.topdesk.com/en/details-about-certain-permissions.html: permission tables per module (read 2026-09-26). Reached on: Supporting Files > Permission Groups.",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C4 roles gemeentebeheerder, raadpleger, samenwerkingsbeheerder; \"Er is géén rol voor het raadplegen van een samenwerking\" (read 2026-09-26). Fixed roles, no mapping onto groups. Reached on: Gebruikersbeheer."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C4 roles gemeentebeheerder, raadpleger, samenwerkingsbeheerder; \"Er is géén rol voor het raadplegen van een samenwerking\" (read 2026-09-26). Fixed roles, no mapping onto groups. Reached on: Gebruikersbeheer.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/sso-attribute-overview: 'The role to be assigned to the user. Required values: ADMIN, MEMBER, or VIEWER' and 'customer_roles ... The custom role to be assigned', mapped from identity provider groups (read 2026-09-26). Reached on: Administration > Users; SSO role attributes."
}
},
{
@@ -3061,7 +3088,7 @@
"name": "Sign in with the organisation's own identity provider.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3079,7 +3106,8 @@
"glpi": "source read at 11.0.9: src/Auth.php:106 EXTERNAL (web server provided identity, for example a SAML or OIDC module in front of GLPI), src/Auth.php:107 CAS with phpCAS::client at src/Auth.php:557, and src/Auth.php:108 X509 certificates, next to LDAP at src/Auth.php:105. Reached on: Setup > Authentication > Other authentication methods.",
"topdesk": "https://docs.topdesk.com/en/automatic-login-methods.html: \"Single Sign-on via SAML requirements TOPdesk uses OpenSAML 3 for authentication. You can connect all common IdP solutions which support SAML 2.0\" (read 2026-09-26). Reached on: Settings > Login Settings.",
"stackiq": "No OIDC/SAML code in lib/ or src/; stackiq creates local Nextcloud users with a password (lib/Service/Stackiq/ContactPersonHandler.php:292)",
- "vng-softwarecatalogus": "unknown: login is by username and password (\"Vul uw GEMMA Softwarecatalogus-gebruikersnaam in\"); no identity provider sign-in is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/user/login (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: login is by username and password (\"Vul uw GEMMA Softwarecatalogus-gebruikersnaam in\"); no identity provider sign-in is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/user/login (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/managing-users: 'SSO : You manage access through your identity provider (IdP) system. Users sign in through your IdP'; guides for Entra ID, Okta, OneLogin (read 2026-09-26). Reached on: Administration > Single Sign-On."
}
},
{
@@ -3088,7 +3116,7 @@
"name": "Keep users and groups in step with a directory such as LDAP.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3106,7 +3134,8 @@
"glpi": "source read at 11.0.9: src/AuthLDAP.php:59 LDAP directories with user import and group import (src/AuthLDAP.php:2816 ldapImportGroup), and the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users (alias ldap:sync at :80). Reached on: Administration > Users > LDAP directory link; Setup > Authentication > LDAP directories. Driven on the lab at 11.0.9 (2026-09-26): /front/ldap.php offers \"Bulk import users from a LDAP directory\" and \"Synchronizing already imported users\".",
"stackiq": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/",
"topdesk": "https://docs.topdesk.com/en/manual-login-with-ldap.html: \"This is also required if you want to import persons from your AD via Supporting files import\" (read 2026-09-26); https://tip.topdesk.com/c/242-support-scim-when-importing-users-from-entra-id-to-topdesk: roadmap card in column \"Launched\", \"Support SCIM when importing users from Entra ID to TOPdesk\" (read 2026-09-26). Reached on: Settings > Import settings > Supporting Files imports.",
- "vng-softwarecatalogus": "unknown: no directory sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: no directory sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/scim-provisioning: 'SCIM facilitates the transfer of user information from a source system, such as an external identity provider (IdP), to a target system, such as SAP LeanIX'; setup guides for Entra ID and Okta (read 2026-09-26). Reached on: Administration > SCIM provisioning."
}
},
{
@@ -3115,7 +3144,7 @@
"name": "Change your own password and see your own account details.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3133,6 +3162,7 @@
"stackiq": "src/components/ContactpersonenList.vue:115 'Change Password' opens src/dialogs/ChangePasswordDialog.vue -> POST /api/contactpersonen/change-password -> lib/Controller/ContactpersonenController.php:718, self-reset allowed at :753; GET /api/me (:1578) used only by src/App.vue and OrganisationSwitcher",
"topdesk": "https://docs.topdesk.com/en/editing-your-personal-profile.html: \"Click on Personal Profile . In the General and Private section, you can edit your personal information. In the Change password section, you can change your password\" (read 2026-09-26). Reached on: Profile picture > Personal Profile.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/wachtwoord-vergeten: \"Op het inlogscherm ... staat een link om een nieuw wachtwoord aan te vragen\" (read 2026-09-26). Reset by mail; viewing own account details is not described. Reached on: Inloggen > Vraag een nieuw wachtwoord aan.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/user-profile: 'Manage your user profile settings. Change or reset your password if needed' on the My Settings profile page (read 2026-09-26). Reached on: User menu > My Settings.",
"glpi": "source read at 11.0.9: front/preference.php renders the user's own form through src/User.php:3105 showMyForm (template pages/admin/user/user.html.twig), whose preference variant shows a 'Change password' button to front/updatepassword.php at templates/pages/admin/user/user.html.twig:277 to :279; the new password form is templates/password_form.html.twig:79."
}
},
@@ -3142,7 +3172,7 @@
"name": "Send registration, activation and account mails from templates an administrator can edit.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
@@ -3160,7 +3190,8 @@
"glpi": "source read at 11.0.9: src/NotificationTargetUser.php:44 user events passwordexpires, passwordforget and passwordinit; their text lives in admin editable templates, src/NotificationTemplate.php:47 and translations src/NotificationTemplateTranslation.php:42, seeded at install/empty_data.php:3212 (passwordinit) and :5640. Reached on: Setup > Notifications > Notification templates.",
"stackiq": "lib/Service/SymfonyEmailService.php:466 registration, :553 activation, :641 user creation mails from templates; src/views/settings/sections/EmailConfiguration.vue:902 saveTemplate is a stub that logs 'not yet implemented in the backend' and still shows success; backend POST /api/email/templates/{templateName} (lib/Controller/SettingsController.php:2194) has no caller in src/; lib/Settings/connections.json email adapter reports the 'null' transport as simulated",
"topdesk": "unknown: email designs are editable for automated actions, but account activation mails are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: new users receive a login mail, but administrator-editable templates are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersbeheer (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: new users receive a login mail, but administrator-editable templates are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersbeheer (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/users-overview: users are invited 'individually or in bulk' with a 'Send Invitation Email' option; editing the text of account mails is not documented (read 2026-09-26). Reached on: Administration > Users > Invite."
}
},
{
@@ -3189,6 +3220,7 @@
"stackiq": "lib/Controller/PublicationController.php:87 publish/depublish (routes.php:208-209, PUT/DELETE /api/publication/{objectType}/{uuid}) with an IDOR guard; lib/Service/PublicationService.php:51 publishable types catalogService, module, connection, organization. No src/ caller of /api/publication (only a comment in src/utils/openDataProjection.js). The publish buttons in src/modals/object/ViewObject.vue:4854 are unreachable: Modals.vue renders ViewObject only for modal 'viewOrganisatie'/'viewContactpersoon', which nothing sets. Workaround: publicationDate/depublicationDate are visible, editable fields on module/catalogService/organization/connection (lib/Settings/softwarecatalogus_register.json:6777 schema).",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: supplier data is public by default and municipal data is never public; publishing or withdrawing one entry is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; publishing a single entry as open data is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'open data\\|opendata' over src/ locales/glpi.pot returns nothing; items have no publish state, the closest is is_helpdesk_visible (install/mysql/glpi-empty.sql:8956 on glpi_appliances), which only shows the item to helpdesk users of the same instance."
}
},
@@ -3218,6 +3250,7 @@
"stackiq": "src/utils/openDataProjection.js:36 STRIPPED_FIELDS (PII projection) is imported by nothing in src/ and has no PHP counterpart (grep 'projection' in lib/ finds none). Usage schema read rule lib/Settings/softwarecatalogus_register.json:3150 has no public group; lib/Controller/GebruikController.php:102 returns an empty result to anonymous callers.",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Beschikbare%20downloads: public CSV downloads of packages, versions and compliance (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: \"Ingevuld door (28) Aantal gemeenten met een versie van het pakket in productie\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C5 contact details \"alleen als contactgegevens voor andere ingelogde gebruikers\" (read 2026-09-26). Reached on: Beschikbare downloads; package page.",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no open data publication is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no open data publication exists (grep -rli 'open data' src/ returns nothing); anonymisation settings cover ticket actors only (install/mysql/glpi-empty.sql:2824 anonymize_support_agents on entities)."
}
},
@@ -4112,226 +4145,1131 @@
"vng-softwarecatalogus": "unknown: only \"De kaart wordt dagelijks bijgewerkt\" is stated; no organisation or contact sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/17042 (read 2026-09-26)",
"glpi": "source read at 11.0.9: automatic actions are scheduled and show their last run, src/CronTask.php:59 with install/mysql/glpi-empty.sql:1610 glpi_crontasks.lastrun, but LDAP user and group synchronisation is not one of them (grep -i ldap over the cron seed in install/empty_data.php:438 finds none); it is the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users, which must be scheduled by the system cron. Organisation (supplier) records have no sync at all. Reached on: Setup > Automatic actions; CLI bin/console ldap:sync. Driven on the lab at 11.0.9 (2026-09-26): /front/crontask.php lists automatic actions with run mode, frequency and last run."
}
- }
- ],
- "pending": [
+ },
{
- "id": "land-usage-record",
- "area": "landscape",
- "name": "Record that your organisation uses a module, as a usage separate from the product itself.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "partial",
- "bluedolphin": "partial",
- "glpi": "partial",
- "topdesk": "unknown",
- "stackiq": "partial",
+ "id": "arch-ggm-link",
+ "area": "architecture",
+ "name": "Relate applications to the entities of the Gemeentelijk Gegevensmodel they hold data for.",
+ "origin": "tender",
+ "originUrl": "https://www.tenderned.nl/aankondigingen/overzicht/398728",
+ "stackiq": "no",
"built": {
- "state": "built",
- "evidence": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/",
+ "state": "none",
+ "evidence": "lib/Settings/softwarecatalogus_register.json:5038 ggm-guid (and ggm-naam, ggm-definitie) are properties of the element schema (register.json:4130), filled by the AMEF import (lib/Repair/RenameDutchCatalogColumns.php:25-27); the module schema (register.json:6777) has no property that points to a GGM entity, and the only element page, Standaarden, is filtered to gemmaType standaard (src/manifest.json:708)",
"owner": "ConductionNL/stackiq"
},
- "reachedOn": "API only: /api/aangeboden-gebruik/*, /api/gebruik and OpenRegister objects API; read-only on Portfolio roadmap /portfolio-roadmap",
+ "reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "feature": "offering-and-usage-listings",
- "featureConfidence": "high",
- "note": "The usage schema models this separation properly, but no stackiq page creates or edits a usage: the ObjectModal accepts type 'usage' (src/modals/Modals.vue:38) yet nothing opens it. Usages are only read by the roadmap, compliance matrix and vulnerability views.",
+ "feature": "gemma-alignment",
+ "featureConfidence": "medium",
+ "note": "Helmond's architecture repository tender (REQ3, REQ61) asks to relate the repository to the GGM. GGM metadata survives an ArchiMate import on architecture elements, but no field or page links an application to a GGM entity.",
+ "vng-softwarecatalogus": "unknown",
"evidence": {
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: municipality adds the supplier's package and version to its own landscape (\"om het pakket toe te voegen aan je omgeving\") (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E1 \"Leveranciers onderhouden de gegevens van hun producten ... Gemeenten en Samenwerkingen onderhouden de gegevens van het eigen applicatieportfolio\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten.",
- "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers.",
- "bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository.",
- "stackiq": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/",
- "topdesk": "unknown: one organisation per environment; a separate usage record is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "glpi": "source read at 11.0.9: use is recorded as installations separate from the software product, src/Item_SoftwareVersion.php:39 (install/mysql/glpi-empty.sql:1064 glpi_items_softwareversions) per device, and licence assignments per item or user; there is no usage record of a module by an organisation as such. Reached on: Assets > Software > Installations tab."
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
},
- "pendingQuestion": "Does the external VNG Softwarecatalogus frontend create usage (gebruik) records through /api/aangeboden-gebruik or the OpenRegister objects API, and is that frontend part of what stackiq ships?"
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
},
{
- "id": "land-migrate-legacy",
- "area": "landscape",
- "name": "Bring over what was registered in the previous catalogue, so nobody types it again.",
- "origin": "competitor",
+ "id": "arch-views-office",
+ "area": "architecture",
+ "name": "Put architecture views into Word or PowerPoint documents straight from the tool.",
+ "origin": "tender",
+ "originUrl": "https://www.tenderned.nl/aankondigingen/overzicht/398728",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "appinfo/routes.php:97-98 the only view exports are ArchiMate exchange files (POST /api/archimate/export, GET /api/archimate/export/organization/{organizationUuid}); no image, docx or pptx export of a view anywhere in lib/ or src/ (the docx/pptx strings in src/modals/object/MergeObject.vue are file-type labels)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "archimate-import-and-export",
+ "featureConfidence": "medium",
+ "note": "Helmond REQ19 asks for architecture views embedded in office documents. stackiq renders no view at all (see arch-gemma-views) and exports only ArchiMate files.",
"vng-softwarecatalogus": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "partial",
- "topdesk": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "arch-data-model",
+ "area": "architecture",
+ "name": "Model data entities and their relations, as an entity relationship or UML diagram, next to the applications.",
+ "origin": "tender",
+ "originUrl": "https://www.tenderned.nl/aankondigingen/overzicht/398728",
"stackiq": "no",
"built": {
"state": "none",
- "evidence": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets",
+ "evidence": "src/manifest.json has no page for the element, relation or view schema other than Standaarden (src/manifest.json:708, filtered to standards); no diagram editor under src/views or src/components (same finding as arch-modelling)",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "There is no importer for the previous VNG Softwarecatalogus's registrations. The repair steps only rename stackiq's own earlier data, and the ArchiMate import brings in the GEMMA model, not organisations' entries.",
+ "featureConfidence": "high",
+ "note": "Helmond REQ54 asks for entity relationship or UML data models. stackiq holds imported ArchiMate elements but models nothing itself.",
+ "vng-softwarecatalogus": "unknown",
"evidence": {
- "stackiq": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets",
- "topdesk": "unknown: no import from the VNG Softwarecatalogus is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: this is the previous catalogue itself; no import of an earlier registration is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "glpi": "source read at 11.0.9: data from earlier GLPI versions is carried over by src/Update.php:172 doUpdates with the chain in install/migrations/ (update_0.85.x_to_0.90.0.php up to the 11.0 steps); data from another catalogue needs the separate datainjection plugin (pluginsGLPI/datainjection tag 2.15.11, inc/backendcsv.class.php). Reached on: web installer update; plugin Data injection."
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
},
- "pendingQuestion": "Is the data from the previous VNG Softwarecatalogus meant to be brought over by a one-off migration outside this repo (for example an OpenRegister register import of an export file)?"
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
},
{
- "id": "conn-register-connection",
- "area": "connections",
- "name": "Register a connection between two applications, with its direction and the standard it uses.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
- "sap-leanix": "yes",
- "bluedolphin": "partial",
- "glpi": "partial",
- "topdesk": "partial",
- "stackiq": "partial",
+ "id": "org-access-review",
+ "area": "organisations",
+ "name": "Review periodically whether every user still needs their access, and withdraw what is no longer needed.",
+ "origin": "tender",
+ "originUrl": "https://www.tenderned.nl/aankondigingen/overzicht/398728",
+ "stackiq": "no",
"built": {
- "state": "built",
- "evidence": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it",
+ "state": "none",
+ "evidence": "lib/Service/ContactpersoonService.php:889 returns a user's lastLogin and src/components/ContactpersonenList.vue:482 stores it, but nothing renders it; no review, recertification or expiry of access in lib/ or src/ (grep recertif, accessReview)",
"owner": "ConductionNL/stackiq"
},
- "reachedOn": "API only: OpenRegister objects API; no stackiq page",
+ "reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "feature": "software-landscape-register",
"featureConfidence": "medium",
- "note": "The connection model with direction and standard is complete, and the demo data ships six, but no stackiq page creates or edits one.",
+ "note": "Helmond REQ78 asks administrators to check periodically that every user still needs access. stackiq fetches the last login of each contact's account and never shows it.",
+ "vng-softwarecatalogus": "unknown",
"evidence": {
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Selecteer vervolgens de betreffende pakketversie. De richting van het berichtenverkeer ... Selecteer vervolgens de betreffende standaard en versie\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > toevoegen.",
- "sap-leanix": "docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
- "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | Rated partial because ArchiMate flow relations.",
- "stackiq": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it",
- "topdesk": "https://docs.topdesk.com/en/hierarchy-of-relationships.html: \"When assets are linked with a link type , one of the assets often supplies a certain feature to another asset. The supplying asset therefore is the parent asset\" (read 2026-09-26). Direction via parent and child; no standard per relation. Reached on: Asset card > Relationships widget.",
- "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1247 glpi_impactrelations stores a directed link from a source item to an impacted item with a name, added via src/Impact.php:1161 'Add relation'; there is no field for the standard or protocol used. Reached on: Appliance > Impact analysis tab, Add relation."
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
},
- "pendingQuestion": "Does the external VNG Softwarecatalogus frontend register koppelingen through the OpenRegister objects API, and does it count as part of stackiq?"
- },
- {
- "id": "conn-usage-of-connection",
- "area": "connections",
- "name": "Record that your organisation actually runs a given connection, not only that it exists.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "no",
- "topdesk": "unknown",
- "stackiq": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "comp-processing-register",
+ "area": "compliance",
+ "name": "Link each application to its entry in the organisation's register of processing activities.",
+ "origin": "tender",
+ "originUrl": "https://www.tenderned.nl/aankondigingen/overzicht/398728",
+ "stackiq": "yes",
"built": {
"state": "built",
- "evidence": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller",
+ "evidence": "lib/Settings/softwarecatalogus_register.json:7287 module.verwerkingsregisterRef (a URL or identifier; the register itself is not modelled); shown in the ModuleDetail data widget, src/manifest.json:500 include list",
"owner": "ConductionNL/stackiq"
},
- "reachedOn": "API only",
+ "reachedOn": "ModuleDetail /modules/:id Application data widget (reached from OrganisatieDetail, see land-detail-page)",
"provider": "stackiq",
"providerHow": "read-from-code",
- "feature": "offering-and-usage-listings",
- "featureConfidence": "medium",
- "note": "The model records which connections a usage runs, but neither usages nor connections have a page.",
+ "feature": "standards-compliance",
+ "featureConfidence": "high",
+ "note": "Helmond REQ4 wants the processing register kept apart from the repository but linked. stackiq stores and shows a reference per application; it does not hold the register.",
+ "vng-softwarecatalogus": "unknown",
"evidence": {
- "stackiq": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller",
- "topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Geef bij status in productie of gepland aan\"; connections are registered in the organisation's own landscape (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen.",
- "glpi": "source read at 11.0.9: an impact relation (install/mysql/glpi-empty.sql:1247) is a single fact in one instance; there is no separate usage record saying the organisation runs it, and grep -n 'usage' src/ImpactRelation.php returns nothing."
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
},
- "pendingQuestion": "Does the external VNG Softwarecatalogus frontend let an organisation record the connections it runs, through /api/koppelingen-gebruik or the objects API?"
- },
- {
- "id": "conn-shared-with-others",
- "area": "connections",
- "name": "See which connections you run together with other organisations.",
- "origin": "own-code",
- "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "no",
- "topdesk": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "mkt-tender-product-info",
+ "area": "market",
+ "name": "As a supplier, keep your product information public in the catalogue so a buyer's tender can point to it instead of asking for separate documentation.",
+ "origin": "tender",
+ "originUrl": "https://www.tenderned.nl/aankondigingen/overzicht/418890",
"stackiq": "partial",
"built": {
"state": "built",
- "evidence": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/",
+ "evidence": "lib/Settings/softwarecatalogus_register.json:7307 module authorization.read grants group public once publicationDate has passed (same rule as share-public-browse); no stackiq route or page serves it anonymously, the public surface is OpenRegister's objects API and the external VNG frontend",
"owner": "ConductionNL/stackiq"
},
- "reachedOn": "API only: /api/aangeboden-gebruik/deelnemers",
+ "reachedOn": "external frontend, not in this repo",
"provider": "stackiq",
"providerHow": "read-from-code",
- "feature": "shared-usage-on-gemma-views",
+ "feature": "offering-and-usage-listings",
"featureConfidence": "medium",
- "note": "Shared usage (with the connections it carries) is answerable through the API, but no stackiq page shows it.",
+ "note": "Standard municipal tender text (Noordwijk 418890, Reimerswaal 417169, FUMO 415897, HLT Samen 383984): a supplier inside the GEMMA scope can make its product information transparent through the Softwarecatalogus. stackiq publishes the data; the page a buyer opens lives in the external frontend.",
+ "vng-softwarecatalogus": "unknown",
"evidence": {
- "stackiq": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/",
- "topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: A10: \"Een Samenwerking geeft aan welke gemeenten gebruik maken van een betreffende koppeling. Die gemeentenamen worden getoond\" (read 2026-09-26). Reached on: Alle koppelingen.",
- "glpi": "source read at 11.0.9: relations live inside one instance (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) and entities are subdivisions of one organisation (src/Entity.php:58); no cross organisation sharing of connections exists (grep -rli 'federat' src/ returns nothing)."
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
},
- "pendingQuestion": "Does the external VNG Softwarecatalogus frontend show shared connections from /api/aangeboden-gebruik/deelnemers?"
- },
- {
- "id": "arch-refcomp-mapping",
- "area": "architecture",
- "name": "Place an application on the GEMMA reference components it fulfils.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "no",
- "topdesk": "unknown",
- "stackiq": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "life-value-assessment",
+ "area": "lifecycle",
+ "name": "Score each application on business value, cost and risk to decide where to invest.",
+ "origin": "tender",
+ "originUrl": "https://www.tenderned.nl/aankondigingen/overzicht/398728",
+ "stackiq": "no",
"built": {
- "state": "built",
- "evidence": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules",
+ "state": "none",
+ "evidence": "lib/Settings/softwarecatalogus_register.json:3092 usage.timeClassification holds only the TIME verdict and its rationale; no business value, technical fit or risk score property on module or usage, and PortfolioReport (src/manifest.json:1040) plots the TIME quadrant only",
"owner": "ConductionNL/stackiq"
},
- "reachedOn": "Modules /modules (FacetedCatalogIndexView) filters by reference component (read only); no stackiq page sets the mapping: module form hides it (hideOnForm), usage has no page",
+ "reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "feature": "gemma-alignment",
- "featureConfidence": "high",
- "note": "The mapping is stored and can be filtered on, but no stackiq screen writes it: the module field is hideOnForm and the usage schema has no index or edit page; writes come through ArchiMate import, the OpenRegister objects API or the external VNG frontend.",
+ "feature": "portfolio-reporting",
+ "featureConfidence": "medium",
+ "note": "Helmond REQ41 asks for analysis of application use, cost, risk and value. stackiq records a TIME classification (life-time-classification) without the scores that would justify it.",
+ "vng-softwarecatalogus": "unknown",
"evidence": {
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Referentiecomponenten aangegeven door leverancier ... Toegevoegde referentiecomponenten\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen.",
- "stackiq": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules",
- "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "glpi": "source read at 11.0.9: grep -rli 'gemma\\|reference component' over src/ locales/glpi.pot returns nothing; the only classification of an appliance is its type dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id)."
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
},
- "pendingQuestion": "Does the Modules page's CnIndexPage create/edit dialog in nextcloud-vue 2.55.1 render module.referenceComponents (hideOnForm:true, items.$ref element in the AMEF register) as a working multiselect of reference components? nextcloud-vue's fieldsFromSchema (src/utils/schema.js:529) does not check hideOnForm."
- },
- {
- "id": "arch-gemma-views",
- "area": "architecture",
- "name": "Open a GEMMA architecture view with your own applications drawn inside it.",
- "origin": "own-code",
- "vng-softwarecatalogus": "yes",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "no",
- "topdesk": "unknown",
- "stackiq": "partial",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "comp-security-officer-signoff",
+ "area": "compliance",
+ "name": "Have the security officer review and sign off the organisation's list of applications in use.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/136",
+ "stackiq": "no",
"built": {
- "state": "built",
- "evidence": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export",
+ "state": "none",
+ "evidence": "no approval of an organisation's application list: ContractApprovalService (lib/Service/ContractApprovalService.php) covers contracts only, and no schema or page records a sign-off on the landscape (grep fiat, sign-off, goedkeur in lib/ and src/)",
"owner": "ConductionNL/stackiq"
},
- "reachedOn": "API only: GET /api/views (src/store/modules/view.js:89 defines a store but nothing imports useViewStore); the drawn view is only visible in Archi after 'Organization Export' on admin settings section ArchiMate Import/Export",
+ "reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "feature": "gemma-alignment",
"featureConfidence": "medium",
- "note": "No stackiq page renders a GEMMA view. The enriched view data is served for an external frontend, and the org export draws applications into view copies that open in Archi.",
+ "vng-softwarecatalogus": "unknown",
"evidence": {
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"de pakketten die getoond worden in het pakketoverzicht te plotten op een GEMMA architectuurkaart ... [Toon kaart]\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Toon kaart.",
- "stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export",
- "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "glpi": "source read at 11.0.9: grep -rli 'gemma\\|archimate' over src/ templates/ locales/glpi.pot returns nothing; the only diagram is the impact graph (src/Impact.php:252 displayGraphView)."
+ "vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #136 'Als CISO wil ik ons gemeentelijk pakketoverzicht kunnen controleren en vervolgens fiatteren'; no approval step for the landscape appears in the incumbent manuals (https://www.softwarecatalogus.nl/node/19703). (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
},
- "pendingQuestion": "Does the external VNG Softwarecatalogus frontend render /api/views/{id} with include_gebruik, and is that frontend in scope for stackiq's column?"
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
},
{
- "id": "arch-shared-overlay",
- "area": "architecture",
- "name": "On a GEMMA view, see the applications you share with partners, drawn apart from your own.",
- "origin": "own-code",
+ "id": "comp-processing-register-generate",
+ "area": "compliance",
+ "name": "Generate a register of processing activities from the applications the organisation uses.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/82",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "lib/Settings/softwarecatalogus_register.json:7287 module.verwerkingsregisterRef only stores a reference, and its description says the register itself is not modelled; no export or report builds one",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "vng-softwarecatalogus": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #82 'Als gebruik-raadpleger wil ik een register van verwerkingen kunnen genereren'; the incumbent exports only package, connection and IBD-foto files (https://www.softwarecatalogus.nl/Beschikbare%20downloads). (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "ctr-collective-agreements",
+ "area": "contracts",
+ "name": "Find suppliers and products covered by collective agreements made for all municipalities.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/50",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "'Addendum' exists only as a glossary object (lib/Settings/softwarecatalogus_register.json:613, lexicon entry in the objects seed at :27); no schema records which supplier signed which collective agreement",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "vng-softwarecatalogus": "partial",
+ "evidence": {
+ "vng-softwarecatalogus": "Open PvE wens #50 (search) and #48 (register collective agreements incl. AVG and BIO terms); the incumbent lists signed addenda per supplier with a filter (https://www.softwarecatalogus.nl/addenda), which covers part of it. (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "share-compliance-documents",
+ "area": "sharing",
+ "name": "Share documents such as DPIAs, processing agreements and pentest reports with other organisations.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/41",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "compliance records carry bewijsReferentie and a Documentation files panel (src/manifest.json:885 KompliantieDetail), and module.dpiaDocumentRef (lib/Settings/softwarecatalogus_register.json:7280) links a DPIA; these are published per record under the register read rules, but nothing shares a processing agreement or pentest report between organisations as such",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "KompliantieDetail /komplianties/:id Evidence documents; ModuleDetail DPIA document field",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "vng-softwarecatalogus": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #41 'relevante documenten zoals DPIA's, verwerkersovereenkomsten en pentesten kunnen delen zodat andere gemeenten hier eenvoudig gebruik van kunnen maken'; the incumbent only holds supplier test reports (https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier). (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "sec-baseline-classification",
+ "area": "security",
+ "name": "Classify each application with a baseline security level for availability, integrity and confidentiality.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/46",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json:7225 module.bbnLevel (BBN1 to BBN3), shown in the ModuleDetail data widget (src/manifest.json:500) and filterable on Modules (src/manifest.json:608); one level per application, not per organisation and not split into availability, integrity and confidentiality",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ModuleDetail /modules/:id and Modules /modules BBN filter",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "vng-softwarecatalogus": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #46 'Als CISO wil ik de pakketten in mijn pakketoverzicht van een BBN classificatie voorzien'; BBN exists only as a GEMMA view per reference component per the news page (https://www.softwarecatalogus.nl/nieuws). (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "mkt-side-by-side-compare",
+ "area": "market",
+ "name": "Select several products and compare their properties and usage side by side in one table.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/31",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no compare view in src/views or src/manifest.json pages; the Modules page lists and filters only (src/views/FacetedCatalogIndexView.vue:108)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "vng-softwarecatalogus": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #31 'meerdere pakketten kunnen selecteren en deze in een overzichtelijke tabel naast elkaar vergelijken'; the incumbent offers filtered lists only (https://www.softwarecatalogus.nl/node/13683). (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "org-act-as-user",
+ "area": "organisations",
+ "name": "Let a functional administrator view the catalogue as another account to reproduce what that user sees.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/104",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no impersonation in lib/ or src/ (grep impersonat); stackiq relies on Nextcloud users",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "vng-softwarecatalogus": "unknown",
+ "evidence": {
+ "vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #104 'Als functioneel beheerder wil ik me kunnen voordoen als een ander account'; not in the incumbent FAQ (https://www.softwarecatalogus.nl/node/16564). (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "comp-common-ground-fit",
+ "area": "compliance",
+ "name": "Declare how a product fits the Common Ground goals and principles.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/147",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "'Common Ground' is only a glossary object (lib/Settings/softwarecatalogus_register.json:543); the module schema has no Common Ground property",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "vng-softwarecatalogus": "partial",
+ "evidence": {
+ "vng-softwarecatalogus": "Open PvE wens #147; the incumbent shows whether a supplier signed the Groeipact Common Ground addendum (https://www.softwarecatalogus.nl/leveranciers), a supplier-level signal, not per product. (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "land-version-carry-connections",
+ "area": "landscape",
+ "name": "Carry an application's connections over automatically when a new version replaces the old one.",
+ "origin": "featureRequest",
+ "originUrl": "https://www.softwarecatalogus.nl/gebruikersonderzoek%202021",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "moduleVersion (lib/Settings/softwarecatalogus_register.json) is created on the Moduleversies index form; no copy of a version with its connections and no carry-over logic in lib/Service/ModuleVersionService.php",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "vng-softwarecatalogus": "partial",
+ "evidence": {
+ "vng-softwarecatalogus": "2021 user survey suggestion 'Koppelingen automatisch bijwerken bij een nieuwe versie van pakket'; release 4.1 added a manual copy of a version including its connections (https://www.softwarecatalogus.nl/node/16564, FAQ A1). (read 2026-09-26)",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "comp-retention-cleanup",
+ "area": "compliance",
+ "name": "Remove attached files and mails automatically a set time after a record is closed, to meet retention rules.",
+ "origin": "changelog",
+ "originUrl": "https://tip.topdesk.com/c/152-more-control-over-card-file-removal",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no retention or file clean-up job in lib/BackgroundJob or lib/Service for stackiq records (grep retention, bewaartermijn)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "topdesk": "yes",
+ "evidence": {
+ "topdesk": "Card 'More control over card & file removal' in Launched (updated 2026-02-09); docs https://docs.topdesk.com/en/file-maintenance.html: 'you can set how many days after closing or archiving a card its uploaded files and linked emails should be removed'. (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from topdesk (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown"
+ },
+ {
+ "id": "land-dependent-fields",
+ "area": "landscape",
+ "name": "Make the options of one field depend on another, such as model depending on brand.",
+ "origin": "roadmap",
+ "originUrl": "https://tip.topdesk.com/c/87-field-dependencies-brand-type-model-",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "register properties are independent enums; no dependent option lists in lib/Settings/softwarecatalogus_register.json",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "topdesk": "no",
+ "evidence": {
+ "topdesk": "Card 'Field Dependencies (brand/type/model)' in Under consideration: 'User can set up dependencies between fields'; not in the field docs (https://docs.topdesk.com/en/editing-fields.html). (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown"
+ },
+ {
+ "id": "land-change-entry-type",
+ "area": "landscape",
+ "name": "Change the type of an existing entry without recreating it.",
+ "origin": "roadmap",
+ "originUrl": "https://tip.topdesk.com/c/89-changing-the-type-of-an-asset",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "each entry lives in one schema (module, catalogService, suite) and no action moves an object to another schema",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "topdesk": "no",
+ "evidence": {
+ "topdesk": "Card 'Changing the type of an asset' in Under consideration: 'User can change the type of an exiting asset'. (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown"
+ },
+ {
+ "id": "ins-ai-action-audit",
+ "area": "insight",
+ "name": "See which actions an AI assistant took on the data, when and on which records.",
+ "origin": "roadmap",
+ "originUrl": "https://tip.topdesk.com/c/252-audit-logging-for-topdesk-mcp-server",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "stackiq has no AI or MCP integration of its own (see share-ai-assistant); the History tab (widget type audit, src/manifest.json:436) shows every change per object but does not single out actions an assistant took",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "topdesk": "no",
+ "evidence": {
+ "topdesk": "Card 'Audit Logging for TOPdesk - MCP Server' in Building: 'you should be able to see exactly what that AI did, which actions it took, when, and on what data'. (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown"
+ },
+ {
+ "id": "sec-multi-factor-sign-in",
+ "area": "security",
+ "name": "Require a second factor when users sign in.",
+ "origin": "roadmap",
+ "originUrl": "https://tip.topdesk.com/c/162-support-multi-factor-authentication-mfa-",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no sign-in code in stackiq; stackiq creates local Nextcloud users (lib/Service/Stackiq/ContactPersonHandler.php:292) and second factors come from Nextcloud two-factor apps platform-wide, as with org-sso",
+ "owner": "nextcloud/server"
+ },
+ "reachedOn": "nothing reaches it in stackiq; Nextcloud two-factor apps apply platform-wide",
+ "provider": "nextcloud",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "topdesk": "partial",
+ "evidence": {
+ "topdesk": "Card 'Support Multi-Factor Authentication (MFA)' in Under consideration; today MFA only comes from the identity provider behind SAML SSO (https://docs.topdesk.com/en/topdesk-mobile.html: 'We test the store application with the Microsoft two-step authentication (2FA) for the SSO'). (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: CHANGELOG.md:277 11.0.0 added Two-Factor Authentication via TOTP; implemented by src/Glpi/Security/TOTPManager.php:60, with the disable action on the user's settings page (front/preference.php).",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from topdesk (roadmap) on 2026-09-26. Also shipped in GLPI 11.0.0 (https://github.com/glpi-project/glpi/releases/tag/11.0.0).",
+ "glpi": "yes",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown"
+ },
+ {
+ "id": "sec-password-policy",
+ "area": "security",
+ "name": "Enforce a strong password policy for local accounts.",
+ "origin": "roadmap",
+ "originUrl": "https://tip.topdesk.com/c/163-enforce-strong-passwords",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "stackiq sets passwords through lib/Controller/ContactpersonenController.php:718 change-password and relies on Nextcloud for rules; a strength policy is the Nextcloud password_policy app, platform-wide",
+ "owner": "nextcloud/server"
+ },
+ "reachedOn": "nothing reaches it in stackiq; the Nextcloud password policy applies platform-wide",
+ "provider": "nextcloud",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "topdesk": "no",
+ "evidence": {
+ "topdesk": "Card 'Enforce strong passwords' in Under consideration: 'By setting rules for things like minimum length, numbers, symbols, or uppercase letters, weak passwords are blocked'. (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown"
+ },
+ {
+ "id": "ops-change-risk-score",
+ "area": "operations",
+ "name": "Get a risk score for a planned change based on past outcomes and dependencies.",
+ "origin": "roadmap",
+ "originUrl": "https://tip.topdesk.com/c/241-ai-risk-prediction-",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "stackiq runs no changes and scores no risk (see ops-change)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "topdesk": "no",
+ "evidence": {
+ "topdesk": "Card 'AI - Risk & prediction' in Under consideration: 'Change risk prediction helps change managers assess how risky a planned change is before it's approved'. (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown"
+ },
+ {
+ "id": "conn-auto-populate-dependencies",
+ "area": "connections",
+ "name": "Fill in an application's dependencies automatically from what is already known about connected items, instead of drawing each link by hand.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/glpi-project/roadmap/discussions/336",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "connections are registered one at a time or arrive through the ArchiMate import (lib/Service/ArchiMateImportService.php); nothing derives dependencies from known relations",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "glpi": "no",
+ "evidence": {
+ "glpi": "source read at 11.0.9: open request #336 (2026-05-22) asks to add all connected assets to the impact analysis at once; in core every impact relation is added by hand through src/Impact.php:1161 'Add relation' into install/mysql/glpi-empty.sql:1247 glpi_impactrelations, and the inventory (src/Glpi/Inventory/Inventory.php:106) does not create impact relations.",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from glpi (featureRequest) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "ctr-linked-contracts",
+ "area": "contracts",
+ "name": "Link contracts to each other, such as a call-off under a framework agreement or a sub-contract that depends on a main contract.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/glpi-project/roadmap/discussions/182",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "catalogContract.contract (lib/Settings/softwarecatalogus_register.json:3282) is a plain uuid to shillinq's governing Contract, not shown on ContractDetail (src/manifest.json:563 data fields) and not a link between catalogue contracts",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "glpi": "no",
+ "evidence": {
+ "glpi": "source read at 11.0.9: open request #182 (2026-03-27) states contracts cannot be linked in GLPI 11; install/mysql/glpi-empty.sql:1536 glpi_contracts_items links a contract to items, and Contract is not among the linkable item types there, with no parent contract column in install/mysql/glpi-empty.sql:1483 glpi_contracts.",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from glpi (featureRequest) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "ctr-contract-owner",
+ "area": "contracts",
+ "name": "Name the person or team responsible for a contract, so expiry warnings go to them.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/glpi-project/roadmap/discussions/290",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "catalogContract.contactPersonUser (lib/Settings/softwarecatalogus_register.json:3398) names the responsible person on the user side, shown on ContractDetail (src/manifest.json:563); expiry warnings do not reach them because the only expiry notification never matches (see ctr-expiry-alert)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "ContractDetail /contracten/:id contract details",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "glpi": "no",
+ "evidence": {
+ "glpi": "source read at 11.0.9: open request #290 (2026-05-07) asks for contract assignees as notification recipients; install/mysql/glpi-empty.sql:1483 glpi_contracts has no users_id or groups_id column, so contract alerts (src/NotificationTargetContract.php:47) go to configured global recipients only.",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from glpi (featureRequest) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "life-dates-follow-status",
+ "area": "lifecycle",
+ "name": "Have in-use and retirement dates filled in automatically when an entry's lifecycle status changes.",
+ "origin": "featureRequest",
+ "originUrl": "https://github.com/glpi-project/roadmap/discussions/457",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "the lifecycle phase is derived from usage dates (src/utils/lifecyclePhase.js derivePhase) and contract status from the end date (lib/Service/ContractStatusService.php:77), the reverse direction; no date is filled when a status changes",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "glpi": "partial",
+ "evidence": {
+ "glpi": "source read at 11.0.9: request #457 (2026-07-27, open) asks to tie dates to status; core already lets an entity fill financial dates when an item enters a chosen status, install/mysql/glpi-empty.sql:2800 autofill_use_date and :2822 autofill_decommission_date on glpi_entities, applied by src/Infocom.php:505 autofillDates, but only for the financial record's dates.",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from glpi (featureRequest) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "org-assigned-only-rights",
+ "area": "organisations",
+ "name": "Let the people responsible for an application see and edit only the entries assigned to them.",
+ "origin": "changelog",
+ "originUrl": "https://github.com/glpi-project/glpi/releases/tag/11.0.0",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "read and write rules in the register scope by organisation ({match: {_organisation: $organisation}}, see org-data-segregation), not by the person or group assigned to an entry",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "glpi": "yes",
+ "evidence": {
+ "glpi": "source read at 11.0.9: CHANGELOG.md:281 11.0.0 added 'View assigned' and 'Update assigned' rights; src/Glpi/Features/AssignableItem.php:68 grants read when the user or group is assigned and src/Glpi/Features/AssignableItem.php:79 checks UPDATE_ASSIGNED; Appliance uses this trait (src/Appliance.php:46 implements AssignableItemInterface).",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from glpi (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "ops-own-house-style",
+ "area": "operations",
+ "name": "Apply the organisation's own colours and house style to the interface.",
+ "origin": "changelog",
+ "originUrl": "https://github.com/glpi-project/glpi/releases/tag/11.0.0",
+ "stackiq": "yes",
+ "built": {
+ "state": "built",
+ "evidence": "stackiq styles use Nextcloud's theming variables (src/views/KwetsbaarhedenView.vue:478 var(--color-primary-element)), so the colours and logo an admin sets in Nextcloud theming apply to stackiq pages",
+ "owner": "nextcloud/server"
+ },
+ "reachedOn": "every stackiq page, through Nextcloud theming",
+ "provider": "nextcloud",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "glpi": "yes",
+ "evidence": {
+ "glpi": "source read at 11.0.9: CHANGELOG.md:276 11.0.0 added custom palette and theme support; src/Glpi/UI/ThemeManager.php:103 getCustomThemesDirectory and :112 getCustomThemes load admin supplied themes, offered in src/Config.php:1612 getPalettes.",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from glpi (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "land-copy-entry",
+ "area": "landscape",
+ "name": "Start a new application entry by copying an existing one with its links.",
+ "origin": "changelog",
+ "originUrl": "https://github.com/glpi-project/glpi/releases/tag/11.0.0",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "library CnIndexPage mass copy on stackiq index pages: @conduction/nextcloud-vue v2.55.1 src/components/CnIndexPage/CnIndexPage.vue:215 CnMassCopyDialog, showMassCopy default true at :1611 (package.json:45 pins ^2.55.1); whether relations are copied along was not traced",
+ "owner": "ConductionNL/nextcloud-vue"
+ },
+ "reachedOn": "index pages such as Module versions /moduleversies: select rows, Copy",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "glpi": "yes",
+ "evidence": {
+ "glpi": "source read at 11.0.9: CHANGELOG.md:285 and :286 11.0.0 added cloning of templates and creating a template from an existing item; appliances are clonable (src/Appliance.php:49 use Clonable) together with their items, contracts, documents and financial record (src/Appliance.php:62 getCloneRelations).",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from glpi (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "topdesk": "unknown"
+ }
+ ],
+ "pending": [
+ {
+ "id": "land-usage-record",
+ "area": "landscape",
+ "name": "Record that your organisation uses a module, as a usage separate from the product itself.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "partial",
+ "bluedolphin": "partial",
+ "glpi": "partial",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: /api/aangeboden-gebruik/*, /api/gebruik and OpenRegister objects API; read-only on Portfolio roadmap /portfolio-roadmap",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "offering-and-usage-listings",
+ "featureConfidence": "high",
+ "note": "The usage schema models this separation properly, but no stackiq page creates or edits a usage: the ObjectModal accepts type 'usage' (src/modals/Modals.vue:38) yet nothing opens it. Usages are only read by the roadmap, compliance matrix and vulnerability views.",
+ "evidence": {
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: municipality adds the supplier's package and version to its own landscape (\"om het pakket toe te voegen aan je omgeving\") (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E1 \"Leveranciers onderhouden de gegevens van hun producten ... Gemeenten en Samenwerkingen onderhouden de gegevens van het eigen applicatieportfolio\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten.",
+ "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers.",
+ "bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository.",
+ "stackiq": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/",
+ "topdesk": "unknown: one organisation per environment; a separate usage record is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: use is recorded as installations separate from the software product, src/Item_SoftwareVersion.php:39 (install/mysql/glpi-empty.sql:1064 glpi_items_softwareversions) per device, and licence assignments per item or user; there is no usage record of a module by an organisation as such. Reached on: Assets > Software > Installations tab."
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend create usage (gebruik) records through /api/aangeboden-gebruik or the OpenRegister objects API, and is that frontend part of what stackiq ships?"
+ },
+ {
+ "id": "land-migrate-legacy",
+ "area": "landscape",
+ "name": "Bring over what was registered in the previous catalogue, so nobody types it again.",
+ "origin": "competitor",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "partial",
+ "topdesk": "unknown",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "note": "There is no importer for the previous VNG Softwarecatalogus's registrations. The repair steps only rename stackiq's own earlier data, and the ArchiMate import brings in the GEMMA model, not organisations' entries.",
+ "evidence": {
+ "stackiq": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets",
+ "topdesk": "unknown: no import from the VNG Softwarecatalogus is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "unknown: this is the previous catalogue itself; no import of an earlier registration is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: data from earlier GLPI versions is carried over by src/Update.php:172 doUpdates with the chain in install/migrations/ (update_0.85.x_to_0.90.0.php up to the 11.0 steps); data from another catalogue needs the separate datainjection plugin (pluginsGLPI/datainjection tag 2.15.11, inc/backendcsv.class.php). Reached on: web installer update; plugin Data injection."
+ },
+ "pendingQuestion": "Is the data from the previous VNG Softwarecatalogus meant to be brought over by a one-off migration outside this repo (for example an OpenRegister register import of an export file)?"
+ },
+ {
+ "id": "conn-register-connection",
+ "area": "connections",
+ "name": "Register a connection between two applications, with its direction and the standard it uses.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "yes",
+ "bluedolphin": "partial",
+ "glpi": "partial",
+ "topdesk": "partial",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: OpenRegister objects API; no stackiq page",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "software-landscape-register",
+ "featureConfidence": "medium",
+ "note": "The connection model with direction and standard is complete, and the demo data ships six, but no stackiq page creates or edits one.",
+ "evidence": {
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Selecteer vervolgens de betreffende pakketversie. De richting van het berichtenverkeer ... Selecteer vervolgens de betreffende standaard en versie\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > toevoegen.",
+ "sap-leanix": "docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
+ "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | Rated partial because ArchiMate flow relations.",
+ "stackiq": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it",
+ "topdesk": "https://docs.topdesk.com/en/hierarchy-of-relationships.html: \"When assets are linked with a link type , one of the assets often supplies a certain feature to another asset. The supplying asset therefore is the parent asset\" (read 2026-09-26). Direction via parent and child; no standard per relation. Reached on: Asset card > Relationships widget.",
+ "glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1247 glpi_impactrelations stores a directed link from a source item to an impacted item with a name, added via src/Impact.php:1161 'Add relation'; there is no field for the standard or protocol used. Reached on: Appliance > Impact analysis tab, Add relation."
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend register koppelingen through the OpenRegister objects API, and does it count as part of stackiq?"
+ },
+ {
+ "id": "conn-usage-of-connection",
+ "area": "connections",
+ "name": "Record that your organisation actually runs a given connection, not only that it exists.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "no",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "offering-and-usage-listings",
+ "featureConfidence": "medium",
+ "note": "The model records which connections a usage runs, but neither usages nor connections have a page.",
+ "evidence": {
+ "stackiq": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller",
+ "topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Geef bij status in productie of gepland aan\"; connections are registered in the organisation's own landscape (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen.",
+ "glpi": "source read at 11.0.9: an impact relation (install/mysql/glpi-empty.sql:1247) is a single fact in one instance; there is no separate usage record saying the organisation runs it, and grep -n 'usage' src/ImpactRelation.php returns nothing."
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend let an organisation record the connections it runs, through /api/koppelingen-gebruik or the objects API?"
+ },
+ {
+ "id": "conn-shared-with-others",
+ "area": "connections",
+ "name": "See which connections you run together with other organisations.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "partial",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "no",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: /api/aangeboden-gebruik/deelnemers",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "shared-usage-on-gemma-views",
+ "featureConfidence": "medium",
+ "note": "Shared usage (with the connections it carries) is answerable through the API, but no stackiq page shows it.",
+ "evidence": {
+ "stackiq": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/",
+ "topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: A10: \"Een Samenwerking geeft aan welke gemeenten gebruik maken van een betreffende koppeling. Die gemeentenamen worden getoond\" (read 2026-09-26). Reached on: Alle koppelingen.",
+ "glpi": "source read at 11.0.9: relations live inside one instance (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) and entities are subdivisions of one organisation (src/Entity.php:58); no cross organisation sharing of connections exists (grep -rli 'federat' src/ returns nothing)."
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend show shared connections from /api/aangeboden-gebruik/deelnemers?"
+ },
+ {
+ "id": "arch-refcomp-mapping",
+ "area": "architecture",
+ "name": "Place an application on the GEMMA reference components it fulfils.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "no",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "Modules /modules (FacetedCatalogIndexView) filters by reference component (read only); no stackiq page sets the mapping: module form hides it (hideOnForm), usage has no page",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "high",
+ "note": "The mapping is stored and can be filtered on, but no stackiq screen writes it: the module field is hideOnForm and the usage schema has no index or edit page; writes come through ArchiMate import, the OpenRegister objects API or the external VNG frontend.",
+ "evidence": {
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Referentiecomponenten aangegeven door leverancier ... Toegevoegde referentiecomponenten\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen.",
+ "stackiq": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules",
+ "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'gemma\\|reference component' over src/ locales/glpi.pot returns nothing; the only classification of an appliance is its type dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id)."
+ },
+ "pendingQuestion": "Does the Modules page's CnIndexPage create/edit dialog in nextcloud-vue 2.55.1 render module.referenceComponents (hideOnForm:true, items.$ref element in the AMEF register) as a working multiselect of reference components? nextcloud-vue's fieldsFromSchema (src/utils/schema.js:529) does not check hideOnForm."
+ },
+ {
+ "id": "arch-gemma-views",
+ "area": "architecture",
+ "name": "Open a GEMMA architecture view with your own applications drawn inside it.",
+ "origin": "own-code",
+ "vng-softwarecatalogus": "yes",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "no",
+ "topdesk": "unknown",
+ "stackiq": "partial",
+ "built": {
+ "state": "built",
+ "evidence": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "API only: GET /api/views (src/store/modules/view.js:89 defines a store but nothing imports useViewStore); the drawn view is only visible in Archi after 'Organization Export' on admin settings section ArchiMate Import/Export",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "feature": "gemma-alignment",
+ "featureConfidence": "medium",
+ "note": "No stackiq page renders a GEMMA view. The enriched view data is served for an external frontend, and the org export draws applications into view copies that open in Archi.",
+ "evidence": {
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"de pakketten die getoond worden in het pakketoverzicht te plotten op een GEMMA architectuurkaart ... [Toon kaart]\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Toon kaart.",
+ "stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export",
+ "topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'gemma\\|archimate' over src/ templates/ locales/glpi.pot returns nothing; the only diagram is the impact graph (src/Impact.php:252 displayGraphView)."
+ },
+ "pendingQuestion": "Does the external VNG Softwarecatalogus frontend render /api/views/{id} with include_gebruik, and is that frontend in scope for stackiq's column?"
+ },
+ {
+ "id": "arch-shared-overlay",
+ "area": "architecture",
+ "name": "On a GEMMA view, see the applications you share with partners, drawn apart from your own.",
+ "origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -5276,6 +6214,36 @@
"vng-softwarecatalogus": "unknown: no plugins are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
},
"pendingQuestion": "Is a store registry configured on a default install, and are any stackiq configuration sets published to it?"
+ },
+ {
+ "id": "org-field-level-permissions",
+ "area": "organisations",
+ "name": "Restrict who can see or edit specific fields of an entry.",
+ "origin": "roadmap",
+ "originUrl": "https://tip.topdesk.com/c/88-permission-for-fields-and-or-widgets",
+ "stackiq": "partial",
+ "built": {
+ "state": "specified",
+ "evidence": "property-level authorization is declared in the register, for example lib/Settings/softwarecatalogus_register.json:1906 (update limited to gebruik-beheerder and admin) and :2194 (read limited to authenticated); executing it is up to OpenRegister, so the row is pending until that is shown",
+ "owner": "ConductionNL/openregister"
+ },
+ "reachedOn": "no page: enforced, if at all, by OpenRegister on every read and write",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "topdesk": "no",
+ "evidence": {
+ "topdesk": "Card 'Permission for fields and/or widgets' in Under consideration: 'User can set up permission for any fields or widgets'. (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown"
}
]
}
From 5e4f50bc2c5fa0bb7a4370b65e38d29581f66960 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:26:59 +0200
Subject: [PATCH 24/45] chore(parity): back-fill VNG and TOPdesk on the 31
demand rows
---
openspec/parity/capabilities.json | 208 +++++++++++++++++-------------
1 file changed, 116 insertions(+), 92 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index 6a492a050..487e7b2fb 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -3280,6 +3280,7 @@
"stackiq": "lib/Service/Federation/FederationService.php:215 announce() calls OpenCatalogi BroadcastService->broadcast(directory URL); only caller is lib/BackgroundJob/FederationSyncJob.php:73. Off by default: lib/Service/Federation/FederationConfig.php:56 federation_enabled=false; lib/Settings/connections.json lists federation as switch-only via occ. isAvailable() is class_exists('OCA\\\\OpenCatalogi\\\\Service\\\\DirectoryService') (FederationService.php:95).",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no shared directory of catalogues or federation between workspaces is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'federat\\|activitypub' over src/ returns nothing; every instance is standalone and the only outbound registration is the plugin marketplace client (src/Glpi/Marketplace/). The marketplace client is src/Glpi/Marketplace/Controller.php:64."
}
},
@@ -3309,6 +3310,7 @@
"stackiq": "lib/Service/Federation/FederationService.php:434 fetchPeerCatalog() calls OpenCatalogi DirectoryService->getDirectory(['url' => $peerUrl]); OpenCatalogi's getDirectory (opencatalogi lib/Service/DirectoryService.php:2409, also on origin/development) reads only filters/limit/offset/include-federated and ignores 'url', so it returns this instance's own directory listings, not the peer's published entries. Provenance marking itself is built: lib/Service/Federation/FederationMerger.php:239 stamps _source.instance. Mirrors are written into the organization schema (FederationService.php:56 PEER_MIRROR_TYPE). No src/ code reads _source, so no page shows where an entry came from.",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; pulling entries from peer catalogues is not documented, only integrations with named tools (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'federat' over src/ returns nothing; data enters only through the UI, the APIs (src/Glpi/Api/APIRest.php:60, src/Glpi/Api/HL/Router.php) and inventory, never from peer catalogues."
}
},
@@ -3338,6 +3340,7 @@
"stackiq": "lib/Controller/FederationController.php:86 addPeer / removePeer (routes.php:246-247), #[AuthorizedAdminSetting(StackiqAdmin)]; lib/Service/Federation/FederationService.php:157/191 with an SSRF host guard; UI src/views/settings/sections/FederationSettings.vue:283 (POST) and :307 (DELETE), mounted from src/views/settings/StackiqSettings.vue:114.",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no peer catalogue management is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'federat' over src/ returns nothing; there is no peer list in the Setup menu (src/Html.php:1330 onwards)."
}
},
@@ -3362,7 +3365,7 @@
"providerHow": "read-from-code",
"note": "Read and write through a REST API is live through OpenRegister, with stackiq's own role-scoped endpoints on top.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48867 'REST & GraphQL API' (2026-07-23): Programmatic access to the workspace graph.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/sap-leanix-apis: 'These APIs are ideal for integration with systems that support RESTful interactions' and 'The GraphQL API enables you to retrieve and update fact sheets and related data' (read 2026-09-26). Reached on: Developer Guide > SAP LeanIX APIs.",
"bluedolphin": "docs, intelligence competitor_features#48972 'REST API' (2026-07-23): Programmatic integration with other systems.",
"glpi": "source read at 11.0.9: legacy REST API src/Glpi/Api/APIRest.php:60 (documented in apirest.md) and the v2 high level API, src/Glpi/Api/HL/Controller/AssetController.php:149 /Assets with GET list (:2825), GET item (:2839) and POST create (:2988), Appliance and Software included (src/Glpi/Api/HL/Controller/AssetController.php:39, :133). Reached on: /apirest.php and /api.php/v2. Driven on the lab at 11.0.9 (2026-09-26): the legacy API answers \"There isn't an active API client matching your IP address\" until an administrator adds an API client, and the v2 API is off until enabled in Setup > General > API.",
"topdesk": "https://docs.topdesk.com/en/required-knowledge.html: \"basic knowledge of REST API requests (see developers.topdesk.com )\" (read 2026-09-26); https://docs.topdesk.com/en/details-about-certain-permissions.html: \"API access > REST API : this permission is necessary for operator cards that are used for accessing the TOPdesk API\" (read 2026-09-26). Reached on: developers.topdesk.com.",
@@ -3376,7 +3379,7 @@
"name": "Read generated documentation of the catalogue API.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3395,7 +3398,8 @@
"glpi": "source read at 11.0.9: src/Glpi/Api/HL/Controller/CoreController.php:322 route /doc serves a Swagger UI 'GLPI API Documentation' (:329 to :331) over the spec built by src/Glpi/Api/HL/OpenAPIGenerator.php. Reached on: /api.php/doc. Driven on the lab at 11.0.9 (2026-09-26): on a fresh install /api.php/v2/doc answers 403 \"The High-Level API is disabled\"; after switching on enable_hlapi in Setup > General > API it serves the Swagger UI \"GLPI API Documentation\".",
"stackiq": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261). The views docs endpoint is login-only; the aangeboden-gebruik docs endpoint is @PublicPage (AangebodenGebruikController.php:860), so anyone can read it (corrected 2026-09-26). Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint.",
"topdesk": "https://developers.topdesk.com/: TOPdesk API reference site, linked from the docs as \"TOPdesk API documentation\" (read 2026-09-26); https://docs.topdesk.com/en/generate-a-document.html: \"see FreeMarker and the TOPdesk API documentation\" (read 2026-09-26). Reached on: developers.topdesk.com.",
- "vng-softwarecatalogus": "unknown: no API documentation for the current catalogue was found; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: no API documentation for the current catalogue was found; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/sap-leanix-apis: 'we provide the OpenAPI explorer . This tool enables you to explore APIs, send requests, and view responses directly in your browser' (read 2026-09-26). Reached on: Workspace > OpenAPI explorer."
}
},
{
@@ -3404,7 +3408,7 @@
"name": "Export your own catalogue data for use elsewhere.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3424,7 +3428,8 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"De publieke informatie is ook beschikbaar als download van exportbestanden ... Mijn pakketten, Mijn koppelingen: Knop [Exporteren]\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Exporteren; Beschikbare downloads.",
"glpi": "source read at 11.0.9: every search list exports to CSV, PDF, ODS and XLSX through src/Glpi/Search/Output/Csv.php, Pdf.php, Ods.php and Xlsx.php, plus impact CSV (front/impactcsv.php) and the APIs (src/Glpi/Api/HL/Controller/AssetController.php:2825). Reached on: any list, Export menu. Driven on the lab at 11.0.9 (2026-09-26): the Appliances list exported to CSV (/front/report.dynamic.php display_type 3) with the created record.",
"stackiq": "ArchiMate export lib/Controller/SettingsController.php:1615 (POST /api/archimate/export) and :1685 per-organisation export (GET /api/archimate/export/organization/{uuid}), called only from src/views/settings/sections/ArchiMateImportExport.vue (admin settings, StackiqSettings.vue:86). CSV export of the portfolio report: lib/Controller/PortfolioReportController.php:105, button src/views/organisaties/PortfolioReport.vue:567. No index page opts into the library's CSV/Excel export (no allowExport in src/manifest.json).",
- "topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: tile actions \"Export to .CSV Export to Excel\" (read 2026-09-26); https://docs.topdesk.com/en/create-odata-reports-for-asset-management.html: \"generate reports by using the TOPdesk OData feed ... Microsoft Power BI, or Microsoft Excel\" (read 2026-09-26). Reached on: Asset dashboard; OData feed."
+ "topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: tile actions \"Export to .CSV Export to Excel\" (read 2026-09-26); https://docs.topdesk.com/en/create-odata-reports-for-asset-management.html: \"generate reports by using the TOPdesk OData feed ... Microsoft Power BI, or Microsoft Excel\" (read 2026-09-26). Reached on: Asset dashboard; OData feed.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/exporting-fact-sheet-data-as-excel-file: 'export fact sheet data as an Excel file'; https://help.sap.com/docs/leanix/ea/exporting-workspace-snapshots: 'Export snapshots of your workspace data through the Pathfinder REST API' (read 2026-09-26). Reached on: Inventory > Export; snapshot API."
}
},
{
@@ -3448,7 +3453,7 @@
"providerHow": "read-from-code",
"note": "No integration with a service management tool exists.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48866 'Out-of-the-box integrations (ServiceNow, Signavio, SAP)' (2026-07-23): Pre-built connectors sync CMDB, process and ERP data.",
+ "sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf: 'ServiceNow integration An integration that connects the subscription services to the customer's ServiceNow subscription to synchronize infrastructure and software asset information'; Jira Service Management integration at https://help.sap.com/docs/leanix/ea/jira-service-management-integration-faqs (read 2026-09-26). Reached on: Administration > Integrations > ServiceNow.",
"bluedolphin": "docs, intelligence competitor_features#48973 'TOPdesk integration' (2026-07-23): Connector to TOPdesk asset/service data. | docs, intelligence competitor_features#27465 'TOPdesk Integration' (2026-04-12): Available on TOPdesk Marketplace for IT landscape insights",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: \"Go to Links > Assets . Click Link asset\" (read 2026-09-26) on calls and changes; TOPdesk is itself the service management tool. Reached on: Call card > Links > Assets.",
"stackiq": "No ITSM connector: lib/Settings/connections.json lists only email, federation and eol-feed; grep for topdesk/servicenow/itsm in lib/ and src/ finds nothing.",
@@ -3477,7 +3482,7 @@
"providerHow": "read-from-code",
"note": "As a Nextcloud app it runs on whatever infrastructure hosts the Nextcloud instance.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
+ "sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf describes 'The SaaS services' and a customer 'workspace'; https://www.leanix.net/hubfs/Legal/Operational-Terms-Exhibit-v.2.0.pdf defines 'the data center utilized by LeanIX to host Customer's Data' with maintenance windows per hosting region. Only a vendor hosted subscription is offered (read 2026-09-26)",
"bluedolphin": "docs, intelligence competitor_features#27467 'SaaS Platform' (2026-04-12): Cloud-native SaaS, no installation required",
"glpi": "source read at 11.0.9: GPL 3 source distributed for installation on own servers (LICENSE, INSTALL.md, install/mysql/glpi-empty.sql schema and the web installer src/Glpi/Controller/InstallController.php). The version is src/autoload/constants.php:43 GLPI_VERSION 11.0.9, the installer controller src/Glpi/Controller/InstallController.php:57, the licence LICENSE:1 GNU GPL version 3.",
"topdesk": "https://docs.topdesk.com/VA2026R3/index.html: \"TOPdesk Virtual Appliance documentation\", releases VA 2023 R2 to VA 2026 R3 (read 2026-09-26); https://tip.topdesk.com/c/255-va-release-q4-2026: roadmap card in column \"Planned\", \"VA Release Q4 2026\" in section \"On premise - VA releases\" (read 2026-09-26). Reached on: Virtual Appliance.",
@@ -3491,7 +3496,7 @@
"name": "Search the catalogue and narrow the results with facets such as reference component and supplier.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -3511,7 +3516,8 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Aan de linkerkant staan zogenaamde filter mogelijkheden. Deze werken ook in combinatie ... Achter de te zetten filters staat een getal\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketversies: facets Leverancier, Standaard, Referentiecomponent, Status planning, Domein, Doelgroep, Bedrijfsfunctie (read 2026-09-26). Reached on: Alle pakketten / Alle pakketversies.",
"glpi": "source read at 11.0.9: every list has a criteria builder, src/Glpi/Search/Input/QueryBuilder.php:72 showGenericSearch, over all search options, for example manufacturer on appliances (src/Appliance.php:229 region, glpi_manufacturers) and status (src/Appliance.php:350); there are no counted facets and no reference component to filter on. Reached on: Management > Appliances, search criteria.",
"stackiq": "lib/Service/FacetService.php:109 DIMENSIONS = referenceComponent, standard, applicationService, domain (GET /api/facets/{schema}, routes.php:195); src/views/FacetedCatalogIndexView.vue renders CnFacetSidebar with these plus search, on the Applications and Services pages. Supplier is only a column (src/manifest.json Modules config columns 'provider'), not a facet, although the module schema marks provider facetable.",
- "topdesk": "https://docs.topdesk.com/en/the-asset-management-module-page.html: \"Asset overview : view all your assets in a filterable list\" (read 2026-09-26). Facets with counts are not described. Reached on: Asset Management > Asset overview."
+ "topdesk": "https://docs.topdesk.com/en/the-asset-management-module-page.html: \"Asset overview : view all your assets in a filterable list\" (read 2026-09-26). Facets with counts are not described. Reached on: Asset Management > Asset overview.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/advanced-filter-options: inventory filters by lifecycle, subscription, tags and fields, and https://help.sap.com/docs/leanix/ea/filtering-in-report-urls: 'Apply a filter using the facet filter column' (read 2026-09-26). Reached on: Inventory > facet filter column."
}
},
{
@@ -3520,7 +3526,7 @@
"name": "Save a filtered view of the catalogue and open it again later.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3538,7 +3544,8 @@
"glpi": "source read at 11.0.9: src/SavedSearch.php:52 SavedSearch, private or shared, listed under Tools > Saved searches (src/Html.php:1309) with optional alerts (front/savedsearch_alert.form.php). Reached on: Tools > Saved searches (front/savedsearch.php). Driven on the lab at 11.0.9 (2026-09-26): Tools > Saved searches (/front/savedsearch.php) lists saved searches with private or shared scope and a default flag.",
"stackiq": "src/views/FacetedCatalogIndexView.vue:68 Saved views menu (save current filters, list, apply); src/store/modules/facets.js:404 saveCurrentAsView POSTs to OpenRegister /apps/openregister/api/views (:61), fetchSavedViews :361 reads them back.",
"topdesk": "https://tip.topdesk.com/c/83-share-saved-overviews-with-operators-and-operator-groups: roadmap card in column \"Launched\", \"User is able to share saved overviews with operators and operator groups - Rename the saved overview\" (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: only VNG-defined \"Marktscans-voorgedefinieerde filters\" are described; users saving their own view is not; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Marktscans (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: only VNG-defined \"Marktscans-voorgedefinieerde filters\" are described; users saving their own view is not; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Marktscans (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/advanced-filter-options mentions 'creating saved searches' and shareable filtered URLs; the feature list says 'Reports can be saved and shared with user to retrieve the specific view later' (https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf) (read 2026-09-26). Reached on: Inventory > Saved searches."
}
},
{
@@ -3562,7 +3569,7 @@
"providerHow": "read-from-code",
"note": "The dashboard shows counts of organisations, applications, services and contracts. The counts are computed by OpenRegister through the library stat widget.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports. | docs, intelligence competitor_features#27424 'Dashboards & Reports' (2026-04-12): Real-time dashboards for CIO-level reporting",
+ "sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf: 'Configurable dashboards visualize inventory content as charts, lists, and KPIs'; https://help.sap.com/docs/leanix/ea/application-portfolio-management-dashboard (read 2026-09-26). Reached on: Dashboards.",
"glpi": "source read at 11.0.9: src/Glpi/Dashboard/Grid.php:1400 adds a 'Number of %s' card for every menu itemtype, so suppliers, appliances, software and contracts are counted (menu types src/Html.php:1298 to :1300); dashboards are stored by src/Glpi/Dashboard/Dashboard.php:66 and shown on the central page (src/Central.php:135). Reached on: Home > Dashboard; Assets > Dashboard.",
"topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: \"open the Asset dashboard to see statistics and visualised information regarding your registered assets\" (read 2026-09-26); https://docs.topdesk.com/en/reporting.html: \"Introducing the Reporting Hub\" (read 2026-09-26). Reached on: Asset Management > Asset dashboard.",
"stackiq": "src/manifest.json:72 Dashboard page with stat widgets kpi-organisations, kpi-modules, kpi-services, kpi-contracts (source metric count on organization/module/catalogService/catalogContract) plus catalog-panels.",
@@ -3593,6 +3600,7 @@
"stackiq": "lib/Dashboard/ConceptOrganisatiesWidget.php registered at lib/AppInfo/Application.php:760; src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters organisations on status === 'concept', but the status enum is Draft/Active/Inactive/merged (lib/Settings/softwarecatalogus_register.json:2321) after lib/Repair/RenameDutchCatalogValues.php:76 renamed 'Concept' to 'Draft'. Accept writes status 'actief' (:129), which is not in the enum either.",
"topdesk": "unknown: not a Nextcloud app; no such widget applies; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the catalogue is not a Nextcloud app; no such widget applies; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; organisations have no concept state and there is no Nextcloud dashboard, so this is not covered (read 2026-09-26)",
"glpi": "source read at 11.0.9: GLPI is not a Nextcloud app and has no concept organisation state (suppliers only have is_active, install/mysql/glpi-empty.sql:7087), so no such widget exists in its own dashboards (src/Glpi/Dashboard/Grid.php:67)."
}
},
@@ -3602,7 +3610,7 @@
"name": "Pick a ready-made report from a list and open it.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3620,7 +3628,8 @@
"glpi": "source read at 11.0.9: src/Report.php:52 Report builds a pick list of ready made reports, src/Report.php:77 default, :81 by contract, :85 by year, :87 financial information, :110 status, chosen from 'Select the report you want to generate' (src/Report.php:143). Reached on: Tools > Reports (front/report.php). Driven on the lab at 11.0.9 (2026-09-26): /front/report.php offers Default report, By contract, By year, Hardware financial and administrative information, Other financial and administrative information, Network report, Loan and Status.",
"stackiq": "src/manifest.json:1021 Reports page (type reports) with one card, Portfolio rationalization, routing to src/manifest.json PortfolioReport /portfolio-report (PortfolioReportView, GET /api/portfolio-report routes.php:303).",
"topdesk": "https://docs.topdesk.com/en/reporting.html: \"Introducing the Reporting Hub ... So far, you could find dashboards and reports in different places\" (read 2026-09-26); https://tip.topdesk.com/c/20-reporting-hub: roadmap card in column \"Launched\", \"Reporting Hub\" (read 2026-09-26). Reached on: TOPdesk menu > Reporting Hub.",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/rapportages: \"Regelmatig worden er rapportages gemaakt over het gebruik van de Softwarecatalogus\" (read 2026-09-26); compliancy monitor and digital accessibility monitor pages. Reached on: Rapportages; Compliancy monitor."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/rapportages: \"Regelmatig worden er rapportages gemaakt over het gebruik van de Softwarecatalogus\" (read 2026-09-26); compliancy monitor and digital accessibility monitor pages. Reached on: Rapportages; Compliancy monitor.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/report-types lists ready report types such as 'Landscape Report', 'Matrix Report', 'Roadmap Report'; the feature list names 'Pre-configured reports with adjustable filters' (https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf) (read 2026-09-26). Reached on: Reports."
}
},
{
@@ -3646,7 +3655,7 @@
"featureConfidence": "high",
"note": "Users cannot build their own report. The one fixed portfolio report can be exported as CSV, but it is not configurable.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48868 'CXO dashboards & reporting' (2026-07-23): Executive dashboards and role-based reports.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/sap-leanix-apis: 'GraphQL is used to create custom reports'; https://help.sap.com/docs/leanix/ea/reporting-framework-and-cli: reporting library with 'Export to PDF and PNG files' (read 2026-09-26). Reached on: Reports > custom reports (reporting framework, Extension Hub).",
"glpi": "source read at 11.0.9: any itemtype list takes arbitrary criteria (src/Glpi/Search/Input/QueryBuilder.php:72), selectable columns, and exports to CSV, PDF, ODS or XLSX (src/Glpi/Search/Output/Xlsx.php); the result can be saved (src/SavedSearch.php:52) and charted on a dashboard (src/Glpi/Dashboard/Grid.php:67). Reached on: any list with criteria, column selection and export.",
"stackiq": "No report builder in src/ or lib/. The only report is the fixed Gartner TIME portfolio report (lib/Controller/PortfolioReportController.php, CSV at :105). The overlay lists portfolio-reporting as status 'soon'.",
"topdesk": "https://docs.topdesk.com/en/reporting.html: \"The Report Wizard is not available for the Asset Management module. Further reporting can be done with the Asset Type Report or the OData feed\" (read 2026-09-26). Reached on: Asset Type Report; OData.",
@@ -3659,7 +3668,7 @@
"name": "Export a filtered list to a spreadsheet.",
"origin": "competitor",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3679,7 +3688,8 @@
"glpi": "source read at 11.0.9: src/Glpi/Search/Output/Csv.php, Ods.php, Xlsx.php and Pdf.php export the filtered list; the output format selector is rendered by src/Html.php:4219 Dropdown::showOutputFormat. Reached on: any filtered list, Export. Driven on the lab at 11.0.9 (2026-09-26): the filtered Appliances list exported to CSV with the created record.",
"stackiq": "Portfolio report CSV: lib/Controller/PortfolioReportController.php:105 (DataDownloadResponse text/csv), button src/views/organisaties/PortfolioReport.vue:567. No index page sets the library's allowExport (grep allowExport/exportable in src/manifest.json and the register finds nothing), so Applications, Contracts and the other lists have no export.",
"topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: \"Export to .CSV Export to Excel\" (read 2026-09-26). Reached on: Asset dashboard tile menu.",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: \"Export to CSV\" on the filtered package-version list (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Ook beschikbaar via knop [Export to csv] op pagina Alle pakketten\" (read 2026-09-26). Reached on: Alle pakketversies > Export to CSV."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: \"Export to CSV\" on the filtered package-version list (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Ook beschikbaar via knop [Export to csv] op pagina Alle pakketten\" (read 2026-09-26). Reached on: Alle pakketversies > Export to CSV.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/exporting-fact-sheet-data-as-excel-file: 'In the inventory, apply filters to narrow down to the fact sheets that you need to export ... export fact sheet data as an Excel file' (read 2026-09-26). Reached on: Inventory > table view > Export."
}
},
{
@@ -3706,6 +3716,7 @@
"stackiq": "No scheduled report or report mail job: lib/BackgroundJob/ holds only ContractStatusJob, EolSyncJob, FederationSyncJob and OrganizationContactSyncJob; grep for report scheduling in lib/ and src/ finds nothing.",
"topdesk": "https://docs.topdesk.com/en/details-about-certain-permissions.html: \"Reports & Selections > Schedule reports with my own authorizations : the operator can schedule reports to be regularly saved or sent to contact persons\" (read 2026-09-26). Reached on: Reports & Selections.",
"vng-softwarecatalogus": "unknown: no scheduled reports are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; scheduled notification digests (https://help.sap.com/docs/leanix/ea/notifications-center) and scheduled snapshot exports by API (https://help.sap.com/docs/leanix/ea/export) exist, but mailing a report to named people on a schedule is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: saved search alerts, src/SavedSearch_Alert.php:45 with count conditions (src/SavedSearch_Alert.php:53 to :58) and a frequency, run by src/SavedSearch_Alert.php:307 cronSavedSearchesAlerts and sent through the notification system to configured recipients; they notify on a result count rather than sending the report itself. Reached on: Tools > Saved searches > Alerts tab."
}
},
@@ -3715,7 +3726,7 @@
"name": "See a report of software cost per organisation or per domain.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "partial",
@@ -3735,7 +3746,8 @@
"glpi": "source read at 11.0.9: src/Budget.php:537 showValuesByEntity shows spend per entity and item type for a budget, and src/Report.php:89 'Other financial and administrative information (licenses, cartridges, consumables)' (front/report.infocom.conso.php); there is no cost per domain or reference component view. Reached on: Management > Budgets > budget tabs; Tools > Reports.",
"stackiq": "src/views/LicensePostureView.vue:84 per-vendor rollup with annual cost from contracts (src/utils/licensePosture.js perVendorRollup); src/views/organisaties/PortfolioReport.vue:143 annualised and one-off cost per TIME quadrant for one selected organisation (lib/Service/PortfolioReportService.php via GET /api/portfolio-report).",
"topdesk": "https://docs.topdesk.com/en/obtain-insights-with-asset-type-report.html: \"do you need an overview of the total costs of new assets?\" (read 2026-09-26); call cost fields in https://docs.topdesk.com/en/fields-for-call-management-reports.html. Reached on: Asset Type Report.",
- "vng-softwarecatalogus": "unknown: costs are not recorded; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: costs are not recorded; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-portfolio-management-dashboard: 'application run cost broken down by business capability'; https://help.sap.com/docs/leanix/ea/dashboard-modeling: 'Report on cost per business capability' (read 2026-09-26). Reached on: Dashboards > Application Portfolio Management Dashboard."
}
},
{
@@ -3744,7 +3756,7 @@
"name": "See in the app which features are available, in beta or coming soon.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "partial",
@@ -3762,6 +3774,7 @@
"stackiq": "src/manifest.json:1048 FeaturesRoadmap page (type roadmap, line 1050), footer menu entry FeaturesRoadmapMenu; content from openspec/features.overlay.json statuses stable/beta/soon.",
"topdesk": "https://docs.topdesk.com/en/topdesk-labs.html: \"As a SaaS user, you can turn on the labs features you are curious about through Functional Settings > Labs\" (read 2026-09-26); https://docs.topdesk.com/en/ai-features.html: \"On your settings page, you can find an overview of all the AI features currently available in your environment\" (read 2026-09-26). Coming-soon items live on the external roadmap, not in the app. Reached on: Functional Settings > Labs.",
"vng-softwarecatalogus": "unknown: FAQ E14 points to a homepage block \"Binnenkort in de Softwarecatalogus\", but today's homepage shows no such block; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/ (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/ai-governance-extension: 'Go to Administration > Optional Features and Early Access' to activate extensions; the public roadmap is outside the app at https://roadmap.leanix.net/ (read 2026-09-26). Reached on: Administration > Optional Features and Early Access.",
"glpi": "source read at 11.0.9: grep -rli 'coming soon' over src/ templates/ returns no in app feature status page; src/Glpi/Features/ holds item traits (for example src/Glpi/Features/Kanban.php), not feature flags. src/Glpi/Features/Kanban.php:45 is a trait, typical of that directory."
}
},
@@ -3771,7 +3784,7 @@
"name": "Follow the progress of a long synchronisation or import.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
@@ -3789,7 +3802,8 @@
"glpi": "source read at 11.0.9: massive actions over many records show a progress bar, src/MassiveAction.php:1294 displayProgressBar; the LDAP synchronisation command shows one per user batch, src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:382; long web operations report through src/Glpi/Controller/ProgressController.php:50 /progress/check/{key}. Inventory imports run per agent request without a progress view. Reached on: massive action screen; CLI ldap:sync.",
"stackiq": "lib/Controller/SettingsController.php:1289 getProgress and :1360 streamProgress (routes.php:119-120) serve lib/Service/ProgressTracker.php, used only by lib/Service/MergeOrganisatieService.php; no src/ caller of /api/progress. The admin ArchiMate import shows a spinner then the final objects-processed count (src/views/settings/sections/ArchiMateImportExport.vue:103). Organisation sync shows a status block with last sync time and organisations to process (src/views/settings/sections/OrganizationSynchronization.vue:211).",
"topdesk": "unknown: import errors can be downloaded as logs; following progress of a running import is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: no progress display for sync or import is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: no progress display for sync or import is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://updates.leanix.net/announcements/product-update-march-2026: 'A real-time progress widget in the inventory side-panel keeps you informed of import status'; integration runs are followed in 'Administration > Integrations > Sync Log' (https://help.sap.com/docs/leanix/ea/collibra-data-catalog-integration) (read 2026-09-26). Reached on: Inventory side panel import progress; Administration > Integrations > Sync Log."
}
},
{
@@ -3816,7 +3830,8 @@
"glpi": "source read at 11.0.9: src/KnowbaseItem.php:57 knowledge base articles with categories and visibility, linked to items through src/KnowbaseItem_Item.php:45 and shown on the appliance Knowledge base tab (src/Appliance.php:104); menu src/Html.php:1307. Reached on: Tools > Knowledge base (front/knowbaseitem.php). Driven on the lab at 11.0.9 (2026-09-26): /front/knowbaseitem.php opens the knowledge base with Search and Browse.",
"topdesk": "https://docs.topdesk.com/en/knowledge-management.html: \"The Knowledge Base is set up and managed by your organization's knowledge managers. Every operator is able to use information from the Knowledge Base\" (read 2026-09-26). Reached on: Modules > Knowledge Management.",
"stackiq": "No knowledge-article schema among the register's schemas (sector, suite, catalogService, vulnerability, contactPerson, organization, usage, catalogContract, connection, software-review, element, view, model, property-definition, relation, module, compliancy, bioMeasure, moduleVersion, sbomComponent in lib/Settings/softwarecatalogus_register.json); ModuleDetail only has a Documentation files panel.",
- "vng-softwarecatalogus": "unknown: the FAQ and manuals are site help, no knowledge base about applications is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: the FAQ and manuals are site help, no knowledge base about applications is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; fact sheets hold links and files in a Resources tab (https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets), but no searchable knowledge base of articles is documented (read 2026-09-26)"
}
},
{
@@ -3843,7 +3858,8 @@
"glpi": "source read at 11.0.9: native inventory receives glpi-agent submissions at src/Glpi/Controller/InventoryController.php:61 /Inventory (legacy :62 /front/inventory.php), processed by src/Glpi/Inventory/Inventory.php:106 with src/Glpi/Inventory/Asset/Software.php creating software and installations. The agent is the separate glpi-project/glpi-agent repository. Reached on: Administration > Inventory; Assets > Software.",
"stackiq": "No discovery agent or agent-ingest endpoint in lib/ or appinfo/routes.php. The nearest capability is SBOM import per module version (lib/Controller/SbomController.php:129), which records components of a known release, not installed software.",
"topdesk": "https://docs.topdesk.com/en/taking-inventory-with-configuration-management.html: \"TOPsis will scan the workstations in your network and import the data into TOPdesk\" (read 2026-09-26) (old Configuration Management); https://docs.topdesk.com/en/migration-status.html: \"For network scanning purposes, we advise you to use other solutions that are available via the TOPdesk Marketplace: Lansweeper integration Microsoft Endpoint Manager integration\" (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; LeanIX has no own installation agent, software assets come in through the ServiceNow integration (https://help.sap.com/docs/leanix/ea/obsolescence-risk-management-import-software-assets) (read 2026-09-26)"
}
},
{
@@ -3870,7 +3886,8 @@
"glpi": "source read at 11.0.9: src/Glpi/Inventory/Request.php:97 NETDISCOVERY_ACTION calls src/Glpi/Inventory/Request.php:237 networkDiscovery, importing devices found by the agent's network discovery; scheduling discovery tasks from the server goes through the HANDLE_NETDISCOVERY_TASK hook (src/Glpi/Inventory/Request.php:448), which the separate glpiinventory plugin implements. Reached on: Administration > Inventory; Assets > Network devices.",
"stackiq": "No network scanning code in lib/ or routes (appinfo/routes.php).",
"topdesk": "https://docs.topdesk.com/en/creating-a-new-import.html: \"Connecting to Lansweeper as Asset Management import source\" (read 2026-09-26); https://tip.topdesk.com/c/186-automated-asset-scanning-tool: roadmap card in column \"Under consideration\", \"The asset discovery tool constantly monitors the entire network for new devices\" (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; network device discovery is not documented (read 2026-09-26)"
}
},
{
@@ -3894,7 +3911,7 @@
"providerHow": "read-from-code",
"note": "No discovery of unregistered SaaS use.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48864 'SaaS Management & discovery' (2026-07-23): Discovers SaaS usage and shadow IT, integrates with the fact sheet model.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/saas-discovery: 'SaaS discovery identifies your organization's SaaS applications through integrations with third-party systems like Single-Sign-on (SSO) ... Eliminate shadow IT and business-managed IT' (read 2026-09-26). Reached on: Discovery > SaaS discovery inbox.",
"stackiq": "No SaaS or SSO-log discovery code in lib/; lib/Settings/connections.json has no such source.",
"topdesk": "unknown: SaaS discovery is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -3907,7 +3924,7 @@
"name": "Register hardware such as laptops and servers alongside software.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3925,7 +3942,8 @@
"glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:208 asset_types lists Computer, Monitor, NetworkEquipment and the other hardware types managed next to software, under the Assets menu. Reached on: Assets > Computers, Monitors, Network devices.",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"Think of a router that provides a computer with access to your network, or a printer\" (read 2026-09-26); any asset type via templates. Reached on: Asset Management.",
"stackiq": "No hardware schema in lib/Settings/softwarecatalogus_register.json (schemas are software, organisation, contract and GEMMA model types only).",
- "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/it-component-modeling-guidelines: IT component subtype 'Hardware ... (e.g., servers, mainframe computers, storage devices)'. Modeled as technology types an application depends on, not individual laptops as assets (read 2026-09-26). Reached on: IT Component fact sheet, subtype Hardware."
}
},
{
@@ -3934,7 +3952,7 @@
"name": "Record configuration items and their relations in a CMDB.",
"origin": "competitor",
"vng-softwarecatalogus": "no",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -3952,7 +3970,8 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"Dubbel beheer (én in de Softwarecatalogus én in de CMDB) ... Een CMDB die separaat wordt bijgehouden\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/19703: \"Zolang de CMDB niet gekoppeld is aan de Softwarecatalogus\" (read 2026-09-26). The docs treat the CMDB as a separate tool.",
"glpi": "source read at 11.0.9: configuration items are the asset types (src/autoload/CFG_GLPI.php:208) plus appliances, with relations recorded as appliance membership (src/Appliance_Item.php:45), impact relations (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) and network port links. Reached on: Assets menu; item > Impact analysis tab.",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"You register these functionalities as custom link types, and these link types are shown in the graphical overview of assets\" (read 2026-09-26). Reached on: Asset card > Relationships widget.",
- "stackiq": "Applications (module lib/Settings/softwarecatalogus_register.json:6777), versions (moduleVersion :7649), suites (suite :1135) and application-to-application connections (connection :3563) with relations; ModuleDetail and SuiteDetail show a Related panel. No manifest page has register+schema 'connection' or 'usage', so connections are not listed or created on their own page."
+ "stackiq": "Applications (module lib/Settings/softwarecatalogus_register.json:6777), versions (moduleVersion :7649), suites (suite :1135) and application-to-application connections (connection :3563) with relations; ModuleDetail and SuiteDetail show a Related panel. No manifest page has register+schema 'connection' or 'usage', so connections are not listed or created on their own page.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/jira-service-management-integration: 'Use the Jira Service Management integration to synchronize data between your configuration management database (CMDB) and SAP LeanIX ... Configuration items from Jira Service Management can be mapped to various fact sheet types'. LeanIX consumes a CMDB, it does not act as one (read 2026-09-26). Reached on: Jira Service Management and ServiceNow integrations."
}
},
{
@@ -3961,7 +3980,7 @@
"name": "Deduplicate and reconcile records that arrive from several sources.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
@@ -3979,6 +3998,7 @@
"stackiq": "Organisation merge: src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail, calling /api/organisaties/{uuid}/merge/dry-run and /merge (src/store/modules/organisatie.js:486/524, lib/Controller/MergeController.php:106, admin-only body guard). Federation mirrors are reconciled per peer by lib/Service/Federation/FederationMerger.php.",
"topdesk": "unknown: deduplication across sources is not described; https://tip.topdesk.com/c/239-ai-cmdb-monitoring- (duplicates) is under consideration; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/aggregation-and-linkage-of-software-records: 'import software records from ServiceNow as aggregated software fact sheets'; https://help.sap.com/docs/leanix/ea/matching-rules: custom matching to avoid 'duplicate fact sheets'; SaaS discovery links the same SaaS found in several SSOs (https://help.sap.com/docs/leanix/ea/saas-discovery) (read 2026-09-26). Reached on: ServiceNow integration > aggregation; matching rules; SaaS discovery inbox.",
"glpi": "source read at 11.0.9: src/RuleImportAsset.php:46 import and link rules decide whether an incoming inventory record matches an existing asset (by serial, UUID, MAC and similar) or creates one; src/RuleDictionnarySoftware.php:44 normalises software names and publishers from different sources; duplicates can be merged afterwards (src/Software.php:1011). Reached on: Administration > Rules > Rules for import and link equipments; Dictionaries."
}
},
@@ -3988,7 +4008,7 @@
"name": "Log incidents and requests against an application.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -4006,7 +4026,8 @@
"glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:301 ticket_types includes Appliance (line 305), so tickets link to an application through src/Item_Ticket.php:41, shown on the appliance Tickets tab (src/Appliance.php:105). Reached on: Assistance > Tickets; Appliance > Tickets tab. Driven on the lab at 11.0.9 (2026-09-26): the default Super-Admin profile lists Computer, Monitor, NetworkEquipment, Peripheral, Phone, Printer, Software, DCRoom, Rack, Enclosure and Database as associable to tickets, not Appliance, so an appliance shows no Tickets tab until an administrator adds it in the profile; rating kept.",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: \"On Call, Change (Activity) ... cards, you can link multiple assets\" (read 2026-09-26). Reached on: Call card > Links > Assets.",
"stackiq": "No incident or request schema or endpoint in lib/Settings/softwarecatalogus_register.json or appinfo/routes.php.",
- "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/portals: an Application Portal 'accessible to everyone to order software, issue support tickets' through configurable links to the helpdesk; incidents themselves stay in the ITSM tool (read 2026-09-26). Reached on: Portals > links to helpdesk."
}
},
{
@@ -4033,7 +4054,8 @@
"glpi": "source read at 11.0.9: changes link to the appliance (src/Appliance.php:107 Change_Item tab) and go through approvals, src/ChangeValidation.php:39 ChangeValidation extends CommonITILValidation. Reached on: Assistance > Changes; Appliance > Changes tab.",
"topdesk": "https://docs.topdesk.com/en/requesting-a-change.html: \"A Preliminary Request for Change can only be dealt with as a Request for Change after it is authorized\" (read 2026-09-26). Reached on: Modules > Change Management.",
"stackiq": "No change-request workflow for applications. The only approval flow is for contracts: src/components/contracts/ContractApprovalPanel.vue on ContractDetail via /api/contracts/{uuid}/approval (routes.php:35-37), delegated to decidiq.",
- "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; architecture decisions have a review process (https://help.sap.com/docs/leanix/ea/architecture-decisions) but a change approval workflow on an application is not documented (read 2026-09-26)"
}
},
{
@@ -4042,7 +4064,7 @@
"name": "Track service level targets for an application or supplier.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -4060,7 +4082,8 @@
"glpi": "source read at 11.0.9: src/SLM.php:42 service level management with src/SLA.php:44 SLA and OLA targets on tickets (install/mysql/glpi-empty.sql:7304 glpi_tickets.slas_id_ttr), assigned by business rules (src/RuleCommonITILObject.php:73) that can key on the linked appliance (src/RuleCommonITILObject.php:305 assign_appliance). Reached on: Setup > Service levels.",
"topdesk": "https://docs.topdesk.com/en/track-when-you-respond-to-calls, response-times.html: \"you register and track how quickly your operators need to respond ... you need a Contract Management and SLM license\" (read 2026-09-26). Reached on: Contract Management and SLM.",
"stackiq": "catalogContract.contractType enum includes 'SLA' (lib/Settings/softwarecatalogus_register.json:3344) as a label only; no service-level target, measurement or breach fields in any schema.",
- "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'Service Level Agreement (SLA) Single Select Corporate-Level SLA, Customer-Level SLA, Service-Level SLA' and an SLA description on the contract. No tracking of targets against results (read 2026-09-26). Reached on: Contract fact sheet > Governance and Regulations."
}
},
{
@@ -4069,7 +4092,7 @@
"name": "Let end users request software through a self-service portal.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -4087,6 +4110,7 @@
"topdesk": "https://docs.topdesk.com/en/mobile-access-to-the-self-service-portal.html: \"The SSP layout is suited to be displayed in a mobile interface\" (read 2026-09-26); https://tip.topdesk.com/c/86-webshop-is-connected-with-asset-management: roadmap card in column \"Building\", \"End-user can order items which are in Asset Management\" (read 2026-09-26); pricing lists \"Self-Service Portal\" and \"Webshop\". Reached on: Self-Service Portal.",
"stackiq": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls.",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/portals: 'create an Application Portal that is accessible to everyone to order software ... Action button: Perform an action, in this case \"Request new Application\"' (read 2026-09-26). Reached on: Portals > Application Portal.",
"glpi": "source read at 11.0.9: the 11.0 service catalog src/Glpi/Form/ServiceCatalog/ServiceCatalog.php:45 lists native forms for self service users (menu src/Html.php:1283), and a form question can offer software items to pick, src/Glpi/Form/QuestionType/QuestionTypeItem.php:180 Software::class, creating a ticket from the answer. Reached on: Self service > Service catalog. Driven on the lab at 11.0.9 (2026-09-26): /ServiceCatalog shows the service catalog with \"Report an issue\" and \"Request a service\"."
}
},
@@ -4166,11 +4190,11 @@
"note": "Helmond's architecture repository tender (REQ3, REQ61) asks to relate the repository to the GGM. GGM metadata survives an ArchiMate import on architecture elements, but no field or page links an application to a GGM entity.",
"vng-softwarecatalogus": "unknown",
"evidence": {
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: the Gemeentelijk Gegevensmodel is not mentioned; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: the Gemeentelijk Gegevensmodel is not mentioned (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4195,13 +4219,13 @@
"feature": "archimate-import-and-export",
"featureConfidence": "medium",
"note": "Helmond REQ19 asks for architecture views embedded in office documents. stackiq renders no view at all (see arch-gemma-views) and exports only ArchiMate files.",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"evidence": {
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"Download de kaart met de knop [download SVG] ... De kaart volledig schaalbaar\" (read 2026-09-26). A map is downloaded as SVG for printing; placing it in Word or PowerPoint is a manual step. Reached on: Mijn softwarecatalogus > Pakketten > Toon kaart > download SVG.",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: architecture views and Word or PowerPoint are not mentioned (0 hits for PowerPoint); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4227,11 +4251,11 @@
"note": "Helmond REQ54 asks for entity relationship or UML data models. stackiq holds imported ArchiMate elements but models nothing itself.",
"vng-softwarecatalogus": "unknown",
"evidence": {
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: no data modelling is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: no data entity or UML modelling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4255,18 +4279,18 @@
"providerHow": "read-from-code",
"featureConfidence": "medium",
"note": "Helmond REQ78 asks administrators to check periodically that every user still needs access. stackiq fetches the last login of each contact's account and never shows it.",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"evidence": {
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/gebruikersbeheer: \"Er opent zich een overzicht met alle geregistreerde gebruikers van uw organisatie ... inclusief wanneer zij voor het laatst hebben ingelogd\" (read 2026-09-26); https://www.softwarecatalogus.nl/: tip \"Controleer of alle gebruikers nog werkzaam zijn bij de gemeente of samenwerking\" (read 2026-09-26). A manual check, no review cycle. Reached on: Menu > Gebruikersbeheer.",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "https://docs.topdesk.com/en/operator-licence-overview.html: the list of operators shows \"When the given operator was last active (meaning their last login)\" (read 2026-09-26). Input for a review; no periodic review process is described. Reached on: Operator licence overview."
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "unknown",
- "topdesk": "unknown"
+ "topdesk": "partial"
},
{
"id": "comp-processing-register",
@@ -4288,11 +4312,11 @@
"note": "Helmond REQ4 wants the processing register kept apart from the repository but linked. stackiq stores and shows a reference per application; it does not hold the register.",
"vng-softwarecatalogus": "unknown",
"evidence": {
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: no link to a register of processing activities is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: no register of processing activities is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4317,13 +4341,13 @@
"feature": "offering-and-usage-listings",
"featureConfidence": "medium",
"note": "Standard municipal tender text (Noordwijk 418890, Reimerswaal 417169, FUMO 415897, HLT Samen 383984): a supplier inside the GEMMA scope can make its product information transparent through the Softwarecatalogus. stackiq publishes the data; the page a buyer opens lives in the external frontend.",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "yes",
"evidence": {
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"De leveranciersinformatie in de Softwarecatalogus is openbaar\" (read 2026-09-26); https://www.softwarecatalogus.nl/inkoopondersteuning%20standaarden: \"De gegenereerde bestekstekst kunt u gebruiken in uw offerte-uitvraag ... Als informatiebron is de GEMMA softwarecatalogus gebruikt\" (read 2026-09-26). Reached on: Supplier login > Productportfolio; Inkoopondersteuning.",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: TOPdesk is a single-organisation tool; public supplier product information is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4350,11 +4374,11 @@
"note": "Helmond REQ41 asks for analysis of application use, cost, risk and value. stackiq records a TIME classification (life-time-classification) without the scores that would justify it.",
"vng-softwarecatalogus": "unknown",
"evidence": {
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: no value, cost or risk scoring is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: no value, cost and risk scoring of applications is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4383,7 +4407,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: a sign-off of the application list is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4413,7 +4437,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: no register of processing activities is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4443,7 +4467,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: collective agreements across organisations are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4473,7 +4497,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: assets hold documents in a Documents widget, but sharing them with other organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4503,7 +4527,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: no availability, integrity and confidentiality classification is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4533,7 +4557,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: no product comparison table is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4563,7 +4587,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: acting as another user is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4593,7 +4617,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: Common Ground is not mentioned; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4623,7 +4647,7 @@
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: versions of applications are not modelled; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
@@ -4650,7 +4674,7 @@
"topdesk": "yes",
"evidence": {
"topdesk": "Card 'More control over card & file removal' in Launched (updated 2026-02-09); docs https://docs.topdesk.com/en/file-maintenance.html: 'you can set how many days after closing or archiving a card its uploaded files and linked emails should be removed'. (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: retention cleanup is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
@@ -4680,7 +4704,7 @@
"topdesk": "no",
"evidence": {
"topdesk": "Card 'Field Dependencies (brand/type/model)' in Under consideration: 'User can set up dependencies between fields'; not in the field docs (https://docs.topdesk.com/en/editing-fields.html). (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: dependent fields are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
@@ -4710,7 +4734,7 @@
"topdesk": "no",
"evidence": {
"topdesk": "Card 'Changing the type of an asset' in Under consideration: 'User can change the type of an exiting asset'. (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: changing an entry type is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
@@ -4740,7 +4764,7 @@
"topdesk": "no",
"evidence": {
"topdesk": "Card 'Audit Logging for TOPdesk - MCP Server' in Building: 'you should be able to see exactly what that AI did, which actions it took, when, and on what data'. (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: no AI assistant is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
@@ -4771,7 +4795,7 @@
"evidence": {
"topdesk": "Card 'Support Multi-Factor Authentication (MFA)' in Under consideration; today MFA only comes from the identity provider behind SAML SSO (https://docs.topdesk.com/en/topdesk-mobile.html: 'We test the store application with the Microsoft two-step authentication (2FA) for the SSO'). (read 2026-09-26)",
"glpi": "source read at 11.0.9: CHANGELOG.md:277 11.0.0 added Two-Factor Authentication via TOTP; implemented by src/Glpi/Security/TOTPManager.php:60, with the disable action on the user's settings page (front/preference.php).",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: login is by username and password (https://www.softwarecatalogus.nl/user/login); a second factor is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
},
@@ -4800,7 +4824,7 @@
"topdesk": "no",
"evidence": {
"topdesk": "Card 'Enforce strong passwords' in Under consideration: 'By setting rules for things like minimum length, numbers, symbols, or uppercase letters, weak passwords are blocked'. (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: a password policy is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
@@ -4830,7 +4854,7 @@
"topdesk": "no",
"evidence": {
"topdesk": "Card 'AI - Risk & prediction' in Under consideration: 'Change risk prediction helps change managers assess how risky a planned change is before it's approved'. (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: change management is not covered; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
@@ -4860,10 +4884,10 @@
"glpi": "no",
"evidence": {
"glpi": "source read at 11.0.9: open request #336 (2026-05-22) asks to add all connected assets to the impact analysis at once; in core every impact relation is added by hand through src/Impact.php:1161 'Add relation' into install/mysql/glpi-empty.sql:1247 glpi_impactrelations, and the inventory (src/Glpi/Inventory/Inventory.php:106) does not create impact relations.",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: connections are entered by hand per the iJw and iWmo manual; automatic filling is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: relations are created by hand in the Relationships widget; automatic filling is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from glpi (featureRequest) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
@@ -4890,16 +4914,16 @@
"glpi": "no",
"evidence": {
"glpi": "source read at 11.0.9: open request #182 (2026-03-27) states contracts cannot be linked in GLPI 11; install/mysql/glpi-empty.sql:1536 glpi_contracts_items links a contract to items, and Contract is not among the linkable item types there, with no parent contract column in install/mysql/glpi-empty.sql:1483 glpi_contracts.",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: contracts are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"TOPdesk allows you to link your services to supplier services, so that the duration of your services will always be in line with the duration of supplier services\" (read 2026-09-26). Linking runs through underpinning services, not contract to contract. Reached on: Contract Management and SLM > Service card."
},
"note": "Mined from glpi (featureRequest) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "topdesk": "unknown"
+ "topdesk": "partial"
},
{
"id": "ctr-contract-owner",
@@ -4920,16 +4944,16 @@
"glpi": "no",
"evidence": {
"glpi": "source read at 11.0.9: open request #290 (2026-05-07) asks for contract assignees as notification recipients; install/mysql/glpi-empty.sql:1483 glpi_contracts has no users_id or groups_id column, so contract alerts (src/NotificationTargetContract.php:47) go to configured global recipients only.",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: contracts are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Operator The TOPdesk operator responsible for managing the contract ... Reminder date Date on which an operator should be reminded about the contract, e.g. ahead of expiry\" (read 2026-09-26); https://docs.topdesk.com/en/events-that-trigger-actions.html: \"notify a manager that a contract will expire in a month\" (read 2026-09-26). Reached on: Contract card > Management > Operator."
},
"note": "Mined from glpi (featureRequest) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "topdesk": "unknown"
+ "topdesk": "yes"
},
{
"id": "life-dates-follow-status",
@@ -4950,10 +4974,10 @@
"glpi": "partial",
"evidence": {
"glpi": "source read at 11.0.9: request #457 (2026-07-27, open) asks to tie dates to status; core already lets an entity fill financial dates when an item enters a chosen status, install/mysql/glpi-empty.sql:2800 autofill_use_date and :2822 autofill_decommission_date on glpi_entities, applied by src/Infocom.php:505 autofillDates, but only for the financial record's dates.",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: statuses and planning dates are entered separately; automatic dates are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "unknown: automated actions can update cards, but dates following a lifecycle status are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from glpi (featureRequest) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
@@ -4980,16 +5004,16 @@
"glpi": "yes",
"evidence": {
"glpi": "source read at 11.0.9: CHANGELOG.md:281 11.0.0 added 'View assigned' and 'Update assigned' rights; src/Glpi/Features/AssignableItem.php:68 grants read when the user or group is assigned and src/Glpi/Features/AssignableItem.php:79 checks UPDATE_ASSIGNED; Appliance uses this trait (src/Appliance.php:46 implements AssignableItemInterface).",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: roles are beheerder and raadpleger per organisation; rights per assigned application are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "https://docs.topdesk.com/en/details-about-certain-permissions.html: \"To restrict access to specific data, link the operator to branch, operator, or category filters\" (read 2026-09-26); https://docs.topdesk.com/en/reservations-management-and-other-modules.html: \"Operator filter: operators can see all reservations, but can only edit reservations that are created by them or their operator group\" (read 2026-09-26). Filters by branch, operator or category; not shown for assets assigned to a person. Reached on: Operator card > filters."
},
"note": "Mined from glpi (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "topdesk": "unknown"
+ "topdesk": "partial"
},
{
"id": "ops-own-house-style",
@@ -5010,16 +5034,16 @@
"glpi": "yes",
"evidence": {
"glpi": "source read at 11.0.9: CHANGELOG.md:276 11.0.0 added custom palette and theme support; src/Glpi/UI/ThemeManager.php:103 getCustomThemesDirectory and :112 getCustomThemes load admin supplied themes, offered in src/Config.php:1612 getPalettes.",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: the catalogue is one VNG-branded site; organisation styling is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "https://docs.topdesk.com/en/self-service-portal-278632.html: \"you can create several SSP designs, with different colours, logos, and search bar backgrounds, to show a distinct look and feel to different branches\" (read 2026-09-26). Self-Service Portal only; operator interface styling is not described. Reached on: Self-Service Portal designer."
},
"note": "Mined from glpi (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "topdesk": "unknown"
+ "topdesk": "partial"
},
{
"id": "land-copy-entry",
@@ -5040,16 +5064,16 @@
"glpi": "yes",
"evidence": {
"glpi": "source read at 11.0.9: CHANGELOG.md:285 and :286 11.0.0 added cloning of templates and creating a template from an existing item; appliances are clonable (src/Appliance.php:49 use Clonable) together with their items, contracts, documents and financial record (src/Appliance.php:62 getCloneRelations).",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: FAQ A1 \"opvoer van een nieuwe versies mogelijk als kopie van een op te geven vorige versie ... Gegevens van die vorige versie worden overgenomen in de nieuwe versie, ook koppelingen worden overgenomen\" (read 2026-09-26). Copies a version of the same package with its connections, not a new application. Reached on: Mijn softwarecatalogus > Pakketten > kopie-symbool.",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "topdesk": "https://docs.topdesk.com/en/copying-assets.html: \"you can save time by copying an existing asset ... Dataset content will not be copied during this action ... Read permissions for any linked asset type\" (read 2026-09-26). Whether links are copied is implied by the permission note, not stated. Reached on: Asset card > More > Copy."
},
"note": "Mined from glpi (changelog) on 2026-09-26.",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "topdesk": "unknown"
+ "topdesk": "partial"
}
],
"pending": [
@@ -6234,7 +6258,7 @@
"topdesk": "no",
"evidence": {
"topdesk": "Card 'Permission for fields and/or widgets' in Under consideration: 'User can set up permission for any fields or widgets'. (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: field-level permissions are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
From 69ef74e4173c3b9d11d1ec94cab467200a1ffa5e Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:30:12 +0200
Subject: [PATCH 25/45] chore(parity): back-fill GLPI on the demand rows from
source at 11.0.9
---
openspec/parity/capabilities.json | 192 ++++++++++++++++++------------
1 file changed, 113 insertions(+), 79 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index 487e7b2fb..87423ff52 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -4138,6 +4138,7 @@
"topdesk": "https://docs.topdesk.com/en/installing-the-topdesk-mobile-store-application.html: \"Scan the QR code to download the app from the Play store\" (read 2026-09-26). Reached on: TOPdesk Mobile app.",
"stackiq": "No mobile app or mobile-specific surface in the repo; the app is the Nextcloud web UI (src/manifest.json).",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for mobile app, iOS and Android, no hits; only a Microsoft Teams app is documented (https://help.sap.com/docs/leanix/ea/sap-leanix-app-for-microsoft-teams) (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'android\\|ios app\\|mobile app' over src/ templates/ returns nothing; the repository ships only the responsive web interface (templates/) and APIs (src/Glpi/Api/HL/Controller/CoreController.php:322 docs), no native mobile client."
}
},
@@ -4147,7 +4148,7 @@
"name": "Run the organisation and contact synchronisation on a schedule and see when it last ran.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "partial",
@@ -4167,6 +4168,7 @@
"stackiq": "lib/BackgroundJob/OrganizationContactSyncJob.php:75 TimedJob every 300 s calling performScheduledSync; admin section src/views/settings/sections/CronjobConfiguration.vue:56 shows each job's interval and an enable switch; src/views/settings/sections/OrganizationSynchronization.vue:211 shows Last Sync from app config last_sync_time (lib/Service/OrganizationSyncService.php:1609, written by recordSyncTime :1674).",
"topdesk": "https://docs.topdesk.com/en/events-that-trigger-actions.html: \"when tracking imports/Exchange exports via system events ... on a schedule\" (read 2026-09-26); https://tip.topdesk.com/c/116-support-for-importing-persons-and-operators-directly-from-local-active-directory: roadmap card in column \"Launched\", person import from AD (read 2026-09-26). Reached on: Settings > Import settings.",
"vng-softwarecatalogus": "unknown: only \"De kaart wordt dagelijks bijgewerkt\" is stated; no organisation or contact sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/17042 (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/configuring-automated-nightly-runs-for-inbound-processors: 'enable automated nightly runs for an inbound Integration API processor'; SaaS discovery retrieves data 'usually twice a day' (https://help.sap.com/docs/leanix/ea/saas-discovery); runs visible in 'Administration > Integrations > Sync Log' (read 2026-09-26). Reached on: Administration > Integrations > Sync Log.",
"glpi": "source read at 11.0.9: automatic actions are scheduled and show their last run, src/CronTask.php:59 with install/mysql/glpi-empty.sql:1610 glpi_crontasks.lastrun, but LDAP user and group synchronisation is not one of them (grep -i ldap over the cron seed in install/empty_data.php:438 finds none); it is the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users, which must be scheduled by the system cron. Organisation (supplier) records have no sync at all. Reached on: Setup > Automatic actions; CLI bin/console ldap:sync. Driven on the lab at 11.0.9 (2026-09-26): /front/crontask.php lists automatic actions with run mode, frequency and last run."
}
},
@@ -4193,12 +4195,12 @@
"vng-softwarecatalogus": "unknown: the Gemeentelijk Gegevensmodel is not mentioned; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'gegevensmodel\\|ggm' over src/ templates/ locales/glpi.pot returns nothing; appliances have no data entity model to relate to (install/mysql/glpi-empty.sql:8935 glpi_appliances).",
"topdesk": "unknown: the Gemeentelijk Gegevensmodel is not mentioned (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4224,12 +4226,12 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"Download de kaart met de knop [download SVG] ... De kaart volledig schaalbaar\" (read 2026-09-26). A map is downloaded as SVG for printing; placing it in Word or PowerPoint is a manual step. Reached on: Mijn softwarecatalogus > Pakketten > Toon kaart > download SVG.",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: the only diagram is the impact graph, whose Download writes PNG or JPEG (js/impact.js:2539, :2546); grep -rli 'docx\\|pptx\\|powerpoint' over src/ finds no Office export of views, only XLSX and ODS list output (src/Glpi/Search/Output/Xlsx.php).",
"topdesk": "unknown: architecture views and Word or PowerPoint are not mentioned (0 hits for PowerPoint); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4254,12 +4256,12 @@
"vng-softwarecatalogus": "unknown: no data modelling is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'entity.relationship\\|uml' over src/ templates/ locales/glpi.pot returns nothing; databases are inventoried as instances and names (src/DatabaseInstance.php:43, src/Database.php:41, install/mysql/glpi-empty.sql:9468 glpi_databases) without entities or relations.",
"topdesk": "unknown: no data entity or UML modelling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4284,12 +4286,12 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/gebruikersbeheer: \"Er opent zich een overzicht met alle geregistreerde gebruikers van uw organisatie ... inclusief wanneer zij voor het laatst hebben ingelogd\" (read 2026-09-26); https://www.softwarecatalogus.nl/: tip \"Controleer of alle gebruikers nog werkzaam zijn bij de gemeente of samenwerking\" (read 2026-09-26). A manual check, no review cycle. Reached on: Menu > Gebruikersbeheer.",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'recertif\\|access review' over src/ templates/ locales/glpi.pot returns nothing; users carry last_login and validity dates (install/mysql/glpi-empty.sql:7813 last_login, :7866 begin_date, :7867 end_date) that an admin can search on, but there is no periodic review campaign.",
"topdesk": "https://docs.topdesk.com/en/operator-licence-overview.html: the list of operators shows \"When the given operator was last active (meaning their last login)\" (read 2026-09-26). Input for a review; no periodic review process is described. Reached on: Operator licence overview."
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "partial"
},
{
@@ -4315,12 +4317,12 @@
"vng-softwarecatalogus": "unknown: no link to a register of processing activities is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'processing activit\\|gdpr' over src/ returns nothing; the records of processing plugin yild/gdprropa (tag 1.0.3, setup.php:56) supports GLPI 10 only.",
"topdesk": "unknown: no register of processing activities is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4346,12 +4348,12 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"De leveranciersinformatie in de Softwarecatalogus is openbaar\" (read 2026-09-26); https://www.softwarecatalogus.nl/inkoopondersteuning%20standaarden: \"De gegenereerde bestekstekst kunt u gebruiken in uw offerte-uitvraag ... Als informatiebron is de GEMMA softwarecatalogus gebruikt\" (read 2026-09-26). Reached on: Supplier login > Productportfolio; Inkoopondersteuning.",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: suppliers have no account or public product page (install/mysql/glpi-empty.sql:7067 glpi_suppliers); anonymous access covers only the FAQ (src/KnowbaseItem.php:131 use_public_faq).",
"topdesk": "unknown: TOPdesk is a single-organisation tool; public supplier product information is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4377,12 +4379,12 @@
"vng-softwarecatalogus": "unknown: no value, cost or risk scoring is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'business value' over src/ locales/glpi.pot returns nothing; appliances carry no value, cost or risk score fields (install/mysql/glpi-empty.sql:8935 glpi_appliances), only the software ticket_tco figure (install/mysql/glpi-empty.sql:6872).",
"topdesk": "unknown: no value, cost and risk scoring of applications is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4406,13 +4408,13 @@
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #136 'Als CISO wil ik ons gemeentelijk pakketoverzicht kunnen controleren en vervolgens fiatteren'; no approval step for the landscape appears in the incumbent manuals (https://www.softwarecatalogus.nl/node/19703). (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: approvals exist only on ITIL objects (src/CommonITILValidation.php:49, children TicketValidation and src/ChangeValidation.php:39); there is no sign off of the appliance list itself. A change could be used to carry an approval, which is not a catalogue sign off.",
"topdesk": "unknown: a sign-off of the application list is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4436,13 +4438,13 @@
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #82 'Als gebruik-raadpleger wil ik een register van verwerkingen kunnen genereren'; the incumbent exports only package, connection and IBD-foto files (https://www.softwarecatalogus.nl/Beschikbare%20downloads). (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'processing activit\\|gdpr' over src/ returns nothing, so there is no register to generate; the report list (src/Report.php:77 to :111) has no such report.",
"topdesk": "unknown: no register of processing activities is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4466,13 +4468,13 @@
"vng-softwarecatalogus": "Open PvE wens #50 (search) and #48 (register collective agreements incl. AVG and BIO terms); the incumbent lists signed addenda per supplier with a filter (https://www.softwarecatalogus.nl/addenda), which covers part of it. (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'collective agreement\\|raamovereenkomst' over src/ locales/glpi.pot returns nothing; contracts (install/mysql/glpi-empty.sql:1483) belong to the instance's own entities and nothing is shared across organisations.",
"topdesk": "unknown: collective agreements across organisations are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4496,13 +4498,13 @@
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #41 'relevante documenten zoals DPIA's, verwerkersovereenkomsten en pentesten kunnen delen zodat andere gemeenten hier eenvoudig gebruik van kunnen maken'; the incumbent only holds supplier test reports (https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier). (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: documents (src/Document.php:67) are visible only inside the instance through entities and profiles; anonymous access is limited to FAQ attachments when use_public_faq is on (src/Document.php:717), and there is no sharing with other organisations.",
"topdesk": "unknown: assets hold documents in a Documents widget, but sharing them with other organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4526,13 +4528,13 @@
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #46 'Als CISO wil ik de pakketten in mijn pakketoverzicht van een BBN classificatie voorzien'; BBN exists only as a GEMMA view per reference component per the news page (https://www.softwarecatalogus.nl/nieuws). (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'confidentialit' over src/ templates/ locales/glpi.pot returns nothing and appliances have no availability, integrity or confidentiality fields (install/mysql/glpi-empty.sql:8935 glpi_appliances); only a repurposed dropdown or a custom asset field could hold it.",
"topdesk": "unknown: no availability, integrity and confidentiality classification is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4556,13 +4558,13 @@
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #31 'meerdere pakketten kunnen selecteren en deze in een overzichtelijke tabel naast elkaar vergelijken'; the incumbent offers filtered lists only (https://www.softwarecatalogus.nl/node/13683). (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: any list can be narrowed to chosen entries with criteria (src/Glpi/Search/Input/QueryBuilder.php:72) and shows the chosen columns in one table, with installation counts per software on the software list; there is no dedicated compare view across products and no market data to compare (src/Glpi/Search/SearchEngine.php:101 searches own records only). Reached on: Assets > Software list with chosen columns.",
"topdesk": "unknown: no product comparison table is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown"
},
{
@@ -4586,13 +4588,13 @@
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #104 'Als functioneel beheerder wil ik me kunnen voordoen als een ander account'; not in the incumbent FAQ (https://www.softwarecatalogus.nl/node/16564). (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: src/Session.php:2054 startImpersonating and :2113 stopImpersonating, allowed by src/Session.php:1995 canImpersonate for users with fewer rights and the Impersonate right (src/User.php:6235); the button 'Impersonate' is on the user form (src/User.php:2974). CHANGELOG.md 11.0.0 adds the dedicated right. Reached on: Administration > Users > user form, Impersonate.",
"topdesk": "unknown: acting as another user is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown"
},
{
@@ -4616,13 +4618,13 @@
"vng-softwarecatalogus": "Open PvE wens #147; the incumbent shows whether a supplier signed the Groeipact Common Ground addendum (https://www.softwarecatalogus.nl/leveranciers), a supplier-level signal, not per product. (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: grep -rli 'common ground' over src/ templates/ locales/glpi.pot returns nothing; software and appliances carry no principle or goal declarations (install/mysql/glpi-empty.sql:6856 glpi_softwares).",
"topdesk": "unknown: Common Ground is not mentioned; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4646,13 +4648,13 @@
"vng-softwarecatalogus": "2021 user survey suggestion 'Koppelingen automatisch bijwerken bij een nieuwe versie van pakket'; release 4.1 added a manual copy of a version including its connections (https://www.softwarecatalogus.nl/node/16564, FAQ A1). (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "source read at 11.0.9: installations can be moved to another version by the massive action src/Item_SoftwareVersion.php:179 move_version, but impact relations (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) point at the item and are never copied to a replacing version or appliance; grep -n 'Impact' src/SoftwareVersion.php returns nothing.",
"topdesk": "unknown: versions of applications are not modelled; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -4677,13 +4679,13 @@
"vng-softwarecatalogus": "unknown: retention cleanup is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: closed tickets are purged after a per entity delay, src/Ticket.php:5363 cronPurgeTicket using install/mysql/glpi-empty.sql:2777 autopurge_delay, and documents left without any linked item are removed by src/Document.php:1713 cronCleanOrphansDocument (described at src/Document.php:1700); catalogue records such as appliances or contracts have no closed state or retention delay. Reached on: Administration > Entities > Assistance tab (automatic purge); Setup > Automatic actions."
},
"note": "Mined from topdesk (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown"
+ "glpi": "partial"
},
{
"id": "land-dependent-fields",
@@ -4707,13 +4709,13 @@
"vng-softwarecatalogus": "unknown: dependent fields are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: native forms show or hide questions on conditions (src/Glpi/Form/Condition/Engine.php:138, src/Glpi/Form/Condition/VisibilityStrategy.php:39), but options of one field do not filter by another on item forms; the open requests github.com/glpi-project/roadmap/discussions/414 (cascading filters) and /240 (custom field conditions) ask for it. Reached on: Administration > Forms, question conditions."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown"
+ "glpi": "partial"
},
{
"id": "land-change-entry-type",
@@ -4737,13 +4739,13 @@
"vng-softwarecatalogus": "unknown: changing an entry type is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: the type of an appliance is an editable dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id), changeable in place or by massive update (src/MassiveAction.php:666); changing the itemtype itself (for example a custom asset to another definition) is not possible, since each custom asset class is bound to one definition (src/Glpi/Asset/Asset.php:113), and the open request github.com/glpi-project/roadmap/discussions/232 asks for it. Reached on: Management > Appliances, Type field."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown"
+ "glpi": "partial"
},
{
"id": "ins-ai-action-audit",
@@ -4767,13 +4769,13 @@
"vng-softwarecatalogus": "unknown: no AI assistant is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: there is no AI assistant in core (grep -rliw 'llm\\|mcp' over src/ returns nothing); the history log (src/Log.php:48) records changes per user or API client, without any AI actor."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown"
+ "glpi": "no"
},
{
"id": "sec-multi-factor-sign-in",
@@ -4827,13 +4829,13 @@
"vng-softwarecatalogus": "unknown: a password policy is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: Setup > General > Security enables a password policy (templates/pages/setup/general/security_setup.html.twig:46 use_password_security, :56 password_min_length, :63 password_need_number, :70 password_need_letter), enforced by src/User.php:7187 validatePassword with checks for length, digits, letters, capitals and symbols (src/User.php:7196 onwards), plus expiry settings (install/empty_data.php:380 password_expiration_delay). Reached on: Setup > General > Security."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown"
+ "glpi": "yes"
},
{
"id": "ops-change-risk-score",
@@ -4857,13 +4859,13 @@
"vng-softwarecatalogus": "unknown: change management is not covered; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: changes carry manual urgency, impact and priority (install/mysql/glpi-empty.sql:659 urgency, :660 impact, :661 priority) and a free text impact analysis (:663 impactcontent); no score is computed from past outcomes or dependencies, and grep -rli 'risk' over src/Change.php returns nothing."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown"
+ "glpi": "no"
},
{
"id": "conn-auto-populate-dependencies",
@@ -5083,7 +5085,7 @@
"name": "Record that your organisation uses a module, as a usage separate from the product itself.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
@@ -5101,7 +5103,7 @@
"note": "The usage schema models this separation properly, but no stackiq page creates or edits a usage: the ObjectModal accepts type 'usage' (src/modals/Modals.vue:38) yet nothing opens it. Usages are only read by the roadmap, compliance matrix and vulnerability views.",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: municipality adds the supplier's package and version to its own landscape (\"om het pakket toe te voegen aan je omgeving\") (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E1 \"Leveranciers onderhouden de gegevens van hun producten ... Gemeenten en Samenwerkingen onderhouden de gegevens van het eigen applicatieportfolio\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten.",
- "sap-leanix": "docs, intelligence competitor_features#48860 'Fact Sheet data model (Application / IT Component / Provider)' (2026-07-23): Structured fact sheets are the core inventory unit for applications, components and providers.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/meta-model: 'An organization uses an application' as a relation between organization and application fact sheets; https://help.sap.com/docs/leanix/ea/organization-modeling-guidelines: 'Organizations are intended to address who is using certain applications' (read 2026-09-26). Reached on: Application fact sheet > Organizations relation.",
"bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository.",
"stackiq": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/",
"topdesk": "unknown: one organisation per environment; a separate usage record is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -5115,7 +5117,7 @@
"name": "Bring over what was registered in the previous catalogue, so nobody types it again.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -5133,6 +5135,7 @@
"stackiq": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets",
"topdesk": "unknown: no import from the VNG Softwarecatalogus is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: this is the previous catalogue itself; no import of an earlier registration is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/importing-fact-sheet-data-through-excel-file and https://help.sap.com/docs/leanix/ea/integration-api: bulk import from spreadsheets and a JSON based Integration API; no importer for a specific previous catalogue is documented (read 2026-09-26). Reached on: Inventory > Import; Integration API.",
"glpi": "source read at 11.0.9: data from earlier GLPI versions is carried over by src/Update.php:172 doUpdates with the chain in install/migrations/ (update_0.85.x_to_0.90.0.php up to the 11.0 steps); data from another catalogue needs the separate datainjection plugin (pluginsGLPI/datainjection tag 2.15.11, inc/backendcsv.class.php). Reached on: web installer update; plugin Data injection."
},
"pendingQuestion": "Is the data from the previous VNG Softwarecatalogus meant to be brought over by a one-off migration outside this repo (for example an OpenRegister register import of an export file)?"
@@ -5161,7 +5164,7 @@
"note": "The connection model with direction and standard is complete, and the demo data ships six, but no stackiq page creates or edits one.",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Selecteer vervolgens de betreffende pakketversie. De richting van het berichtenverkeer ... Selecteer vervolgens de betreffende standaard en versie\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > toevoegen.",
- "sap-leanix": "docs, intelligence competitor_features#27421 'Integration Architecture' (2026-04-12): Visualize data flows and integration patterns between applications",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines: 'Interfaces should have one provider application and could have multiple consumer applications', data flow direction incl. 'Bi-Directional', and 'type of transfer' (read 2026-09-26). Reached on: Inventory > Interface fact sheet.",
"bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | Rated partial because ArchiMate flow relations.",
"stackiq": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it",
"topdesk": "https://docs.topdesk.com/en/hierarchy-of-relationships.html: \"When assets are linked with a link type , one of the assets often supplies a certain feature to another asset. The supplying asset therefore is the parent asset\" (read 2026-09-26). Direction via parent and child; no standard per relation. Reached on: Asset card > Relationships widget.",
@@ -5195,6 +5198,7 @@
"stackiq": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller",
"topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Geef bij status in productie of gepland aan\"; connections are registered in the organisation's own landscape (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen.",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; interfaces belong to one workspace, and a usage of a connection separate from its existence is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: an impact relation (install/mysql/glpi-empty.sql:1247) is a single fact in one instance; there is no separate usage record saying the organisation runs it, and grep -n 'usage' src/ImpactRelation.php returns nothing."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend let an organisation record the connections it runs, through /api/koppelingen-gebruik or the objects API?"
@@ -5225,6 +5229,7 @@
"stackiq": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/",
"topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: A10: \"Een Samenwerking geeft aan welke gemeenten gebruik maken van een betreffende koppeling. Die gemeentenamen worden getoond\" (read 2026-09-26). Reached on: Alle koppelingen.",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; each workspace is one customer's own, and connections run jointly with other organisations are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: relations live inside one instance (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) and entities are subdivisions of one organisation (src/Entity.php:58); no cross organisation sharing of connections exists (grep -rli 'federat' src/ returns nothing)."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend show shared connections from /api/aangeboden-gebruik/deelnemers?"
@@ -5255,6 +5260,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Referentiecomponenten aangegeven door leverancier ... Toegevoegde referentiecomponenten\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen.",
"stackiq": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, VNG and municipal, no hits; the reference catalog offers business capability blueprints by industry (https://help.sap.com/docs/leanix/ea/reference-catalog) but GEMMA reference components are not mentioned (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'gemma\\|reference component' over src/ locales/glpi.pot returns nothing; the only classification of an appliance is its type dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id)."
},
"pendingQuestion": "Does the Modules page's CnIndexPage create/edit dialog in nextcloud-vue 2.55.1 render module.referenceComponents (hideOnForm:true, items.$ref element in the AMEF register) as a working multiselect of reference components? nextcloud-vue's fieldsFromSchema (src/utils/schema.js:529) does not check hideOnForm."
@@ -5285,6 +5291,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"de pakketten die getoond worden in het pakketoverzicht te plotten op een GEMMA architectuurkaart ... [Toon kaart]\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Toon kaart.",
"stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'gemma\\|archimate' over src/ templates/ locales/glpi.pot returns nothing; the only diagram is the impact graph (src/Impact.php:252 displayGraphView)."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend render /api/views/{id} with include_gebruik, and is that frontend in scope for stackiq's column?"
@@ -5315,6 +5322,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: cooperation packages: \"kies bij Organisaties welke gemeenten ... de betreffende applicatie gebruiken ... Het pakket verschijnt dan ook alleen op de lijst en kaart van de samenwerking en niet bij de gemeenten\" (read 2026-09-26). Drawing shared apart from own is not described. Reached on: Samenwerking > Pakketten > Organisaties.",
"stackiq": "lib/Service/ViewService.php:1187 getDeelnamesGebruikData + :924 tags shared usage with _type='deelnames' and _sourceOrganization; lib/Service/ArchiMateExportService.php:3005 org export gives every nested application the same green fillColor, deelnames only get their own folder (:3086)",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, no hits; no partner overlay on a reference view is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no GEMMA views (grep -rli 'gemma' src/ returns nothing) and no partner sharing; the impact graph (src/Impact.php:1559 makeDataForCytoscape) draws one instance's items only."
},
"pendingQuestion": "Does the external VNG frontend draw deelnames nodes differently from own usage on a GEMMA view?"
@@ -5345,6 +5353,7 @@
"stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/docs, /api/views/{viewId} -> lib/Controller/ViewController.php:82,218 (@NoAdminRequired) -> lib/Service/ViewService.php:108,166 read views from the AMEF register; GEMMA elements are element objects in the AMEF register, readable through the OpenRegister objects API",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no API over GEMMA in the catalogue is documented; GEMMA overviews are copied from GEMMA Online tables; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: the v2 API controllers (src/Glpi/Api/HL/Controller/, for example AssetController.php:149 /Assets) expose GLPI itemtypes only; grep -rli 'gemma' src/ returns nothing."
},
"pendingQuestion": "Is the view API reachable without a Nextcloud login (no #[PublicPage] on ViewController), and does the row require public access?"
@@ -5375,6 +5384,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"via de optie Voeg extra standaarden toe de gewenste standaard te selecteren ... Ondersteuning(gepland) en Compliancy\" (read 2026-09-26). Reached on: Supplier login > productversie > standaarden.",
"stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.standardVersion ($ref element, queryParams gemmaType=standaardversie) + compliancy.module + compliancy.standardGemma (string); src/manifest.json Komplianties /komplianties index on the voorzieningen register; ModuleDetail md-compliance object-list has allowCreate:false; module.standardVersions is hideOnForm",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; technology standards apply to tech stack items (https://help.sap.com/docs/leanix/ea/technology-standards-management-capabilities), declaring support for a version of an interoperability standard per application is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no standards model (grep -rli 'standaard' src/ locales/glpi.pot returns nothing); software versions (install/mysql/glpi-empty.sql:6900) carry no supported standard."
},
"pendingQuestion": "On /komplianties, does the create form's standardVersion select (items $ref element, which lives only in the AMEF register) list standard versions, or does it resolve against the voorzieningen register and come back empty/404 as the Standaarden page did before its register fix?"
@@ -5405,6 +5415,7 @@
"stackiq": "lib/Controller/AanbodController.php:200 acceptAanbod and :303 denyAanbod, lib/Service/AanbodService.php:289 checks the active organisation is aanbieder or afnemer then re-owns the object; routes appinfo/routes.php PUT /api/aanbod/{uuid}/accept, DELETE /api/aanbod/{uuid}/deny; also /api/aangeboden-gebruik/{id}/set-self and /deny",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: suppliers see \"Mijn gemeenten\" (who registered their packages) but accepting or declining a usage is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; suppliers have no role in a customer workspace, so accepting a claimed usage is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers have no login or role (install/mysql/glpi-empty.sql:7067 glpi_suppliers is a plain record; profiles in src/Profile.php:55 are for users), so no supplier can accept or decline a claimed usage."
},
"pendingQuestion": "Does the external VNG Softwarecatalogus frontend (not in this repo) call PUT /api/aanbod/{uuid}/accept and /api/aangeboden-gebruik/{id}/set-self, and is that frontend part of what we ship?"
@@ -5435,6 +5446,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle gemeenten helpt bijvoorbeeld in het verkrijgen van inzicht welke gemeenten dezelfde pakketten gebruiken ... Ook met betrekking tot een bepaald beleidsthema, referentiecomponent of standaard\" (read 2026-09-26). Reached on: Inlogmenu > Alle gemeenten / Alle pakketoverzichten.",
"stackiq": "lib/Controller/ViewController.php (routes GET /api/views, /api/views/{viewId}) enriches GEMMA views with shared usage (deelnames); src/store/modules/view.js:89 calls it but no component imports that store",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; comparison with other customers' landscapes is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no reference components (grep -rli 'reference component' src/ returns nothing) and no data from comparable organisations, since each instance is standalone (src/Entity.php:58 entities are internal)."
},
"pendingQuestion": "Does the external VNG frontend render /api/views with the deelnames enrichment, and does that count as a stackiq page?"
@@ -5445,7 +5457,7 @@
"name": "See which organisations use a given application.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -5465,6 +5477,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Marktscans: \"kunnen ingelogde gemeenten of samenwerkingen zien bij welke collega-gemeenten betreffende pakketversie in het applicatielandschap staat (klik daarvoor op het getal boven Ingevuld door)\" (read 2026-09-26). Reached on: Package page > Ingevuld door.",
"stackiq": "register :2656 usage (consumer, module); usage read rule lets aanbod-beheerder read usages where provider = own organisation (:3137); ModuleDetail md-related widget src/manifest.json:491; GET /api/koppelingen-gebruik/{uuid} and /api/gebruik in lib/Controller/AangebodenGebruikController.php, lib/Controller/GebruikController.php",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/organization-modeling-guidelines: 'Organizations are intended to address who is using certain applications', within one customer's own business units, regions and legal entities, not across outside organisations (read 2026-09-26). Reached on: Application fact sheet > Organizations relation.",
"glpi": "source read at 11.0.9: within one instance the version Summary tab shows installations per entity, src/Item_SoftwareVersion.php:850 showForVersionByEntity, and the installation list carries the entity column (src/Item_SoftwareVersion.php:484); organisations outside the instance are not visible. Reached on: Assets > Software > version > Summary tab."
},
"pendingQuestion": "Does the generic 'related' widget on ModuleDetail list usage objects that point at the module (inverse relation), and for which roles?"
@@ -5495,6 +5508,7 @@
"stackiq": "lib/Service/ReviewService.php:232 forces pending; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; src/views/settings/StackiqSettings.vue:98 ModerationQueue type=software-review via src/utils/adminApi.js; lib/Settings/register.d/catalog-ratings.json public read only matches status approved but every catalogue group reads all reviews and may create them",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no reviews are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; there are no reviews, so no review moderation is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: there are no product reviews (see mkt-reviews); the only moderation is knowledge base publication by rights on src/KnowbaseItem.php:57, unrelated to reviews."
},
"pendingQuestion": "Does the installed OpenRegister let a catalogue user create a software-review with status=approved through /reviews (the generic create), bypassing ReviewService?"
@@ -5505,7 +5519,7 @@
"name": "Keep your application landscape and connections hidden from suppliers.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "unknown",
@@ -5524,6 +5538,7 @@
"stackiq": "register usage authorization (:3137) reads scoped to _organisation or consumer; aanbod-beheerder also reads usages where provider = own organisation; connection read (:3855) public when published and by provider; openspec/specs/vendor-visibility-rbac",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E2: \"Leveranciers kunnen alleen hun eigen applicatieversies die in gebruik zijn bij gemeenten en samenwerkingen zien ... overigens ziet de leverancier geen status-informatie. Die is vertrouwelijk\" (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/manage-workspace-access: 'If a workspace has activated Invitation Only: Visible if the user is invited to this workspace and has a role'; the workspace is 'a self-contained, customer-specific environment' (https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf) (read 2026-09-26). Reached on: Administration > Workspace access.",
"glpi": "source read at 11.0.9: suppliers are records without accounts (install/mysql/glpi-empty.sql:7067 glpi_suppliers) and all data is visible only through the profiles and entities assigned to users (install/mysql/glpi-empty.sql:5917 glpi_profiles_users), so a supplier sees nothing unless given an account. Reached on: Administration > Profiles."
},
"pendingQuestion": "Does the installed OpenRegister enforce the declared authorization.read match rules (e.g. {group: aanbod-beheerder, match: {provider: $organisation}}) on usage and connection reads?"
@@ -5551,7 +5566,7 @@
"note": "The software is free and published entries are publicly readable, but the repo ships no hosted public catalogue; the public-facing frontend is the external VNG one.",
"evidence": {
"vng-softwarecatalogus": "unknown: public browsing is open (\"Iedereen kan de softwarecatalogus raadplegen\", FAQ E6) but no page states the use is free of charge; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden (read 2026-09-26)",
- "sap-leanix": "docs, intelligence competitor_features#48871 'Cloud-only SaaS, per-application tiered pricing' (2026-07-23): GAP: no self-host; priced per application tier (400/600/1000 apps), considered expensive.",
+ "sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf: usage metric 'Application' counted for the subscription, add on products 'subject to additional subscription fees'; https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Application fact sheets are counted for pricing calculations' (read 2026-09-26)",
"glpi": "source read at 11.0.9: LICENSE:1 GNU General Public License version 3, so any municipality or supplier can run it without licence fees; there is no free hosted public service, the paid cloud is GLPI Network by Teclib. Reached on: self hosted install.",
"stackiq": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; catalogService and organization carry public read rules for published entries; module's public read also admits every object with registeredBy Supplier, a rule with no publication-date or status condition (lib/Settings/softwarecatalogus_register.json:7322-7327, corrected 2026-09-26); public intake POST /api/intake/register",
"topdesk": "https://www.topdesk.com/en/pricing/: \"Essential ... £51 Per agent/month\", \"Engaged ... £72\", \"Excellent ... £101\" (read 2026-09-26)"
@@ -5582,7 +5597,7 @@
"note": "You see an 'approaching end of support' badge when you open the roadmap. A pushed warning rests only on a register declaration, and that rule addresses catalogue admins and the version's managers, not the organisations using the application.",
"evidence": {
"vng-softwarecatalogus": "unknown: suppliers set a status \"Einde ondersteuning\" and municipalities are notified of supplier changes, but an advance warning before support ends is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/pakketversies (read 2026-09-26)",
- "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | docs, intelligence competitor_features#27418 'Technology Risk Management' (2026-04-12): Track technology obsolescence and end-of-life risks",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/obsolescence-risk-management-monitor-mitigation: 'You can use automation features to initiate an end-of-life process for applications and alert the responsible individuals well before the end-of-life of an IT component' (read 2026-09-26). Reached on: Administration > Automations (end of life process).",
"stackiq": "src/views/LifecycleRoadmapView.vue:73-86 EOL passed/approaching/withdrawn badges with EOL_WINDOW_DAYS=180 (:143); lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications eol-approaching (scheduled, dateEndSupport withinNext P180D, recipients software-catalog-admins + object-acl manage) is a declaration only; no notification code in lib (no INotificationManager use)",
"topdesk": "https://docs.topdesk.com/en/events-that-trigger-actions.html: \"…when a card date will be reached within a particular period of time\" (read 2026-09-26). Works on any date field, e.g. a self-defined end-of-support date; no built-in end-of-support. Reached on: Action Management > events.",
"glpi": "source read at 11.0.9: alerts exist for dates GLPI stores, licence expiry (src/NotificationTargetSoftwareLicense.php:46 'Alarms on expired licenses'), contract end and notice (src/NotificationTargetContract.php:47) and warranty expiry (src/Infocom.php:651 cronInfocom); no end of support date exists on an application or version (install/mysql/glpi-empty.sql:6900 glpi_softwareversions). Reached on: Setup > Notifications; Setup > Automatic actions."
@@ -5595,7 +5610,7 @@
"name": "Fill in end-of-support dates automatically from a public end-of-life feed.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -5612,7 +5627,7 @@
"featureConfidence": "high",
"note": "The matcher is complete, but it is off by default, only an admin can switch it on, each module needs an eolProductSlug, and the feed data only exists when integriq's endoflife.date source is provisioned.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48863 'Technology risk & obsolescence (EOL/lifecycle)' (2026-07-23): Tracks technology lifecycle, end-of-life and obsolescence risk. | Rated partial because obsolescence tracking; source of dates not named.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/it-components-in-reference-catalog: 'When you link an IT component fact sheet to a catalog item, the fact sheet stays in sync with that metadata automatically. You no longer need to track vendor lifecycle dates manually'. Requires Technology Risk and Compliance; the catalog is SAP's own, not a public feed (read 2026-09-26). Reached on: IT Component fact sheet linked to the reference catalog.",
"stackiq": "lib/BackgroundJob/EolSyncJob.php (registered appinfo/info.xml:101) + appinfo/routes.php:292-295 /api/eol-sync/* -> lib/Service/EolSyncService.php:145 run() reads eol_cycle objects via OpenRegister ObjectService (:328), stamps dateEndSupport on module versions via EolMatcherService; enabled defaults to false (lib/Service/SettingsService.php:7211); lib/Settings/connections.json eol-feed is a switch, off until enabled; the cycles are fetched by integriq's endoflife-date source",
"topdesk": "unknown: no end-of-life feed is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: end-of-support comes from supplier input; no public feed is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -5626,7 +5641,7 @@
"name": "Record which application is planned to replace another.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "unknown",
@@ -5646,6 +5661,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json usage.plannedReplacement ($ref module) + plannedReplacementDate; read by src/views/LifecycleRoadmapView.vue:400; no usage page in src/manifest.json and navigationStore.setModal('usage') is never called (src/modals/Modals.vue:38 lists usage but nothing opens it)",
"topdesk": "unknown: no replacement link is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"geplande harmonisaties ... status gepland met bijbehorende datum ... de uit te faseren applicaties van die status worden voorzien inclusief datum\" (read 2026-09-26). No explicit replaces link. Reached on: Mijn softwarecatalogus > Pakketten > Planning.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/advanced-filter-options: 'analyze your target architecture landscape, provided that you have also modeled successors effectively'; roadmap report option 'showSuccessors' (https://help.sap.com/docs/leanix/ea/report-url-parameter-reference) (read 2026-09-26). Reached on: Fact sheet > Successor relation; Roadmap Report.",
"glpi": "source read at 11.0.9: a software can be flagged as an 'Upgrade from' another software, templates/pages/assets/software.html.twig:46 to :50 (is_update with softwares_id, install/mysql/glpi-empty.sql:6864 and :6865); this records succession after the fact, with no planned replacement link for appliances. Reached on: Assets > Software form, Upgrade from."
},
"pendingQuestion": "Is the external VNG Softwarecatalogus frontend (which writes usage objects) counted as part of stackiq for this row?"
@@ -5671,7 +5687,7 @@
"providerHow": "read-from-code",
"note": "The TIME classification is stored and reported per quadrant, but there is no page in stackiq where a user classifies an application.",
"evidence": {
- "sap-leanix": "docs, intelligence competitor_features#48862 'Application Portfolio Management' (2026-07-23): Rationalise, assess and plan the application portfolio (TIME/6R).",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/time: 'TIME stands for Tolerate, Invest, Migrate, and Eliminate. It categorizes applications based on their strategic value' (read 2026-09-26). Reached on: Application fact sheet > TIME classification.",
"stackiq": "lib/Settings/softwarecatalogus_register.json usage.timeClassification enum Tolerate/Invest/Migrate/Eliminate + timeRationale + timeReviewDate; read by lib/Service/PortfolioReportService.php and rendered in src/views/organisaties/PortfolioReport.vue:112 quadrant chart; src/modals/object/ObjectModal.vue:178 has the enum select but is never opened for usage",
"topdesk": "unknown: no TIME classification is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no TIME classification is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -5685,7 +5701,7 @@
"name": "Register a contract for a service with its number, type, term and cost.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -5705,7 +5721,8 @@
"vng-softwarecatalogus": "unknown: contracts are not described in the public docs; their absence is not stated either; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1483 glpi_contracts with name, num (contract number), contracttypes_id, begin_date, duration, notice and renewal, and costs in install/mysql/glpi-empty.sql:1458 glpi_contractcosts. Reached on: Management > Contracts. Driven on the lab at 11.0.9 (2026-09-26): created \"Lab contract\" with number C-001, start date, 12 month duration and 1 month notice.",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Contract Number (mandatory) ... Type ... Start Date (mandatory) ... End Date (mandatory) ... Costs (Services)\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM > New.",
- "stackiq": "src/manifest.json:527 Contracten type:index over catalogContract (contractNumber, contractType, startDate, endDate, cost, status); register :3252 catalogContract requires service AND usage; no manifest page has schema usage (grep src/manifest.json)"
+ "stackiq": "src/manifest.json:527 Contracten type:index over catalogContract (contractNumber, contractType, startDate, endDate, cost, status); register :3252 catalogContract requires service AND usage; no manifest page has schema usage (grep src/manifest.json)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: contract fact sheet with 'Contract Number', 'Contract Pricing Type', lifecycle phases for start, notice and end, and licensing, maintenance and support costs, linked to applications and providers (read 2026-09-26). Reached on: Inventory > Contract fact sheet (contract extension)."
},
"pendingQuestion": "Does the installed OpenRegister accept a catalogContract without the required usage (schema hardValidation false), and can the related-object picker create a usage inline?"
},
@@ -5715,7 +5732,7 @@
"name": "Get warned before a contract expires.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "partial",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -5734,7 +5751,7 @@
"note": "The only expiry warning is a declared OpenRegister notification whose filter value 'Actief' never matches the English status 'Active', so even if OpenRegister dispatches it, no contract qualifies. No page shows contracts that are about to expire.",
"evidence": {
"vng-softwarecatalogus": "unknown: contracts are not described in the public docs; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "docs, intelligence competitor_features#27427 'SaaS Management' (2026-04-12): Track SaaS usage, costs, and renewal dates | Rated partial because SaaS renewal dates.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/step-2-set-up-contract-lifecycle-automations: 'Prevent missed renewals through proactive notification workflows ... Enable timely decisions with escalation alerts before notice periods' (read 2026-09-26). Reached on: Administration > Automations (contract lifecycle).",
"stackiq": "lib/Settings/softwarecatalogus_register.json:3255 x-openregister-notifications contract-expiry filters status equals 'Actief' but the status enum is Active/Expired/In negotiation (:3428), and the subject uses {{contractNummer}}/{{eindDatum}} while fields are contractNumber/endDate; Contracten quick filter 'Expiring / expired' filters status Expired only (src/manifest.json:527)",
"topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"To prevent the accidental extension of unwanted contracts, TOPdesk warns you when contracts are about to expire\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Reminder date Date on which an operator should be reminded about the contract, e.g. ahead of expiry\" (read 2026-09-26). Reached on: Contract card > Reminder date.",
"glpi": "source read at 11.0.9: src/Contract.php:1092 cronContract computes end and notice dates and sends the events of src/NotificationTargetContract.php:47 (end of contract, notice, periodicity, periodicity notice); install/mysql/glpi-empty.sql:1508 glpi_contracts.alert sets which alerts apply. Reached on: Management > Contracts, Email alarms field; Setup > Notifications."
@@ -5768,6 +5785,7 @@
"stackiq": "lib/Service/ContractApprovalService.php:254 submitForApproval dispatches OCA\\Decidiq\\Event\\DecisionRequestedEvent (fail-closed), :412 projectOutcome sets status Active only on approved; src/manifest.json:579 ContractApprovalPanel on ContractDetail; but register :3428 status enum incl. Active is an editable form field and approvalState (register.d/contracts-to-decidesk.json) is not readOnly; the declared x-openregister-lifecycle uses Dutch states 'In onderhandeling'/'Actief' that match no enum value",
"topdesk": "https://docs.topdesk.com/en/registering-and-validating-contracts.html: \"Create a new Preliminary Contract card ... Validate the contract. You have created an active contract\" (read 2026-09-26). A validation step, no recorded approval decision. Reached on: Contract card > Validate Contract.",
"vng-softwarecatalogus": "unknown: contracts are not described in the public docs; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; contracts carry a renewal decision field and fact sheets a quality seal approval (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model), but gating a contract's activation on a recorded approval is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -n 'alidation' src/Contract.php returns nothing and no ContractValidation class exists; approvals exist only for ITIL objects (src/ChangeValidation.php:39), and the contract status is a free dropdown (install/mysql/glpi-empty.sql:1512 states_id)."
},
"pendingQuestion": "Does the installed OpenRegister enforce x-openregister-lifecycle transitions on catalogContract.status, given its states are Dutch ('Actief') and the enum is English ('Active')?"
@@ -5778,7 +5796,7 @@
"name": "See which organisations and usages are exposed to a vulnerability.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -5796,6 +5814,7 @@
"stackiq": "src/utils/vulnerabilityExposure.js:54 in-production join vulnerability.modules -> usage.module -> usage.consumer; count shown in the list (src/views/KwetsbaarhedenView.vue:111); per-organisation rows in VulnerabilityExposurePanel on KwetsbaarheidDetail tab (src/manifest.json:997), but a list row opens the edit modal, not the detail page (KwetsbaarhedenView.vue:417)",
"topdesk": "unknown: vulnerabilities are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/searching-for-sbom-library-components-by-package-url: 'Vulnerability remediation tracking: Retrieve the business applications linked to a vulnerable component ... assess the blast radius of a pkg:maven/org.apache.logging.log4j/log4j-core vulnerability'. Only for self-built software with SBOMs (read 2026-09-26). Reached on: SBOM explorer and component search API (Technology Risk and Compliance).",
"glpi": "source read at 11.0.9: no vulnerability data exists (grep -rli 'cve' src/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74), so exposure cannot be derived even though installations per entity are known (src/Item_SoftwareVersion.php:850)."
},
"pendingQuestion": "Is KwetsbaarheidDetail reachable from any page, for example by clicking a vulnerability in ModuleDetail's Related panel?"
@@ -5806,7 +5825,7 @@
"name": "Get an alert when a vulnerability is reported for software you use.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "no",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -5826,6 +5845,7 @@
"stackiq": "register.json:1622 x-openregister-notifications 'vulnerability-reported' on vulnerability, trigger created, channels nc-notification + email, recipients group software-catalog-admins and object-acl manage (a declaration only)",
"topdesk": "unknown: vulnerabilities are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/api-updates-sbom-async-processing: asynchronous SBOM processing 'will allow us to add additional post-processing mechanisms in the future, such as vulnerability checks. Though there's no established timeline' (read 2026-09-26)",
"glpi": "source read at 11.0.9: no vulnerability events among notification targets; software notifications are licence expiry only (src/NotificationTargetSoftwareLicense.php:46)."
},
"pendingQuestion": "Does the installed OpenRegister dispatch the x-openregister-notifications 'vulnerability-reported' rule on the vulnerability schema, and can recipients be the consumers of the affected modules?"
@@ -5856,6 +5876,7 @@
"stackiq": "lib/Controller/IntakeController.php:74 PublicPage + AnonRateLimit(5/h) on POST /api/intake/register; lib/Service/IntakeService.php:146 forces registrationStatus pending, publicationDate null; no caller in src/. Separately, organization authorization.create includes 'public' (register :2467)",
"topdesk": "unknown: organisations signing themselves up is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Als leverancier kunt u zich aanmelden door de volgende gegevens te sturen naar softwarecatalogus@vng.nl\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-gemeente-aanmelden: cooperations without an account \"vraag deze dan aan door een mail te sturen\" (read 2026-09-26). Sign-up by e-mail, no online form.",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; workspaces are provisioned per customer (https://help.sap.com/docs/leanix/ea/sap-for-me-super-cloud-admin-for-workspace-provisioning), self sign up of organisations is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers are created by staff only (src/Supplier.php:75 sets is_active on add from the staff form) and there is no public sign up page among front/ pages (front/lostpassword.php and front/initpassword.php are the only anonymous account pages)."
},
"pendingQuestion": "Does the external VNG frontend post to /api/intake/register, and does OpenRegister's generic public create on organization let an anonymous caller set registrationStatus/status/publicationDate directly?"
@@ -5866,7 +5887,7 @@
"name": "Turn a contact person into a user account with the right role automatically.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "partial",
@@ -5886,6 +5907,7 @@
"stackiq": "lib/Controller/ContactpersonenController.php:393 convertToUser -> lib/Service/Stackiq/ContactPersonHandler.php:292 createUserAccount reads objectData['email'] (:299); automatic path lib/EventListener/StackiqEventListener.php -> lib/Service/ContactpersoonService.php:128 also reads contactData['email']; contactPerson schema (:1788) declares no email (identity moved to Nextcloud Contacts via contactsUid); UI: src/components/ContactpersonenList.vue:97 'Convert to User' inside OrganisatieCard",
"topdesk": "https://docs.topdesk.com/en/step-2, operator-import-with-a-linked-person.html: \"To create operators with a person card linked via the Supporting Files import\" (read 2026-09-26); https://docs.topdesk.com/en/assigning-or-editing-self-service-portal-login-data.html: \"select the TOPdesk field Has access to Self-Service Portal and map it\" (read 2026-09-26). Reached on: Supporting Files imports.",
"vng-softwarecatalogus": "unknown: no conversion of contact persons into accounts is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersbeheer (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/users-overview: 'You can also invite contacts from the Subscriptions tab on a specific fact sheet'; roles come from the invitation or SSO, not automatically from the contact's role (read 2026-09-26). Reached on: Fact sheet > Subscriptions > Invite.",
"glpi": "source read at 11.0.9: contacts (src/Contact.php:45) and users are separate itemtypes with no conversion action; user accounts come from manual creation, LDAP import (src/AuthLDAP.php:59) or authorisation rules (src/RuleRight.php:297 profile action)."
},
"pendingQuestion": "Does a contactPerson created via the current form reach createUserAccount with an email (e.g. resolved from Nextcloud Contacts by contactsUid somewhere I did not find), or does conversion fail for every post-migration contact?"
@@ -5916,6 +5938,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"Handleiding beheer gemeente-samenwerking ... Samenwerkingsverbanden die als doel hebben om de applicatielandschappen van de aangesloten gemeenten te harmoniseren\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30355: cooperation selects the member municipalities per package (read 2026-09-26). Reached on: Samenwerking account > Pakketten.",
"stackiq": "register organization.type 'Collaboration' + participants/deelnames (:2236); usage.participants (:2718); shared landscape endpoint GET /api/aangeboden-gebruik/deelnemers (lib/Controller/AangebodenGebruikController.php) has no caller in src/",
"topdesk": "unknown: cooperations of organisations are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; cooperations of separate organisations sharing a landscape are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: entities form a tree (src/Entity.php:58 extends CommonTreeDropdown) and records flagged recursive are shared with all child entities (src/Appliance.php:325 is_recursive), so a parent entity can hold a landscape shared by several subordinate units; there is no cooperation of independent organisations. Reached on: Administration > Entities; Appliance Child entities field."
},
"pendingQuestion": "Does the external VNG frontend show a cooperation's shared landscape from /api/aangeboden-gebruik/deelnemers?"
@@ -5926,7 +5949,7 @@
"name": "Keep each organisation's records visible only to that organisation unless published.",
"origin": "own-code",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -5945,7 +5968,8 @@
"glpi": "source read at 11.0.9: every query on entity scoped items is restricted to the user's active entities, src/DbUtils.php:920 getEntitiesRestrictCriteria; records carry entities_id and is_recursive (install/mysql/glpi-empty.sql:8937 and :8938 on glpi_appliances), so an entity's records stay invisible to other entities unless shared down the tree. Reached on: entity selector in the header.",
"stackiq": "register authorization.read rules with {match: {_organisation: $organisation}} on catalogContract (:3474), contactPerson (:1788), usage (:3137), connection (:3855); public reads only for published entries; lib/Controller/ContactpersonenController.php:293 org guard on the custom endpoint",
"topdesk": "https://docs.topdesk.com/en/details-about-certain-permissions.html: \"To restrict access to specific data, link the operator to branch, operator, or category filters\" (read 2026-09-26). Reached on: Operator card > filters.",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E6: \"Alle gegevens ingevoerd door de gemeenten en samenwerkingen zijn alleen zichtbaar voor gemeentelijke raadplegers en beheerders\"; E2 \"Ingelogde gemeenten en samenwerkingsverbanden kunnen de applicatielandschappen en koppelingen van collega-gemeenten ... bekijken\" (read 2026-09-26)"
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E6: \"Alle gegevens ingevoerd door de gemeenten en samenwerkingen zijn alleen zichtbaar voor gemeentelijke raadplegers en beheerders\"; E2 \"Ingelogde gemeenten en samenwerkingsverbanden kunnen de applicatielandschappen en koppelingen van collega-gemeenten ... bekijken\" (read 2026-09-26)",
+ "sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf: 'Virtual workspaces to control users' read and edit permissions for fact sheets and their content in a federated organization'; https://help.sap.com/docs/leanix/ea/virtual-workspaces-configuration (read 2026-09-26). Reached on: Administration > Virtual Workspaces."
},
"pendingQuestion": "Does the installed OpenRegister evaluate authorization.read match rules with $organisation on the generic object list and detail endpoints the stackiq pages use?"
},
@@ -5975,6 +5999,7 @@
"stackiq": "lib/Service/Stackiq/ContactPersonHandler.php:646 first contact of an organisation gets the organisation-admin groups; lib/Service/Stackiq/HierarchyHandler.php:79 ensureOrganizationBeheerder and :130 setupManagerRelationships make later users report to the primary beheerder",
"topdesk": "unknown: first-user administrator rules are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/17042: \"Vanuit de gemeente is minimaal één gebruiker aangewezen als beheerder. Deze gebruiker kan nieuwe accounts aanmaken voor collega's\" (read 2026-09-26). Reached on: Gebruikersbeheer.",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; admins invite and manage users (https://help.sap.com/docs/leanix/ea/managing-users), but making an organisation's first user its administrator is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: an administrator can delegate user management per entity with a profile holding user rights, and GLPI stops a delegate from granting a profile stronger than their own, src/Profile.php:744 currentUserHaveMoreRightThan and src/Profile.php:679 getUnderActiveProfileRestrictCriteria; nothing makes the first user of an organisation its administrator automatically. Reached on: Administration > Users > Authorizations tab."
},
"pendingQuestion": "Same as org-contact-to-account: does conversion get an email for a post-migration contact?"
@@ -5985,7 +6010,7 @@
"name": "Let anyone browse the published catalogue without signing in.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -6005,6 +6030,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E6: \"Iedereen kan de softwarecatalogus raadplegen ... De gegevens ingevoerd door de leveranciers zijn openbaar\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketten: package list readable without login (read 2026-09-26). Reached on: Alle pakketten.",
"stackiq": "lib/Settings/softwarecatalogus_register.json:7307 module authorization.read grants group public on publicationDate<=$now (and, separately, on registeredBy=Supplier); lib/Settings/softwarecatalogus_register.json:1559 catalogService same; suite read is plain 'public' (lib/Settings/softwarecatalogus_register.json:1270). No stackiq route is #[PublicPage] except intake/review aggregate/gebruik (lib/Controller/GebruikController.php:102 returns an empty envelope to anonymous callers). The app's pages are all behind Nextcloud login (appinfo/routes.php:313 SPA catch-all).",
"topdesk": "unknown: the Self-Service Portal requires a login per the SSP login settings; public browsing of assets is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/portal-faqs: portals make data 'available to a broad audience outside the IT organization ... an Application Portal that is accessible to everyone'. Whether portal visitors must sign in is not stated (read 2026-09-26). Reached on: Administration > Self Service Portal.",
"glpi": "source read at 11.0.9: the only anonymous content is the public FAQ, gated by use_public_faq (src/KnowbaseItem.php:131, src/Document.php:717); asset, appliance and software lists all require a session (src/Glpi/Controller/GenericListController.php checks canView)."
},
"pendingQuestion": "Does the installed OpenRegister honour the {group: public, match: {publicationDate: {$lte: $now}}} read rule on module/catalogService for an anonymous GET /apps/openregister/api/objects, and which public frontend (the external VNG Softwarecatalogus site) is the intended browse surface?"
@@ -6033,7 +6059,8 @@
"glpi": "source read at 11.0.9: the v2 API routes without authentication are only the index, documentation and getting started pages, src/Glpi/Api/HL/Controller/CoreController.php:301, :322, :397, :407; all data routes require OAuth or session auth, and there is no supplier offering to expose.",
"stackiq": "Anonymous read of the supplier offering depends on declared rules: lib/Settings/softwarecatalogus_register.json:7307 module read includes public on publicationDate<=$now and on registeredBy=Supplier; lib/Settings/softwarecatalogus_register.json:1559 catalogService public on publicationDate. Stackiq's own offering endpoint lib/Controller/AanbodController.php (routes.php:202) is authenticated-only (@NoAdminRequired + in-body guard). Rate limit only on GebruikController (#[AnonRateLimit]).",
"topdesk": "unknown: the REST API requires an operator or API account; a public API is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
- "vng-softwarecatalogus": "unknown: no public API is documented; public data is offered as CSV downloads; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: no public API is documented; public data is offered as CSV downloads; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; all APIs authenticate with workspace tokens (https://help.sap.com/docs/leanix/ea/authentication-to-sap-leanix-services), a public API over a supplier offering is not documented (read 2026-09-26)"
},
"pendingQuestion": "Does the installed OpenRegister execute the module/catalogService public read rules for anonymous API callers, and is any API key or rate limit applied to that public surface?"
},
@@ -6043,7 +6070,7 @@
"name": "Show catalogue content on a shared external portal next to other apps' content.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
@@ -6061,6 +6088,7 @@
"stackiq": "lib/Portal/PortalContributionProvider.php:130 getContribution() declares read-only, organisation-scoped collections (catalogService, usage, catalogContract, compliancy) for the vendor-org and participant-org audiences. Portaliq discovers it by FQCN from the Stackiq in appinfo/info.xml (portaliq lib/Contribution/PortalProviderLocator.php:49/77). No info.xml dependency; inert without portaliq.",
"topdesk": "unknown: no shared external portal is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no external portal integration is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://updates.leanix.net/announcements/embed-reports-diagrams-into-portals (2025-12-22): 'Portals can also serve as the primary entry point for business users ... diagrams and reports ... can now be added to portals'; https://help.sap.com/docs/leanix/ea/portals (read 2026-09-26). Reached on: Portals.",
"glpi": "source read at 11.0.9: no embeddable widget or external portal integration for catalogue content; the self service interface (src/Glpi/Form/ServiceCatalog/ServiceCatalog.php:45) is GLPI's own helpdesk portal and grep -rli 'iframe embed\\|oembed' over src/ returns nothing."
},
"pendingQuestion": "Does the installed portaliq render stackiq's contribution (its PortalProviderLocator iterating installed apps), and is that portal live for any stackiq customer?"
@@ -6071,7 +6099,7 @@
"name": "Let an AI assistant query and update the catalogue through a tool interface.",
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "no",
@@ -6089,6 +6117,7 @@
"stackiq": "No MCP, tool-provider, TaskProcessing or ContextChat code in stackiq lib/ or src/ (grep 'mcp|ToolProvider|assistant|TaskProcessing|ContextChat' in lib/ finds nothing). OpenRegister ships a generic MCP endpoint (openregister appinfo/routes.php:1969 /api/mcp/v1/discover and the JSON-RPC endpoint) over all registers.",
"topdesk": "https://tip.topdesk.com/c/200-ai-mcp-based-service-: roadmap card in column \"Building\", \"Model Context Protocol (MCP-based service) allows secure, controlled connectivity between your TOPdesk environment and LLM-powered assistants\" (read 2026-09-26); the shipped TOPdesk Robin works inside tickets (https://docs.topdesk.com/en/td-robin-for-operators.html).",
"vng-softwarecatalogus": "unknown: no assistant or tool interface is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/mcp-server-toolsets: toolset 'inventory ... Get fact sheet information', with create tools for surveys, architecture decisions, diagrams and automations; no tool to update fact sheet fields is listed (read 2026-09-26). Reached on: MCP server (https://mcp.leanix.net/services/mcp-server/v1/mcp).",
"glpi": "source read at 11.0.9: grep -rli 'mcp\\|model context\\|openai\\|llm' over src/ returns nothing; AI tool access would go through the generic v2 API (src/Glpi/Api/HL/Controller/AssetController.php:149) with no tool interface of its own."
},
"pendingQuestion": "Does OpenRegister's MCP server expose the voorzieningen register's objects (module, catalogService, organization) for read and write to an AI client with a stackiq user's rights?"
@@ -6099,7 +6128,7 @@
"name": "Notify another system automatically when a catalogue entry changes.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -6117,6 +6146,7 @@
"stackiq": "Stackiq has no webhook code. The Flows page (src/manifest.json:1057, settings-section menu entry FlowsMenu) authors OpenRegister's native flows scoped to app stackiq; OpenRegister's flow event catalogue has object.created/object.updated (openregister lib/Service/Flow/EventCatalogService.php:53-54), and OpenRegister has its own webhooks admin (openregister appinfo/routes.php:1909).",
"topdesk": "https://docs.topdesk.com/en/let-your-topdesk-talk-to-other-applications.html: \"Send a request from TOPdesk to another program ... This way you can create an integration with almost any software that has an API\" (read 2026-09-26) triggered by card events (https://docs.topdesk.com/en/events-that-trigger-actions.html). Reached on: Action Management > action sequences.",
"vng-softwarecatalogus": "unknown: notifications go to people by mail and inbox, no system webhooks are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/webhooks: 'Webhooks let you receive updates about events as they happen in near real time ... PUSH webhooks : As events occur in SAP LeanIX , they're sent through HTTP POST requests to the specified target URL' (read 2026-09-26). Reached on: Administration > Webhooks.",
"glpi": "source read at 11.0.9: src/Webhook.php:64 Webhook sends HTTP calls on new, update and delete events (src/Webhook.php:311 getDefaultEventsList) for management itemtypes including Appliance, Budget, Contact and others (src/Webhook.php:398). Reached on: Setup > Webhooks (src/Html.php:1331). Driven on the lab at 11.0.9 (2026-09-26): Setup > Webhooks (/front/webhook.php) lists webhooks with type, event and category."
},
"pendingQuestion": "Can a flow created on stackiq's Flows page be triggered by object.updated on a catalogue schema and make an outbound HTTP call to an external system?"
@@ -6127,7 +6157,7 @@
"name": "Look back at who changed what in the catalogue, and when.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "yes",
@@ -6147,7 +6177,8 @@
"glpi": "source read at 11.0.9: src/Appliance.php:58 dohistory is true and src/Appliance.php:112 adds the Historical tab (src/Log.php:48 Log), recording who changed which field and when. Reached on: Management > Appliances > Historical tab. Driven on the lab at 11.0.9 (2026-09-26): the appliance Historical tab listed two entries, including the contract link made by glpi.",
"topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: \"History widget : shows both present and past changes that have been made to an asset\" (read 2026-09-26); https://docs.topdesk.com/en/cards-in-call-management.html: \"Audit trail tab Previous events while processing this call\" (read 2026-09-26). Reached on: Asset card > History widget.",
"stackiq": "src/manifest.json:436 (and 10 more detail pages: ContactpersoonDetail, ModuleDetail, ContractDetail, SuiteDetail, StandaardDetail, BioMaatregelDetail, ReviewDetail, KompliantieDetail, ModuleversieDetail, KwetsbaarheidDetail) declare a sidebar tab History with widget type audit, which reads OpenRegister's audit trail for that one object.",
- "vng-softwarecatalogus": "unknown: only a \"Laatst gewijzigd\" date on supplier pages and a mutation date in exports are shown; who changed what is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: only a \"Laatst gewijzigd\" date on supplier pages and a mutation date in exports are shown; who changed what is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets: the fact sheet change log shows 'Old Value / New Value', 'User', 'Time' and 'Entries in the log cannot be deleted manually' (read 2026-09-26). Reached on: Fact sheet > History log."
},
"pendingQuestion": "Is OpenRegister's audit trail enabled for the voorzieningen register on a default install, so the History tab shows entries?"
},
@@ -6177,6 +6208,7 @@
"stackiq": "src/composables/useLiveCollections.js:40 subscribes via the library's useObjectSubscription; used in src/views/KwetsbaarhedenView.vue:197, LicensePostureView.vue:209, LifecycleRoadmapView.vue:184, ComplianceMatrixView.vue:326, PortfolioReport.vue:323. The standard index pages (Contracts, Organisations and others) rely on whatever the library's CnIndexPage does.",
"topdesk": "unknown: live list updates are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no live list updates are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; target architecture diagrams apply changes immediately (https://help.sap.com/docs/leanix/ea/working-with-fact-sheets-in-diagrams), but a self refreshing inventory list is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'websocket\\|EventSource' over src/ finds only src/Glpi/Api/HL/Controller/NotificationController.php:303 'websocket: Not used by GLPI core'; lists refresh on reload only."
},
"pendingQuestion": "Does the installed OpenRegister publish or-collection-{register}-{schema} events over a transport (notify_push or SSE) that the nc-vue liveUpdatesPlugin receives, so these pages update without a reload?"
@@ -6187,7 +6219,7 @@
"name": "Receive in-app notifications about changes that concern you.",
"origin": "own-code",
"vng-softwarecatalogus": "yes",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial",
"topdesk": "partial",
@@ -6207,7 +6239,8 @@
"glpi": "source read at 11.0.9: besides mail there is a browser notification mode, src/NotificationAjax.php:42 and src/Notification_NotificationTemplate.php:56 MODE_AJAX, but it only carries events that notification targets define (tickets, changes, contracts, licences, saved search alerts and similar); changes to an appliance raise no notification event. Reached on: Setup > Notifications > Browser followups configuration.",
"stackiq": "Only declarations: x-openregister-notifications on vulnerability (lib/Settings/softwarecatalogus_register.json:1622), usage (:2662), catalogContract (:3253), software-review (:3962), module (:6781), moduleVersion (:7652). Stackiq has no INotifier or notification code of its own (grep in lib/). The contract-expiry rule filters status equals 'Actief' (lib/Settings/softwarecatalogus_register.json:3255) while the enum is Active/Expired/In negotiation, so it can never match.",
"topdesk": "https://docs.topdesk.com/en/topdesk-mobile.html: \"change your notification settings\" in the mobile app (read 2026-09-26); https://docs.topdesk.com/en/action-management.html: \"specific mobile alerts for operators\" (read 2026-09-26). Mostly email and mobile alerts, no in-app inbox described. Reached on: TOPdesk Mobile; Action Management.",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Gemeenten, samenwerkingen, en leveranciers hebben nu rechtsboven bij het inlogmenu een inbox-symbool met daarbij het aantal nieuwe berichten\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E17 \"De softwarecatalogus bevat een notificatievoorziening en een inbox voor gemeenten en samenwerkingen\" (read 2026-09-26). Reached on: Inlogmenu > Inbox."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Gemeenten, samenwerkingen, en leveranciers hebben nu rechtsboven bij het inlogmenu een inbox-symbool met daarbij het aantal nieuwe berichten\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E17 \"De softwarecatalogus bevat een notificatievoorziening en een inbox voor gemeenten en samenwerkingen\" (read 2026-09-26). Reached on: Inlogmenu > Inbox.",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/notifications: 'Notification Channels ... Email : This is the primary channel for notifications ... Microsoft Teams', for fact sheet updates, subscriptions, to-dos and surveys; no in-app channel is listed (read 2026-09-26). Reached on: User menu > My Settings > Notifications."
},
"pendingQuestion": "Does the installed OpenRegister dispatch the x-openregister-notifications rules on vulnerability, software-review, moduleVersion and the scheduled rules on catalogContract/usage/module, as Nextcloud notifications to the listed recipients?"
},
@@ -6217,7 +6250,7 @@
"name": "Extend the product with plugins installed from a marketplace.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes",
"topdesk": "partial",
@@ -6235,7 +6268,8 @@
"glpi": "source read at 11.0.9: src/Glpi/Marketplace/View.php:53 marketplace view at front/marketplace.php (src/Glpi/Marketplace/View.php:103) and src/Glpi/Marketplace/Controller.php:64 download and install of plugins; src/Glpi/Marketplace/View.php:185 notes that a registration, at least a free one, is required. Reached on: Setup > Plugins > Marketplace. Driven on the lab at 11.0.9 (2026-09-26): Setup > Plugins > Marketplace, Discover tab: \"A registration, at least a free one, is required to use marketplace\"; plugins can still be installed by hand from their repositories.",
"topdesk": "https://marketplace.topdesk.com/: \"Showing all 133 results\" of integrations (read 2026-09-26); https://docs.topdesk.com/en/exporting-and-importing.html: \"import an action sequence example from the TOPdesk Marketplace\" (read 2026-09-26). Integrations and action-sequence templates, not installable plugins. Reached on: TOPdesk Marketplace.",
"stackiq": "src/manifest.json:225 Store page (type store, footer menu StoreMenu) over the OpenRegister store plane, with store.types openregister.configset and openregister.flows; its own note says that with no registry configured it shows only the app's built-in items.",
- "vng-softwarecatalogus": "unknown: no plugins are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: no plugins are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/extension-hub: 'The SAP LeanIX extension hub is a centralized location where you can discover and install ready-to-use extensions for your SAP LeanIX workspace. These include meta model extensions, surveys, and custom reports'; public hub at https://exthub.leanix.net/en (read 2026-09-26). Reached on: Extension Hub."
},
"pendingQuestion": "Is a store registry configured on a default install, and are any stackiq configuration sets published to it?"
},
@@ -6261,13 +6295,13 @@
"vng-softwarecatalogus": "unknown: field-level permissions are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: custom fields of custom asset types can be made read only or hidden per profile, src/Glpi/Asset/CustomFieldType/AbstractType.php:79 'Readonly for these profiles' and :80 'Hidden for these profiles'; ITIL templates hide or lock ticket fields (src/ITILTemplateHiddenField.php:43, src/ITILTemplateReadonlyField.php:43). Core Appliance and Software fields have rights per itemtype only (src/Appliance.php:59 rightname). Reached on: Setup > Asset definitions > Fields; Assistance templates."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown"
+ "glpi": "partial"
}
]
}
From 4d6fb66db022a716afb0e6f453f0b9727ecd5377 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:54:23 +0200
Subject: [PATCH 26/45] feat(parity): LeanIX and BlueDolphin read 2026-09-26,
11 more demand rows, sources for all five systems
---
openspec/parity/capabilities.json | 920 ++++++++++++++++++++++++------
1 file changed, 738 insertions(+), 182 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index 87423ff52..de87c34c0 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -75,17 +75,90 @@
"key": "sap-leanix",
"name": "SAP LeanIX",
"vendor": "SAP",
- "readOn": "2026-07-23",
+ "readOn": "2026-09-26",
"evidenceGrade": "docs-only",
- "unknownReason": "Not covered by the 24 intelligence rows for this system (docs passes dated 2026-04-12 and 2026-07-23); no trial was opened."
+ "unknownReason": "The public SAP LeanIX documentation, announcements and roadmap do not cover these capabilities; GEMMA and BIO rows stay unknown because no LeanIX page mentions either.",
+ "readNote": "Public SAP LeanIX documentation read 2026-09-26 through help.sap.com public JSON endpoints, the updates.leanix.net announcements and the Productboard roadmap card data at roadmap.leanix.net. No trial, no login.",
+ "sources": {
+ "docs": "https://help.sap.com/docs/leanix/ea",
+ "sourceRepo": null,
+ "featurePage": "https://www.leanix.net/en/products/application-portfolio-management",
+ "featureRequests": "https://roadmap.leanix.net/",
+ "issueTracker": null,
+ "roadmap": "https://roadmap.leanix.net/",
+ "changelog": "https://updates.leanix.net/",
+ "apiReference": "https://help.sap.com/docs/leanix/ea/sap-leanix-apis",
+ "marketplace": "https://exthub.leanix.net/en",
+ "pricing": "https://www.leanix.net/en/enterprise-architecture/pricing",
+ "accessibilityStatement": "https://www.leanix.net/en/enterprise-architecture/accessibility",
+ "securityDocs": "https://www.leanix.net/en/products/security-and-trust",
+ "demoInstance": null,
+ "community": "https://community.leanix.net/",
+ "reviews": "https://www.peerspot.com/products/leanix-reviews",
+ "videos": "https://www.youtube.com/@SAPLeanIX",
+ "caseStudies": "https://www.leanix.net/en/customers/success-stories",
+ "partnerDirectory": null,
+ "trainingCurriculum": "https://learning.sap.com/products/business-transformation-management/leanix",
+ "jobPostings": null,
+ "tenders": null,
+ "nullReasons": {
+ "sourceRepo": "Closed source SaaS; only a public reporting library exists (github.com/leanix/leanix-reporting, named in https://help.sap.com/docs/leanix/ea/reporting-framework-and-cli), not the product source.",
+ "issueTracker": "No public issue tracker; bugs and configuration requests go to SAP for Me, which needs a login (stated in the 2026 product update newsletters on updates.leanix.net).",
+ "demoInstance": "No public demo instance; https://www.leanix.net/en/demo-eam is a demo request form, and sandbox workspaces are a paid add on.",
+ "partnerDirectory": "https://www.leanix.net/en/partner-program explains the partner program but no browsable partner directory was found; /en/partner and /en/partners/find-a-partner answer 404.",
+ "jobPostings": "LeanIX jobs are listed on jobs.sap.com (linked from the LeanIX home page), which answered 403 to scripted reads, so it could not be confirmed today.",
+ "tenders": "no tender in the intelligence database names LeanIX in its name, description or requirement text (searched 2026-09-26); category tenders for architecture tools (Helmond 398728, Breda 413833, Noord-Brabant 434026, Zutphen 363416, Apeldoorn 321765) name no product"
+ },
+ "readHow": "All checks on 2026-09-26. docs: help.sap.com is a JavaScript app, so the 663 pages of the LeanIX EA deliverable were read in full through the portal's public JSON endpoints (http.svc/deliverableMetadata and http.svc/pagecontent, curl, HTTP 200) and cited by their readable URLs; docs-eam.leanix.net and docs.leanix.net redirect there (curl -L, 200). changelog: updates.leanix.net (LaunchNotes) index pages 1 to 25 and all 171 announcements from pages 1 to 17 (Sept 2025 to Sept 2026) fetched with curl, 200. roadmap and featureRequests: roadmap.leanix.net is a Productboard portal whose card data (392 cards, Voting, In progress, On roadmap, Released) is embedded in the page and was parsed; new idea submissions are allowed per the portal config and the product updates say to share feature ideas there; card URLs follow the /c/- form the vendor uses inside its own card texts; ideas.leanix.net did not resolve (curl 000); Productboard answers 200 for any path so card paths were confirmed only through the embedded data. featurePage, pricing, accessibilityStatement, securityDocs, caseStudies: curl 200 on links taken from the leanix.net home page (pricing gives the model, per application, no public prices; the accessibility page is titled 'Accessibility Statement'). apiReference: help page read through the JSON endpoint; the OpenAPI explorer itself is inside a workspace behind login. marketplace: store.leanix.net redirects to exthub.leanix.net/en, curl 200. community: curl 200. reviews: peerspot page title 'LeanIX reviews 2026', curl 200; Gartner Peer Insights, G2 and TrustRadius answered 403. videos: YouTube page title 'SAP LeanIX - YouTube', curl 200. trainingCurriculum: learning.sap.com, curl 200. Also read: www.leanix.net/en/legal/commercial and its PDFs Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf and Operational-Terms-Exhibit-v.2.0.pdf (curl 200, text extracted). Not readable: www.sap.com trust center and accessibility pages (403), jobs.sap.com (403), g2.com, gartner.com, trustradius.com (403). The browser connection browser-3 was used only to discover the help portal's JSON endpoints; no login and no trial were used. Ruling 2026-09-26: LeanIX was read through help.sap.com public JSON endpoints and the Productboard roadmap card data."
+ }
},
{
"key": "bluedolphin",
"name": "BlueDolphin",
"vendor": "ValueBlue",
- "readOn": "2026-07-23",
+ "readOn": "2026-09-26",
"evidenceGrade": "docs-only",
- "unknownReason": "Not covered by the 22 intelligence rows for this system (docs passes dated 2026-04-12 and 2026-07-23); no trial was opened."
+ "unknownReason": "The public BlueDolphin help centre and product news do not cover these capabilities; GEMMA and BIO rows stay unknown except arch-ggm-link, which rests on a third-party Gemeente Delft README.",
+ "readNote": "Public BlueDolphin documentation read 2026-09-26 at help.bluedolphin.io and bluedolphin.io product news (ValueBlue rebranded to BlueDolphin in April 2026; the old support domains are dead or behind a challenge). No trial, no login.",
+ "sources": {
+ "docs": "https://help.bluedolphin.io/en/",
+ "sourceRepo": null,
+ "featurePage": "https://bluedolphin.io/products/",
+ "featureRequests": null,
+ "issueTracker": null,
+ "roadmap": null,
+ "changelog": "https://bluedolphin.io/product-news/",
+ "apiReference": "https://public-api.eu.bluedolphin.app/swagger/index.html",
+ "marketplace": null,
+ "pricing": "https://bluedolphin.io/pricing/",
+ "accessibilityStatement": null,
+ "securityDocs": "https://bluedolphin.io/pricing/",
+ "demoInstance": null,
+ "community": "https://community.bluedolphin.io/",
+ "reviews": "https://www.peerspot.com/products/bluedolphin-reviews",
+ "videos": "https://www.youtube.com/@bluedolphinhq",
+ "caseStudies": "https://bluedolphin.io/customer-stories/",
+ "partnerDirectory": null,
+ "trainingCurriculum": "https://bluedolphin.io/academy/",
+ "jobPostings": null,
+ "tenders": [
+ "TenderNed 421044 Tactisch beheer Blue Dolphin (Provincie Noord-Brabant, 2026-04-16)",
+ "TenderNed 367217 Tactisch beheerder Blue Dolphin (Provincie Noord-Brabant, 2025-02-11)",
+ "TenderNed 227678 onderhandse gunning Architectuurtool (Amersfoort, 2021-05-12), description names BlueDolphin"
+ ],
+ "nullReasons": {
+ "sourceRepo": "Closed source SaaS; no public repository found.",
+ "featureRequests": "No public ideas portal found; the product news page and the success page mention no ideas channel, and the community (Hivebrite) needs a login for most content.",
+ "issueTracker": "No public issue tracker; support requests go through the help center and in app chat.",
+ "roadmap": "No public roadmap found; https://bluedolphin.io/success/ says upcoming features are shown in live quarterly webinars for customers.",
+ "marketplace": "The integrations Marketplace is inside the product (paid add on, https://help.bluedolphin.io/en/articles/11967779-add-an-integration-in-bluedolphin); the Microsoft marketplace listings found by search answered 403 to scripted reads.",
+ "accessibilityStatement": "No accessibility statement or VPAT found on bluedolphin.io or in the help center.",
+ "demoInstance": "No public demo instance; a free trial needs a sign up (https://bluedolphin.app/free-trial/) and demos are booked through a form.",
+ "partnerDirectory": "https://bluedolphin.io/partners/ describes the partner program and shows logos without a browsable directory of partners.",
+ "jobPostings": "careers.bluedolphin.io redirects (301) to the LinkedIn company page, which was not read."
+ },
+ "readHow": "All checks on 2026-09-26. The vendor rebranded from ValueBlue to BlueDolphin in April 2026: support.valueblue.nl no longer resolves (DNS ENOTFOUND), valueblue.zendesk.com answers 403 with a Cloudflare challenge (also in the headless browser-3, so it was left), and www.valueblue.com fails the TLS handshake. docs: help.bluedolphin.io sitemap.xml read with curl (200) and all 267 English articles downloaded with curl (200) and grepped; every cited help URL was checked against that sitemap. bluedolphin.io answers 403 to curl, so its pages were read with WebFetch (home, products, pricing, product-news, success, integrations-partners, capability-based-planning, application-portfolio-management-application-rationalization, customer-stories and two municipality stories, academy, partners, and the product update posts of October, November and December 2025 and February, May, June and July 2026); its post, page and customer story sitemaps were read with curl (200). apiReference: Swagger at public-api.eu.bluedolphin.app answered 200 to curl and is named in the help center quick start guide. securityDocs: the pricing page lists 'SOC 2 Certified' and 'ISO 27001 Certified', BYOK and data center localization; no separate trust page was found. community: WebFetch, Hivebrite platform, mostly behind login. reviews: peerspot page, curl 200; Capterra and G2 answered 403. videos: YouTube page title 'BlueDolphin HQ - YouTube', curl 200. A third party README (github.com/Gemeente-Delft/Gemeentelijk-Gegevensmodel, raw file via curl 200) was read for the GGM row. Not readable: valueblue.zendesk.com, support.valueblue.nl, www.valueblue.com, capterra.com, g2.com, the Microsoft marketplace listings, and the LinkedIn careers target. No login and no trial were used. Ruling 2026-09-26: BlueDolphin was read from help.bluedolphin.io; ValueBlue rebranded in April 2026 and the old support domains are dead or challenged."
+ }
},
{
"key": "glpi",
@@ -306,7 +379,7 @@
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"klik dan op de knop + achter de beschrijving van het pakket om het pakket toe te voegen aan je omgeving ... Pakketversie ... Referentiecomponenten ... Vul onder Planning bij Status in gebruik in\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus: \"Wanneer Gemeenten en samenwerkingen hun applicatielandschap hebben ingevoerd, wordt deze automatisch geplot op de GEMMA referentiecomponentenkaart\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Voeg pakket toe.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Applications are software systems or programs that process or analyze business data'; application fact sheet with description and lifecycle, supplier via 'provider -> IT component -> application relation' (https://help.sap.com/docs/leanix/ea/provider-modeling-guidelines) (read 2026-09-26). Reached on: Inventory > Application fact sheet.",
- "bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository. | docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967529-welcome-to-the-objects: 'a centralized space for managing architectural objects ... create, edit, delete'; https://help.bluedolphin.io/en/articles/11967745-update-an-object-definition shows an object definition 'New Application' with property 'Supplier'; status as lifecycle state (https://help.bluedolphin.io/en/articles/11967531-object-lifecycle-state) (read 2026-09-26). Reached on: Objects > Application Component object.",
"glpi": "source read at 11.0.9: src/Appliance.php:46 class Appliance is GLPI's application itemtype; install/mysql/glpi-empty.sql:8935 glpi_appliances carries name, comment (description), manufacturers_id and states_id (status); src/Appliance.php:350 search option Status; supplier through the Management tab Infocom (install/mysql/glpi-empty.sql:3263 glpi_infocoms.suppliers_id) and Contract_Item (src/Appliance.php:99); menu src/Html.php:1300 lists Appliance under Management, served by src/Glpi/Kernel/Listener/RequestListener/LegacyItemtypeRouteListener.php:100. Reached on: Management > Appliances (front/appliance.php). Driven on the lab at 11.0.9 (2026-09-26): created the appliance \"Zaaksysteem lab\" with a description through /front/appliance.form.php; it appears in the Appliances list and CSV export.",
"topdesk": "https://docs.topdesk.com/en/migrating-objects-to-asset-management.html: \"In the new Asset Management you design your own template for each type of asset you have\" (read 2026-09-26); https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"Create a new template for software cards\" (read 2026-09-26). Applications are a self-designed asset type, no application model ships. Reached on: Modules > Asset Management > Template Designer / Asset overview > New.",
"stackiq": "src/manifest.json:592 Modules page (FacetedCatalogIndexView, schema module) with the library CnIndexPage create form at src/views/FacetedCatalogIndexView.vue:108; lib/Settings/softwarecatalogus_register.json:6777 module schema has name, shortDescription/longDescription and provider (Supplier) but NO status property; status lives on usage (register.json:2654, enum Acquisition..In production) which has no page"
@@ -319,7 +392,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
@@ -339,6 +412,7 @@
"stackiq": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')",
"topdesk": "unknown: assets can be linked parent to child, but no application module concept is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the docs model a pakket and its pakketversies only, no module level is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967518-grouping-and-child-objects-in-architecture-views: 'The child objects option allows you to define hierarchical relationships between objects based on the composition relationship type ... breaking down a system into its components' (read 2026-09-26). Reached on: View > object context menu > Child objects.",
"glpi": "source read at 11.0.9: src/Appliance_Item.php:45 links an Appliance to member items; src/autoload/CFG_GLPI.php:562 appliance_types includes Software, Appliance, Database and DatabaseInstance, so an application can be split into software and sub-appliances on its Items tab (src/Appliance.php:98). There is no module entity that belongs to a supplier product: grep -i 'module' src/Software.php src/Appliance.php returns no module concept. Reached on: Management > Appliances > Items tab."
}
},
@@ -369,6 +443,7 @@
"stackiq": "src/manifest.json:915 Moduleversies type:index (columns version, module, dateInUse, status) + :937 ModuleversieDetail; register.json:7649 moduleVersion schema with dateInUse (register.json:7746), dateInDevelopment, dateEndSupport, dateWithdrawn",
"topdesk": "unknown: no version records per application or module are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Titel is de naam van uw productversie ... Status geeft aan of uw product in ontwikkeling, in productie, of teruggetrokken is ... startdata van ontwikkeling, test en distributie\" (read 2026-09-26). Versions are recorded per package (pakketversie), not per module. Reached on: Supplier login > Productportfolio > product > plus (versie toevoegen).",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ (267 articles); versions appear only as a field in an example import source (https://help.bluedolphin.io/en/articles/11967767-uploading-a-source), no version records with dates are documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'if versioning is relevant ... you can capture it in the Release field of the application fact sheets'; each fact sheet carries lifecycle phase dates, but the guide says 'versioning for applications doesn't add significant value' (read 2026-09-26). Reached on: Application fact sheet > Name and Description > Release."
}
},
@@ -379,7 +454,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
@@ -398,6 +473,7 @@
"stackiq": "src/dialogs/SuiteWizardDialog.vue:183 onSubmit saves a suite via objectStore.saveObject('suite') with applications[] (src/utils/suiteWizard.js:44 requires at least one); mounted by src/views/suites/SuitesIndexView.vue:46 on manifest page Suites (src/manifest.json:666)",
"topdesk": "unknown: no suite bundling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no bundling of packages into a suite is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967518-grouping-and-child-objects-in-architecture-views: child objects by composition and an ArchiMate 'Grouping' object 'to cluster related elements logically'. Modeling structure only, not a product offered to others (read 2026-09-26). Reached on: View > Child objects or Grouping.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Adobe Creative Cloud is a suite that bundles various applications ... It is modeled as the parent entity'; a platform fact sheet can group applications. Modeled for the buyer's own inventory, not as a product offered to others (read 2026-09-26). Reached on: Application fact sheet hierarchy, Platform fact sheet.",
"glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:562 appliance_types contains Appliance and Software, so an Appliance can bundle existing appliances and software through src/Appliance_Item.php:45 (table install/mysql/glpi-empty.sql:8979 glpi_appliances_items). There is no notion of offering the bundle as a product to others. Reached on: Management > Appliances > Items tab."
}
@@ -409,7 +485,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "yes",
"stackiq": "yes",
@@ -428,6 +504,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: facet \"Ondersteunde technologie: On-premise, Dienst - Software as a Service (SAAS)\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30355: \"Onder het tabblad Technologie selecteer je de onderliggende technieken van het pakket. Veelal Saas of on-premise\" (read 2026-09-26). Hosting as SaaS is a property of a package version, no separate service record (hosting, support) is documented. Reached on: Alle pakketversies > filter Ondersteunde technologie.",
"stackiq": "src/manifest.json:647 Diensten page (FacetedCatalogIndexView, schema catalogService) with the CnIndexPage create form; register.json:1324 catalogService with provider (required), modules[] (register.json:1419) and type enum Functional/Application/Technical management, Implementation support, Training, Licence reseller (register.json:1459)",
"topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"Services you offer may rely on services of external suppliers. These services are called underpinning services. TOPdesk allows you to link your services to supplier services\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: \"On Call, Change (Activity), Operational Activity, Knowledge Item, Problem, and Service cards, you can link multiple assets in one go\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM > Service card > Links > Assets.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967596-archimate-annotation-translation-en-nl lists ArchiMate object definitions 'Business Service', 'Technology Service' and 'Contract', which can model a hosting or support service; no supplier service register as such is documented (read 2026-09-26). Reached on: Objects > Technology Service object.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/it-component-modeling-guidelines: IT component subtype 'Service : Services refer to the provisioning of services related to IT components (usually provided by a 3rd party) ... Examples: Maintenance/Support Service ... Hosting Service'; linked to providers (read 2026-09-26). Reached on: Inventory > IT Component fact sheet, subtype Service.",
"glpi": "source read at 11.0.9: no supplier service itemtype; services are held as contracts, src/ContractType.php:37 admin dropdown of contract types (for example hosting or support), install/mysql/glpi-empty.sql:1550 glpi_contracts_suppliers ties the contract to a Supplier and install/mysql/glpi-empty.sql:1536 glpi_contracts_items ties it to the Appliance or Software it covers. Reached on: Management > Contracts (front/contract.php), Suppliers tab."
}
@@ -439,7 +516,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
@@ -456,6 +533,7 @@
"stackiq": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395",
"topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: facets \"Domein\" (Bestuur, Fysieke leefomgeving, Sociaal domein, ...) and \"Doelgroep\" (Gemeente, Generiek, Inwoners en ondernemers, Ketenpartners) (read 2026-09-26). Domains are municipal policy domains, the catalogue serves municipalities only, not other government sectors. Reached on: Alle pakketversies > filters Domein, Doelgroep.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967603-manage-object-questionnaires: 'A questionnaire is a group of fields that add more details to objects' configured by admins, which can hold a sector field; no sector list is shipped (read 2026-09-26). Reached on: Admin > Object questionnaires.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/tags-and-custom-fields: tags and tag groups for 'quick, high-level classification', filterable and usable as reporting views; no predefined government sector list is documented (read 2026-09-26). Reached on: Fact sheet > Tags.",
"glpi": "source read at 11.0.9: no government sector concept, grep -i 'sector' over src/*.php and locales/glpi.pot hits only menu sectorization (src/Html.php:1019); the nearest holder is the single-valued Appliance type dropdown install/mysql/glpi-empty.sql:8941 appliancetypes_id, or an admin custom dropdown (install/mysql/glpi-empty.sql:10113 glpi_dropdowns_dropdowndefinitions) used as a field of a custom asset. Multi-valued tagging needs the separate tag plugin (github.com/pluginsGLPI/tag, not read). Reached on: Management > Appliances, Appliance type field."
}
@@ -467,7 +545,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "partial",
@@ -487,6 +565,7 @@
"stackiq": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')",
"topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: \"Assignment widget : assigns locations and persons to the asset\" (read 2026-09-26). No separate business and technical owner roles are described. Reached on: Asset card > Assignment widget.",
"vng-softwarecatalogus": "unknown: the landscape entry fields listed (pakketversie, referentiecomponenten, technologie, status) include no business or technical owner; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30355 (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967633-datacollector-select-tricks: an example import maps '[Application Owner]' into object properties; ownership otherwise is modeled as questionnaire fields or ArchiMate relations. No built in business and technical owner fields are documented (read 2026-09-26). Reached on: Object properties or questionnaire fields.",
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:8935 glpi_appliances holds users_id and users_id_tech; src/Appliance.php:186 search option User and src/Appliance.php:195 Group (business side), src/Appliance.php:240 'Technician in charge' and the 'Group in charge' option a few lines below (technical side). Reached on: Management > Appliances, form fields User, Group, Technician in charge, Group in charge. Driven on the lab at 11.0.9 (2026-09-26): the saved appliance holds users_id and users_id_tech (glpi_appliances row 1), shown as User and Technician in charge."
}
},
@@ -497,7 +576,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "yes",
"stackiq": "no",
@@ -516,7 +595,8 @@
"glpi": "source read at 11.0.9: native custom fields exist only for admin defined custom asset types, src/Glpi/Asset/CustomFieldDefinition.php:52 child of AssetDefinition (install/mysql/glpi-empty.sql:10159 glpi_assets_customfielddefinitions keyed on assets_assetdefinitions_id), set up under Setup > Asset definitions (src/Html.php:1330). The core Appliance and Software types take no custom fields in core; that needs the fields plugin, read at pluginsGLPI/fields tag 1.24.5, inc/container.class.php:91 containers with a list of itemtypes. Reached on: Setup > Asset definitions > Custom fields; or plugin Fields. Driven on the lab at 11.0.9 (2026-09-26): Setup > Asset definitions (/front/asset/assetdefinition.php) is where custom asset types and their fields are defined; appliances themselves take no custom fields in core.",
"stackiq": "Looked in src/manifest.json, src/views, lib/Controller: no field-definition or schema-extension UI in stackiq; the data model is fixed in lib/Settings/softwarecatalogus_register.json",
"topdesk": "https://docs.topdesk.com/en/creating-new-fields.html: \"Whether it is a contact person, a purchase price, or a reminder date ... Use fields in a fieldset or dataset widget to register any useful information about an asset\" (read 2026-09-26). Reached on: Asset Management > Template Designer > Fields.",
- "vng-softwarecatalogus": "unknown: no user-defined fields are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: no user-defined fields are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967603-manage-object-questionnaires: 'it is possible to add questionnaires to an object type in the Admin module. A questionnaire is a group of fields that add more details to objects' (read 2026-09-26). Reached on: Admin > Object questionnaires."
}
},
{
@@ -541,7 +621,7 @@
"note": "The generic index page offers a file import (CSV per schema, or a register-wide JSON/Excel) that OpenRegister executes. Nothing stackiq-specific maps a spreadsheet's supplier names to organisation references, so relation columns must already hold identifiers.",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/importing-fact-sheet-data-through-excel-file and https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: 'using the import option, you can update multiple fact sheets in bulk' via Excel export and import (read 2026-09-26). Reached on: Inventory > Import (Excel).",
- "bluedolphin": "docs, intelligence competitor_features#48971 'Data import (Excel)' (2026-07-23): Bulk import of application/portfolio data.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967629-import-and-export-options-with-bluedolphin: import 'Access databases, Excel files, and CSV files' with the DataCollector; https://help.bluedolphin.io/en/articles/11967643-use-datasource-to-create-objects (read 2026-09-26). Reached on: Admin > Sources; DataCollection Frontend.",
"stackiq": "Library CnIndexPage (@conduction/nextcloud-vue 2.55.1, package-lock) showMassImport default true (CnIndexPage.vue:1599) and self-mode handleMassImport (selfModeActions.js:168) POSTs to /apps/openregister/api/registers/{register}/import with the schema for CSV (selfModeIO.js:82); rendered on the Modules page's CnIndexPage (src/views/FacetedCatalogIndexView.vue:108)",
"topdesk": "https://docs.topdesk.com/en/generate-import-file.html: \"Importing assets speeds up this task ... export an asset template to XLSX format\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-new-import.html: \"You can use a file (CSV or XLSX), connect with an MS SQL database or import from Microsoft Intune , or Lansweeper\" (read 2026-09-26). Reached on: Settings > Import settings > Asset Management imports.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"Een import vanuit die tools naar de Softwarecatalogus zodat 2-richtingverkeer mogelijk wordt voor actualisatie, is vooralsnog niet voorhanden\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/19703: inventory goes in a spreadsheet, then \"Kies met de + toets het pakket dat opgevoerd moet worden\", one package at a time (read 2026-09-26)",
@@ -555,7 +635,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "partial",
"stackiq": "partial",
@@ -575,6 +655,7 @@
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines and https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: the application fact sheet holds lifecycle, relations to IT components, organizations, interfaces, cost on relations, and a Relations Explorer on one fact sheet (read 2026-09-26). Reached on: Inventory > Application fact sheet.",
"stackiq": "src/manifest.json:491 ModuleDetail: md-versions (:504), md-compliance (:503), md-related generic Related panel (:502); no contract widget (catalogContract links to service/usage, register.json:3250, not to module); md-data include lists stale keys beschrijvingKort/beschrijvingLang/contactpersoon (:500)",
"topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: twelve widgets incl. \"History\", \"Relationships\", \"Relationship grid\", \"Documents\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: assets linked to calls, changes, services (read 2026-09-26). Versions and compliance are not part of it. Reached on: Asset card.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967521-object-viewer: 'shows all the object properties like title, name, or lifecycle state. Also, you can see the relationships, history, objects being used in other views, or questionnaires' (read 2026-09-26). Reached on: Objects > object properties / Objectviewer.",
"glpi": "source read at 11.0.9: src/Appliance.php:98 onwards defineTabs puts Items, Contracts, Documents, Management (Infocom), Certificates, Domains, Knowledge base, Tickets, Problems, Changes and Impact on the one appliance page; versions sit on the separate Software page (src/SoftwareVersion.php:42), and no compliance tab exists (grep -i 'complian' src/Appliance.php returns nothing). Reached on: Management > Appliances > appliance form tabs."
}
},
@@ -585,7 +666,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "partial",
@@ -604,6 +685,7 @@
"stackiq": "Library CnIndexPage mass delete/copy/export (showMassDelete default true, CnIndexPage.vue:1617; selfModeActions.js:63 handleMassDelete) on index pages; stackiq's MassPublishObjects/MassLockObjects dialogs (src/dialogs/Dialogs.vue:8-14) are only opened from src/modals/object/ViewObject.vue:4865, and ViewObject is only mounted for modals 'viewOrganisatie'/'viewContactpersoon' (src/modals/Modals.vue:7,19) which nothing in src/ sets",
"topdesk": "https://docs.topdesk.com/en/editing-assets-in-bulk.html: \"select multiple assets by ticking their boxes ... You can use bulk edit for updating up to 500 assets\" (read 2026-09-26); editable are assignments, drop-down, date, number, text and checkbox fields. Bulk publish or delete is not described. Reached on: Asset Management > Asset overview > select > bulk edit.",
"vng-softwarecatalogus": "unknown: no multi-select publish, lock or delete is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967533-edit-multiple-objects: 'edit multiple objects at the same time'; the API offers 'Delete multiple objects' (https://help.bluedolphin.io/en/articles/11967756-delete-multiple-objects); no publish or lock action (read 2026-09-26). Reached on: Objects > Edit selected objects.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: 'switch to table view in the inventory, you can perform inline editing across multiple fact sheets'; https://help.sap.com/docs/leanix/ea/archiving-deleting-and-recovering-fact-sheets: 'Archiving Fact Sheets in Bulk' through an Excel action column. No publish or lock action is documented (read 2026-09-26). Reached on: Inventory > Table view; Excel import with action column.",
"glpi": "source read at 11.0.9: every search list offers massive actions, src/MassiveAction.php:666 Update (any field, for example status), src/MassiveAction.php:698 Put in trashbin, src/MassiveAction.php:652 Delete permanently, src/MassiveAction.php:656 Restore. There is no publish state; locking applies to inventory fields only. Reached on: any list, for example Management > Appliances, Actions button. Driven on the lab at 11.0.9 (2026-09-26): the Appliances list carries the massive actions control."
}
@@ -632,6 +714,7 @@
"stackiq": "src/components/organisations/OrganisationMergePanel.vue:46 (admin-only controls) mounted as OrganisatieDetail bodyWidget org-merge (src/manifest.json:430); lib/Controller/MergeController.php:106 execute with isAdmin check at :142; generic src/modals/object/MergeObject.vue only mounted for modal 'mergeOrganisatie' which nothing sets",
"topdesk": "https://docs.topdesk.com/en/migration-status.html: \"You cannot merge the two cards into one card\" (read 2026-09-26); https://tip.topdesk.com/c/239-ai-cmdb-monitoring-: roadmap card in column \"Under consideration\", \"AI can continuously scan your configuration database for duplicate records ... and surfaces them for review\" (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no merge of entries is described; the news page only mentions a pseudo-supplier \"Open Source Pakketten\" created against duplicate spellings; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/nieuws (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; imports merge source records that share a key into one object (https://help.bluedolphin.io/en/articles/11967635-four-things-you-need-to-know-before-you-start-importing-sources), but merging two existing entries by a user is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea (all 663 EA pages grepped for merge); duplicates are handled by archiving (https://help.sap.com/docs/leanix/ea/archiving-deleting-and-recovering-fact-sheets 'removing outdated or duplicate fact sheets'), no merge of two fact sheets is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/Software.php:109 'Merging' tab on a recursive software, src/Software.php:926 showMergeCandidates lists same named software, src/Software.php:997 massive action Merge, src/Software.php:1011 private function merge moves versions and licences into the kept entry; dropdowns get Replace, src/CommonDropdown.php:680. Reached on: Assets > Software > Merging tab."
}
@@ -658,7 +741,7 @@
"note": "Nothing asks owners to confirm or correct their entries.",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/reviewing-responses: 'Review and approve survey responses before they are saved to fact sheets'; https://help.sap.com/docs/leanix/ea/application-modernization-collect-data: 'Create a new survey to get key information from application or business owners' (read 2026-09-26). Reached on: Surveys.",
- "bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967524-create-a-survey: surveys 'gather input from stakeholders outside your core BlueDolphin users ... allowing external stakeholders to contribute directly to the Enterprise Architecture repository' on an object's questionnaire (read 2026-09-26). Reached on: Object > Questionnaire tab > Create survey.",
"stackiq": "No survey, attestation or owner-confirmation code in lib/ or src/ (searched survey/enquete/confirm entry)",
"topdesk": "unknown: Survey Management runs general surveys (and \"will reach end of life ... November 2026\"), not confirmation of entries by owners; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C7: \"Leveranciers krijgen ook periodiek notificatiemails met een aantal automatische controles en de Te corrigeren fouten staan ook op het dashboard van ingelogde leveranciers\" (read 2026-09-26); https://www.softwarecatalogus.nl/suggesties_overnemen: suppliers send suggestions that municipalities accept or decline (read 2026-09-26). No survey to application owners.",
@@ -672,7 +755,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
@@ -689,6 +772,7 @@
"stackiq": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)",
"topdesk": "unknown: the only readiness score described is the AI readiness score for the knowledge base; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/voortgang-verbeteren: \"Met het aantal sterren (*) wordt een indicatie van volledigheid van ingevulde gegevens aangegeven\", criteria include referentiecomponenten filled, statuses, koppelingen and \"Datum laatste wijziging is recenter dan 3 maanden geleden\" (read 2026-09-26). Scored per organisation, not per application entry. Reached on: Homepage block Voortgang gemeenten; organisation page header.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967713-governance-insights: governance report 'Object completeness : Lists all objects and the completeness score of each object' (read 2026-09-26). Reached on: Insights > Governance reports > Object completeness.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/fact-sheet-completeness: 'The fact sheet completion score measures how much of the required data has been filled out for a fact sheet ... You can view the fact sheet completion score in the fact sheet's header' (read 2026-09-26). Reached on: Fact sheet header > completion score.",
"glpi": "source read at 11.0.9: grep -ril 'completeness' over src/ templates/ locales/glpi.pot returns nothing; no score of how filled in an item is exists in core. The item form tabs (src/Appliance.php:98 onwards) show no score."
}
@@ -700,7 +784,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
@@ -717,6 +801,7 @@
"stackiq": "src/manifest.json:3 setup wizard step load-demo-data (:24); lib/Controller/SetupController.php:202 runAction load-demo-data (AuthorizedAdminSetting); lib/Service/DemoDataService.php:202 install() imports lib/Settings/stackiq_mock_register.json (120 objects, 6 per schema) through OpenRegister ConfigurationService::importFromApp",
"topdesk": "unknown: no example data set is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the catalogue is one hosted service; no loadable example data set is described (a \"VNG Realisatie Demo\" supplier appears in the live data); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967592-download-and-update-the-templates-in-the-library: 'A quick way of getting started with BlueDolphin and discovering its possibilities is by downloading a standard template'; standard templates are 'Preconfigured BlueDolphin sites that can contain objects, views, questionnaires' (https://help.bluedolphin.io/en/articles/11967590-introduction-to-templates) (read 2026-09-26). Reached on: Admin > Templates > Library > Standard templates.",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; demo and sandbox workspaces are mentioned (https://help.sap.com/docs/leanix/ea/automations 'Demo and sandbox workspaces allow up to 10,000 automations per month') but loading an example data set into a workspace is not described (read 2026-09-26)",
"glpi": "source read at 11.0.9: on a clean install dashboards render placeholder figures from src/Glpi/Dashboard/FakeProvider.php:65 FakeProvider, with the banner 'You are viewing demonstration data.' and a 'Disable demonstration' button (src/Glpi/Dashboard/Grid.php:427, :428, :448); CHANGELOG.md 11.0.0 lists it. No example records (applications, contracts, suppliers) are loaded; the console entry point src/Glpi/Console/Application.php:66 has no demo data command. Reached on: Home > Dashboard on a fresh install. Driven on the lab at 11.0.9 (2026-09-26): glpi_configs.is_demo_dashboards is 1 on the fresh install, so the dashboard cards come from FakeProvider until an administrator disables the demonstration."
}
@@ -745,6 +830,7 @@
"stackiq": "src/dialogs/SuiteWizardDialog.vue (3 steps) is the only wizard, opened from src/views/suites/SuitesIndexView.vue:46; applications, services and connections use the bare CnIndexPage form (FacetedCatalogIndexView.vue:108) or nothing",
"topdesk": "unknown: wizards exist for imports and migration, not for adding an application; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the manuals describe forms (\"Hierna opent een formulier\"), no step-by-step wizard; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30355 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; creating an object is a form (https://help.bluedolphin.io/en/articles/11967530-create-a-new-object), and the survey setup has three steps, but a step by step wizard for adding an application is not documented (read 2026-09-26)",
"sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/creating-fact-sheets describes creating a fact sheet in the inventory with reference catalog suggestions and duplicate hints, not a step by step wizard; wizards are documented only for KPI and integration mapping configuration (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'wizard' over src/ templates/ locales/glpi.pot returns nothing for item creation; appliances are added through the plain form only (install/mysql/glpi-empty.sql:8935 glpi_appliances has no is_template column)."
}
@@ -773,6 +859,7 @@
"stackiq": "src/components/sbom/SbomComponentsPanel.vue lists sbomComponent rows (name/version/purl/licenses) as the ModuleversieDetail 'Components' sidebar tab (src/manifest.json:961); register.json:7920 sbomComponent schema",
"topdesk": "unknown: no software components per version are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no third-party component list per version is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for SBOM and bill of materials, no hits (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/uploading-sboms-from-fact-sheets: 'Upload SBOM files directly from a microservice fact sheet'; https://help.sap.com/docs/leanix/ea/tech-stack-discovery-from-sboms: 'the system automatically analyzes the SBOM components and builds a structured view of your technology stack'. Part of SAP LeanIX Technology Risk and Compliance (read 2026-09-26). Reached on: Microservice fact sheet > SBOM (Technology Risk and Compliance).",
"glpi": "source read at 11.0.9: grep -ril 'sbom\\|cyclonedx\\|spdx' over src/ templates/ locales/glpi.pot returns nothing; software versions carry no component list (install/mysql/glpi-empty.sql:6900 glpi_softwareversions)."
}
@@ -784,7 +871,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
@@ -804,6 +891,7 @@
"stackiq": "register.json:6869 module.cloudDienstverleningsmodel enum On-premises, IaaS, PaaS, SaaS; register.json:6906 hostingLocation and hostingJurisdiction; usage.cloudDienstverleningsmodel (register.json:3050); on ModuleDetail md-data include (src/manifest.json:500)",
"topdesk": "unknown: only possible as a self-defined field; no hosting model is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Indien een leverancier zowel SaaS als On premise ondersteunt, kan je aangeven welke van deze twee varianten gebruikt wordt binnen de gemeente\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen > tabblad Technologie.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967633-datacollector-select-tricks: an example import carries '[Hosting Type]' into object properties; hosting is otherwise modeled with ArchiMate technology objects. No built in hosting field is documented (read 2026-09-26). Reached on: Object properties or questionnaire field.",
"glpi": "source read at 11.0.9: no hosting model field; the closest holders are the admin editable Environment dropdown on an appliance, src/Appliance.php:277 ApplianceEnvironment search option (install/mysql/glpi-empty.sql:8945 applianceenvironments_id), plus locations_id and the Appliance type dropdown. grep -i 'saas' over src/ finds nothing; 'On-premise' in locales/glpi.pot:12997 is only an icon label. Reached on: Management > Appliances, Environment field."
}
},
@@ -833,6 +921,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"De richting van het berichtenverkeer, de landelijke voorziening waarmee gekoppeld is/wordt, in dit geval GGK\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus: \"kunnen koppelingen tussen applicaties onderling en met Landelijke Voorzieningen vastgelegd worden\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > koppeling toevoegen.",
"stackiq": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection",
"topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; connections are generic ArchiMate relationships between objects (https://help.bluedolphin.io/en/articles/11967550-working-with-object-relationships), national provisions such as basisregistraties are not mentioned (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Modeling External Applications ... applications of business partners, service providers, authorities', linked 'through an interface to analyze dependencies'. Generic external application modeling, no catalogue of national provisions such as basisregistraties (read 2026-09-26). Reached on: Application fact sheet (external) + Interface fact sheet.",
"glpi": "source read at 11.0.9: no national provision concept (grep -ril 'basisregistratie' src/ locales/glpi.pot returns nothing); a provision can be held as another Appliance and linked through an impact relation, install/mysql/glpi-empty.sql:1247 glpi_impactrelations (source item, impacted item, name), with Appliance enabled for impact at src/autoload/CFG_GLPI.php:649. Reached on: Appliance > Impact analysis tab, Add relation."
}
@@ -844,7 +933,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
@@ -863,6 +952,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle koppelingen ... staan de koppelingen van alle gemeenten en samenwerkingsverbanden ... Door te klikken op het icoontje rechts van een koppeling, krijg je nog enige detail informatie\" (read 2026-09-26). Reached on: Inlogmenu > Alle koppelingen (logged-in municipal users).",
"stackiq": "No manifest page with schema connection (src/manifest.json and src/manifest.d/*.json); the Integrations page (src/manifest.d/connection-registry.json:23) lists integriq app_connection, explicitly not stackiq's connection schema (its _note)",
"topdesk": "unknown: relations are shown per asset and in a graphical overview; a list of all relations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967713-governance-insights: governance report 'Objects and relationships : Lists all relations between two objects with relevant information like relation definition, related object title', with clickable object titles. A report, not a dedicated connections page (read 2026-09-26). Reached on: Insights > Governance reports > Objects and relationships.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines: 'Interfaces are connections between applications that illustrate how data exchange occurs', each a fact sheet listed in the inventory by fact sheet type (read 2026-09-26). Reached on: Inventory > filter fact sheet type Interface.",
"glpi": "source read at 11.0.9: src/ImpactRelation.php:39 ImpactRelation has only prepareInputForAdd and getIDFromInput (src/ImpactRelation.php:47, :107), no search options and no list page; relations are only seen per item in the Impact analysis tab (src/Impact.php:91). Driven on the lab at 11.0.9 (2026-09-26): /front/impactrelation.php opens by URL only (no menu entry) as a generic list whose only criterion and column is ID, so relations cannot be browsed by endpoint; rating unchanged."
}
@@ -874,7 +964,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "partial",
@@ -893,6 +983,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Mijn pakketoverzicht ... Onder het eerste tabblad zitten de pakketten en onder het tweede tabblad de koppelingen\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: \"Door op een applicatienaam in het Models venster te klikken, zie je in de Visualiser alle koppelingen tussen die applicatie met andere applicaties\" (in Archi after export) (read 2026-09-26). No per-application connection view inside the catalogue is described. Reached on: Mijn softwarecatalogus > Koppelingen.",
"stackiq": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"Links between assets are created and managed via the Relationships widget. For current relationships with other assets, the widget shows the template's icon, the Asset ID\" (read 2026-09-26). Generic asset relations, not interfaces. Reached on: Asset card > Relationships widget.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967550-working-with-object-relationships: 'select the Objects and go to the Relationships tab ... View the current relationships of an object' (read 2026-09-26). Reached on: Objects > object > Relationships tab.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/circle-map-report: the Interface Circle Map 'helps you track changes and updates in application dependencies', and https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: relations incl. interfaces shown on the fact sheet and in the Relations Explorer (read 2026-09-26). Reached on: Application fact sheet > Relations (Provided and Consumed Interfaces).",
"glpi": "source read at 11.0.9: src/Impact.php:91 getTabNameForItem adds the 'Impact analysis' tab (src/Impact.php:80) to every impact enabled itemtype, Appliance and Software included (src/autoload/CFG_GLPI.php:649 and :663), with a list view src/Impact.php:270 displayListView of every related item in both directions. Reached on: Management > Appliances > Impact analysis tab. Driven on the lab at 11.0.9 (2026-09-26): the appliance page carries an Impact analysis tab with Add assets for every impact enabled item type."
}
@@ -921,7 +1012,7 @@
"note": "No page draws connections. The ArchiMate export can be opened in Archi, but it carries GEMMA views and usages, not the catalogue's connections.",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/data-flow: data flow diagrams help 'understand how applications are connected, identify dependencies, and trace data movement between systems' (read 2026-09-26). Reached on: Diagrams > Data Flow Diagram.",
- "bluedolphin": "docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models. | docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin: 'insight into connections between business processes, applications, and their underlying infrastructure. This way, you can visualize chains and information flows'; https://help.bluedolphin.io/en/articles/11967545-spider-tool adds related objects with 'all existing relationships' to a view (read 2026-09-26). Reached on: Views > architecture view.",
"glpi": "source read at 11.0.9: src/Impact.php:252 displayGraphView and src/Impact.php:1559 makeDataForCytoscape draw the relation network, with editing tools add asset, add relation, add group at src/Impact.php:1160. Reached on: Appliance > Impact analysis tab, graph view. Driven on the lab at 11.0.9 (2026-09-26): the Impact analysis tab renders the graph editor with Add assets, Edit group and Edit edge tools.",
"stackiq": "No diagram rendering in src/ (no graph library; src/store/modules/view.js GET /api/views has no importer outside itself); lib/Service/ArchiMateExportService.php exports GEMMA views as ArchiMate XML without koppeling objects (no 'koppeling' in lib/Service/ArchiMate*)",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"After you define the relationship between assets, you can use the graphical overview to see a visual representation of their relationship\" (read 2026-09-26). Reached on: Asset card > graphical overview.",
@@ -949,7 +1040,7 @@
"providerHow": "read-from-code",
"note": "The only way to see what depends on an application is the generic list of objects that reference it, which OpenRegister's relation index fills. There is no impact view or retirement check.",
"evidence": {
- "bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin: 'overlapping application functions are quickly made visible, and their impact analyses are available in no time'; spider tool shows derived relationships (https://help.bluedolphin.io/en/articles/11967545-spider-tool) (read 2026-09-26). Reached on: Views > spider tool.",
"glpi": "source read at 11.0.9: src/Impact.php:49 class Impact 'Impact analysis', src/Impact.php:713 bfs walks the graph by direction and src/Impact.php:612 buildListData lists what is impacted, with ongoing tickets, problems and changes on impacted items (src/Impact.php:313). Reached on: Tools > Impact analysis (src/Html.php:1309) and the item's Impact analysis tab.",
"topdesk": "https://docs.topdesk.com/en/managing-disruptions-in-your-asset-management-process.html: \"you want to know how far the reach of the disruption is ... the operational/impacted status for assets ... Status impacts are also only shown in the graphical overview when a link type is used\" (read 2026-09-26). Disruption impact, not a pre-change dependency analysis. Reached on: Asset card > General widget > Determine status automatically.",
"stackiq": "src/manifest.json:502 ModuleDetail md-related (library CnRelatedObjectsWidget: /used lists every object that references this module: usages, connections, suites, services, vulnerabilities); no dependency or impact computation in lib/ or src/",
@@ -964,7 +1055,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
@@ -981,6 +1072,7 @@
"stackiq": "register.json:3563 connection.type enum (file transfer, digikoppeling, message que, webservices, api, ...) exists, but no connection list page to filter",
"topdesk": "unknown: custom link types exist, but filtering relations by type is not described; https://tip.topdesk.com/c/90-graphical-overview-improvements is still under consideration; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: connections carry a standard and \"het soort overdracht\" (upload naar portaal, webservices), but the docs do not name a type filter on the connection list; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967713-governance-insights: 'Objects and Relationships (with metadata): Select a source object definition, a relationship type, and a target object definition'; relationship types follow ArchiMate definitions, not API or file exchange categories (read 2026-09-26). Reached on: Insights > Objects and Relationships (with metadata).",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines: interface subtypes 'Logical interface, API, MCP server' and 'You can capture data flow directions, type of transfer, and frequency with the interface fact sheet'; subtypes and fields are filterable in the inventory (read 2026-09-26). Reached on: Inventory > Interface > filter by subtype or transfer type.",
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1247 glpi_impactrelations has only a free name besides the two endpoints, no connection type (API, file, message), so there is nothing to filter on; the graph settings (src/Impact.php:1167 impact_settings) cover depth and direction."
}
@@ -992,7 +1084,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
@@ -1010,6 +1102,7 @@
"stackiq": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label",
"topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no register of APIs an application exposes is described; standards are declared instead; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967596-archimate-annotation-translation-en-nl lists the ArchiMate object definition 'Application Interface' (Applicatie-interface), which can hold an application's APIs as related objects; no API catalogue feature is documented (read 2026-09-26). Reached on: Objects > Application Interface object.",
"glpi": "source read at 11.0.9: no API entity in core, grep -ril 'openapi' src/*.php finds no itemtype for exposed APIs; an admin can define an 'API' custom asset type (src/Html.php:1330 Setup > Asset definitions, src/Glpi/Asset/AssetDefinition.php) and attach it to the application as an Appliance item (src/Appliance_Item.php:45) or impact relation (install/mysql/glpi-empty.sql:1247). Reached on: Setup > Asset definitions, then Appliance > Items tab."
}
},
@@ -1020,7 +1113,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "unknown",
"stackiq": "no",
@@ -1040,6 +1133,7 @@
"stackiq": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*",
"topdesk": "unknown: exporting the relation graph is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: \"Pakketten én koppelingen worden in 1 model geëxporteerd ... AMEFF-export\" (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Mijn koppelingen: Knop [Exporteren] op tabblad Koppelingen\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten or Koppelingen > Exporteren > AMEFF-export.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967514-download-a-view: a view downloads as 'PNG, SVG, PDF, and AMEFF format ... You can use AMEFF files to exchange Architecture views between different applications that support ArchiMate'. The graph is exported per drawn view (read 2026-09-26). Reached on: View > Download > AMEFF.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams: diagrams export 'in the following formats: PDF, SVG, PNG, HTML embed code, and XML' and open in draw.io; https://help.sap.com/docs/leanix/ea/exporting-fact-sheet-data-as-excel-file exports fact sheet data. No export of an application's relation graph as data is documented as such (read 2026-09-26). Reached on: Diagrams > Export (XML, draw.io); Inventory > Export."
}
},
@@ -1050,7 +1144,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "partial",
"stackiq": "partial",
@@ -1067,6 +1161,7 @@
"stackiq": "src/manifest.d/connection-registry.json:23 Integrations page (register integriq, schema app_connection) with visibleIf appInstalled 'integriq' (:17) and permission admin (:15,:27); Add integration handler leaves for integriq (src/services/connectionRegistry.js:43); rows synced from lib/Settings/connections.json (email, federation, eol-feed); status worked out by integriq",
"topdesk": "https://docs.topdesk.com/en/connections.html: \"TOPdesk offers a storage space for usernames, passwords, and authentication tokens used in automated actions ... Better overview: Observe when specific credentials are applied\" (read 2026-09-26); https://docs.topdesk.com/en/using-the-automated-actions-overview.html: \"contains all asset actions, webhooks, scheduled actions ... The last execution status\" (read 2026-09-26). Reached on: Settings > Connections; Action Management > Automated Actions.",
"vng-softwarecatalogus": "unknown: no overview of the catalogue's own outside integrations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967779-add-an-integration-in-bluedolphin: 'Click Add integration in the bottom right corner of the Marketplace page' for TOPdesk, ServiceNow and JIRA; 'Marketplace (Integration) is a paid add-on' (read 2026-09-26). Reached on: System settings > Marketplace > Add integration.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/discovering-ai-agents-using-api: 'Go to the Integrations section in the administration area. Choose Add Integration'; https://help.sap.com/docs/leanix/ea/collibra-data-catalog-integration: 'Administration > Integrations > Sync Log' to check each integration (read 2026-09-26). Reached on: Administration > Integrations (Add Integration, Sync Log).",
"glpi": "source read at 11.0.9: outside integrations are set up on separate Setup pages, not one overview: src/Html.php:1331 Webhook, src/Html.php:1333 OAuthClient and MailCollector, Auth (LDAP, SSO) on src/Html.php:1332; src/Webhook.php:64 Webhook and src/OAuthClient.php:45 OAuthClient each have their own list. Reached on: Setup > Webhooks, Setup > OAuth clients, Setup > Authentication."
}
@@ -1094,7 +1189,7 @@
"featureConfidence": "high",
"note": "Works end to end but only a Nextcloud admin can import: the endpoint rejects non-admins and the upload control lives only on the admin settings page.",
"evidence": {
- "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27459 'ArchiMate & BPMN Support' (2026-04-12): Full ArchiMate and BPMN modeling in one platform | Rated yes because full ArchiMate support; import format not named in the reading.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967637-import-ameff-files: 'AMEFF stands for the ArchiMate Model Exchange File Format ... Click the Upload AMEFF file button' with 'Map and import Objects, Map and import Relationships, Import Views' (read 2026-09-26). Reached on: Admin > System > Import.",
"stackiq": "appinfo/routes.php:96 POST /api/archimate/import -> lib/Controller/SettingsController.php:1490 importArchiMate (isAdmin check :1496) -> lib/Service/ArchiMateImportService.php (5961 lines); UI src/views/settings/sections/ArchiMateImportExport.vue:32 file input + :791 importArchiMateFile",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: only export to AMEFF is documented; importing an ArchiMate file into the catalogue is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools (read 2026-09-26)",
@@ -1126,7 +1221,7 @@
"note": "The export produces a downloadable AMEF XML, but only from the admin settings page; organisation admins may call the API but have no page for it.",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: \"De softwarecatalogus ondersteund een koppeling met architectuurtools. Dit wordt gedaan via de exportfunctionaliteit van een ArchiMate Exchange Format-bestand ... Archi (Open Source), Bizzdesign, Mavim, Sparx, Dragon1 en Value Blue\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Exporteren > AMEFF-export.",
- "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967514-download-a-view: 'AMEFF Generates an AMEFF export file (only for Architecture views)'. Export is per view, not of the whole catalogue (read 2026-09-26). Reached on: View > Download > AMEFF.",
"stackiq": "appinfo/routes.php:97 POST /api/archimate/export -> lib/Controller/SettingsController.php:1615 exportArchiMate (admin or org-admin via verifyOrgExportPermission :1735) -> lib/Service/ArchiMateService.php:232 exportToArchiMate (docblock: organization filter 'currently not implemented'); UI ArchiMateImportExport.vue:591 'Export Base' button",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; exports are PDF, SVG, PNG, HTML and draw.io XML (https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams); no ArchiMate exchange format export is documented, ArchiMate 3.2 is only a visual template (https://help.sap.com/docs/leanix/ea/styles-and-patterns) (read 2026-09-26)",
@@ -1159,6 +1254,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools: export file named \"GEMMA_Softwarecatalogus__ameff_model\" (read 2026-09-26); https://www.softwarecatalogus.nl/Archi_modellen_samenvoegen: \"De export van de Softwarecatalogus bevat de GEMMA en alle pakketten en koppelingen van de gemeente\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: \"GEMMA views met daarop geplot de pakketten van de gemeente\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Exporteren > AMEFF-export.",
"stackiq": "appinfo/routes.php:98 GET /api/archimate/export/organization/{organizationUuid} -> lib/Controller/SettingsController.php:1685 exportOrgArchiMate -> lib/Service/ArchiMateService.php:302 -> lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications in GEMMA view copies; UI ArchiMateImportExport.vue:602 'Organization Export' with Modules/Deelnames/Gebruik checkboxes",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for GEMMA, no hits; views export to AMEFF (https://help.bluedolphin.io/en/articles/11967514-download-a-view), but an organisation's landscape plotted on GEMMA is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no GEMMA content and no ArchiMate file export are documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'archimate\\|gemma' over src/ templates/ locales/glpi.pot returns nothing; no GEMMA plotting or per entity model export. Export formats are src/Glpi/Search/Output/Csv.php:38 and src/Glpi/Search/Output/Pdf.php:43, no model file."
}
@@ -1189,6 +1285,7 @@
"stackiq": "appinfo/routes.php:107 POST /api/archimate/test-round-trip -> lib/Controller/SettingsController.php:2886 (@NoAdminRequired, any logged-in user) -> lib/Service/ArchiMateService.php:1496 testRoundTrip: reads $importResult['imported_count'] (:1528), a key no import path sets, and compares it to exportToArchiMate's 'exported_count' which is the literal string 'calculated_in_export_service' (:271), so it can never report success; it also imports a test model into the live register",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the merge guide checks the result inside Archi via its status log; the catalogue itself offers no round-trip check; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Archi_modellen_samenvoegen (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; AMEFF import and per view AMEFF export exist (https://help.bluedolphin.io/en/articles/11967637-import-ameff-files, https://help.bluedolphin.io/en/articles/11967514-download-a-view), but a check that a model survives the round trip is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no model file import and export pair (ArchiMate or similar) is documented, so no round trip check exists in the docs (read 2026-09-26)",
"glpi": "source read at 11.0.9: there is no model import or export to round trip, grep -ril 'archimate' over src/ templates/ locales/glpi.pot returns nothing. Export formats are src/Glpi/Search/Output/Csv.php:38 and src/Glpi/Search/Output/Pdf.php:43, no model file."
}
@@ -1219,6 +1316,7 @@
"stackiq": "appinfo/routes.php:103 POST /api/archimate/import/cancel -> lib/Service/SettingsService.php:5200 calls ArchiMateService::cancelArchiMateImport(), which does not exist in lib/Service/ArchiMateService.php (Error, not caught by catch(\\Exception)); routes.php:119-120 /api/progress/{operationId} read ProgressTracker, but the ArchiMate import never writes to it (only SbomImportService gets it, lib/AppInfo/Application.php:507); ArchiMateImportExport.vue:538 shows only a spinner, no cancel button",
"topdesk": "unknown: ArchiMate is not mentioned anywhere in the documentation (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no model import is documented; for export only \"Er verschijnt een venster met de melding dat de export gegenereerd wordt\"; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools (read 2026-09-26)",
+ "bluedolphin": "unknown: https://help.bluedolphin.io/en/articles/11967637-import-ameff-files says only 'When BlueDolphin has completed the action, a checkmark will appear'; progress while running and cancelling are not documented (read 2026-09-26)",
"sap-leanix": "https://updates.leanix.net/announcements/product-update-march-2026: 'The new asynchronous import process runs entirely in the background ... A real-time progress widget in the inventory side-panel keeps you informed of import status'. This is the Excel import, not a model import, and cancelling is not described (read 2026-09-26). Reached on: Inventory side panel > import progress widget.",
"glpi": "source read at 11.0.9: no model import exists (grep -ril 'archimate' src/ returns nothing), so there is no import to follow; the generic progress endpoint src/Glpi/Controller/ProgressController.php serves other long operations. The progress route is src/Glpi/Controller/ProgressController.php:50 /progress/check/{key}, used by the installer (src/Glpi/Controller/InstallController.php:57)."
}
@@ -1249,6 +1347,7 @@
"stackiq": "src/manifest.json StandaardDetail /standaarden/:id st-data widget shows all element fields (documentation, gemmaNotes) of a standard; FacetedCatalogIndexView.vue:150 shows reference components by name only",
"topdesk": "unknown: GEMMA is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/lexicon: lexicon of catalogue terms (Addendum, Referentiecomponent, Standaard, SaaS); terms in page text link to it (read 2026-09-26); https://www.softwarecatalogus.nl/node/13683: \"Alle referentiecomponenten ... de toelichting bij de referentiecomponenten\" (read 2026-09-26). Reached on: Lexicon; Alle referentiecomponenten.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for GEMMA, no hits; object definitions follow ArchiMate (https://help.bluedolphin.io/en/articles/11967599-object-definitions) but in place definitions of GEMMA terms are not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no GEMMA terms and no in-place glossary of reference architecture terms are documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -ril 'gemma\\|glossary' over src/ templates/ locales/glpi.pot returns nothing; no reference term definitions ship in core. The knowledge base (src/KnowbaseItem.php:57) is the only place definitions could be written by hand."
}
@@ -1277,7 +1376,7 @@
"note": "The mapping to GEMMA reference components exists, but there is no map view in stackiq; you only see it as a facet list or in Archi after an admin export.",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/meta-model: 'A business capability is supported by an application'; https://help.sap.com/docs/leanix/ea/application-portfolio-assessment lists a 'Business capability map' (read 2026-09-26). Reached on: Reports > Landscape Report on Business Capabilities.",
- "bluedolphin": "docs, intelligence competitor_features#27460 'Application Portfolio Management' (2026-04-12): Map applications to business goals and functions",
+ "bluedolphin": "https://bluedolphin.io/capability-based-planning/: 'Drag and drop multi-layer current and future state capability mapping' and 'Drill down instantly from capability scores to the processes, applications, and technologies'; https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'Connect applications to capabilities' (read 2026-09-26). Reached on: Views > capability map.",
"stackiq": "module.referenceComponents / usage.usedForReferenceComponents in lib/Settings/softwarecatalogus_register.json hold the application-to-reference-component mapping; lib/Service/ArchiMateExportService.php:2734 draws it only into exported view copies",
"topdesk": "unknown: no capability or function map is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"de pakketten die getoond worden in het pakketoverzicht te plotten op een GEMMA architectuurkaart ... [Toon kaart]\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: view \"RD02 Bedrijfsfuncties ruimtelijk domein met referentiecomponenten\" with the municipality's packages plotted (read 2026-09-26). Mapping runs through fixed GEMMA reference components and business functions, not the organisation's own capability model. Reached on: Mijn softwarecatalogus > Pakketten > kaart kiezen > Toon kaart.",
@@ -1306,7 +1405,7 @@
"note": "Models are imported and exported as ArchiMate files; nothing lets a user draw or edit a model inside stackiq.",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams and https://help.sap.com/docs/leanix/ea/working-with-fact-sheets-in-diagrams: free draw and data flow diagrams edited in the diagram editor, with an ArchiMate 3.2 shape template (https://help.sap.com/docs/leanix/ea/styles-and-patterns) (read 2026-09-26). Reached on: Diagrams > New Diagram (diagram editor).",
- "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#48968 'Free-form diagramming' (2026-07-23): Freeform diagrams alongside formal models.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967507-create-an-architecture-view and https://help.bluedolphin.io/en/articles/11967516-add-objects-to-architecture-views: users create and edit ArchiMate architecture views in the view editor (read 2026-09-26). Reached on: Views > Create view.",
"stackiq": "src/manifest.json has no page for the view or element schema beyond Standaarden; no diagram editor in src/views or src/components",
"topdesk": "unknown: no architecture modelling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the docs send users to Archi or other tools for modelling; drawing inside the catalogue is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30890 (read 2026-09-26)",
@@ -1334,7 +1433,7 @@
"providerHow": "read-from-code",
"note": "Business processes are not modelled; the only link applications have is to GEMMA reference components.",
"evidence": {
- "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | docs, intelligence competitor_features#27464 'Process Mapping' (2026-04-12): Map processes, applications, data, and technology",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967673-process-linked-to-ea-perspectives: 'The Create BPMN diagram button allows you to create a diagram directly from a business process'; https://help.bluedolphin.io/en/articles/11967500-getting-started-with-process-publication-portal: 'For each application, you will find different processes in which the selected application is involved' (read 2026-09-26). Reached on: Processes > Process browser.",
"stackiq": "no process schema in lib/Settings/softwarecatalogus_register.json (20 schemas listed under components.schemas); no process page in src/manifest.json",
"topdesk": "unknown: no process modelling linked to applications is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no process modelling is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -1349,7 +1448,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
@@ -1367,6 +1466,7 @@
"stackiq": "searched src/manifest.json and the register for scenario/future-state/toekomst: nothing; usage.status 'Planned' and plannedReplacement (register) are per-usage fields, not a comparable landscape",
"topdesk": "unknown: Long-Term Planning scenarios are for maintenance planning and the module \"will reach end of life ... November 2026\"; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"geplande harmonisaties ... met een status gepland met bijbehorende datum. Zo kan ook het uiteindelijke doel-landschap in 1 overzicht inzichtelijk worden gemaakt\" (read 2026-09-26). No side-by-side comparison of today and target. Reached on: Mijn softwarecatalogus (samenwerking) > Pakketten > status Gepland.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967531-object-lifecycle-state: 'Objects can be either Current (default) or Future state. Select the Future option to reflect how the object will look in the future', shown distinctly on views; https://bluedolphin.io/capability-based-planning/: 'Map current and future state capabilities' (read 2026-09-26). Reached on: Objects and views with Current and Future lifecycle state.",
"glpi": "source read at 11.0.9: grep -rli 'future state\\|what-if\\|scenario' over src/*.php returns nothing; the impact graph (src/Impact.php:49) shows only the current relations, with no plateau or target landscape."
}
},
@@ -1377,7 +1477,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "partial",
"sap-leanix": "partial",
- "bluedolphin": "yes",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
@@ -1391,7 +1491,7 @@
"providerHow": "read-from-code",
"note": "No report or view lists reference components that no application in your landscape covers.",
"evidence": {
- "bluedolphin": "docs, intelligence competitor_features#48967 'Multi-modal analysis (gaps / dependencies)' (2026-07-23): Analyses ArchiMate/BPMN/free-form models to surface gaps and weak dependencies.",
+ "bluedolphin": "https://bluedolphin.io/capability-based-planning/: 'Run gap analyses to define a clear roadmap' and 'Identify capability gaps'. Gaps are found on the customer's own capability map; no reference architecture such as GEMMA is documented (read 2026-09-26). Reached on: Capability maps.",
"stackiq": "grep for uncovered/gap/coverage in lib and src found nothing; lib/Service/FacetService.php counts modules per reference component but never lists components with zero coverage",
"topdesk": "unknown: GEMMA reference components are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tile \"Pakketten met meer mogelijkheden: U heeft in uw pakketoverzicht pakketten die geschikt zijn voor referentiecomponenten waarbij u nog geen pakket heeft opgevoerd\" (read 2026-09-26). It lists uncovered components only where an owned package could fill them. Reached on: Dashboard tile Pakketten met meer mogelijkheden.",
@@ -1420,7 +1520,7 @@
"providerHow": "read-from-code",
"note": "Nothing drafts diagrams.",
"evidence": {
- "bluedolphin": "docs, intelligence competitor_features#48970 'AI-powered diagramming' (2026-07-23): AI assists diagram generation. | docs, intelligence competitor_features#27461 'AI-Powered Diagramming' (2026-04-12): Auto-generate BPMN diagrams with built-in AI",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/12528662-ai-capabilities-of-bluedolphin: 'Modelling Assistant or BPMN Generator instantly creates BPMN 2.0-compliant process diagrams from a simple prompt or by uploading existing documentation' (read 2026-09-26). Reached on: Processes > Modeling Assistant.",
"stackiq": "no diagram generation in lib/Service or src; no AI integration for diagrams",
"topdesk": "unknown: the AI features cover tickets and knowledge, not diagrams; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no assistant is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -1454,6 +1554,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle standaarden: Dit overzicht is een opsomming van alle standaarden waaraan pakketten mogelijk moeten voldoen. Alle standaarden hebben een toelichting en indien aanwezig een toelichting op het compliancy-instrument\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle standaarden.",
"stackiq": "src/manifest.json page Standaarden /standaarden (index on @resolve:amef_register schema element, filter gemmaType=standaard, columns name/gemmaThema/gemmaStatus/url) and StandaardDetail /standaarden/:id with compliance claims per standard; menu entry Standards (order 50)",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no register of standards applications must support is documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/technology-standards-management-capabilities: Technology Risk and Compliance helps 'establish technology standards' for frameworks and languages. These are technology standards for components, not interoperability standards an application must support (read 2026-09-26). Reached on: Technology Risk and Compliance > technology standards.",
"glpi": "source read at 11.0.9: no standards itemtype, grep -ril 'standaard\\|forum standaardisatie' src/ locales/glpi.pot returns nothing and the word standard in src/Appliance.php occurs only in addStandardTab (src/Appliance.php:100)."
}
@@ -1465,7 +1566,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
@@ -1484,6 +1585,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.evidence (file, pdf/jpeg/png/doc, 10 MB), compliancy.url, compliancy.evidenceReference; src/manifest.json KompliantieDetail cm-files widget type integration integrationId files 'Evidence documents'",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Door de vakje achter de standaard aan te vinken voor Ondersteuning(gepland) en Compliancy, wordt de optie om een testrapport of auditrapport op te voeren geopend\" (read 2026-09-26). Reached on: Supplier login > productversie > Voeg extra standaarden toe.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967535-object-attachments: 'You can enrich your Blue Dolphin objects with additional information from saved files'. Files attach to the object, not to a specific compliance claim (read 2026-09-26). Reached on: Object > General tab > attachments.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets: 'The Resources tab ... You can upload files up to 10 MB' and links on any fact sheet. Files attach to the fact sheet, not to a specific compliance claim (read 2026-09-26). Reached on: Fact sheet > Resources tab.",
"glpi": "source read at 11.0.9: any document can be attached to an appliance through the Documents tab, src/Appliance.php:100 Document_Item tab and src/Document_Item.php:46, stored in install/mysql/glpi-empty.sql:2585 glpi_documents; there is no compliance claim to attach it to. Reached on: Management > Appliances > Documents tab."
}
@@ -1514,6 +1616,7 @@
"stackiq": "src/utils/complianceMatrix.js:9-17 cell state verified = compliancy record with evidence (hasEvidence :107 checks evidence/evidenceReference/url), claimed = link without evidence; rendered by src/views/ComplianceMatrixView.vue",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C8: \"Gepubliceerde testrapporten voor een aantal standaarden die in de compliancy-monitor staan, worden sinds eind 2016 door VNG Realisatie gecontroleerd en daarna op status goedgekeurd of afgekeurd gezet\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketversies: facet \"Standaard met testrapport: Toon alleen pakketversies met compliancy aangetoond in een testrapport\" (read 2026-09-26). Reached on: Alle pakketversies > filter Standaard met testrapport; Compliancy monitor.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no distinction between verified and asserted compliance claims is documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; a quality seal approves fact sheet data as a whole (https://help.sap.com/docs/leanix/ea/updating-lifecycle-phase-and-approving-quality-seal) but no distinction between verified and supplier asserted compliance claims is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no compliance claim model, grep -rli 'complian' over src/Appliance.php src/Software.php returns nothing; nothing to mark verified or claimed (src/Appliance.php:46 fields are inventory and management fields only)."
}
@@ -1544,6 +1647,7 @@
"stackiq": "src/manifest.json ComplianceMatrix /compliance-matrix custom page -> src/customComponents.js ComplianceMatrixView -> src/views/ComplianceMatrixView.vue (modules x selected standard versions or BIO measures, src/utils/complianceMatrix.js:270 columns)",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/compliancy_monitor: per standard (e.g. \"Betalen en invorderen services 1.0\") a table of Leverancier, Pakketversie, Compliancy \"Ok\" or \"Niet ok\" (read 2026-09-26). Fixed per standard, not a matrix of chosen applications against chosen standards. Reached on: Homepage > Compliancy monitor.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; heat maps by conditional layout and a Power BI relations cross-table exist (https://help.bluedolphin.io/en/articles/11967711-power-bi-for-bluedolphin-quickstart), but a matrix of applications against standards is not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/meta-model-dora-extension: 'You can create a regulatory dictionary, categorize DORA requirements, and link DORA obligations directly to specific IT and business architecture elements'; https://help.sap.com/docs/leanix/ea/report-types: Matrix Report maps relations cell by cell. Regulation obligations, not interoperability standards (read 2026-09-26). Reached on: DORA extension + Reports > Matrix Report.",
"glpi": "source read at 11.0.9: there are no standards in core (grep -rli 'standaard\\|forum standaardisatie' src/ locales/glpi.pot returns nothing), so no application by standard matrix; search output (src/Glpi/Search/Output/Spreadsheet.php) only tabulates item fields. The spreadsheet output is src/Glpi/Search/Output/Csv.php:38 and siblings."
}
@@ -1574,6 +1678,7 @@
"stackiq": "appinfo/routes.php:275 POST /api/bulk-sync-standards -> lib/Controller/SettingsController.php:3598 (isAdmin check) -> lib/Service/ModuleComplianceService.php:527 bulkSyncModuleStandards (reads up to 1000 compliancy records and updates module standards); UI src/views/settings/sections/StatisticsOverview.vue:79 button -> src/modals/BulkSyncDialog.vue:321",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: only per-version copying is described (\"opvoer van een nieuwe versies mogelijk als kopie van een op te geven vorige versie\"); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no standards set to refresh across applications is documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no action that refreshes the standards set of many applications is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no standards model exists (see comp-standards-register); massive actions (src/MassiveAction.php:666 Update) update item fields only."
}
@@ -1604,6 +1709,7 @@
"stackiq": "src/manifest.json BioMaatregelen /bio-maatregelen index (columns code,name,thema,bioVersion,bbnNiveau) and BioMaatregelDetail; register property is bbnLevel (lib/Settings/softwarecatalogus_register.json bioMeasure), so the bbnNiveau column is empty; no BIO catalogue is seeded (only 6 demo objects in lib/Settings/stackiq_mock_register.json)",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: BIO measures are not in the catalogue docs; BBN views live on GEMMA Online per the news page; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/nieuws (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for BIO and Baseline Informatiebeveiliging, no hits; the only security template is an 'ISO27001 Management System template' for 'an Information Security Management System' (https://help.bluedolphin.io/en/articles/11967582-iso27001-management-system-template), not the BIO measure set (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for BIO and Baseline Informatiebeveiliging, no hits; LeanIX documents DORA and GDPR content only (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'iso 27001\\|27002' and grep -rwi 'bio' over src/ locales/glpi.pot return nothing; no security measure catalogue ships (menus at src/Html.php:1295 onwards list none)."
}
@@ -1634,6 +1740,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.bioMeasure links a module to a BIO measure; src/manifest.json ModuleDetail md-compliance lists claims incl. bioMaatregel column, BioMaatregelDetail bm-compliance lists modules per measure; compliancy has no status/met-not-met field",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no BIO assessment per application is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for BIO, no hits; recording which BIO measures an application meets is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for BIO, no hits; no BIO measure assessment per application is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no measure catalogue and no assessment itemtype; grep -rli 'iso 27001\\|27002' over src/ locales/glpi.pot returns nothing and Appliance tabs (src/Appliance.php:98 onwards) hold no assessment."
}
@@ -1664,6 +1771,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json module.dpiaStatus (enum not required/required/executed), dpiaDate, dpiaNextAssessment, dpiaDocumentRef; src/manifest.json ModuleDetail md-data includes the DPIA fields; Modules /modules quick filter 'Without DPIA (BBN2+)'",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no DPIA field is described; the VWO addendum is a supplier-level processing agreement; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/leveranciers (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for DPIA, GDPR and AVG, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for DPIA and data protection impact assessment, no hits; only data classification of data objects for GDPR is documented (https://help.sap.com/docs/leanix/ea/data-object-modeling-guidelines 'classified into personally identifiable data (e.g., to cater to GDPR use cases)') (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'dpia\\|impact assessment\\|gdpr' over src/ returns nothing, locales/glpi.pot:12792 'gdpr-tools' is only an icon name. The GDPR records plugin yild/gdprropa read at tag 1.0.3 has 'PIA required' and 'PIA status' (inc/record.class.php:459, :468) but declares GLPI 10 only, setup.php:56 max 10.99.99, so it does not run on 11.0.9."
}
@@ -1692,6 +1800,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/inkoopondersteuning%20standaarden: \"De verplichte standaarden zijn: ... de open standaarden die onder het pas-toe-of-leg-uit regime van de overheid binnen het werkingsgebied vallen\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: package version shows \"Verplichte standaarden ... Ondersteuning Compliancy Testrapport\" (read 2026-09-26). Comply-or-explain standards are mixed into the mandatory set, not shown as their own list. Reached on: Package page > Standaarden; Inkoopondersteuning.",
"stackiq": "grep for forum standaardisatie / pas toe of leg uit / comply-or-explain in lib and src: no hits; standards come only from the GEMMA AMEF import (element gemmaType=standaard)",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for Forum Standaardisatie, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for Forum Standaardisatie and comply or explain, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'standaard\\|forum standaardisatie\\|comply' over src/ locales/glpi.pot returns nothing relevant; no comply or explain list in core (Setup menu src/Html.php:1330 onwards)."
}
@@ -1703,7 +1812,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
@@ -1720,6 +1829,7 @@
"stackiq": "grep for completeness/health score/quality score in lib and src: no hits; lib/Command/ReferencesAuditCommand.php:34 (occ stackiq:references:audit) only audits cross-app uuid references, it is not a scored rule set",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C7: automatic checks and \"Te corrigeren fouten ... Bijvoorbeeld over het ontbreken van pakketversies, of tegenstrijdigheid in de status van een pakketversie en vermelde datum distributie\" (read 2026-09-26); https://www.softwarecatalogus.nl/voortgang-verbeteren: star criteria for completeness (read 2026-09-26). Reached on: Supplier dashboard Te corrigeren fouten; Voortgang sterren.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967713-governance-insights: 'Governance reports will help maintain oversight of object usage, completeness, and relationships', incl. 'Object completeness ... completeness score of each object' and 'Objects not on any view' (read 2026-09-26). Reached on: Insights > Governance reports.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-portfolio-management-dashboard: 'Data Quality KPI ... Overall Completion of Applications ... Broken quality seal ... Missing Business Capability'; completion score weights set by admins (https://help.sap.com/docs/leanix/ea/fact-sheet-completeness) (read 2026-09-26). Reached on: Dashboards > Application Portfolio Management Dashboard > Data Quality KPIs.",
"glpi": "source read at 11.0.9: grep -ril 'completeness' over src/ templates/ locales/glpi.pot returns nothing and no rule set scores register quality; the rules engine (src/Glpi/Rules/, src/RuleCollection.php) assigns and imports data, it does not score it. The rules engine base is src/RuleCollection.php:48."
}
@@ -1731,7 +1841,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
- "bluedolphin": "partial",
+ "bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
@@ -1745,7 +1855,7 @@
"providerHow": "read-from-code",
"note": "Nothing sends questionnaires to suppliers or stores their answers.",
"evidence": {
- "bluedolphin": "docs, intelligence competitor_features#48974 'Questionnaires / data collection' (2026-07-23): Surveys to gather portfolio data from stakeholders. | Rated partial because questionnaires collect portfolio data.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967524-create-a-survey: surveys 'allowing external stakeholders to contribute directly to the Enterprise Architecture repository', sent 'to multiple recipients simultaneously via email' from an object's questionnaire, answers kept on the object (read 2026-09-26). Reached on: Object > Questionnaire tab > Create survey.",
"stackiq": "grep for questionnaire/vragenlijst in lib and src: no hits; no questionnaire schema in lib/Settings/softwarecatalogus_register.json",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no questionnaire to suppliers is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -1779,6 +1889,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"Deze handleiding is bedoeld voor de leveranciers en legt uit hoe de leveranciers hun productportfolio kunnen aanvullen en beheren ... voeg pakket toe\" (read 2026-09-26). Reached on: Supplier login > Productportfolio.",
"stackiq": "src/manifest.json:592 Modules and :647 Diensten are FacetedCatalogIndexView over schema module/catalogService (CnIndexPage, showAdd default true); lib/Settings/softwarecatalogus_register.json:6779 module has provider + publicationDate (visible on form) and public read when publicationDate <= now or registeredBy Supplier",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; BlueDolphin is a per customer EA repository, supplier publication of offerings is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; LeanIX is a customer's internal EA workspace, no supplier facing publication of offerings is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers are records kept by the buying organisation, install/mysql/glpi-empty.sql:7067 glpi_suppliers, with no supplier login or offering page; profiles (src/Profile.php) cover internal users and the self-service helpdesk only."
}
@@ -1809,6 +1920,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Ik ben op zoek naar een nieuw pakket voor referentiecomponent voor BAG-administratie\" and standards filters combine (read 2026-09-26); https://www.softwarecatalogus.nl/pakketten: facets Referentiecomponent and Standaard (read 2026-09-26). Reached on: Alle pakketten > filters.",
"stackiq": "lib/Service/FacetService.php:109 DIMENSIONS referenceComponent, standard, applicationService, domain for schemas module and catalogService (:102); src/views/FacetedCatalogIndexView.vue:108 CnFacetSidebar narrows CnIndexPage; route GET /api/facets/{schema} called from src/services/facets.js",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no market wide software search is documented (read 2026-09-26)",
"sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/applications-in-reference-catalog: the catalog 'covers SAP applications, SAP AI agents, and SaaS applications' and is used to link your own fact sheets; market search by reference component and standard is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: search covers only the organisation's own records (src/Glpi/Search/SearchEngine.php); there is no market wide catalogue and no reference component or standard to filter on (grep -ril 'gemma\\|reference component' src/ returns nothing). The marketplace (src/Glpi/Marketplace/) lists GLPI plugins, not software for a task. The search engine is src/Glpi/Search/SearchEngine.php:101; the marketplace is src/Glpi/Marketplace/Controller.php:64."
}
@@ -1837,6 +1949,7 @@
"stackiq": "src/manifest.json:386 Organisaties type:index over schema organization with status filter and OrganisatieCard; register :2022 organization.type is facetable (Municipality/Supplier/Collaboration/Community); public read of Active suppliers in organization authorization (:2467)",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/leveranciers: \"Leveranciers ... Zoek in leveranciers ... 354 resultaten gevonden\", filter \"Met ondertekend addendum\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle leveranciers.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no directory of suppliers across the market is documented (read 2026-09-26)",
"sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/provider-modeling-guidelines: 'SAP LeanIX has a catalog of 9000 providers' added automatically with IT components; browsing that catalog as a directory with filters is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/Supplier.php:46 Supplier list under Management (src/Html.php:1298) with search, filters and a supplier type (install/mysql/glpi-empty.sql:7072 suppliertypes_id), but it holds only the suppliers this organisation entered, not all organisations offering to government. Reached on: Management > Suppliers (front/supplier.php). Driven on the lab at 11.0.9 (2026-09-26): created supplier \"Lab Leverancier BV\" through /front/supplier.form.php; it appears in the Suppliers list."
}
@@ -1865,6 +1978,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle gemeenten ... inclusief contactgegevens van gemeenten ... U kunt contact onderhouden met deze gemeenten\" (read 2026-09-26). Reached on: Inlogmenu > Alle gemeenten.",
"stackiq": "Looked in src/components, src/views and lib/Controller for any contact or messaging between organisations sharing a module: none. Usage read rules (register :3137) hide other organisations' usages from municipalities.",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; a vendor community is referenced in the docs (https://help.bluedolphin.io/en/articles/11967582-iso27001-management-system-template 'a post on the community'), but finding peers who use the same product is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; a vendor community exists (https://community.leanix.net/) but no in product way to find organisations using the same product is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: each GLPI instance holds one organisation's data (entities are internal subdivisions, src/Entity.php), so there is no view of other organisations using the same product; grep -rli 'peer' src/*.php matches only relation and network code such as src/CommonDBConnexity.php, no peer organisation feature."
}
@@ -1895,6 +2009,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle pakketversies en planningen ... gelijk zichtbaar de planning van de diverse pakketversies\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketversies: facet \"Status planning ... Filter op in ontwikkeling en zie de distributie planningsdata\" (read 2026-09-26). Reached on: Wat is er te vinden > Alle pakketversies en planningen.",
"stackiq": "register :7651 moduleVersion with status enum in development/in use/end of support/withdrawn and dateInDevelopment/dateInUse/dateEndSupport, read public; src/manifest.json:915 Moduleversies index + ModuleversieDetail",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; roadmap templates are for the customer's own plans (https://help.bluedolphin.io/en/articles/11967586-roadmap), suppliers' declared roadmaps are not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/it-components-in-reference-catalog: 'The catalog provides standardized IT component data including lifecycle dates, vendor information ... You no longer need to track vendor lifecycle dates manually'. Vendor lifecycle and support dates, not planned releases; needs Technology Risk and Compliance (read 2026-09-26). Reached on: IT Component fact sheet linked to the reference catalog.",
"glpi": "source read at 11.0.9: suppliers (install/mysql/glpi-empty.sql:7067 glpi_suppliers) carry address and contact fields only, and software versions (install/mysql/glpi-empty.sql:6900) carry no planned release date; grep -rli 'roadmap' src/*.php returns nothing."
}
@@ -1925,6 +2040,7 @@
"stackiq": "src/manifest.json:514 ModuleDetail bodyWidget ReviewsPanel; src/components/reviews/ReviewsPanel.vue:63 opens SubmitReviewModal; POST /api/reviews -> lib/Service/ReviewService.php:232 stamps author and forces status pending; rating 1..10 in software-review schema (:3961)",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no reviews are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; user reviews with ratings of applications are not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no user review of an application with a rating is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no product review model; satisfaction surveys rate ticket handling only (src/CommonITILSatisfaction.php) and knowledge base comments (src/KnowbaseItem_Comment.php) carry no rating. Ticket satisfaction is src/CommonITILSatisfaction.php:43 and knowledge base comments src/KnowbaseItem_Comment.php:43."
}
@@ -1955,6 +2071,7 @@
"stackiq": "lib/Service/ReviewAggregateService.php:51 approved-only average + count; GET /api/reviews/aggregate (PublicPage) called from src/utils/reviewAggregate.js imported by src/components/reviews/ReviewsPanel.vue",
"topdesk": "unknown: TOPdesk is a single-organisation tool; no market-wide catalogue is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no ratings are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no review ratings exist in the docs to aggregate (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no review ratings exist in the docs to aggregate (read 2026-09-26)",
"glpi": "source read at 11.0.9: with no product reviews there is no average rating; the only averages are ticket satisfaction statistics (src/CommonITILSatisfaction.php). Ticket satisfaction is src/CommonITILSatisfaction.php:43."
}
@@ -1983,6 +2100,7 @@
"stackiq": "register :6856 module.contactPerson -> contactPerson with x-relation-filter organization = @object.provider; catalogService and suite also carry contactPerson; src/manifest.json:500 ModuleDetail md-data include lists 'contactpersoon', 'beschrijvingKort', 'beschrijvingLang', which are not module properties (renamed to contactPerson/shortDescription/longDescription)",
"topdesk": "unknown: supplier contacts are registered per supplier (\"Registering a supplier contact\"); contacts per product are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the docs name one contact per supplier (\"Bij elke leverancier is een contactpersoon opgevoerd\"); whether a product can carry its own is not stated; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/30402 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; supplier contact persons per product are not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; subscriptions name internal users per fact sheet, but supplier contact persons per product are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: contacts link to a supplier as a whole, src/Contact_Supplier.php:39 (install/mysql/glpi-empty.sql:1429 glpi_contacts_suppliers), not to a product; per application there is only the free text contact field on an appliance (src/Appliance.php:214) and the user or technician in charge. Reached on: Management > Suppliers > Contacts tab; Appliance contact field."
}
@@ -1994,7 +2112,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "yes",
@@ -2012,6 +2130,7 @@
"topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier ... The Supplier Card has been created\" and \"Registering a supplier contact\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Create a new preliminary contract or preliminary supplier contract\" (read 2026-09-26). Reached on: Supporting Files > New > Supplier.",
"stackiq": "register :2022 organization (one record, type Supplier); module.provider (:6921) and catalogService.provider (:3762) are $ref organization; catalogContract points at service (+usage), register :3252; OrganisatieDetail src/manifest.json:403 lists the supplier's services and applications",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"De verbinding met de leveranciersgegevens garandeert juiste schrijfwijzes van leveranciers- en pakketnamen en juiste versienummering\" (read 2026-09-26); https://www.softwarecatalogus.nl/leveranciers: one record per supplier with contact and addenda (read 2026-09-26). There are no contracts to point to it. Reached on: Alle leveranciers > supplier page.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967745-update-an-object-definition shows 'Supplier' as an object property value on an application definition; a supplier could be a separate ArchiMate actor object, but a vendor record that products and contracts point to is not documented (read 2026-09-26). Reached on: Object property Supplier.",
"glpi": "source read at 11.0.9: one Supplier record (src/Supplier.php:46, install/mysql/glpi-empty.sql:7067) is referenced by contracts through install/mysql/glpi-empty.sql:1550 glpi_contracts_suppliers and by the financial record of any item through install/mysql/glpi-empty.sql:3263 glpi_infocoms.suppliers_id. Reached on: Management > Suppliers."
}
},
@@ -2022,7 +2141,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "yes",
@@ -2042,6 +2161,7 @@
"sap-leanix": "https://help.sap.com/docs/leanix/ea/advanced-filter-options: 'The lifecycle filter enables filtering of fact sheets by their lifecycle state: plan, phase-in, active, phase-out, and end-of-life' (read 2026-09-26). Reached on: Application fact sheet > Lifecycle.",
"topdesk": "https://docs.topdesk.com/en/managing-disruptions-in-your-asset-management-process.html: built-in \"operational/impacted status for assets\" (read 2026-09-26); lifecycle phases need a self-defined drop-down field (https://docs.topdesk.com/en/creating-new-fields.html). No planned, in use, phase-out model ships. Reached on: Asset card > General widget.",
"stackiq": "src/manifest.json LifecycleRoadmap /portfolio-roadmap custom page -> src/views/LifecycleRoadmapView.vue:55 groups the selected organisation's usages by phase, derived from usage dates by src/utils/lifecyclePhase.js derivePhase (:408); usage.status enum Acquisition/Planned/In production/To be phased out/Phased out in lib/Settings/softwarecatalogus_register.json",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967531-object-lifecycle-state: 'Objects can be either Current (default) or Future state'; https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'TIME powered application lifecycle management ... Capture lifecycle'. Only current and future are documented as states, not planned, in use and phasing out (read 2026-09-26). Reached on: Objects > Object lifecycle state.",
"glpi": "source read at 11.0.9: appliances carry a status, install/mysql/glpi-empty.sql:8950 glpi_appliances.states_id and src/Appliance.php:350 search option Status, whose values are an admin defined tree dropdown src/State.php:45 (install/mysql/glpi-empty.sql:7027 glpi_states), so phases such as planned, in use and being phased out are set up and filtered on. Reached on: Management > Appliances, Status field; Setup > Dropdowns > Statuses of items."
}
},
@@ -2052,7 +2172,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "yes",
@@ -2072,6 +2192,7 @@
"sap-leanix": "https://help.sap.com/docs/leanix/ea/report-types: 'Roadmap Report Visualizes fact sheets on a timeline to show the evolution of the IT landscape'; https://help.sap.com/docs/leanix/ea/application-rationalization-create-roadmap (read 2026-09-26). Reached on: Reports > Roadmap Report.",
"stackiq": "src/views/LifecycleRoadmapView.vue:28 organisation select, :55 phase groups, :96-110 phase-out date, planned replacement and link to the replacing module (:400 plannedReplacement, :423 plannedReplacementDate), ordered by nearest urgency (:428)",
"topdesk": "unknown: no replacement roadmap is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967586-roadmap: a roadmap template where 'The first axis shows the years and the second axis shows per business unit what should be done during those years', drawn as a view; https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'Portfolio decisions flow directly into roadmaps' (read 2026-09-26). Reached on: Views > Roadmap template.",
"glpi": "source read at 11.0.9: replacements can be planned as projects linked to the appliance, src/Appliance.php:108 Item_Project tab (src/Item_Project.php:45) and src/Project.php:50 Project with Kanban; the Gantt view is the separate gantt plugin (src/Project.php:599 checks isActivated('gantt')). No per organisation application roadmap view exists. Reached on: Tools > Projects, Appliance > Projects tab."
}
},
@@ -2082,7 +2203,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "no",
@@ -2100,6 +2221,7 @@
"stackiq": "grep for overlap/redundant in lib and src finds only code comments and the Reports card description (src/manifest.json:1031 'Overlapping and ageing software'); lib/Service/PortfolioReportService.php computes TIME quadrants, EOL exposure, cloud share and cost, no grouping by reference component; the /modules facet counts modules per reference component across the whole catalogue, not your landscape",
"topdesk": "unknown: no functional classification to detect overlap is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tile \"Referentiecomponenten met meerdere pakketten: Deze tegel signaleert dat er meer dan 1 pakket(versie) bij eenzelfde referentiecomponent in productie is\" (read 2026-09-26). Reached on: Dashboard tile Referentiecomponenten met meerdere pakketten.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin: 'overlapping application functions are quickly made visible'; https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'automatically detect redundancies' and 'Connect applications to capabilities for capability-based rationalization' (read 2026-09-26). Reached on: Application functions and capability maps.",
"glpi": "source read at 11.0.9: no reference component model to detect overlap on, grep -rli 'reference component\\|gemma' over src/ locales/glpi.pot returns nothing; appliances only carry a free type dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id)."
}
},
@@ -2110,7 +2232,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
@@ -2128,6 +2250,7 @@
"stackiq": "appinfo/routes.php:303 GET /api/portfolio-report -> lib/Controller/PortfolioReportController.php -> lib/Service/PortfolioReportService.php + PortfolioReportDerivation.php; UI src/views/organisaties/PortfolioReport.vue (TIME chart :112, quadrant summary :126 with EOL exposure/cloud/cost, rows :176, CSV export :50)",
"topdesk": "unknown: no rationalisation report is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Referentiecomponenten met meerdere pakketten ... per referentiecomponent aan welke pakketversies daaraan gekoppeld zijn\" (read 2026-09-26). Overlap only, ageing not covered. Reached on: Dashboard tile.",
+ "bluedolphin": "https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'TIME analysis across your entire application portfolio', 'automatically detect redundancies, surface lifecycle risks' and 'Out of the box reports and insights'. No named rationalisation report is described in the help center (read 2026-09-26). Reached on: Insights and APM views.",
"glpi": "source read at 11.0.9: the built in report list src/Report.php:77 to src/Report.php:111 holds default, by contract, by year, financial, network, loan and status reports; none covers overlapping or ageing software."
}
},
@@ -2157,6 +2280,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json usage.moduleVersion ($ref moduleVersion); read by src/views/LifecycleRoadmapView.vue:397 for EOL state; ModuleversieDetail mv-related shows related usages; no usage create/edit page in src/manifest.json",
"topdesk": "unknown: versions in use are only possible as a self-defined field; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Pakketversie - selecteer de versie die in gebruik is\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; recording the version an organisation runs is not documented beyond configurable fields (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: version can be captured 'in the Release field of the application fact sheets', which the guide says rarely adds value; IT components carry release per catalog item (https://help.sap.com/docs/leanix/ea/it-components-in-reference-catalog) (read 2026-09-26). Reached on: Application or IT Component fact sheet > Release.",
"glpi": "source read at 11.0.9: src/Item_SoftwareVersion.php:39 records which software version is installed on which item (install/mysql/glpi-empty.sql:1064 glpi_items_softwareversions with date_install at :1074), filled by hand or by native inventory, and listed on the Software Installations tab (src/Software.php:129). Reached on: Assets > Software > Installations tab."
}
@@ -2187,6 +2311,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications module-version-published (trigger created, recipients object-acl manage + group software-catalog-admins); no notification code in lib (no INotificationManager use)",
"topdesk": "unknown: no supplier version feed is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/suggesties_overnemen: \"Wanneer een leverancier een pakketversie registreert kan deze een suggestie versturen naar de gemeenten en samenwerkingen die dit pakket afnemen\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C2: \"Via de notificatiefunctie krijgt u een signaal zodra het versienummer is toegevoegd\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Suggesties; Inbox.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; notifications about supplier releases are not documented (read 2026-09-26)",
"sap-leanix": "unknown: https://updates.leanix.net/announcements/work-with-complete-technology-version-coverage-without-raising-manual-requests (2026-09-17) says the catalog is 'kept current as new versions are released', with version concurrency management planned for Q4; a notification to users about a new version is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: GLPI has no feed of supplier releases; software versions appear only when entered or inventoried (src/SoftwareVersion.php:42), and notification events for software are licence expiry only (src/NotificationTargetSoftwareLicense.php)."
}
@@ -2216,6 +2341,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json sbomComponent has name/version/purl/licenses/type/hashes/bomRef/vexCveIds, no lifecycle or EOL field; the EOL feed (lib/Service/EolSyncService.php:290) only stamps versions of modules with eolProductSlug; no relation from an application to the platform it runs on",
"topdesk": "unknown: no technology lifecycle is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: technologies per version are recorded (\"Pakketversie is beschikbaar voor één of meerdere technologien; databases, OS, SAAS\") but no lifecycle for them is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; technology objects carry only current or future state (https://help.bluedolphin.io/en/articles/11967531-object-lifecycle-state), end of support tracking of technology is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: underlying technology is held as items (database instances src/DatabaseInstance.php, operating systems, software) and each can carry a financial record with warranty and decommission date, install/mysql/glpi-empty.sql:3282 glpi_infocoms.decommission_date; there is no end of support date or lifecycle feed (grep -i 'end_of_support' install/mysql/glpi-empty.sql returns nothing). Reached on: any item > Management tab (Infocom)."
}
},
@@ -2240,7 +2366,7 @@
"providerHow": "read-from-code",
"note": "Strategic goals are not modelled.",
"evidence": {
- "bluedolphin": "docs, intelligence competitor_features#27466 'Strategy Alignment' (2026-04-12): Connect architecture to strategic objectives",
+ "bluedolphin": "https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'Applications natively connected to BPMN, ERD, strategy, and initiatives' and 'Align applications with strategic initiatives and roadmaps'; https://bluedolphin.io/capability-based-planning/: 'Connect capabilities directly to business objectives' (read 2026-09-26). Reached on: Objects and relationships to strategy elements.",
"stackiq": "no goal/strategy schema among the 20 in lib/Settings/softwarecatalogus_register.json; grep for strateg/doel in src/manifest.json: none",
"topdesk": "unknown: no strategic goals are described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no strategic goals are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -2274,6 +2400,7 @@
"stackiq": "openspec/features.overlay.json maintenance-and-supplier-roadmap status 'soon'; no maintenance schema in lib/Settings/softwarecatalogus_register.json and no page in src/manifest.json",
"topdesk": "https://docs.topdesk.com/en/operations-management.html: \"In TOPdesk you can easily schedule operational activities in the user-friendly planner. If you wish to schedule a recurring activity, you can use a series\" (read 2026-09-26); https://docs.topdesk.com/en/linking-assets-to-cards.html: assets can be linked to \"Operational Activity\" cards (read 2026-09-26). Reached on: Modules > Operations Management > Planner.",
"vng-softwarecatalogus": "unknown: no maintenance announcements are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; planned maintenance of applications is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; planned maintenance is documented only for LeanIX's own service status (https://help.sap.com/docs/leanix/ea/status-pages-and-status-emails), not for applications in the inventory (read 2026-09-26)",
"glpi": "source read at 11.0.9: no maintenance window on an item ('Maintenance mode' in locales/glpi.pot:7534 is GLPI's own downtime switch); planned work is a change linked to the appliance, src/Appliance.php:107 Change_Item tab, with planned tasks carrying begin and end (install/mysql/glpi-empty.sql:792 glpi_changetasks, :799 begin, :800 end) shown in the planning. Reached on: Appliance > Changes tab; Assistance > Planning."
}
@@ -2304,6 +2431,7 @@
"stackiq": "lib/Service/ContractStatusService.php:77 shouldExpire and :114 expirePastContracts set Active -> Expired when endDate < now; lib/BackgroundJob/ContractStatusJob.php:57 daily, registered in appinfo/info.xml:99",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Status: Configurable drop-down showing the contract's lifecycle status, e.g. draft, active ... Reminder date\" (read 2026-09-26); https://docs.topdesk.com/en/terminating-a-contract.html: \"The contract will terminate once the end date passes\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; 'Contract' exists as an ArchiMate object definition (https://help.bluedolphin.io/en/articles/11967596-archimate-annotation-translation-en-nl) and contract dates appear in an import example (https://help.bluedolphin.io/en/articles/11967633-datacollector-select-tricks), but a contract status that moves by itself is not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'The contract fact sheet uses lifecycle phases to represent the current state of a contract': Plan, Phase In, Contract Start Date (active), Contract Notice Period, Contract End Date (expired). Requires the contract extension (read 2026-09-26). Reached on: Contract fact sheet > Lifecycle.",
"glpi": "source read at 11.0.9: contract status is a manual dropdown (install/mysql/glpi-empty.sql:1512 glpi_contracts.states_id); expiry is computed, src/Contract.php:654 virtual 'Expiration' column from begin date, duration and renewal, and src/Contract.php:1092 cronContract sends end and notice alerts, but the status itself never moves by itself. Reached on: Management > Contracts list, Expiration column."
}
@@ -2335,6 +2463,7 @@
"stackiq": "src/components/contracts/ContractApprovalPanel.vue:183 canSubmitRenewal for status Expired; POST /api/contracts/{uuid}/approval/renewal -> ContractApprovalService.php:254 with decisionType contract-renewal; lib/EventListener/DecisionConcludedListener.php projects the outcome (approvalState, status Active) via DECISION_CONCLUDED_EVENTS registered in lib/AppInfo/Application.php:830",
"topdesk": "https://docs.topdesk.com/en/extending-a-contract.html: \"Under Create , select Extend contract ... The contract is now a preliminary contract ... Click Validate Contract\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Sequence Number ... goes up by 1 each time the contract is extended ... so you can trace the contract's extension history\" (read 2026-09-26). Reached on: Contract card > Create > Extend contract.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; contract renewal decisions are not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'Contract Renewal Status ... Backlog, In Review, In Progress, or Done', 'Contract Renewal Decision ... Renew, Terminate, or No Decision', 'Contract Renewal Comments' (read 2026-09-26). Reached on: Contract fact sheet > Contract Renewal.",
"glpi": "source read at 11.0.9: src/Contract.php:60 to :62 renewal kinds never, tacit and express, with the renewal computation in the alert cron (src/Contract.php:1293); there is no renewal decision record or outcome, only the contract's renewal setting and an optional approval through a change. Reached on: Management > Contracts, Renewal field."
}
@@ -2346,7 +2475,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "no",
@@ -2366,6 +2495,7 @@
"stackiq": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: assets link to \"Service cards\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"On the Services tab, link the services that apply to this contract\" (read 2026-09-26). Contract to asset runs through the service. Reached on: Contract > Services tab > Service > Links > Assets.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967596-archimate-annotation-translation-en-nl lists the object definition 'Contract', which can be related to an application and then shows in its Relationships tab (https://help.bluedolphin.io/en/articles/11967550-working-with-object-relationships); https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'Capture lifecycle, technical debt, business value, risk, cost, contracts' (read 2026-09-26). Reached on: Application object > Relationships tab (Contract objects).",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: relation 'Attached to Contract - Application Many-to-Many Links the contract to the applications it licenses or supports' (read 2026-09-26). Reached on: Application fact sheet > Contracts relation."
}
},
@@ -2376,7 +2506,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "yes",
@@ -2396,7 +2526,8 @@
"glpi": "source read at 11.0.9: contract costs have a period and a budget, install/mysql/glpi-empty.sql:1458 glpi_contractcosts with begin_date, end_date, cost and budgets_id; the contract list sums them in the 'Total cost' column (src/Contract.php:773) and a budget with a period shows spend per entity and type (src/Budget.php:537 showValuesByEntity). Reached on: Management > Contracts (Total cost column); Management > Budgets.",
"stackiq": "lib/Service/PortfolioReportDerivation.php:163 annualisedCost (Monthly x12, Annually x1, One-off separate); lib/Service/PortfolioReportService.php:337 sumContractCost per quadrant; src/views/organisaties/PortfolioReport.vue:167 and :248 show annualised cost; src/utils/contractCost.js:111 totalAnnualisedCost used by src/views/LicensePostureView.vue per vendor",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Costs (Services) ... Total internal cost, based on the service levels linked\" (read 2026-09-26); https://docs.topdesk.com/en/obtain-insights-with-asset-type-report.html: \"do you need an overview of the total costs of new assets? Use the Asset Type Report\" (read 2026-09-26). Reached on: Contract card > Financial; Asset Type Report.",
- "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967733-quick-start-guide shows a questionnaire field 'Estimate of annual application costs' of type currency; https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'portfolio analysis from cost, risk, lifecycle' (read 2026-09-26). Reached on: Application questionnaire > annual cost field."
}
},
{
@@ -2426,6 +2557,7 @@
"stackiq": "register :6937 module.licentietype enum Closed source/Open source and module.licence (five open-source licence names); catalogContract.contractType enum SLA/Licence/Maintenance (:3341)",
"topdesk": "unknown: licence cards hold number, code, purchase and expiration date; a licence model is only possible as a self-defined field; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/nieuws: \"is er de leverancier Open Source Pakketten aangemaakt. Onder deze leverancier staat nu een aantal veelgebruikte open source pakketten geregistreerd\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: Archi listed under supplier \"Open Source pakketten\", version \"Open source\" (read 2026-09-26). Other licence models are not recorded. Reached on: Alle pakketten > Leverancier Open Source pakketten.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; licence data appears only as example source columns ('Monthly License Costs', https://help.bluedolphin.io/en/articles/11967633-datacollector-select-tricks), a licence model field is not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'Contract Pricing Type Single select Consumption Based, Yearly Commitment, or Perpetual Licenses'. No open source or per user licence model field on the application is documented (read 2026-09-26). Reached on: Contract fact sheet > Contract Pricing Type."
}
},
@@ -2453,6 +2585,7 @@
"stackiq": "src/views/LicensePostureView.vue:11 open-source vs closed-source share weighted by in-production usage, :64 per-vendor rollup, per-organisation open-source-first report; derived in src/utils/licensePosture.js",
"topdesk": "unknown: no portfolio licence posture is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; a portfolio licence posture view is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; licence analysis exists only for SBOM components of self-built software (https://help.sap.com/docs/leanix/ea/sbom-explorer 'assess license risks by filtering for unpermitted licenses'), not a portfolio share of open source applications (read 2026-09-26)",
"glpi": "source read at 11.0.9: licences can be listed and filtered by type in search (install/mysql/glpi-empty.sql:6775 softwarelicensetypes_id), but the dashboard's per type charts cover asset types and Software only (src/Glpi/Dashboard/Grid.php:1452), not licences, and no portfolio share view exists. Reached on: Management > Licenses, filtered by type."
}
@@ -2484,6 +2617,7 @@
"stackiq": "grep for seat/licence count across lib/, src/ and the register finds no seat or quantity field on catalogContract (:3252), module or usage",
"topdesk": "https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"add fields to fill the number of licences you have purchased and still have left ... the Relationship grid widget on the software cards will display details about the licences\" (read 2026-09-26). Reached on: Asset Management > software card > Relationship grid.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; licences bought against used are not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for seats and licence counts, no hits; the contract fact sheet has cost fields but no licence quantity (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model) (read 2026-09-26)"
}
},
@@ -2511,6 +2645,7 @@
"stackiq": "No entitlement or consumption fields exist (see ctr-seat-count); no service computes a licence position in lib/Service/",
"topdesk": "https://docs.topdesk.com/en/managing-licences-in-asset-management.html: \"Knowing which software tools are used by whom ... the legal implications of using a tool without being licensed\" (read 2026-09-26). Entitlement against linked users, no measured consumption. Reached on: Asset Management > licence cards.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no entitlement against consumption computation is documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no entitlement against consumption computation is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: entitlement is compared with licence assignments (src/SoftwareLicense.php:158 computeValidityIndicator), while measured installations are counted separately (src/Item_SoftwareVersion.php:39); core has no computed effective licence position report reconciling the two for an audit. Reached on: Assets > Software > Licenses and Installations tabs."
}
@@ -2540,6 +2675,7 @@
"stackiq": "grep for budget across lib/, src/ and lib/Settings finds no budget schema or field; catalogContract has cost + costPeriod only (register :3363)",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Budget holder: Cost-accounting owner of the contract\" and \"Applicable to ... Budget holder\" (read 2026-09-26). No budget with a period is described. Reached on: Contract card > Financial.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for budget, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; the contract has a 'Contract Cost Center' string (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model) but charging costs against a budget with a period is not documented (read 2026-09-26)"
}
},
@@ -2568,6 +2704,7 @@
"stackiq": "grep for depreciation/afschrijving finds nothing in lib/, src/ or the register",
"topdesk": "unknown: depreciation is not mentioned (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for depreciation, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for depreciation and amortisation, no hits (read 2026-09-26)"
}
},
@@ -2578,7 +2715,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "yes",
@@ -2598,6 +2735,7 @@
"stackiq": "src/manifest.json:567 ContractDetail ct-files integration 'files' (Documents panel); catalogContract.documentReference text field (register :3252)",
"topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"You can view the contracts in a variety of formats, including PDF\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Archive Number (Free text) Reference to a physical or external archived copy of the contract document\" (read 2026-09-26). Reached on: Contract card.",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967535-object-attachments: files can be uploaded to any object, which covers a Contract object (https://help.bluedolphin.io/en/articles/11967596-archimate-annotation-translation-en-nl); no contract record with a document slot is documented (read 2026-09-26). Reached on: Contract object > attachments.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets: 'Files : You can upload files up to 10 MB. Uploaded files are then visible in the Resources tab', which applies to the contract fact sheet of the contract extension (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model) (read 2026-09-26). Reached on: Contract fact sheet > Resources tab.",
"glpi": "source read at 11.0.9: src/Contract.php:126 adds the Documents tab (Document_Item) to every contract, storing the signed file in install/mysql/glpi-empty.sql:2585 glpi_documents. Reached on: Management > Contracts > Documents tab."
}
@@ -2627,6 +2765,7 @@
"stackiq": "usage.cloudDienstverleningsmodel (register :3050) plus contract cost; lib/Service/PortfolioReportService.php:302 per-usage annualised cost and cloud-transition share; src/views/organisaties/PortfolioReport.vue:166 cloudTransitionLabel per row",
"topdesk": "unknown: no SaaS spend tracking is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: contracts, licences and costs are not described anywhere in the public docs (the 2021 user survey asks which other tool municipalities use for contract management); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersonderzoek%202021 (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for SaaS and spend, no SaaS subscription tracking is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -i 'saas' over src/ returns nothing; spend is only what is entered on contracts and financial records (install/mysql/glpi-empty.sql:1458 glpi_contractcosts), with no discovery of subscriptions bought outside IT."
}
},
@@ -2654,6 +2793,7 @@
"vng-softwarecatalogus": "unknown: no vulnerability register is described; the docs do not state its absence either (the IBD-foto export only hands CPE identifiers to the IBD); searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Hoe%20maak%20je%20een%20ICT-foto%20voor%20de%20IBD%3F (read 2026-09-26)",
"stackiq": "src/views/KwetsbaarhedenView.vue:378 reportVulnerability opens the generic ObjectModal for 'vulnerability'; register.json:1619 vulnerability schema with cveCode (pattern CVE-yyyy-n, :1679) and cvssScore 0-10",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for vulnerability and CVE, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no vulnerability record with CVE code and score exists, vulnerabilities are handled by searching SBOM components (https://help.sap.com/docs/leanix/ea/searching-for-sbom-library-components-by-package-url 'after a CVE alert') (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'cve\\|vulnerab\\|cvss' over src/ templates/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74 (a PHP version warning) and a session comment at src/Session.php:1085; no vulnerability itemtype exists."
}
@@ -2682,6 +2822,7 @@
"stackiq": "register.json:1701 vulnerability.modules links to module (applications), not moduleVersion; version level only via read-time SBOM match (src/utils/sbomVulnerabilityMatch.js, sbomComponent.vexCveIds register.json:8024) on the ModuleversieDetail Components tab",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for vulnerability and CVE, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; a PURL search finds services using a given library version, but linking a vulnerability record to affected versions is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no vulnerability model (see src/Glpi/System/Requirement/PhpSupportedVersion.php:74 as the only 'vulnerabilities' hit), so nothing links to software versions (install/mysql/glpi-empty.sql:6900)."
}
@@ -2710,6 +2851,7 @@
"stackiq": "src/components/sbom/SbomComponentsPanel.vue:53-90 upload control (.json) -> POST /api/moduleversies/{uuid}/sbom (appinfo/routes.php:92) -> lib/Controller/SbomController.php:129 importSbom -> lib/Service/SbomParserService.php:77 parse (CycloneDX JSON) and :127 parseSpdx (SPDX 2.x JSON)",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for SBOM, CycloneDX and SPDX, no hits (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/uploading-sboms-from-fact-sheets: 'select a CycloneDX or SPDX file in JSON or XML format' on a microservice fact sheet; also through the Self-Built Software Discovery API. Technology Risk and Compliance product (read 2026-09-26). Reached on: Microservice fact sheet > SBOM > Upload SBOM.",
"glpi": "source read at 11.0.9: grep -ril 'sbom\\|cyclonedx\\|spdx' over src/ templates/ locales/glpi.pot returns nothing; inventory import (src/Glpi/Inventory/) takes glpi-agent JSON only. Inventory import is src/Glpi/Inventory/Inventory.php:106."
}
@@ -2738,6 +2880,7 @@
"stackiq": "src/utils/sbomVulnerabilityMatch.js header: 'no HTTP request to an external advisory feed is ever made'; lib/Service/EolSyncService.php syncs endoflife.date support dates, not CVEs",
"topdesk": "unknown: no CVE matching is described; the roadmap card https://tip.topdesk.com/c/186-automated-asset-scanning-tool (under consideration) mentions monitoring \"security vulnerabilities\" as a future idea; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the catalogue does not match CVEs itself; its \"IBD-foto\" export lists supplier, product and CPE so the IBD can do so; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Hoe%20maak%20je%20een%20ICT-foto%20voor%20de%20IBD%3F (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for CVE, no hits (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/api-updates-sbom-async-processing: 'Switching to asynchronous processing will allow us to add additional post-processing mechanisms in the future, such as vulnerability checks. Though there's no established timeline for these enhancements' (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'cve' over src/ templates/ finds no feed matching (only src/Glpi/System/Requirement/PhpSupportedVersion.php:74 text); no pluginsGLPI cve repository exists (git ls-remote https://github.com/pluginsGLPI/cve: repository not found)."
}
@@ -2767,6 +2910,7 @@
"stackiq": "src/utils/vulnerabilitySeverity.js derives a severity band per vulnerability from CVSS; no per-application risk score in lib/ or src/ (searched risk)",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; risk can be captured in questionnaires ('Risk Assessment' example in https://help.bluedolphin.io/en/articles/11967710-using-the-odata-feed), but a risk score from vulnerabilities and support status is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: with no vulnerability data (only hit src/Glpi/System/Requirement/PhpSupportedVersion.php:74) and no support status field on software (install/mysql/glpi-empty.sql:6856 glpi_softwares), no risk score is computed; grep -i 'risk' over src/Appliance.php src/Software.php returns nothing."
}
},
@@ -2794,6 +2938,7 @@
"stackiq": "register.json:1619 vulnerability has no fixed-in version field; src/utils/vulnerabilityExposure.js computeExposure carries the deployed moduleVersion per usage but nothing compares it to a fix",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for patch and vulnerability, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no per vulnerability patch status is documented, and vulnerability checks are a future item (https://help.sap.com/docs/leanix/ea/api-updates-sbom-async-processing) (read 2026-09-26)",
"glpi": "source read at 11.0.9: installed versions are known (src/Item_SoftwareVersion.php:39) but no vulnerability or fixed in version exists to compare against (grep -rli 'cve' src/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74)."
}
@@ -2822,6 +2967,7 @@
"stackiq": "src/manifest.json:969 Kwetsbaarheden custom page -> src/views/KwetsbaarhedenView.vue table with severity tabs; row click openDetail (:417) opens the record in the generic ObjectModal",
"topdesk": "unknown: vulnerabilities are not mentioned (0 hits for \"vulnerab\"); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability, SBOM or risk functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for vulnerability, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no vulnerability list exists, only the SBOM explorer of components (https://help.sap.com/docs/leanix/ea/sbom-explorer) (read 2026-09-26)",
"glpi": "source read at 11.0.9: no vulnerability itemtype and no such entry in any menu (src/Html.php:1295 to :1334 list Management, Tools, Administration and Setup types)."
}
@@ -2833,7 +2979,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "yes",
"stackiq": "yes",
@@ -2850,6 +2996,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Als leverancier kunt u zich aanmelden door de volgende gegevens te sturen naar softwarecatalogus@vng.nl\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C4 roles for gemeente and samenwerking accounts (read 2026-09-26); organisation types gemeente, samenwerking, leverancier. Reached on: Registration via VNG helpdesk.",
"stackiq": "src/manifest.json:386 Organisaties type:index over schema organization (Add form); register :2022 organization.type enum Municipality/Supplier/Collaboration/Community, required contactsUid + type",
"topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier ... In the Tasks block, specify whether first or second line incidents, or services or changes, may be assigned to the supplier\" (read 2026-09-26); branches are registered as Branch cards (https://docs.topdesk.com/en/drop-down-lists-settings.html \"the Person and Branch cards\"). Reached on: Supporting Files > New > Supplier / Branch.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967491-business-units: business units 'represent more or less standalone parts of your organization, such as sales, marketing, OpCo France'; outside organisations can be ArchiMate business actor objects. No register of municipalities, suppliers or cooperations with a type is documented (read 2026-09-26). Reached on: System settings > Business Units.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/organization-modeling-guidelines: organization subtypes 'Business Unit, Customer, Region, Legal Entity, Team' for 'your hierarchical business architecture'; suppliers are separate provider fact sheets. No municipality or cooperation types for outside organisations (read 2026-09-26). Reached on: Inventory > Organization fact sheet.",
"glpi": "source read at 11.0.9: external organisations are suppliers with a type dropdown (src/Supplier.php:46, install/mysql/glpi-empty.sql:7072 suppliertypes_id); the organisation's own units are entities (src/Entity.php:58). There is no generic organisation register covering municipalities or cooperations. Reached on: Management > Suppliers; Administration > Entities."
}
@@ -2880,6 +3027,7 @@
"stackiq": "src/views/settings/StackiqSettings.vue:92 ModerationQueue (type organisation) -> src/utils/adminApi.js -> GET /api/moderation/pending, POST /api/moderation/{uuid}/approve|reject; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; lib/Service/ModerationService.php:230 approval sets registrationStatus active and stamps publicationDate (:173)",
"topdesk": "unknown: no review queue for organisations is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Om te kunnen deelnemen aan de softwarecatalogus controleren wij of de leverancier voldoet aan de richtlijnen van de softwarecatalogus\" (read 2026-09-26). Manual review by e-mail, no queue described.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; organisations do not self register, so no moderation queue is documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; organisations do not self register, so no moderation queue is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers are created by staff (src/Supplier.php:75 sets is_active on a new record) and there is no self registration or approval queue for organisations; grep -i 'moderat' over src/Supplier.php src/Entity.php returns nothing."
}
@@ -2908,6 +3056,7 @@
"stackiq": "register organization.status enum Draft/Active/Inactive is visible:false (:2022); src/manifest.json:403 OrganisatieDetail overrides status editable:false; src/modals/object/ChangeOrganisatieStatusDialog.vue:211 is never opened (no setDialog('changeOrganisatieStatus') in src); src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters status 'concept' and :129 writes 'actief', neither an enum value",
"topdesk": "unknown: cards can be archived; concept, active, inactive states for organisations are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: suppliers carry a \"heeft geldig convenant\" flag and may be removed, but no concept, active, inactive status is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/leveranciers (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; concept, active and inactive states for organisations are not documented (read 2026-09-26)",
"sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/organization-modeling-guidelines does not describe concept, active and inactive states for organizations; only archiving of fact sheets in general (https://help.sap.com/docs/leanix/ea/archiving-deleting-and-recovering-fact-sheets) (read 2026-09-26)",
"glpi": "source read at 11.0.9: a supplier is active or inactive, src/Supplier.php:365 is_active search option (install/mysql/glpi-empty.sql:7087 glpi_suppliers.is_active); there is no concept state. Reached on: Management > Suppliers, Active field."
}
@@ -2936,6 +3085,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30402: \"Bij elke leverancier is een contactpersoon opgevoerd. Deze persoon is verantwoordelijk voor de inhoud\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E4 contact details of municipalities (read 2026-09-26). One contact, no roles. Reached on: Supplier page header.",
"stackiq": "src/manifest.json:418 OrganisatieDetail org-contactpersonen object-list (role, roles) with rowRoute ContactpersoonDetail; register :1788 contactPerson (contactsUid, role, organization, roles enum of catalogue roles)",
"topdesk": "https://docs.topdesk.com/en/managing-external-relations.html: \"Registering a supplier contact ... The Supplier card where the contact person is active must be registered first\" (read 2026-09-26). Roles per contact are not described. Reached on: Supporting Files > New > Supplier Contact.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; contact persons with roles per organisation are not documented beyond generic questionnaire fields (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/subscription-roles: users subscribe to any fact sheet, including organization fact sheets, with roles 'such as application owner, project manager'. Contacts must be workspace users; external contact persons are not documented (read 2026-09-26). Reached on: Organization fact sheet > Subscriptions.",
"glpi": "source read at 11.0.9: contacts (src/Contact.php:45, install/mysql/glpi-empty.sql:1390 glpi_contacts) carry a contact type and a title (:1402 contacttypes_id, :1405 usertitles_id) and are linked to suppliers through src/Contact_Supplier.php:39. Reached on: Management > Contacts; Supplier > Contacts tab."
}
@@ -2947,7 +3097,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "yes",
@@ -2965,6 +3115,7 @@
"stackiq": "src/components/organisations/OrganisationSwitcher.vue:48 'Manage members' (isBeheerder) opens src/modals/GrantOrganisationAccessModal.vue; POST /api/organisations/{uuid}/members -> lib/Controller/OrganisationMembersController.php:108 authorizeBeheerder then OpenRegister joinOrganisation (:123)",
"topdesk": "https://docs.topdesk.com/en/step-2, operator-import-with-a-linked-person.html: \"Create new operators via import\" (read 2026-09-26); permissions via permission groups (https://docs.topdesk.com/en/automated-actions.html). Administrators create accounts; no invitation flow. Reached on: Supporting Files > Operators.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/gebruikersbeheer: \"Beheerders van gemeenten, samenwerkingen of leveranciers kunnen voor collega's een account aanmaken ... ontvangt deze nieuwe gebruiker een e-mail met daarin de inloginstructies\" (read 2026-09-26). Reached on: Menu > Gebruikersbeheer > Gebruiker toevoegen.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967616-user-management: admins 'Add new users' and BlueDolphin sends 'An invitation with a link to activate the account'; business units scope what users see (https://help.bluedolphin.io/en/articles/11967491-business-units) (read 2026-09-26). Reached on: Admin > Users.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/users-overview: 'Invited users who haven't yet accepted the invitation request. You can reinvite a user'; https://help.sap.com/docs/leanix/ea/virtual-workspaces-configuration: 'Set up virtual workspaces to manage access for custom user groups' (read 2026-09-26). Reached on: Administration > Users > Invite.",
"glpi": "source read at 11.0.9: an administrator gives a user a profile on an entity, install/mysql/glpi-empty.sql:5917 glpi_profiles_users with profiles_id and entities_id, set on the user's Authorizations tab or automatically by authorisation rules (src/RuleRight.php:297 profiles_id action, :273 entities_id action). There is no emailed invitation link. Reached on: Administration > Users > Authorizations tab."
}
@@ -2976,7 +3127,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "unknown",
"stackiq": "yes",
@@ -2994,6 +3145,7 @@
"stackiq": "src/components/organisations/OrganisationSwitcher.vue:197 POST /apps/openregister/api/organisations/{uuid}/set-active; mounted in src/App.vue:55",
"topdesk": "unknown: one account acting for several organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C4: \"Een account kan ook beide rollen gekregen hebben. In het inlogmenu kan dan van rol gewisseld worden ... Gecombineerde rollen kunnen alleen door VNG Realisatie aangemaakt worden\" (read 2026-09-26). Reached on: Inlogmenu > rol wisselen.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967491-business-units: 'When there are multiple business units, you can switch between them by selecting a business unit from the dropdown'. Switching is between parts of one tenant, not between separate organisations (read 2026-09-26). Reached on: Top menu > business unit dropdown.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/manage-workspace-access: 'Provide users with access to exactly their relevant workspaces ... direct URL, base URLs or the workspace chooser to access available workspaces' (read 2026-09-26). Reached on: Workspace chooser.",
"glpi": "source read at 11.0.9: one user can hold several profile and entity pairs (install/mysql/glpi-empty.sql:5917 glpi_profiles_users) and switch between them in the session, src/Session.php:461 changeActiveEntities and src/Session.php:592 changeProfile. Reached on: user menu, entity and profile selector."
}
@@ -3022,6 +3174,7 @@
"stackiq": "src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail; POST /api/organisaties/{uuid}/merge -> lib/Controller/MergeController.php:142 isAdmin; lib/Service/MergeOrganisatieService.php:111 re-points usage.consumer/participants, contactPerson.organization, connection.provider and @self.organisation of catalogContract/compliancy; module.provider and catalogService.provider are not re-pointed",
"topdesk": "unknown: merging organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no merge of organisations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; objects can be copied or moved between business units and workspaces (https://help.bluedolphin.io/en/articles/11967491-business-units), but merging two organisations with their relations is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for merge of fact sheets or organizations, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: entities cannot be merged, src/Entity.php:202 forbids the dropdown merge action for Entity; records can be moved into another entity with src/Transfer.php:50 Transfer (massive action add_transfer_list, src/MassiveAction.php:598), keeping or cleaning linked items per transfer options. Reached on: Administration > Entities; list Actions > Add to transfer list."
}
@@ -3051,6 +3204,7 @@
"stackiq": "src/components/organisations/OrganisationMergePanel.vue:324 organisatieStore.dryRunMerge shows dryRunCounts before execute; POST /api/organisaties/{uuid}/merge/dry-run -> lib/Service/MergeOrganisatieService.php:160 dryRun",
"topdesk": "unknown: merging organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no merge of organisations is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no merge preview is documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no merge, so no merge preview is documented (read 2026-09-26)"
}
},
@@ -3061,7 +3215,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -3079,6 +3233,7 @@
"stackiq": "src/views/settings/StackiqSettings.vue:80 UserGroupsConfiguration -> GET/POST /api/user-groups/config (src/store/modules/settings.js:830); lib/Controller/SettingsController.php:3379; lib/Service/Stackiq/GroupHandler.php:103 generic groups, :167 fixed role groups (aanbod-beheerder, gebruik-beheerder, ...), group choice by organisation type (:471)",
"topdesk": "https://docs.topdesk.com/en/automated-actions.html: \"Assign these permissions via Supporting Files > Permission Groups > [Permission Group]\" (read 2026-09-26); https://docs.topdesk.com/en/details-about-certain-permissions.html: permission tables per module (read 2026-09-26). Reached on: Supporting Files > Permission Groups.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C4 roles gemeentebeheerder, raadpleger, samenwerkingsbeheerder; \"Er is géén rol voor het raadplegen van een samenwerking\" (read 2026-09-26). Fixed roles, no mapping onto groups. Reached on: Gebruikersbeheer.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967624-manage-roles-and-permissions: 'BlueDolphin uses Role-Based Access Control (RBAC). Every user is linked to one or more roles ... Add and delete custom roles' (read 2026-09-26). Reached on: Admin > Roles.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/sso-attribute-overview: 'The role to be assigned to the user. Required values: ADMIN, MEMBER, or VIEWER' and 'customer_roles ... The custom role to be assigned', mapped from identity provider groups (read 2026-09-26). Reached on: Administration > Users; SSO role attributes."
}
},
@@ -3089,7 +3244,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "no",
@@ -3107,6 +3262,7 @@
"topdesk": "https://docs.topdesk.com/en/automatic-login-methods.html: \"Single Sign-on via SAML requirements TOPdesk uses OpenSAML 3 for authentication. You can connect all common IdP solutions which support SAML 2.0\" (read 2026-09-26). Reached on: Settings > Login Settings.",
"stackiq": "No OIDC/SAML code in lib/ or src/; stackiq creates local Nextcloud users with a password (lib/Service/Stackiq/ContactPersonHandler.php:292)",
"vng-softwarecatalogus": "unknown: login is by username and password (\"Vul uw GEMMA Softwarecatalogus-gebruikersnaam in\"); no identity provider sign-in is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/user/login (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967579-configure-single-sign-on-sso-with-okta-saml and https://help.bluedolphin.io/en/articles/11967575-configure-single-sign-on-sso-with-office-365-openid: SSO setup guides for Okta SAML, ADFS and Office 365 OpenID (read 2026-09-26). Reached on: Admin > Identity providers.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/managing-users: 'SSO : You manage access through your identity provider (IdP) system. Users sign in through your IdP'; guides for Entra ID, Okta, OneLogin (read 2026-09-26). Reached on: Administration > Single Sign-On."
}
},
@@ -3117,7 +3273,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "no",
@@ -3135,6 +3291,7 @@
"stackiq": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/",
"topdesk": "https://docs.topdesk.com/en/manual-login-with-ldap.html: \"This is also required if you want to import persons from your AD via Supporting files import\" (read 2026-09-26); https://tip.topdesk.com/c/242-support-scim-when-importing-users-from-entra-id-to-topdesk: roadmap card in column \"Launched\", \"Support SCIM when importing users from Entra ID to TOPdesk\" (read 2026-09-26). Reached on: Settings > Import settings > Supporting Files imports.",
"vng-softwarecatalogus": "unknown: no directory sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967618-automatic-user-provisioning-with-scim-2-0: 'BlueDolphin supports automatic user provisioning ... manage BlueDolphin users and their role assignments', with guides for Entra ID, Okta and SailPoint (read 2026-09-26). Reached on: Admin > SCIM provisioning.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/scim-provisioning: 'SCIM facilitates the transfer of user information from a source system, such as an external identity provider (IdP), to a target system, such as SAP LeanIX'; setup guides for Entra ID and Okta (read 2026-09-26). Reached on: Administration > SCIM provisioning."
}
},
@@ -3145,7 +3302,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -3162,6 +3319,7 @@
"stackiq": "src/components/ContactpersonenList.vue:115 'Change Password' opens src/dialogs/ChangePasswordDialog.vue -> POST /api/contactpersonen/change-password -> lib/Controller/ContactpersonenController.php:718, self-reset allowed at :753; GET /api/me (:1578) used only by src/App.vue and OrganisationSwitcher",
"topdesk": "https://docs.topdesk.com/en/editing-your-personal-profile.html: \"Click on Personal Profile . In the General and Private section, you can edit your personal information. In the Change password section, you can change your password\" (read 2026-09-26). Reached on: Profile picture > Personal Profile.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/wachtwoord-vergeten: \"Op het inlogscherm ... staat een link om een nieuw wachtwoord aan te vragen\" (read 2026-09-26). Reset by mail; viewing own account details is not described. Reached on: Inloggen > Vraag een nieuw wachtwoord aan.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967481-user-profile: users see 'Profile > Personal information'; https://help.bluedolphin.io/en/articles/11967487-forgotten-password: 'To have your password reset, you need to contact your BlueDolphin administrator' and change the temporary password after login (read 2026-09-26). Reached on: Account > Profile.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/user-profile: 'Manage your user profile settings. Change or reset your password if needed' on the My Settings profile page (read 2026-09-26). Reached on: User menu > My Settings.",
"glpi": "source read at 11.0.9: front/preference.php renders the user's own form through src/User.php:3105 showMyForm (template pages/admin/user/user.html.twig), whose preference variant shows a 'Change password' button to front/updatepassword.php at templates/pages/admin/user/user.html.twig:277 to :279; the new password form is templates/password_form.html.twig:79."
}
@@ -3173,7 +3331,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
@@ -3191,6 +3349,7 @@
"stackiq": "lib/Service/SymfonyEmailService.php:466 registration, :553 activation, :641 user creation mails from templates; src/views/settings/sections/EmailConfiguration.vue:902 saveTemplate is a stub that logs 'not yet implemented in the backend' and still shows success; backend POST /api/email/templates/{templateName} (lib/Controller/SettingsController.php:2194) has no caller in src/; lib/Settings/connections.json email adapter reports the 'null' transport as simulated",
"topdesk": "unknown: email designs are editable for automated actions, but account activation mails are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: new users receive a login mail, but administrator-editable templates are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersbeheer (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967616-user-management: BlueDolphin sends 'An invitation with a link to activate the account' and temporary credentials; editing the mail templates is not documented (read 2026-09-26). Reached on: Admin > Users > send invites.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/users-overview: users are invited 'individually or in bulk' with a 'Send Invitation Email' option; editing the text of account mails is not documented (read 2026-09-26). Reached on: Administration > Users > Invite."
}
},
@@ -3220,6 +3379,7 @@
"stackiq": "lib/Controller/PublicationController.php:87 publish/depublish (routes.php:208-209, PUT/DELETE /api/publication/{objectType}/{uuid}) with an IDOR guard; lib/Service/PublicationService.php:51 publishable types catalogService, module, connection, organization. No src/ caller of /api/publication (only a comment in src/utils/openDataProjection.js). The publish buttons in src/modals/object/ViewObject.vue:4854 are unreachable: Modals.vue renders ViewObject only for modal 'viewOrganisatie'/'viewContactpersoon', which nothing sets. Workaround: publicationDate/depublicationDate are visible, editable fields on module/catalogService/organization/connection (lib/Settings/softwarecatalogus_register.json:6777 schema).",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: supplier data is public by default and municipal data is never public; publishing or withdrawing one entry is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: https://help.bluedolphin.io/en/articles/11967513-publish-a-view publishes a read-only view to 'all BlueDolphin users in your tenant'; publishing an entry as open data is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; publishing a single entry as open data is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'open data\\|opendata' over src/ locales/glpi.pot returns nothing; items have no publish state, the closest is is_helpdesk_visible (install/mysql/glpi-empty.sql:8956 on glpi_appliances), which only shows the item to helpdesk users of the same instance."
}
@@ -3250,6 +3410,7 @@
"stackiq": "src/utils/openDataProjection.js:36 STRIPPED_FIELDS (PII projection) is imported by nothing in src/ and has no PHP counterpart (grep 'projection' in lib/ finds none). Usage schema read rule lib/Settings/softwarecatalogus_register.json:3150 has no public group; lib/Controller/GebruikController.php:102 returns an empty result to anonymous callers.",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Beschikbare%20downloads: public CSV downloads of packages, versions and compliance (read 2026-09-26); https://www.softwarecatalogus.nl/pakket/archi: \"Ingevuld door (28) Aantal gemeenten met een versie van het pakket in productie\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: C5 contact details \"alleen als contactgegevens voor andere ingelogde gebruikers\" (read 2026-09-26). Reached on: Beschikbare downloads; package page.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; no open data publication is documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no open data publication is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no open data publication exists (grep -rli 'open data' src/ returns nothing); anonymisation settings cover ticket actors only (install/mysql/glpi-empty.sql:2824 anonymize_support_agents on entities)."
}
@@ -3280,6 +3441,7 @@
"stackiq": "lib/Service/Federation/FederationService.php:215 announce() calls OpenCatalogi BroadcastService->broadcast(directory URL); only caller is lib/BackgroundJob/FederationSyncJob.php:73. Off by default: lib/Service/Federation/FederationConfig.php:56 federation_enabled=false; lib/Settings/connections.json lists federation as switch-only via occ. isAvailable() is class_exists('OCA\\\\OpenCatalogi\\\\Service\\\\DirectoryService') (FederationService.php:95).",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; announcing a catalogue in a shared directory is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no shared directory of catalogues or federation between workspaces is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'federat\\|activitypub' over src/ returns nothing; every instance is standalone and the only outbound registration is the plugin marketplace client (src/Glpi/Marketplace/). The marketplace client is src/Glpi/Marketplace/Controller.php:64."
}
@@ -3310,6 +3472,7 @@
"stackiq": "lib/Service/Federation/FederationService.php:434 fetchPeerCatalog() calls OpenCatalogi DirectoryService->getDirectory(['url' => $peerUrl]); OpenCatalogi's getDirectory (opencatalogi lib/Service/DirectoryService.php:2409, also on origin/development) reads only filters/limit/offset/include-federated and ignores 'url', so it returns this instance's own directory listings, not the peer's published entries. Provenance marking itself is built: lib/Service/Federation/FederationMerger.php:239 stamps _source.instance. Mirrors are written into the organization schema (FederationService.php:56 PEER_MIRROR_TYPE). No src/ code reads _source, so no page shows where an entry came from.",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; AMEFF files can move views between BlueDolphin tenants (https://help.bluedolphin.io/en/articles/11967636-import-bluedolphin-ameff-files), but pulling published entries from peer catalogues with provenance is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; pulling entries from peer catalogues is not documented, only integrations with named tools (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'federat' over src/ returns nothing; data enters only through the UI, the APIs (src/Glpi/Api/APIRest.php:60, src/Glpi/Api/HL/Router.php) and inventory, never from peer catalogues."
}
@@ -3340,6 +3503,7 @@
"stackiq": "lib/Controller/FederationController.php:86 addPeer / removePeer (routes.php:246-247), #[AuthorizedAdminSetting(StackiqAdmin)]; lib/Service/Federation/FederationService.php:157/191 with an SSRF host guard; UI src/views/settings/sections/FederationSettings.vue:283 (POST) and :307 (DELETE), mounted from src/views/settings/StackiqSettings.vue:114.",
"topdesk": "unknown: open data publication and catalogue federation are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no exchange with peer catalogues is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; peer catalogue management is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; no peer catalogue management is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'federat' over src/ returns nothing; there is no peer list in the Setup menu (src/Html.php:1330 onwards)."
}
@@ -3366,7 +3530,7 @@
"note": "Read and write through a REST API is live through OpenRegister, with stackiq's own role-scoped endpoints on top.",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/sap-leanix-apis: 'These APIs are ideal for integration with systems that support RESTful interactions' and 'The GraphQL API enables you to retrieve and update fact sheets and related data' (read 2026-09-26). Reached on: Developer Guide > SAP LeanIX APIs.",
- "bluedolphin": "docs, intelligence competitor_features#48972 'REST API' (2026-07-23): Programmatic integration with other systems.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967730-about-the-bluedolphin-api: 'The BlueDolphin Public API is available by default for all tenants ... based on REST principles', with create, update, retrieve and delete endpoints for objects and relationships (read 2026-09-26). Reached on: Admin > Public API keys.",
"glpi": "source read at 11.0.9: legacy REST API src/Glpi/Api/APIRest.php:60 (documented in apirest.md) and the v2 high level API, src/Glpi/Api/HL/Controller/AssetController.php:149 /Assets with GET list (:2825), GET item (:2839) and POST create (:2988), Appliance and Software included (src/Glpi/Api/HL/Controller/AssetController.php:39, :133). Reached on: /apirest.php and /api.php/v2. Driven on the lab at 11.0.9 (2026-09-26): the legacy API answers \"There isn't an active API client matching your IP address\" until an administrator adds an API client, and the v2 API is off until enabled in Setup > General > API.",
"topdesk": "https://docs.topdesk.com/en/required-knowledge.html: \"basic knowledge of REST API requests (see developers.topdesk.com )\" (read 2026-09-26); https://docs.topdesk.com/en/details-about-certain-permissions.html: \"API access > REST API : this permission is necessary for operator cards that are used for accessing the TOPdesk API\" (read 2026-09-26). Reached on: developers.topdesk.com.",
"stackiq": "Every catalogue entity is an OpenRegister object (src/manifest.json pages read register @resolve:voorzieningen_register), so OpenRegister's /apps/openregister/api/objects/{register}/{schema} CRUD applies, gated by the schema authorization rules (lib/Settings/softwarecatalogus_register.json:6777 module and others). Stackiq adds its own routed endpoints in appinfo/routes.php (e.g. :202 /api/aanbod, :255-261 /api/aangeboden-gebruik, :298 /api/gebruik, :303 /api/portfolio-report).",
@@ -3380,7 +3544,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -3399,6 +3563,7 @@
"stackiq": "openapi.json at repo root has an info block and 0 paths. Hand-written JSON docs: lib/Controller/ViewController.php:373 (GET /api/views/docs, routes.php:186) and lib/Controller/AangebodenGebruikController.php:866 (GET /api/aangeboden-gebruik/docs, routes.php:261). The views docs endpoint is login-only; the aangeboden-gebruik docs endpoint is @PublicPage (AangebodenGebruikController.php:860), so anyone can read it (corrected 2026-09-26). Hand-written markdown in docs/API_REFERENCE.md and docs/View_API.md on the docs site. No src/ caller of either docs endpoint.",
"topdesk": "https://developers.topdesk.com/: TOPdesk API reference site, linked from the docs as \"TOPdesk API documentation\" (read 2026-09-26); https://docs.topdesk.com/en/generate-a-document.html: \"see FreeMarker and the TOPdesk API documentation\" (read 2026-09-26). Reached on: developers.topdesk.com.",
"vng-softwarecatalogus": "unknown: no API documentation for the current catalogue was found; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967733-quick-start-guide: 'Open API Documentation EU https://public-api.eu.bluedolphin.app /swagger/index.html' and per endpoint reference articles in the help center (read 2026-09-26). Reached on: Swagger at https://public-api.eu.bluedolphin.app/swagger/index.html.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/sap-leanix-apis: 'we provide the OpenAPI explorer . This tool enables you to explore APIs, send requests, and view responses directly in your browser' (read 2026-09-26). Reached on: Workspace > OpenAPI explorer."
}
},
@@ -3409,7 +3574,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -3429,6 +3594,7 @@
"glpi": "source read at 11.0.9: every search list exports to CSV, PDF, ODS and XLSX through src/Glpi/Search/Output/Csv.php, Pdf.php, Ods.php and Xlsx.php, plus impact CSV (front/impactcsv.php) and the APIs (src/Glpi/Api/HL/Controller/AssetController.php:2825). Reached on: any list, Export menu. Driven on the lab at 11.0.9 (2026-09-26): the Appliances list exported to CSV (/front/report.dynamic.php display_type 3) with the created record.",
"stackiq": "ArchiMate export lib/Controller/SettingsController.php:1615 (POST /api/archimate/export) and :1685 per-organisation export (GET /api/archimate/export/organization/{uuid}), called only from src/views/settings/sections/ArchiMateImportExport.vue (admin settings, StackiqSettings.vue:86). CSV export of the portfolio report: lib/Controller/PortfolioReportController.php:105, button src/views/organisaties/PortfolioReport.vue:567. No index page opts into the library's CSV/Excel export (no allowExport in src/manifest.json).",
"topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: tile actions \"Export to .CSV Export to Excel\" (read 2026-09-26); https://docs.topdesk.com/en/create-odata-reports-for-asset-management.html: \"generate reports by using the TOPdesk OData feed ... Microsoft Power BI, or Microsoft Excel\" (read 2026-09-26). Reached on: Asset dashboard; OData feed.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967710-using-the-odata-feed: 'working with the data available through the BlueDolphin OData service'; views export as AMEFF (https://help.bluedolphin.io/en/articles/11967514-download-a-view) (read 2026-09-26). Reached on: OData feed; view download.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/exporting-fact-sheet-data-as-excel-file: 'export fact sheet data as an Excel file'; https://help.sap.com/docs/leanix/ea/exporting-workspace-snapshots: 'Export snapshots of your workspace data through the Pathfinder REST API' (read 2026-09-26). Reached on: Inventory > Export; snapshot API."
}
},
@@ -3454,7 +3620,7 @@
"note": "No integration with a service management tool exists.",
"evidence": {
"sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf: 'ServiceNow integration An integration that connects the subscription services to the customer's ServiceNow subscription to synchronize infrastructure and software asset information'; Jira Service Management integration at https://help.sap.com/docs/leanix/ea/jira-service-management-integration-faqs (read 2026-09-26). Reached on: Administration > Integrations > ServiceNow.",
- "bluedolphin": "docs, intelligence competitor_features#48973 'TOPdesk integration' (2026-07-23): Connector to TOPdesk asset/service data. | docs, intelligence competitor_features#27465 'TOPdesk Integration' (2026-04-12): Available on TOPdesk Marketplace for IT landscape insights",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967779-add-an-integration-in-bluedolphin: 'out-of-the-box integrations with ITSM platforms like TOPdesk, ServiceNow, and JIRA'; https://help.bluedolphin.io/en/articles/11967782-bluedolphin-to-topdesk-integration and https://help.bluedolphin.io/en/articles/12148500-bluedolphin-to-servicenow-integration (read 2026-09-26). Reached on: System settings > Marketplace (paid add on).",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: \"Go to Links > Assets . Click Link asset\" (read 2026-09-26) on calls and changes; TOPdesk is itself the service management tool. Reached on: Call card > Links > Assets.",
"stackiq": "No ITSM connector: lib/Settings/connections.json lists only email, federation and eol-feed; grep for topdesk/servicenow/itsm in lib/ and src/ finds nothing.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: C19: \"Met de exportfunctie kunt u de gegevens in andere tools synchroon houden ... We verwachten in 2019 een pilot met Topdesk ... Een import vanuit die tools naar de Softwarecatalogus ... is vooralsnog niet voorhanden\" (read 2026-09-26); https://www.softwarecatalogus.nl/RID%20de%20Liemers: RID de Liemers signals updates through its TOPdesk change process by hand (read 2026-09-26)",
@@ -3483,7 +3649,7 @@
"note": "As a Nextcloud app it runs on whatever infrastructure hosts the Nextcloud instance.",
"evidence": {
"sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf describes 'The SaaS services' and a customer 'workspace'; https://www.leanix.net/hubfs/Legal/Operational-Terms-Exhibit-v.2.0.pdf defines 'the data center utilized by LeanIX to host Customer's Data' with maintenance windows per hosting region. Only a vendor hosted subscription is offered (read 2026-09-26)",
- "bluedolphin": "docs, intelligence competitor_features#27467 'SaaS Platform' (2026-04-12): Cloud-native SaaS, no installation required",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/15603627-microsoft-copilot-to-bluedolphin-with-mcp: 'BlueDolphin is a SaaS enterprise architecture and business design repository'; tenants run on the vendor's EU and US clusters (https://help.bluedolphin.io/en/articles/11967733-quick-start-guide) (read 2026-09-26)",
"glpi": "source read at 11.0.9: GPL 3 source distributed for installation on own servers (LICENSE, INSTALL.md, install/mysql/glpi-empty.sql schema and the web installer src/Glpi/Controller/InstallController.php). The version is src/autoload/constants.php:43 GLPI_VERSION 11.0.9, the installer controller src/Glpi/Controller/InstallController.php:57, the licence LICENSE:1 GNU GPL version 3.",
"topdesk": "https://docs.topdesk.com/VA2026R3/index.html: \"TOPdesk Virtual Appliance documentation\", releases VA 2023 R2 to VA 2026 R3 (read 2026-09-26); https://tip.topdesk.com/c/255-va-release-q4-2026: roadmap card in column \"Planned\", \"VA Release Q4 2026\" in section \"On premise - VA releases\" (read 2026-09-26). Reached on: Virtual Appliance.",
"stackiq": "appinfo/info.xml: a Nextcloud app (id stackiq, EUPL-1.2) installed on the customer's own Nextcloud with OpenRegister; stackiq-compose.yaml at repo root for a local stack.",
@@ -3497,7 +3663,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "partial",
@@ -3517,6 +3683,7 @@
"glpi": "source read at 11.0.9: every list has a criteria builder, src/Glpi/Search/Input/QueryBuilder.php:72 showGenericSearch, over all search options, for example manufacturer on appliances (src/Appliance.php:229 region, glpi_manufacturers) and status (src/Appliance.php:350); there are no counted facets and no reference component to filter on. Reached on: Management > Appliances, search criteria.",
"stackiq": "lib/Service/FacetService.php:109 DIMENSIONS = referenceComponent, standard, applicationService, domain (GET /api/facets/{schema}, routes.php:195); src/views/FacetedCatalogIndexView.vue renders CnFacetSidebar with these plus search, on the Applications and Services pages. Supplier is only a column (src/manifest.json Modules config columns 'provider'), not a facet, although the module schema marks provider facetable.",
"topdesk": "https://docs.topdesk.com/en/the-asset-management-module-page.html: \"Asset overview : view all your assets in a filterable list\" (read 2026-09-26). Facets with counts are not described. Reached on: Asset Management > Asset overview.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967727-add-filters-to-the-data: 'narrow down repository data based on object properties' with 'Created by, Created on, Changed by, Changed on, and Completeness' and related objects (read 2026-09-26). Reached on: Repository > filters.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/advanced-filter-options: inventory filters by lifecycle, subscription, tags and fields, and https://help.sap.com/docs/leanix/ea/filtering-in-report-urls: 'Apply a filter using the facet filter column' (read 2026-09-26). Reached on: Inventory > facet filter column."
}
},
@@ -3527,7 +3694,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "yes",
@@ -3545,6 +3712,7 @@
"stackiq": "src/views/FacetedCatalogIndexView.vue:68 Saved views menu (save current filters, list, apply); src/store/modules/facets.js:404 saveCurrentAsView POSTs to OpenRegister /apps/openregister/api/views (:61), fetchSavedViews :361 reads them back.",
"topdesk": "https://tip.topdesk.com/c/83-share-saved-overviews-with-operators-and-operator-groups: roadmap card in column \"Launched\", \"User is able to share saved overviews with operators and operator groups - Rename the saved overview\" (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: only VNG-defined \"Marktscans-voorgedefinieerde filters\" are described; users saving their own view is not; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Marktscans (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967727-add-filters-to-the-data: 'You can now save any set of filters as a reusable Quick filter'; https://help.bluedolphin.io/en/articles/14996415-custom-insights: 'You can save, rename, and share report configurations' (read 2026-09-26). Reached on: Repository > Save Query (Quick filter).",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/advanced-filter-options mentions 'creating saved searches' and shareable filtered URLs; the feature list says 'Reports can be saved and shared with user to retrieve the specific view later' (https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf) (read 2026-09-26). Reached on: Inventory > Saved searches."
}
},
@@ -3555,7 +3723,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "yes",
@@ -3573,7 +3741,8 @@
"glpi": "source read at 11.0.9: src/Glpi/Dashboard/Grid.php:1400 adds a 'Number of %s' card for every menu itemtype, so suppliers, appliances, software and contracts are counted (menu types src/Html.php:1298 to :1300); dashboards are stored by src/Glpi/Dashboard/Dashboard.php:66 and shown on the central page (src/Central.php:135). Reached on: Home > Dashboard; Assets > Dashboard.",
"topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: \"open the Asset dashboard to see statistics and visualised information regarding your registered assets\" (read 2026-09-26); https://docs.topdesk.com/en/reporting.html: \"Introducing the Reporting Hub\" (read 2026-09-26). Reached on: Asset Management > Asset dashboard.",
"stackiq": "src/manifest.json:72 Dashboard page with stat widgets kpi-organisations, kpi-modules, kpi-services, kpi-contracts (source metric count on organization/module/catalogService/catalogContract) plus catalog-panels.",
- "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tiles for logged-in municipalities (read 2026-09-26); https://www.softwarecatalogus.nl/: \"Voortgang gemeenten Aantal gemeenten per voortgangscategorie ... Aantal ingelogde gemeenten in 2026: 69\" (read 2026-09-26). No contracts. Reached on: Dashboard; homepage."
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: dashboard tiles for logged-in municipalities (read 2026-09-26); https://www.softwarecatalogus.nl/: \"Voortgang gemeenten Aantal gemeenten per voortgangscategorie ... Aantal ingelogde gemeenten in 2026: 69\" (read 2026-09-26). No contracts. Reached on: Dashboard; homepage.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/14600459-home-page-guide: 'The traditional dashboard has been replaced by a new Home page'; count dashboards come as Power BI templates, 'the Basic Dashboard and the Governance Dashboard' (https://help.bluedolphin.io/en/articles/11967711-power-bi-for-bluedolphin-quickstart) (read 2026-09-26). Reached on: Power BI template dashboards over OData."
}
},
{
@@ -3600,6 +3769,7 @@
"stackiq": "lib/Dashboard/ConceptOrganisatiesWidget.php registered at lib/AppInfo/Application.php:760; src/views/widgets/ConceptOrganisatiesWidget.vue:100 filters organisations on status === 'concept', but the status enum is Draft/Active/Inactive/merged (lib/Settings/softwarecatalogus_register.json:2321) after lib/Repair/RenameDutchCatalogValues.php:76 renamed 'Concept' to 'Draft'. Accept writes status 'actief' (:129), which is not in the enum either.",
"topdesk": "unknown: not a Nextcloud app; no such widget applies; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: the catalogue is not a Nextcloud app; no such widget applies; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; organisations in concept and a Nextcloud dashboard are not covered (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; organisations have no concept state and there is no Nextcloud dashboard, so this is not covered (read 2026-09-26)",
"glpi": "source read at 11.0.9: GLPI is not a Nextcloud app and has no concept organisation state (suppliers only have is_active, install/mysql/glpi-empty.sql:7087), so no such widget exists in its own dashboards (src/Glpi/Dashboard/Grid.php:67)."
}
@@ -3611,7 +3781,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "yes",
@@ -3629,6 +3799,7 @@
"stackiq": "src/manifest.json:1021 Reports page (type reports) with one card, Portfolio rationalization, routing to src/manifest.json PortfolioReport /portfolio-report (PortfolioReportView, GET /api/portfolio-report routes.php:303).",
"topdesk": "https://docs.topdesk.com/en/reporting.html: \"Introducing the Reporting Hub ... So far, you could find dashboards and reports in different places\" (read 2026-09-26); https://tip.topdesk.com/c/20-reporting-hub: roadmap card in column \"Launched\", \"Reporting Hub\" (read 2026-09-26). Reached on: TOPdesk menu > Reporting Hub.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/rapportages: \"Regelmatig worden er rapportages gemaakt over het gebruik van de Softwarecatalogus\" (read 2026-09-26); compliancy monitor and digital accessibility monitor pages. Reached on: Rapportages; Compliancy monitor.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967713-governance-insights: 'Access the Insights from the Main menu under the Visualization section. When you open Insights, the column lists all available reports' (read 2026-09-26). Reached on: Main menu > Visualization > Insights.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/report-types lists ready report types such as 'Landscape Report', 'Matrix Report', 'Roadmap Report'; the feature list names 'Pre-configured reports with adjustable filters' (https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf) (read 2026-09-26). Reached on: Reports."
}
},
@@ -3639,7 +3810,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "no",
@@ -3659,7 +3830,8 @@
"glpi": "source read at 11.0.9: any itemtype list takes arbitrary criteria (src/Glpi/Search/Input/QueryBuilder.php:72), selectable columns, and exports to CSV, PDF, ODS or XLSX (src/Glpi/Search/Output/Xlsx.php); the result can be saved (src/SavedSearch.php:52) and charted on a dashboard (src/Glpi/Dashboard/Grid.php:67). Reached on: any list with criteria, column selection and export.",
"stackiq": "No report builder in src/ or lib/. The only report is the fixed Gartner TIME portfolio report (lib/Controller/PortfolioReportController.php, CSV at :105). The overlay lists portfolio-reporting as status 'soon'.",
"topdesk": "https://docs.topdesk.com/en/reporting.html: \"The Report Wizard is not available for the Asset Management module. Further reporting can be done with the Asset Type Report or the OData feed\" (read 2026-09-26). Reached on: Asset Type Report; OData.",
- "vng-softwarecatalogus": "unknown: only CSV exports for use in a spreadsheet are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)"
+ "vng-softwarecatalogus": "unknown: only CSV exports for use in a spreadsheet are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/14996415-custom-insights: save configurations of supported built in reports; for deeper reports 'you need to use our OData feed and connect it to a BI tool of your choice' (https://help.bluedolphin.io/en/articles/11967711-power-bi-for-bluedolphin-quickstart) (read 2026-09-26). Reached on: Insights > Custom insights; OData with Power BI."
}
},
{
@@ -3669,7 +3841,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -3689,6 +3861,7 @@
"stackiq": "Portfolio report CSV: lib/Controller/PortfolioReportController.php:105 (DataDownloadResponse text/csv), button src/views/organisaties/PortfolioReport.vue:567. No index page sets the library's allowExport (grep allowExport/exportable in src/manifest.json and the register finds nothing), so Applications, Contracts and the other lists have no export.",
"topdesk": "https://docs.topdesk.com/en/asset-dashboard.html: \"Export to .CSV Export to Excel\" (read 2026-09-26). Reached on: Asset dashboard tile menu.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakketversies: \"Export to CSV\" on the filtered package-version list (read 2026-09-26); https://www.softwarecatalogus.nl/Beschikbare%20downloads: \"Ook beschikbaar via knop [Export to csv] op pagina Alle pakketten\" (read 2026-09-26). Reached on: Alle pakketversies > Export to CSV.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967708-connect-power-bi-and-excel-to-the-odata-feed-windows-os connects Excel to the OData feed; the DataCollection 'Export is no longer supported' (https://help.bluedolphin.io/en/articles/11967630-install-and-configure-datacollection-frontend-and-service). A direct export of a filtered list is not documented (read 2026-09-26). Reached on: Excel via OData feed.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/exporting-fact-sheet-data-as-excel-file: 'In the inventory, apply filters to narrow down to the fact sheets that you need to export ... export fact sheet data as an Excel file' (read 2026-09-26). Reached on: Inventory > table view > Export."
}
},
@@ -3716,6 +3889,7 @@
"stackiq": "No scheduled report or report mail job: lib/BackgroundJob/ holds only ContractStatusJob, EolSyncJob, FederationSyncJob and OrganizationContactSyncJob; grep for report scheduling in lib/ and src/ finds nothing.",
"topdesk": "https://docs.topdesk.com/en/details-about-certain-permissions.html: \"Reports & Selections > Schedule reports with my own authorizations : the operator can schedule reports to be regularly saved or sent to contact persons\" (read 2026-09-26). Reached on: Reports & Selections.",
"vng-softwarecatalogus": "unknown: no scheduled reports are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; surveys can be scheduled (https://bluedolphin.io/application-portfolio-management-application-rationalization/ 'Keep data current by scheduling surveys'), but sending reports on a schedule is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; scheduled notification digests (https://help.sap.com/docs/leanix/ea/notifications-center) and scheduled snapshot exports by API (https://help.sap.com/docs/leanix/ea/export) exist, but mailing a report to named people on a schedule is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: saved search alerts, src/SavedSearch_Alert.php:45 with count conditions (src/SavedSearch_Alert.php:53 to :58) and a frequency, run by src/SavedSearch_Alert.php:307 cronSavedSearchesAlerts and sent through the notification system to configured recipients; they notify on a result count rather than sending the report itself. Reached on: Tools > Saved searches > Alerts tab."
}
@@ -3747,6 +3921,7 @@
"stackiq": "src/views/LicensePostureView.vue:84 per-vendor rollup with annual cost from contracts (src/utils/licensePosture.js perVendorRollup); src/views/organisaties/PortfolioReport.vue:143 annualised and one-off cost per TIME quadrant for one selected organisation (lib/Service/PortfolioReportService.php via GET /api/portfolio-report).",
"topdesk": "https://docs.topdesk.com/en/obtain-insights-with-asset-type-report.html: \"do you need an overview of the total costs of new assets?\" (read 2026-09-26); call cost fields in https://docs.topdesk.com/en/fields-for-call-management-reports.html. Reached on: Asset Type Report.",
"vng-softwarecatalogus": "unknown: costs are not recorded; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; cost is a questionnaire field (https://help.bluedolphin.io/en/articles/11967733-quick-start-guide) but no cost report per organisation or domain is documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-portfolio-management-dashboard: 'application run cost broken down by business capability'; https://help.sap.com/docs/leanix/ea/dashboard-modeling: 'Report on cost per business capability' (read 2026-09-26). Reached on: Dashboards > Application Portfolio Management Dashboard."
}
},
@@ -3774,6 +3949,7 @@
"stackiq": "src/manifest.json:1048 FeaturesRoadmap page (type roadmap, line 1050), footer menu entry FeaturesRoadmapMenu; content from openspec/features.overlay.json statuses stable/beta/soon.",
"topdesk": "https://docs.topdesk.com/en/topdesk-labs.html: \"As a SaaS user, you can turn on the labs features you are curious about through Functional Settings > Labs\" (read 2026-09-26); https://docs.topdesk.com/en/ai-features.html: \"On your settings page, you can find an overview of all the AI features currently available in your environment\" (read 2026-09-26). Coming-soon items live on the external roadmap, not in the app. Reached on: Functional Settings > Labs.",
"vng-softwarecatalogus": "unknown: FAQ E14 points to a homepage block \"Binnenkort in de Softwarecatalogus\", but today's homepage shows no such block; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/ (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; an in app view of available, beta and coming features is not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/ai-governance-extension: 'Go to Administration > Optional Features and Early Access' to activate extensions; the public roadmap is outside the app at https://roadmap.leanix.net/ (read 2026-09-26). Reached on: Administration > Optional Features and Early Access.",
"glpi": "source read at 11.0.9: grep -rli 'coming soon' over src/ templates/ returns no in app feature status page; src/Glpi/Features/ holds item traits (for example src/Glpi/Features/Kanban.php), not feature flags. src/Glpi/Features/Kanban.php:45 is a trait, typical of that directory."
}
@@ -3785,7 +3961,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
@@ -3803,6 +3979,7 @@
"stackiq": "lib/Controller/SettingsController.php:1289 getProgress and :1360 streamProgress (routes.php:119-120) serve lib/Service/ProgressTracker.php, used only by lib/Service/MergeOrganisatieService.php; no src/ caller of /api/progress. The admin ArchiMate import shows a spinner then the final objects-processed count (src/views/settings/sections/ArchiMateImportExport.vue:103). Organisation sync shows a status block with last sync time and organisations to process (src/views/settings/sections/OrganizationSynchronization.vue:211).",
"topdesk": "unknown: import errors can be downloaded as logs; following progress of a running import is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no progress display for sync or import is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967642-source-processing: the source processing module shows when 'the system is currently handling multiple items simultaneously' and items ready for processing; AMEFF import only shows a checkmark when done (https://help.bluedolphin.io/en/articles/11967637-import-ameff-files) (read 2026-09-26). Reached on: Source processing module.",
"sap-leanix": "https://updates.leanix.net/announcements/product-update-march-2026: 'A real-time progress widget in the inventory side-panel keeps you informed of import status'; integration runs are followed in 'Administration > Integrations > Sync Log' (https://help.sap.com/docs/leanix/ea/collibra-data-catalog-integration) (read 2026-09-26). Reached on: Inventory side panel import progress; Administration > Integrations > Sync Log."
}
},
@@ -3831,6 +4008,7 @@
"topdesk": "https://docs.topdesk.com/en/knowledge-management.html: \"The Knowledge Base is set up and managed by your organization's knowledge managers. Every operator is able to use information from the Knowledge Base\" (read 2026-09-26). Reached on: Modules > Knowledge Management.",
"stackiq": "No knowledge-article schema among the register's schemas (sector, suite, catalogService, vulnerability, contactPerson, organization, usage, catalogContract, connection, software-review, element, view, model, property-definition, relation, module, compliancy, bioMeasure, moduleVersion, sbomComponent in lib/Settings/softwarecatalogus_register.json); ModuleDetail only has a Documentation files panel.",
"vng-softwarecatalogus": "unknown: the FAQ and manuals are site help, no knowledge base about applications is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; the Knowledge AI Assistant 'only uses Bluedolphin's publicly available documentation' (https://help.bluedolphin.io/en/articles/12528662-ai-capabilities-of-bluedolphin), a customer knowledge base of articles about applications is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; fact sheets hold links and files in a Resources tab (https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets), but no searchable knowledge base of articles is documented (read 2026-09-26)"
}
},
@@ -3859,6 +4037,7 @@
"stackiq": "No discovery agent or agent-ingest endpoint in lib/ or appinfo/routes.php. The nearest capability is SBOM import per module version (lib/Controller/SbomController.php:129), which records components of a known release, not installed software.",
"topdesk": "https://docs.topdesk.com/en/taking-inventory-with-configuration-management.html: \"TOPsis will scan the workstations in your network and import the data into TOPdesk\" (read 2026-09-26) (old Configuration Management); https://docs.topdesk.com/en/migration-status.html: \"For network scanning purposes, we advise you to use other solutions that are available via the TOPdesk Marketplace: Lansweeper integration Microsoft Endpoint Manager integration\" (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; the DataCollector uploads data from databases and files (https://help.bluedolphin.io/en/articles/11967629-import-and-export-options-with-bluedolphin), an installation discovery agent is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; LeanIX has no own installation agent, software assets come in through the ServiceNow integration (https://help.sap.com/docs/leanix/ea/obsolescence-risk-management-import-software-assets) (read 2026-09-26)"
}
},
@@ -3887,6 +4066,7 @@
"stackiq": "No network scanning code in lib/ or routes (appinfo/routes.php).",
"topdesk": "https://docs.topdesk.com/en/creating-a-new-import.html: \"Connecting to Lansweeper as Asset Management import source\" (read 2026-09-26); https://tip.topdesk.com/c/186-automated-asset-scanning-tool: roadmap card in column \"Under consideration\", \"The asset discovery tool constantly monitors the entire network for new devices\" (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; network discovery is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; network device discovery is not documented (read 2026-09-26)"
}
},
@@ -3915,6 +4095,7 @@
"stackiq": "No SaaS or SSO-log discovery code in lib/; lib/Settings/connections.json has no such source.",
"topdesk": "unknown: SaaS discovery is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for SaaS discovery, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: inventory handlers under src/Glpi/Inventory/Asset/ (Software.php, Process.php, VirtualMachine.php and others) read what the agent sees on devices; grep -i 'saas' over src/ returns nothing, so cloud subscriptions nobody registered are not discovered. The software handler is src/Glpi/Inventory/Asset/Software.php:56."
}
},
@@ -3925,7 +4106,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "no",
@@ -3943,6 +4124,7 @@
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"Think of a router that provides a computer with access to your network, or a printer\" (read 2026-09-26); any asset type via templates. Reached on: Asset Management.",
"stackiq": "No hardware schema in lib/Settings/softwarecatalogus_register.json (schemas are software, organisation, contract and GEMMA model types only).",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967596-archimate-annotation-translation-en-nl lists 'Device' and 'Node' object definitions, and the welcome page names 'servers, applications' as assets (https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin). Modeled as architecture objects, not as an asset register (read 2026-09-26). Reached on: Objects > Device or Node object.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/it-component-modeling-guidelines: IT component subtype 'Hardware ... (e.g., servers, mainframe computers, storage devices)'. Modeled as technology types an application depends on, not individual laptops as assets (read 2026-09-26). Reached on: IT Component fact sheet, subtype Hardware."
}
},
@@ -3953,7 +4135,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "no",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -3971,6 +4153,7 @@
"glpi": "source read at 11.0.9: configuration items are the asset types (src/autoload/CFG_GLPI.php:208) plus appliances, with relations recorded as appliance membership (src/Appliance_Item.php:45), impact relations (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) and network port links. Reached on: Assets menu; item > Impact analysis tab.",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-other-assets.html: \"You register these functionalities as custom link types, and these link types are shown in the graphical overview of assets\" (read 2026-09-26). Reached on: Asset card > Relationships widget.",
"stackiq": "Applications (module lib/Settings/softwarecatalogus_register.json:6777), versions (moduleVersion :7649), suites (suite :1135) and application-to-application connections (connection :3563) with relations; ModuleDetail and SuiteDetail show a Related panel. No manifest page has register+schema 'connection' or 'usage', so connections are not listed or created on their own page.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin lists 'Configuration management' among configurable application areas, with objects such as servers and their relationships; CMDB data comes in from ServiceNow and TOPdesk (https://help.bluedolphin.io/en/articles/11967783-servicenow-to-bluedolphin-integration). An architecture repository rather than an operational CMDB (read 2026-09-26). Reached on: Objects and relationships; ServiceNow integration.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/jira-service-management-integration: 'Use the Jira Service Management integration to synchronize data between your configuration management database (CMDB) and SAP LeanIX ... Configuration items from Jira Service Management can be mapped to various fact sheet types'. LeanIX consumes a CMDB, it does not act as one (read 2026-09-26). Reached on: Jira Service Management and ServiceNow integrations."
}
},
@@ -3981,7 +4164,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
@@ -3998,6 +4181,7 @@
"stackiq": "Organisation merge: src/manifest.json:430 OrganisationMergePanel on OrganisatieDetail, calling /api/organisaties/{uuid}/merge/dry-run and /merge (src/store/modules/organisatie.js:486/524, lib/Controller/MergeController.php:106, admin-only body guard). Federation mirrors are reconciled per peer by lib/Service/Federation/FederationMerger.php.",
"topdesk": "unknown: deduplication across sources is not described; https://tip.topdesk.com/c/239-ai-cmdb-monitoring- (duplicates) is under consideration; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967635-four-things-you-need-to-know-before-you-start-importing-sources: 'for each record an object will be created or merged with an already existing object'; https://help.bluedolphin.io/en/articles/11967644-use-datasource-to-enrich-objects enriches objects from a second source (read 2026-09-26). Reached on: Admin > Sources; Source processing.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/aggregation-and-linkage-of-software-records: 'import software records from ServiceNow as aggregated software fact sheets'; https://help.sap.com/docs/leanix/ea/matching-rules: custom matching to avoid 'duplicate fact sheets'; SaaS discovery links the same SaaS found in several SSOs (https://help.sap.com/docs/leanix/ea/saas-discovery) (read 2026-09-26). Reached on: ServiceNow integration > aggregation; matching rules; SaaS discovery inbox.",
"glpi": "source read at 11.0.9: src/RuleImportAsset.php:46 import and link rules decide whether an incoming inventory record matches an existing asset (by serial, UUID, MAC and similar) or creates one; src/RuleDictionnarySoftware.php:44 normalises software names and publishers from different sources; duplicates can be merged afterwards (src/Software.php:1011). Reached on: Administration > Rules > Rules for import and link equipments; Dictionaries."
}
@@ -4027,6 +4211,7 @@
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: \"On Call, Change (Activity) ... cards, you can link multiple assets\" (read 2026-09-26). Reached on: Call card > Links > Assets.",
"stackiq": "No incident or request schema or endpoint in lib/Settings/softwarecatalogus_register.json or appinfo/routes.php.",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; incidents stay in the ITSM tool, logging them against an application in BlueDolphin is not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/portals: an Application Portal 'accessible to everyone to order software, issue support tickets' through configurable links to the helpdesk; incidents themselves stay in the ITSM tool (read 2026-09-26). Reached on: Portals > links to helpdesk."
}
},
@@ -4055,6 +4240,7 @@
"topdesk": "https://docs.topdesk.com/en/requesting-a-change.html: \"A Preliminary Request for Change can only be dealt with as a Request for Change after it is authorized\" (read 2026-09-26). Reached on: Modules > Change Management.",
"stackiq": "No change-request workflow for applications. The only approval flow is for contracts: src/components/contracts/ContractApprovalPanel.vue on ContractDetail via /api/contracts/{uuid}/approval (routes.php:35-37), delegated to decidiq.",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; a change approval workflow on an application is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; architecture decisions have a review process (https://help.sap.com/docs/leanix/ea/architecture-decisions) but a change approval workflow on an application is not documented (read 2026-09-26)"
}
},
@@ -4083,6 +4269,7 @@
"topdesk": "https://docs.topdesk.com/en/track-when-you-respond-to-calls, response-times.html: \"you register and track how quickly your operators need to respond ... you need a Contract Management and SLM license\" (read 2026-09-26). Reached on: Contract Management and SLM.",
"stackiq": "catalogContract.contractType enum includes 'SLA' (lib/Settings/softwarecatalogus_register.json:3344) as a label only; no service-level target, measurement or breach fields in any schema.",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for SLA and service level, no hits (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: 'Service Level Agreement (SLA) Single Select Corporate-Level SLA, Customer-Level SLA, Service-Level SLA' and an SLA description on the contract. No tracking of targets against results (read 2026-09-26). Reached on: Contract fact sheet > Governance and Regulations."
}
},
@@ -4110,6 +4297,7 @@
"topdesk": "https://docs.topdesk.com/en/mobile-access-to-the-self-service-portal.html: \"The SSP layout is suited to be displayed in a mobile interface\" (read 2026-09-26); https://tip.topdesk.com/c/86-webshop-is-connected-with-asset-management: roadmap card in column \"Building\", \"End-user can order items which are in Asset Management\" (read 2026-09-26); pricing lists \"Self-Service Portal\" and \"Webshop\". Reached on: Self-Service Portal.",
"stackiq": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls.",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; the process portal publishes processes (https://help.bluedolphin.io/en/articles/11967500-getting-started-with-process-publication-portal), but requesting software is not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/portals: 'create an Application Portal that is accessible to everyone to order software ... Action button: Perform an action, in this case \"Request new Application\"' (read 2026-09-26). Reached on: Portals > Application Portal.",
"glpi": "source read at 11.0.9: the 11.0 service catalog src/Glpi/Form/ServiceCatalog/ServiceCatalog.php:45 lists native forms for self service users (menu src/Html.php:1283), and a form question can offer software items to pick, src/Glpi/Form/QuestionType/QuestionTypeItem.php:180 Software::class, creating a ticket from the answer. Reached on: Self service > Service catalog. Driven on the lab at 11.0.9 (2026-09-26): /ServiceCatalog shows the service catalog with \"Report an issue\" and \"Request a service\"."
}
@@ -4120,7 +4308,7 @@
"name": "Use the product from a native mobile app.",
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "no",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "yes",
@@ -4138,7 +4326,8 @@
"topdesk": "https://docs.topdesk.com/en/installing-the-topdesk-mobile-store-application.html: \"Scan the QR code to download the app from the Play store\" (read 2026-09-26). Reached on: TOPdesk Mobile app.",
"stackiq": "No mobile app or mobile-specific surface in the repo; the app is the Nextcloud web UI (src/manifest.json).",
"vng-softwarecatalogus": "unknown: operational IT management functions are not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for mobile app, iOS and Android, no hits; only a Microsoft Teams app is documented (https://help.sap.com/docs/leanix/ea/sap-leanix-app-for-microsoft-teams) (read 2026-09-26)",
+ "bluedolphin": "unknown: https://help.bluedolphin.io/en/articles/11967477-minimum-system-requirements lists desktop browsers (Chrome, Firefox, Edge) and says Safari 'is not supported'; a native mobile app is not documented (read 2026-09-26)",
+ "sap-leanix": "https://updates.leanix.net/announcements/explore-portals-on-mobile-devices (2025-09-18): 'Since the mobile app was decommissioned in June 2023, we planned to make portals mobile responsive'; only portals are mobile friendly (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'android\\|ios app\\|mobile app' over src/ templates/ returns nothing; the repository ships only the responsive web interface (templates/) and APIs (src/Glpi/Api/HL/Controller/CoreController.php:322 docs), no native mobile client."
}
},
@@ -4149,7 +4338,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "partial",
"stackiq": "partial",
@@ -4168,6 +4357,7 @@
"stackiq": "lib/BackgroundJob/OrganizationContactSyncJob.php:75 TimedJob every 300 s calling performScheduledSync; admin section src/views/settings/sections/CronjobConfiguration.vue:56 shows each job's interval and an enable switch; src/views/settings/sections/OrganizationSynchronization.vue:211 shows Last Sync from app config last_sync_time (lib/Service/OrganizationSyncService.php:1609, written by recordSyncTime :1674).",
"topdesk": "https://docs.topdesk.com/en/events-that-trigger-actions.html: \"when tracking imports/Exchange exports via system events ... on a schedule\" (read 2026-09-26); https://tip.topdesk.com/c/116-support-for-importing-persons-and-operators-directly-from-local-active-directory: roadmap card in column \"Launched\", person import from AD (read 2026-09-26). Reached on: Settings > Import settings.",
"vng-softwarecatalogus": "unknown: only \"De kaart wordt dagelijks bijgewerkt\" is stated; no organisation or contact sync is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/node/17042 (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin: 'This data can then be synchronized with BlueDolphin based on a scheduled task, periodically (for example, every hour)'; https://help.bluedolphin.io/en/articles/11967629-import-and-export-options-with-bluedolphin: 'Automatically via interval' (read 2026-09-26). Reached on: DataCollection Service; Admin > Sources.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/configuring-automated-nightly-runs-for-inbound-processors: 'enable automated nightly runs for an inbound Integration API processor'; SaaS discovery retrieves data 'usually twice a day' (https://help.sap.com/docs/leanix/ea/saas-discovery); runs visible in 'Administration > Integrations > Sync Log' (read 2026-09-26). Reached on: Administration > Integrations > Sync Log.",
"glpi": "source read at 11.0.9: automatic actions are scheduled and show their last run, src/CronTask.php:59 with install/mysql/glpi-empty.sql:1610 glpi_crontasks.lastrun, but LDAP user and group synchronisation is not one of them (grep -i ldap over the cron seed in install/empty_data.php:438 finds none); it is the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users, which must be scheduled by the system cron. Organisation (supplier) records have no sync at all. Reached on: Setup > Automatic actions; CLI bin/console ldap:sync. Driven on the lab at 11.0.9 (2026-09-26): /front/crontask.php lists automatic actions with run mode, frequency and last run."
}
@@ -4193,13 +4383,13 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: the Gemeentelijk Gegevensmodel is not mentioned; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, GGM and Gemeentelijk Gegevensmodel, no hits; data objects exist (https://help.sap.com/docs/leanix/ea/data-object-modeling-guidelines) but no GGM content (read 2026-09-26)",
+ "bluedolphin": "https://github.com/Gemeente-Delft/Gemeentelijk-Gegevensmodel/blob/master/README.md (third party, maintained by Gemeente Delft): 'Een aantal gemeenten gebruikt het GGM inmiddels ook met ... Blue Dolphin' and 'hiervoor gebruik je het AMEFF-bestand van het GGM uit de GEMMA-repository voor de Architectuur module van BlueDolphin'; AMEFF import at https://help.bluedolphin.io/en/articles/11967637-import-ameff-files. Not a vendor feature (read 2026-09-26). Reached on: Admin > System > Import (GGM AMEFF), then relationships.",
"glpi": "source read at 11.0.9: grep -rli 'gegevensmodel\\|ggm' over src/ templates/ locales/glpi.pot returns nothing; appliances have no data entity model to relate to (install/mysql/glpi-empty.sql:8935 glpi_appliances).",
"topdesk": "unknown: the Gemeentelijk Gegevensmodel is not mentioned (0 hits); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown"
},
@@ -4224,13 +4414,13 @@
"vng-softwarecatalogus": "partial",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"Download de kaart met de knop [download SVG] ... De kaart volledig schaalbaar\" (read 2026-09-26). A map is downloaded as SVG for printing; placing it in Word or PowerPoint is a manual step. Reached on: Mijn softwarecatalogus > Pakketten > Toon kaart > download SVG.",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/using-reports: 'Using the HTML Embed Code, you can embed and have live data from the SAP LeanIX inside a tool such as Confluence and PowerPoint (using a Web Viewer add-ins)'; diagrams export as PDF, SVG, PNG (https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams). No direct Word or PowerPoint export (read 2026-09-26). Reached on: Reports > Export > HTML embed; Diagrams > Export.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967514-download-a-view: 'To use the image of a view, for example, in a document, you can download the view as a file in PNG, SVG, PDF'. No direct Word or PowerPoint insertion is documented (read 2026-09-26). Reached on: View > Download.",
"glpi": "source read at 11.0.9: the only diagram is the impact graph, whose Download writes PNG or JPEG (js/impact.js:2539, :2546); grep -rli 'docx\\|pptx\\|powerpoint' over src/ finds no Office export of views, only XLSX and ODS list output (src/Glpi/Search/Output/Xlsx.php).",
"topdesk": "unknown: architecture views and Word or PowerPoint are not mentioned (0 hits for PowerPoint); searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown"
},
@@ -4254,13 +4444,13 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: no data modelling is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/data-object-modeling-guidelines: 'we capture data in the data object fact sheet', related to applications and classified; entity relationship or UML diagrams of data entities are not documented (read 2026-09-26). Reached on: Inventory > Data Object fact sheet.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967570-keys-and-relationships: 'Primary keys are unique identifiers for a data object and can be used to create a relationship between data objects'; https://help.bluedolphin.io/en/articles/11967568-logical-data-dictionary; views of type 'Logical Data' (https://help.bluedolphin.io/en/articles/11967483-views-button-explanation) (read 2026-09-26). Reached on: Views > Logical Data view.",
"glpi": "source read at 11.0.9: grep -rli 'entity.relationship\\|uml' over src/ templates/ locales/glpi.pot returns nothing; databases are inventoried as instances and names (src/DatabaseInstance.php:43, src/Database.php:41, install/mysql/glpi-empty.sql:9468 glpi_databases) without entities or relations.",
"topdesk": "unknown: no data entity or UML modelling is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "sap-leanix": "partial",
+ "bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown"
},
@@ -4284,13 +4474,13 @@
"vng-softwarecatalogus": "partial",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/gebruikersbeheer: \"Er opent zich een overzicht met alle geregistreerde gebruikers van uw organisatie ... inclusief wanneer zij voor het laatst hebben ingelogd\" (read 2026-09-26); https://www.softwarecatalogus.nl/: tip \"Controleer of alle gebruikers nog werkzaam zijn bij de gemeente of samenwerking\" (read 2026-09-26). A manual check, no review cycle. Reached on: Menu > Gebruikersbeheer.",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for access review and recertification, no hits; user statuses are listed in https://help.sap.com/docs/leanix/ea/users-overview but periodic access review is not documented (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/13714834-power-bi-for-bluedolphin-governance: the Basic Governance dashboard 'supports access reviews and permission audits'. A Power BI template; withdrawing access is a manual admin step (read 2026-09-26). Reached on: Power BI governance dashboard; Admin > Users.",
"glpi": "source read at 11.0.9: grep -rli 'recertif\\|access review' over src/ templates/ locales/glpi.pot returns nothing; users carry last_login and validity dates (install/mysql/glpi-empty.sql:7813 last_login, :7866 begin_date, :7867 end_date) that an admin can search on, but there is no periodic review campaign.",
"topdesk": "https://docs.topdesk.com/en/operator-licence-overview.html: the list of operators shows \"When the given operator was last active (meaning their last login)\" (read 2026-09-26). Input for a review; no periodic review process is described. Reached on: Operator licence overview."
},
"sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "partial"
},
@@ -4315,8 +4505,8 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: no link to a register of processing activities is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for processing activities, ROPA and Article 30, no hits (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for processing activities and verwerkingsregister, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'processing activit\\|gdpr' over src/ returns nothing; the records of processing plugin yild/gdprropa (tag 1.0.3, setup.php:56) supports GLPI 10 only.",
"topdesk": "unknown: no register of processing activities is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4346,8 +4536,8 @@
"vng-softwarecatalogus": "yes",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"De leveranciersinformatie in de Softwarecatalogus is openbaar\" (read 2026-09-26); https://www.softwarecatalogus.nl/inkoopondersteuning%20standaarden: \"De gegenereerde bestekstekst kunt u gebruiken in uw offerte-uitvraag ... Als informatiebron is de GEMMA softwarecatalogus gebruikt\" (read 2026-09-26). Reached on: Supplier login > Productportfolio; Inkoopondersteuning.",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; suppliers keeping public product information in the catalogue is not documented (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; public supplier product information is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers have no account or public product page (install/mysql/glpi-empty.sql:7067 glpi_suppliers); anonymous access covers only the FAQ (src/KnowbaseItem.php:131 use_public_faq).",
"topdesk": "unknown: TOPdesk is a single-organisation tool; public supplier product information is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4377,13 +4567,13 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: no value, cost or risk scoring is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/application-rationalization: baseline data points 'Business criticality', 'Functional and technical fit'; TCO per application (https://help.sap.com/docs/leanix/ea/application-total-cost-of-ownership-extension) and obsolescence risk feed TIME classification (https://help.sap.com/docs/leanix/ea/time) (read 2026-09-26). Reached on: Application fact sheet > Business criticality, Functional fit, Technical fit.",
+ "bluedolphin": "https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'Capture lifecycle, technical debt, business value, risk, cost, contracts, ESG, and security data' and 'multidimensional portfolio analysis from cost, risk, lifecycle, and business criticality perspectives' with TIME analysis (read 2026-09-26). Reached on: APM questionnaires and TIME analysis.",
"glpi": "source read at 11.0.9: grep -rli 'business value' over src/ locales/glpi.pot returns nothing; appliances carry no value, cost or risk score fields (install/mysql/glpi-empty.sql:8935 glpi_appliances), only the software ticket_tco figure (install/mysql/glpi-empty.sql:6872).",
"topdesk": "unknown: no value, cost and risk scoring of applications is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
"glpi": "no",
"topdesk": "unknown"
},
@@ -4406,13 +4596,13 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #136 'Als CISO wil ik ons gemeentelijk pakketoverzicht kunnen controleren en vervolgens fiatteren'; no approval step for the landscape appears in the incumbent manuals (https://www.softwarecatalogus.nl/node/19703). (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/quality-seal: the quality seal 'assigns accountability to the responsible or accountable user to approve the quality of a fact sheet'; https://help.sap.com/docs/leanix/ea/subscription-roles lists a default 'Security officer' role as Observer. Approval is per fact sheet, not a sign off of the whole list (read 2026-09-26). Reached on: Fact sheet > Quality seal.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; a security officer sign off of the application list is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: approvals exist only on ITIL objects (src/CommonITILValidation.php:49, children TicketValidation and src/ChangeValidation.php:39); there is no sign off of the appliance list itself. A change could be used to carry an approval, which is not a catalogue sign off.",
"topdesk": "unknown: a sign-off of the application list is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown"
@@ -4436,8 +4626,8 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #82 'Als gebruik-raadpleger wil ik een register van verwerkingen kunnen genereren'; the incumbent exports only package, connection and IBD-foto files (https://www.softwarecatalogus.nl/Beschikbare%20downloads). (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for register of processing activities, no hits (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; generating a register of processing activities is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'processing activit\\|gdpr' over src/ returns nothing, so there is no register to generate; the report list (src/Report.php:77 to :111) has no such report.",
"topdesk": "unknown: no register of processing activities is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4466,8 +4656,8 @@
"vng-softwarecatalogus": "partial",
"evidence": {
"vng-softwarecatalogus": "Open PvE wens #50 (search) and #48 (register collective agreements incl. AVG and BIO terms); the incumbent lists signed addenda per supplier with a filter (https://www.softwarecatalogus.nl/addenda), which covers part of it. (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; collective or framework agreements for all municipalities are not covered (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; collective agreements for municipalities are not covered (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'collective agreement\\|raamovereenkomst' over src/ locales/glpi.pot returns nothing; contracts (install/mysql/glpi-empty.sql:1483) belong to the instance's own entities and nothing is shared across organisations.",
"topdesk": "unknown: collective agreements across organisations are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4496,8 +4686,8 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #41 'relevante documenten zoals DPIA's, verwerkersovereenkomsten en pentesten kunnen delen zodat andere gemeenten hier eenvoudig gebruik van kunnen maken'; the incumbent only holds supplier test reports (https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier). (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; files attach to fact sheets inside one workspace (https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets), sharing them with other organisations is not documented (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; attachments stay on objects inside one tenant (https://help.bluedolphin.io/en/articles/11967535-object-attachments), sharing them with other organisations is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: documents (src/Document.php:67) are visible only inside the instance through entities and profiles; anonymous access is limited to FAQ attachments when use_public_faq is on (src/Document.php:717), and there is no sharing with other organisations.",
"topdesk": "unknown: assets hold documents in a Documents widget, but sharing them with other organisations is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4526,8 +4716,8 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #46 'Als CISO wil ik de pakketten in mijn pakketoverzicht van een BBN classificatie voorzien'; BBN exists only as a GEMMA view per reference component per the news page (https://www.softwarecatalogus.nl/nieuws). (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for confidentiality, integrity and availability levels; only data objects are classified by sensitivity (https://help.sap.com/docs/leanix/ea/data-object-modeling-guidelines 'public, sensitive, restrictive, and confidential') (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; availability, integrity and confidentiality levels per application are not documented beyond generic questionnaires (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'confidentialit' over src/ templates/ locales/glpi.pot returns nothing and appliances have no availability, integrity or confidentiality fields (install/mysql/glpi-empty.sql:8935 glpi_appliances); only a repurposed dropdown or a custom asset field could hold it.",
"topdesk": "unknown: no availability, integrity and confidentiality classification is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4556,8 +4746,8 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #31 'meerdere pakketten kunnen selecteren en deze in een overzichtelijke tabel naast elkaar vergelijken'; the incumbent offers filtered lists only (https://www.softwarecatalogus.nl/node/13683). (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; a side by side product comparison table is not documented, only inventory table views (https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; comparing products side by side is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: any list can be narrowed to chosen entries with criteria (src/Glpi/Search/Input/QueryBuilder.php:72) and shows the chosen columns in one table, with installation counts per software on the software list; there is no dedicated compare view across products and no market data to compare (src/Glpi/Search/SearchEngine.php:101 searches own records only). Reached on: Assets > Software list with chosen columns.",
"topdesk": "unknown: no product comparison table is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4586,8 +4776,8 @@
"vng-softwarecatalogus": "unknown",
"evidence": {
"vng-softwarecatalogus": "unknown: the live softwarecatalogus.nl does not describe this and does not state its absence; the open PvE wens on the successor repository is not evidence about the incumbent (ruling 2026-09-26). Live page searched: Open PvE wens #104 'Als functioneel beheerder wil ik me kunnen voordoen als een ander account'; not in the incumbent FAQ (https://www.softwarecatalogus.nl/node/16564). (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; impersonation is mentioned only for an integration user when building ServiceNow filters (https://help.sap.com/docs/leanix/ea/fact-sheet-mapping-between-servicenow-and-sap-leanix), not for admins viewing as another user (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; viewing the tool as another account is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/Session.php:2054 startImpersonating and :2113 stopImpersonating, allowed by src/Session.php:1995 canImpersonate for users with fewer rights and the Impersonate right (src/User.php:6235); the button 'Impersonate' is on the user form (src/User.php:2974). CHANGELOG.md 11.0.0 adds the dedicated right. Reached on: Administration > Users > user form, Impersonate.",
"topdesk": "unknown: acting as another user is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4616,8 +4806,8 @@
"vng-softwarecatalogus": "partial",
"evidence": {
"vng-softwarecatalogus": "Open PvE wens #147; the incumbent shows whether a supplier signed the Groeipact Common Ground addendum (https://www.softwarecatalogus.nl/leveranciers), a supplier-level signal, not per product. (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for Common Ground, no hits (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for Common Ground, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'common ground' over src/ templates/ locales/glpi.pot returns nothing; software and appliances carry no principle or goal declarations (install/mysql/glpi-empty.sql:6856 glpi_softwares).",
"topdesk": "unknown: Common Ground is not mentioned; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
@@ -4646,13 +4836,13 @@
"vng-softwarecatalogus": "partial",
"evidence": {
"vng-softwarecatalogus": "2021 user survey suggestion 'Koppelingen automatisch bijwerken bij een nieuwe versie van pakket'; release 4.1 added a manual copy of a version including its connections (https://www.softwarecatalogus.nl/node/16564, FAQ A1). (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/creating-fact-sheets: 'Cloning fact sheets is particularly useful when you need to create a successor fact sheet ... A cloned fact sheet includes ... All relations, except one-to-one relations', and the clone can be linked as successor. The carry over happens when a user clones (read 2026-09-26). Reached on: Fact sheet > Clone (as successor).",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; carrying relationships to a new version is not documented; objects can be copied (https://help.bluedolphin.io/en/articles/11967529-welcome-to-the-objects) without a stated relation copy (read 2026-09-26)",
"glpi": "source read at 11.0.9: installations can be moved to another version by the massive action src/Item_SoftwareVersion.php:179 move_version, but impact relations (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) point at the item and are never copied to a replacing version or appliance; grep -n 'Impact' src/SoftwareVersion.php returns nothing.",
"topdesk": "unknown: versions of applications are not modelled; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown"
@@ -4677,13 +4867,13 @@
"evidence": {
"topdesk": "Card 'More control over card & file removal' in Launched (updated 2026-02-09); docs https://docs.topdesk.com/en/file-maintenance.html: 'you can set how many days after closing or archiving a card its uploaded files and linked emails should be removed'. (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: retention cleanup is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/archiving-deleting-and-recovering-fact-sheets: an archived fact sheet 'remains recoverable for 90 days ... After the retention period, the archived fact sheet is automatically and permanently deleted'. Retention covers archived records as a whole, not files and mails after closure (read 2026-09-26). Reached on: Archive > automatic deletion after retention period.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for retention, only questionnaire data retention on BPMN configuration is mentioned (https://help.bluedolphin.io/en/articles/15874771-questionnaires-for-bpmn-elements); timed removal of files is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: closed tickets are purged after a per entity delay, src/Ticket.php:5363 cronPurgeTicket using install/mysql/glpi-empty.sql:2777 autopurge_delay, and documents left without any linked item are removed by src/Document.php:1713 cronCleanOrphansDocument (described at src/Document.php:1700); catalogue records such as appliances or contracts have no closed state or retention delay. Reached on: Administration > Entities > Assistance tab (automatic purge); Setup > Automatic actions."
},
"note": "Mined from topdesk (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "partial"
},
@@ -4707,8 +4897,8 @@
"evidence": {
"topdesk": "Card 'Field Dependencies (brand/type/model)' in Under consideration: 'User can set up dependencies between fields'; not in the field docs (https://docs.topdesk.com/en/editing-fields.html). (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: dependent fields are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; dependent fields appear only in transformation templates (https://help.sap.com/docs/leanix/ea/creating-custom-transformation-templates), not for fact sheet field options (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; questionnaire field options depending on another field are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: native forms show or hide questions on conditions (src/Glpi/Form/Condition/Engine.php:138, src/Glpi/Form/Condition/VisibilityStrategy.php:39), but options of one field do not filter by another on item forms; the open requests github.com/glpi-project/roadmap/discussions/414 (cascading filters) and /240 (custom field conditions) ask for it. Reached on: Administration > Forms, question conditions."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
@@ -4737,8 +4927,8 @@
"evidence": {
"topdesk": "Card 'Changing the type of an asset' in Under consideration: 'User can change the type of an exiting asset'. (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: changing an entry type is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; changing the fact sheet type or subtype of an existing entry is not documented as such (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; changing the type of a BPMN element is documented (https://help.bluedolphin.io/en/articles/11967561-add-an-object), changing the object definition of an existing repository object is not (read 2026-09-26)",
"glpi": "source read at 11.0.9: the type of an appliance is an editable dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id), changeable in place or by massive update (src/MassiveAction.php:666); changing the itemtype itself (for example a custom asset to another definition) is not possible, since each custom asset class is bound to one definition (src/Glpi/Asset/Asset.php:113), and the open request github.com/glpi-project/roadmap/discussions/232 asks for it. Reached on: Management > Appliances, Type field."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
@@ -4767,8 +4957,8 @@
"evidence": {
"topdesk": "Card 'Audit Logging for TOPdesk - MCP Server' in Building: 'you should be able to see exactly what that AI did, which actions it took, when, and on what data'. (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no AI assistant is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; the fact sheet change log records user and time (https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets), but a view of actions taken by an AI assistant is not documented (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; the MCP server is read only (https://help.bluedolphin.io/en/articles/15602927-add-bluedolphin-mcp-server-to-an-ai-assistant) and AI credit usage is reported, but a log of AI actions on records is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: there is no AI assistant in core (grep -rliw 'llm\\|mcp' over src/ returns nothing); the history log (src/Log.php:48) records changes per user or API client, without any AI actor."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
@@ -4798,10 +4988,10 @@
"topdesk": "Card 'Support Multi-Factor Authentication (MFA)' in Under consideration; today MFA only comes from the identity provider behind SAML SSO (https://docs.topdesk.com/en/topdesk-mobile.html: 'We test the store application with the Microsoft two-step authentication (2FA) for the SSO'). (read 2026-09-26)",
"glpi": "source read at 11.0.9: CHANGELOG.md:277 11.0.0 added Two-Factor Authentication via TOTP; implemented by src/Glpi/Security/TOTPManager.php:60, with the disable action on the user's settings page (front/preference.php).",
"vng-softwarecatalogus": "unknown: login is by username and password (https://www.softwarecatalogus.nl/user/login); a second factor is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for multi factor and two factor, no hits; strong sign in is left to the identity provider through SSO (https://help.sap.com/docs/leanix/ea/managing-users) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for multi factor and two factor, no hits; strong sign in is left to the SSO identity provider (read 2026-09-26)"
},
- "note": "Mined from topdesk (roadmap) on 2026-09-26. Also shipped in GLPI 11.0.0 (https://github.com/glpi-project/glpi/releases/tag/11.0.0).",
+ "note": "Mined from topdesk (roadmap) on 2026-09-26. Also mined from glpi (changelog, https://github.com/glpi-project/glpi/releases/tag/11.0.0).",
"glpi": "yes",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
@@ -4827,13 +5017,13 @@
"evidence": {
"topdesk": "Card 'Enforce strong passwords' in Under consideration: 'By setting rules for things like minimum length, numbers, symbols, or uppercase letters, weak passwords are blocked'. (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: a password policy is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/password-rules: 'We offer two options for password rules: regular and strict', set through support for the workspace (read 2026-09-26). Reached on: Workspace password rules (via support).",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; local passwords are managed in 'BlueDolphin's private Active Directory' (https://help.bluedolphin.io/en/articles/11967616-user-management) but no password policy setting is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: Setup > General > Security enables a password policy (templates/pages/setup/general/security_setup.html.twig:46 use_password_security, :56 password_min_length, :63 password_need_number, :70 password_need_letter), enforced by src/User.php:7187 validatePassword with checks for length, digits, letters, capitals and symbols (src/User.php:7196 onwards), plus expiry settings (install/empty_data.php:380 password_expiration_delay). Reached on: Setup > General > Security."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"glpi": "yes"
},
@@ -4857,8 +5047,8 @@
"evidence": {
"topdesk": "Card 'AI - Risk & prediction' in Under consideration: 'Change risk prediction helps change managers assess how risky a planned change is before it's approved'. (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: change management is not covered; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; a risk score for a planned change from past outcomes is not documented (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; change risk scoring is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: changes carry manual urgency, impact and priority (install/mysql/glpi-empty.sql:659 urgency, :660 impact, :661 priority) and a free text impact analysis (:663 impactcontent); no score is computed from past outcomes or dependencies, and grep -rli 'risk' over src/Change.php returns nothing."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
@@ -4887,14 +5077,14 @@
"evidence": {
"glpi": "source read at 11.0.9: open request #336 (2026-05-22) asks to add all connected assets to the impact analysis at once; in core every impact relation is added by hand through src/Impact.php:1161 'Add relation' into install/mysql/glpi-empty.sql:1247 glpi_impactrelations, and the inventory (src/Glpi/Inventory/Inventory.php:106) does not create impact relations.",
"vng-softwarecatalogus": "unknown: connections are entered by hand per the iJw and iWmo manual; automatic filling is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/jira-service-management-integration: 'Dependencies and relationships identified in Jira Service Management are automatically documented in SAP LeanIX'; SAP Cloud ALM 'Discovered flows' suggest missing interfaces (https://help.sap.com/docs/leanix/ea/enabling-discovered-flows) (read 2026-09-26). Reached on: Integrations and discovery inbox.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967645-use-datasource-to-create-relationships: 'how to automatically create relationships between objects based on a loaded datasource', for example application component to node (read 2026-09-26). Reached on: Admin > Sources > relationship creation.",
"topdesk": "unknown: relations are created by hand in the Relationships widget; automatic filling is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from glpi (featureRequest) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "yes",
"topdesk": "unknown"
},
{
@@ -4917,8 +5107,8 @@
"evidence": {
"glpi": "source read at 11.0.9: open request #182 (2026-03-27) states contracts cannot be linked in GLPI 11; install/mysql/glpi-empty.sql:1536 glpi_contracts_items links a contract to items, and Contract is not among the linkable item types there, with no parent contract column in install/mysql/glpi-empty.sql:1483 glpi_contracts.",
"vng-softwarecatalogus": "unknown: contracts are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model lists contract relations to providers and applications only; contract to contract links such as call offs are not documented (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; links between contracts such as call offs are not documented (read 2026-09-26)",
"topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"TOPdesk allows you to link your services to supplier services, so that the duration of your services will always be in line with the duration of supplier services\" (read 2026-09-26). Linking runs through underpinning services, not contract to contract. Reached on: Contract Management and SLM > Service card."
},
"note": "Mined from glpi (featureRequest) on 2026-09-26.",
@@ -4947,13 +5137,13 @@
"evidence": {
"glpi": "source read at 11.0.9: open request #290 (2026-05-07) asks for contract assignees as notification recipients; install/mysql/glpi-empty.sql:1483 glpi_contracts has no users_id or groups_id column, so contract alerts (src/NotificationTargetContract.php:47) go to configured global recipients only.",
"vng-softwarecatalogus": "unknown: contracts are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/step-2-set-up-contract-lifecycle-automations: automations 'notify contract owners at key milestones' and 'Ensure data quality by prompting for required ownership information', owners set through subscriptions (read 2026-09-26). Reached on: Contract fact sheet > Subscriptions; contract automations.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; a contract owner who receives expiry warnings is not documented (read 2026-09-26)",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Operator The TOPdesk operator responsible for managing the contract ... Reminder date Date on which an operator should be reminded about the contract, e.g. ahead of expiry\" (read 2026-09-26); https://docs.topdesk.com/en/events-that-trigger-actions.html: \"notify a manager that a contract will expire in a month\" (read 2026-09-26). Reached on: Contract card > Management > Operator."
},
"note": "Mined from glpi (featureRequest) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"topdesk": "yes"
},
@@ -4977,8 +5167,8 @@
"evidence": {
"glpi": "source read at 11.0.9: request #457 (2026-07-27, open) asks to tie dates to status; core already lets an entity fill financial dates when an item enters a chosen status, install/mysql/glpi-empty.sql:2800 autofill_use_date and :2822 autofill_decommission_date on glpi_entities, applied by src/Infocom.php:505 autofillDates, but only for the financial record's dates.",
"vng-softwarecatalogus": "unknown: statuses and planning dates are entered separately; automatic dates are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; lifecycle phases are set by dates (https://help.sap.com/docs/leanix/ea/advanced-filter-options), filling dates automatically when a status changes is not documented (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; dates filled automatically on a lifecycle state change are not documented (read 2026-09-26)",
"topdesk": "unknown: automated actions can update cards, but dates following a lifecycle status are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from glpi (featureRequest) on 2026-09-26.",
@@ -5007,13 +5197,13 @@
"evidence": {
"glpi": "source read at 11.0.9: CHANGELOG.md:281 11.0.0 added 'View assigned' and 'Update assigned' rights; src/Glpi/Features/AssignableItem.php:68 grants read when the user or group is assigned and src/Glpi/Features/AssignableItem.php:79 checks UPDATE_ASSIGNED; Appliance uses this trait (src/Appliance.php:46 implements AssignableItemInterface).",
"vng-softwarecatalogus": "unknown: roles are beheerder and raadpleger per organisation; rights per assigned application are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/subscription-roles: admins 'control what users can do within a fact sheet based on their subscription type'; virtual workspaces restrict visibility by group (https://help.sap.com/docs/leanix/ea/virtual-workspaces-configuration). Seeing only one's own assigned entries is not documented (read 2026-09-26). Reached on: Administration > Subscription permissions.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; permissions are per role and object definition (https://help.bluedolphin.io/en/articles/11967624-manage-roles-and-permissions) and views can be private, but limiting users to entries assigned to them is not documented (read 2026-09-26)",
"topdesk": "https://docs.topdesk.com/en/details-about-certain-permissions.html: \"To restrict access to specific data, link the operator to branch, operator, or category filters\" (read 2026-09-26); https://docs.topdesk.com/en/reservations-management-and-other-modules.html: \"Operator filter: operators can see all reservations, but can only edit reservations that are created by them or their operator group\" (read 2026-09-26). Filters by branch, operator or category; not shown for assets assigned to a person. Reached on: Operator card > filters."
},
"note": "Mined from glpi (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "partial",
"bluedolphin": "unknown",
"topdesk": "partial"
},
@@ -5037,13 +5227,13 @@
"evidence": {
"glpi": "source read at 11.0.9: CHANGELOG.md:276 11.0.0 added custom palette and theme support; src/Glpi/UI/ThemeManager.php:103 getCustomThemesDirectory and :112 getCustomThemes load admin supplied themes, offered in src/Config.php:1612 getPalettes.",
"vng-softwarecatalogus": "unknown: the catalogue is one VNG-branded site; organisation styling is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/branding-settings: 'Personalize your workspace's appearance to reflect your brand identity' and upload 'a custom logo to be used in exported reports and diagrams' (read 2026-09-26). Reached on: Administration > Branding.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; a colour palette for objects and shapes exists (https://help.bluedolphin.io/en/articles/11967691-using-the-color-palette-for-objects-and-free-shapes) but interface branding is not documented (read 2026-09-26)",
"topdesk": "https://docs.topdesk.com/en/self-service-portal-278632.html: \"you can create several SSP designs, with different colours, logos, and search bar backgrounds, to show a distinct look and feel to different branches\" (read 2026-09-26). Self-Service Portal only; operator interface styling is not described. Reached on: Self-Service Portal designer."
},
"note": "Mined from glpi (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
+ "sap-leanix": "yes",
"bluedolphin": "unknown",
"topdesk": "partial"
},
@@ -5067,15 +5257,345 @@
"evidence": {
"glpi": "source read at 11.0.9: CHANGELOG.md:285 and :286 11.0.0 added cloning of templates and creating a template from an existing item; appliances are clonable (src/Appliance.php:49 use Clonable) together with their items, contracts, documents and financial record (src/Appliance.php:62 getCloneRelations).",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: FAQ A1 \"opvoer van een nieuwe versies mogelijk als kopie van een op te geven vorige versie ... Gegevens van die vorige versie worden overgenomen in de nieuwe versie, ook koppelingen worden overgenomen\" (read 2026-09-26). Copies a version of the same package with its connections, not a new application. Reached on: Mijn softwarecatalogus > Pakketten > kopie-symbool.",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/creating-fact-sheets: 'Cloning a Fact Sheet ... A cloned fact sheet includes the following data from the original fact sheet: All attributes All relations, except one-to-one relations' and attachments (read 2026-09-26). Reached on: Fact sheet > Clone.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967529-welcome-to-the-objects: on the Object properties tab you can 'create a copy of the object with a different name'; whether relationships are copied is not stated (read 2026-09-26). Reached on: Objects > object > Object properties > copy.",
"topdesk": "https://docs.topdesk.com/en/copying-assets.html: \"you can save time by copying an existing asset ... Dataset content will not be copied during this action ... Read permissions for any linked asset type\" (read 2026-09-26). Whether links are copied is implied by the permission note, not stated. Reached on: Asset card > More > Copy."
},
"note": "Mined from glpi (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "partial",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "partial",
"topdesk": "partial"
+ },
+ {
+ "id": "land-ai-agent-inventory",
+ "area": "landscape",
+ "name": "Register the AI agents and AI models the organisation uses and link them to the applications and processes they support.",
+ "origin": "changelog",
+ "originUrl": "https://updates.leanix.net/announcements/discover-verify-and-govern-ai-assets-with-sap-ai-agent-hub",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no schema for AI agents or models in lib/Settings/softwarecatalogus_register.json (20 schemas, none for AI systems)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "sap-leanix": "yes",
+ "evidence": {
+ "sap-leanix": "Announcement of 2026-05-12: 'We have expanded the AI Agent Hub ... New discovery sources: ServiceNow and SAP AI Core ... automatically populate your workspace with AI assets'; AI agent is an application subtype and AI model an IT component subtype (https://help.sap.com/docs/leanix/ea/application-modeling-guidelines) (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from sap-leanix (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "arch-decision-register",
+ "area": "architecture",
+ "name": "Record architecture decisions with a status and review flow, and link each decision to the applications it affects.",
+ "origin": "changelog",
+ "originUrl": "https://updates.leanix.net/announcements/classify-architecture-decisions-with-dropdown-fields",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "the only decisions are contract approval and renewal decisions delegated to decidiq (catalogContract.decisions, lib/Settings/softwarecatalogus_register.json, and lib/Service/ContractApprovalService.php); no architecture decision record",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "sap-leanix": "yes",
+ "evidence": {
+ "sap-leanix": "Announcement of 2026-07-13: admins 'add single-select and multi-select dropdown fields to architecture decision templates'; https://help.sap.com/docs/leanix/ea/architecture-decisions: 'Document decisions about enterprise architecture in a structured, template-driven format ... Track decisions through a review process with defined statuses', shown on linked fact sheets (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from sap-leanix (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "ins-natural-language-query",
+ "area": "insight",
+ "name": "Ask a question about the landscape in plain language inside the tool and get an answer that cites the entries it used.",
+ "origin": "changelog",
+ "originUrl": "https://updates.leanix.net/announcements/answer-your-questions-in-seconds-with-the-enterprise-architecture-assistant",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no assistant in stackiq lib/ or src/ (see share-ai-assistant, where only OpenRegister's generic MCP endpoint exists outside the app)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "sap-leanix": "yes",
+ "evidence": {
+ "sap-leanix": "Announcement of 2026-06-23: 'Ask a question in plain language, and the assistant provides a sourced answer from your workspace ... Every answer is attributed to its source'. A premium AI feature needing AI units (read 2026-09-26)",
+ "bluedolphin": "Product news entry of 2026-09-01 'Communicate in natural language to find business information in BlueDolphin'; https://help.bluedolphin.io/en/articles/12528662-ai-capabilities-of-bluedolphin: 'AI Navigator answers questions asked in plain language ... Answers are grounded in your BlueDolphin repository and include direct links to relevant content' (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from sap-leanix (changelog) on 2026-09-26. Also mined from bluedolphin (changelog, https://bluedolphin.io/product-news/).",
+ "bluedolphin": "yes",
+ "vng-softwarecatalogus": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "comp-ai-act-classification",
+ "area": "compliance",
+ "name": "Classify the AI systems in the landscape by EU AI Act risk category and keep the evidence the act requires.",
+ "origin": "roadmap",
+ "originUrl": "https://roadmap.leanix.net/c/812-meta-model-eu-ai-act-extension",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no AI system or AI Act risk property on module or any other schema in lib/Settings/softwarecatalogus_register.json",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "sap-leanix": "partial",
+ "evidence": {
+ "sap-leanix": "Roadmap card 'Meta model: EU AI Act extension' is In progress (read from the portal data on 2026-09-26); today the legacy AI agent extension already has an 'AI Risk ... according to the EU AI Act' single select (https://help.sap.com/docs/leanix/ea/ai-agent-extension-to-meta-model), so a basic risk field exists but the full extension is not shipped (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from sap-leanix (roadmap) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "life-version-tolerance",
+ "area": "lifecycle",
+ "name": "Set how many releases behind the latest version a technology may run, and flag the components that fall outside that window.",
+ "origin": "roadmap",
+ "originUrl": "https://roadmap.leanix.net/c/830-ea-assistant-technology-successor-planning",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "the end-of-life feed only stamps support end dates on module versions (lib/Service/EolSyncService.php:145, EolMatcherService); no rule for how many releases behind a version may run",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "sap-leanix": "no",
+ "evidence": {
+ "sap-leanix": "Roadmap card 'EA Assistant: Technology Successor Planning' is On roadmap; https://updates.leanix.net/announcements/work-with-complete-technology-version-coverage-without-raising-manual-requests (2026-09-17): 'version concurrency management, which we plan to implement in Q4. You will be able to define version tolerance windows' (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from sap-leanix (roadmap) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "arch-diagram-version-compare",
+ "area": "architecture",
+ "name": "Compare two saved versions of an architecture diagram and see what was added, removed or changed.",
+ "origin": "changelog",
+ "originUrl": "https://updates.leanix.net/announcements/compare-the-content-of-different-diagram-versions",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "stackiq renders no architecture view (see arch-gemma-views), so there is nothing to compare; ArchiMate files are imported and exported whole",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "sap-leanix": "yes",
+ "evidence": {
+ "sap-leanix": "Announcement of 2025-09-03: 'Selecting Compare Changes ... on a prior diagram version shows color-coded highlighting (green for additions, red for removals, yellow for modifications), a side-by-side view of differences, and an additional text-based summary' (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from sap-leanix (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "bluedolphin": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "share-lifecycle-conditional-sync",
+ "area": "sharing",
+ "name": "Send entries to connected outside systems only once they reach a chosen lifecycle state.",
+ "origin": "changelog",
+ "originUrl": "https://bluedolphin.io/blog/november-2025-product-updates-effortless-enterprise-architecture-management/",
+ "stackiq": "unknown",
+ "built": {
+ "state": "none",
+ "evidence": "stackiq has no sync code of its own; outgoing events go through OpenRegister flows authored on the Flows page (src/manifest.json:1057, see share-webhooks), and whether a flow can gate on a lifecycle status was not traced",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "openregister",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "bluedolphin": "yes",
+ "evidence": {
+ "bluedolphin": "November 2025 update (2025-11-13): 'Conditional Syncing for Integrations and Webhooks' lets teams 'control exactly what data syncs to third-party systems based on lifecycle state' (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from bluedolphin (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "ins-usage-analytics",
+ "area": "insight",
+ "name": "See which views and pages of the catalogue are actually used, and which guest users can reach them.",
+ "origin": "changelog",
+ "originUrl": "https://bluedolphin.io/blog/february-2026-bluedolphin-updates-more-visibility-better-governance-smarter-insights/",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no page view or usage tracking in lib/ or src/ (grep analytics, pageview)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "bluedolphin": "yes",
+ "evidence": {
+ "bluedolphin": "February 2026 update (2026-02-10): new reports show 'which guest users have access to BlueDolphin' and 'which views are being used across the platform'; https://help.bluedolphin.io/en/articles/13868249-usage-insights (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from bluedolphin (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "land-move-between-workspaces",
+ "area": "landscape",
+ "name": "Move one or many entries to another workspace or section without recreating them.",
+ "origin": "changelog",
+ "originUrl": "https://bluedolphin.io/blog/june-2026-bluedolphin-updates/",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "entries belong to an organisation through OpenRegister multitenancy (see org-data-segregation); no stackiq page or action moves an entry to another organisation or register",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "bluedolphin": "yes",
+ "evidence": {
+ "bluedolphin": "June 2026 update (2026-06-11): 'You can move one or multiple objects to another workspace directly from the Repository without leaving your current view', skipping objects already in the target (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from bluedolphin (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "arch-process-step-fields",
+ "area": "architecture",
+ "name": "Record structured fields on individual process steps, such as risk level or a compliance check.",
+ "origin": "changelog",
+ "originUrl": "https://bluedolphin.io/blog/july-2026-bluedolphin-updates/",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "stackiq models no processes (see arch-process-mapping)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "bluedolphin": "yes",
+ "evidence": {
+ "bluedolphin": "July 2026 update (2026-07-09): customers can 'define questionnaires directly on BPMN elements such as tasks and events'; https://help.bluedolphin.io/en/articles/15874771-questionnaires-for-bpmn-elements: 'centralize documentation like risk levels, compliance checks, and technical specifications' (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from bluedolphin (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
+ },
+ {
+ "id": "arch-view-tags",
+ "area": "architecture",
+ "name": "Tag saved diagrams and views and filter the view list by tag, owner or status to find them again.",
+ "origin": "changelog",
+ "originUrl": "https://help.bluedolphin.io/en/articles/16096602-discover-and-manage-views-in-the-views-list",
+ "stackiq": "no",
+ "built": {
+ "state": "none",
+ "evidence": "no page lists or tags views (src/store/modules/view.js defines a view store nothing imports, see arch-gemma-views)",
+ "owner": "ConductionNL/stackiq"
+ },
+ "reachedOn": "nothing reaches it",
+ "provider": "stackiq",
+ "providerHow": "read-from-code",
+ "featureConfidence": "medium",
+ "bluedolphin": "yes",
+ "evidence": {
+ "bluedolphin": "Product news entry of 2026-09-08 'Bring structure to your Views list with tags' (https://bluedolphin.io/product-news/); the linked article lists view filters 'Owner Contributors Tags Favorited Private Project Status Type' (read 2026-09-26)",
+ "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ },
+ "note": "Mined from bluedolphin (changelog) on 2026-09-26.",
+ "vng-softwarecatalogus": "unknown",
+ "sap-leanix": "unknown",
+ "glpi": "unknown",
+ "topdesk": "unknown"
}
],
"pending": [
@@ -5104,7 +5624,7 @@
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: municipality adds the supplier's package and version to its own landscape (\"om het pakket toe te voegen aan je omgeving\") (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E1 \"Leveranciers onderhouden de gegevens van hun producten ... Gemeenten en Samenwerkingen onderhouden de gegevens van het eigen applicatieportfolio\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/meta-model: 'An organization uses an application' as a relation between organization and application fact sheets; https://help.sap.com/docs/leanix/ea/organization-modeling-guidelines: 'Organizations are intended to address who is using certain applications' (read 2026-09-26). Reached on: Application fact sheet > Organizations relation.",
- "bluedolphin": "docs, intelligence competitor_features#48965 'Application Portfolio Management' (2026-07-23): APM integrated with the overall EA repository.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967550-working-with-object-relationships: relationships between objects, such as an actor or business unit using an application, carry a type and lifecycle state; https://help.bluedolphin.io/en/articles/11967604-manage-relationship-questionnaires adds details to a relationship. No usage record separate from the product is documented as such (read 2026-09-26). Reached on: Relationships between actor and application objects.",
"stackiq": "register.json:2654 usage schema (consumer, module, moduleVersion, status); no manifest page has schema usage (src/manifest.json pages list); src/views/LifecycleRoadmapView.vue:339 and src/views/KwetsbaarhedenView.vue:316 only READ usage; lib/Controller/AangebodenGebruikController.php:654 setGebruikSelfToActiveOrg (PUT /api/aangeboden-gebruik/{id}/set-self) has no caller in src/",
"topdesk": "unknown: one organisation per environment; a separate usage record is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"glpi": "source read at 11.0.9: use is recorded as installations separate from the software product, src/Item_SoftwareVersion.php:39 (install/mysql/glpi-empty.sql:1064 glpi_items_softwareversions) per device, and licence assignments per item or user; there is no usage record of a module by an organisation as such. Reached on: Assets > Software > Installations tab."
@@ -5118,7 +5638,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "no",
@@ -5135,6 +5655,7 @@
"stackiq": "lib/Repair/* only migrate stackiq's own old slugs/keys (e.g. lib/Repair/MigrateRegisterSlug.php, RenameDutchCatalogValues.php); lib/Service/ArchiMateImportService.php imports GEMMA/AMEF ArchiMate models, not catalogue registrations; src/modals/object/MigrationObject.vue is only mounted for modal 'migrationOrganisatie' (src/modals/Modals.vue:10), which nothing sets",
"topdesk": "unknown: no import from the VNG Softwarecatalogus is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: this is the previous catalogue itself; no import of an earlier registration is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967629-import-and-export-options-with-bluedolphin: import from 'Access databases, Excel files, and CSV files'; https://help.bluedolphin.io/en/articles/11967637-import-ameff-files for ArchiMate models. No importer for a specific previous catalogue (read 2026-09-26). Reached on: Admin > Sources; Admin > System > Import.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/importing-fact-sheet-data-through-excel-file and https://help.sap.com/docs/leanix/ea/integration-api: bulk import from spreadsheets and a JSON based Integration API; no importer for a specific previous catalogue is documented (read 2026-09-26). Reached on: Inventory > Import; Integration API.",
"glpi": "source read at 11.0.9: data from earlier GLPI versions is carried over by src/Update.php:172 doUpdates with the chain in install/migrations/ (update_0.85.x_to_0.90.0.php up to the 11.0 steps); data from another catalogue needs the separate datainjection plugin (pluginsGLPI/datainjection tag 2.15.11, inc/backendcsv.class.php). Reached on: web installer update; plugin Data injection."
},
@@ -5147,7 +5668,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "partial",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "partial",
"stackiq": "partial",
@@ -5165,7 +5686,7 @@
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Selecteer vervolgens de betreffende pakketversie. De richting van het berichtenverkeer ... Selecteer vervolgens de betreffende standaard en versie\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > toevoegen.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines: 'Interfaces should have one provider application and could have multiple consumer applications', data flow direction incl. 'Bi-Directional', and 'type of transfer' (read 2026-09-26). Reached on: Inventory > Interface fact sheet.",
- "bluedolphin": "docs, intelligence competitor_features#48964 'ArchiMate & BPMN modeling' (2026-07-23): Standards-based enterprise architecture and process modeling. | Rated partial because ArchiMate flow relations.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967604-manage-relationship-questionnaires: a relationship carries 'a source and a target object, a type of the relationship, a lifecycle state, and a free text label', and relationship questionnaires add fields such as the standard used (read 2026-09-26). Reached on: Objects > Relationships tab; relationship questionnaire.",
"stackiq": "register.json:3563 connection schema: moduleA (:3689), moduleB, dataExchangeDirection AtoB/BtoA/bi-directional (:3676), standardVersions (:3735), type; no manifest page has schema connection; src/modals/Modals.vue:39 accepts 'connection' but nothing opens it",
"topdesk": "https://docs.topdesk.com/en/hierarchy-of-relationships.html: \"When assets are linked with a link type , one of the assets often supplies a certain feature to another asset. The supplying asset therefore is the parent asset\" (read 2026-09-26). Direction via parent and child; no standard per relation. Reached on: Asset card > Relationships widget.",
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1247 glpi_impactrelations stores a directed link from a source item to an impacted item with a name, added via src/Impact.php:1161 'Add relation'; there is no field for the standard or protocol used. Reached on: Appliance > Impact analysis tab, Add relation."
@@ -5198,6 +5719,7 @@
"stackiq": "register.json:3020 usage.koppelingen (connections used within this usage); no page for usage or connection; lib/Controller/AangebodenGebruikController.php:208 /api/koppelingen-gebruik/{uuid} returns koppelingen+gebruiken, no src caller",
"topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"Geef bij status in productie of gepland aan\"; connections are registered in the organisation's own landscape (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; recording that an organisation runs a connection, separate from its existence, is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; interfaces belong to one workspace, and a usage of a connection separate from its existence is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: an impact relation (install/mysql/glpi-empty.sql:1247) is a single fact in one instance; there is no separate usage record saying the organisation runs it, and grep -n 'usage' src/ImpactRelation.php returns nothing."
},
@@ -5229,6 +5751,7 @@
"stackiq": "register.json:2718 usage.participants; lib/Controller/AangebodenGebruikController.php:578 GET /api/aangeboden-gebruik/deelnemers (usages where the active org is a participant) and :208 /api/koppelingen-gebruik/{uuid}; no caller in src/",
"topdesk": "unknown: usage of relations across organisations is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: A10: \"Een Samenwerking geeft aan welke gemeenten gebruik maken van een betreffende koppeling. Die gemeentenamen worden getoond\" (read 2026-09-26). Reached on: Alle koppelingen.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; each tenant is one customer's repository, and connections run jointly with other organisations are not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; each workspace is one customer's own, and connections run jointly with other organisations are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: relations live inside one instance (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) and entities are subdivisions of one organisation (src/Entity.php:58); no cross organisation sharing of connections exists (grep -rli 'federat' src/ returns nothing)."
},
@@ -5260,6 +5783,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"Referentiecomponenten aangegeven door leverancier ... Toegevoegde referentiecomponenten\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > toevoegen.",
"stackiq": "lib/Settings/softwarecatalogus_register.json module.referenceComponents (array of element $ref, hideOnForm:true) and usage.usedForReferenceComponents; src/manifest.json ModuleDetail md-data include list omits referenceComponents; src/services/facets.js:31 + lib/Service/FacetService.php:659 read the mapping for the referenceComponent facet on /modules",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for GEMMA, no hits; a third party README (https://github.com/Gemeente-Delft/Gemeentelijk-Gegevensmodel/blob/master/README.md) says municipalities load the GGM data model into BlueDolphin via AMEFF, but GEMMA reference components as a mapping target are not documented by the vendor (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, VNG and municipal, no hits; the reference catalog offers business capability blueprints by industry (https://help.sap.com/docs/leanix/ea/reference-catalog) but GEMMA reference components are not mentioned (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'gemma\\|reference component' over src/ locales/glpi.pot returns nothing; the only classification of an appliance is its type dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id)."
},
@@ -5291,6 +5815,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F: \"de pakketten die getoond worden in het pakketoverzicht te plotten op een GEMMA architectuurkaart ... [Toon kaart]\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Toon kaart.",
"stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/{viewId}; lib/Service/ViewService.php:415 enrichViewNodes adds modules/usage/deelnames per node; lib/Service/ArchiMateExportService.php:2734 copyAndEnrichViews nests the org's applications inside copies of GEMMA views in the org ArchiMate export",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for GEMMA, no hits; GEMMA views with own applications drawn in are not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -rli 'gemma\\|archimate' over src/ templates/ locales/glpi.pot returns nothing; the only diagram is the impact graph (src/Impact.php:252 displayGraphView)."
},
@@ -5322,6 +5847,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: cooperation packages: \"kies bij Organisaties welke gemeenten ... de betreffende applicatie gebruiken ... Het pakket verschijnt dan ook alleen op de lijst en kaart van de samenwerking en niet bij de gemeenten\" (read 2026-09-26). Drawing shared apart from own is not described. Reached on: Samenwerking > Pakketten > Organisaties.",
"stackiq": "lib/Service/ViewService.php:1187 getDeelnamesGebruikData + :924 tags shared usage with _type='deelnames' and _sourceOrganization; lib/Service/ArchiMateExportService.php:3005 org export gives every nested application the same green fillColor, deelnames only get their own folder (:3086)",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for GEMMA, no hits (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, no hits; no partner overlay on a reference view is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no GEMMA views (grep -rli 'gemma' src/ returns nothing) and no partner sharing; the impact graph (src/Impact.php:1559 makeDataForCytoscape) draws one instance's items only."
},
@@ -5353,6 +5879,7 @@
"stackiq": "appinfo/routes.php:185-187 GET /api/views, /api/views/docs, /api/views/{viewId} -> lib/Controller/ViewController.php:82,218 (@NoAdminRequired) -> lib/Service/ViewService.php:108,166 read views from the AMEF register; GEMMA elements are element objects in the AMEF register, readable through the OpenRegister objects API",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no API over GEMMA in the catalogue is documented; GEMMA overviews are copied from GEMMA Online tables; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for GEMMA, no hits; the public API serves the tenant's own objects (https://help.bluedolphin.io/en/articles/11967730-about-the-bluedolphin-api) (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for GEMMA, no hits (read 2026-09-26)",
"glpi": "source read at 11.0.9: the v2 API controllers (src/Glpi/Api/HL/Controller/, for example AssetController.php:149 /Assets) expose GLPI itemtypes only; grep -rli 'gemma' src/ returns nothing."
},
@@ -5384,6 +5911,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"via de optie Voeg extra standaarden toe de gewenste standaard te selecteren ... Ondersteuning(gepland) en Compliancy\" (read 2026-09-26). Reached on: Supplier login > productversie > standaarden.",
"stackiq": "lib/Settings/softwarecatalogus_register.json compliancy.standardVersion ($ref element, queryParams gemmaType=standaardversie) + compliancy.module + compliancy.standardGemma (string); src/manifest.json Komplianties /komplianties index on the voorzieningen register; ModuleDetail md-compliance object-list has allowCreate:false; module.standardVersions is hideOnForm",
"topdesk": "unknown: GEMMA and standards are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; declaring support for a version of a standard per application is not documented beyond generic questionnaire fields (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; technology standards apply to tech stack items (https://help.sap.com/docs/leanix/ea/technology-standards-management-capabilities), declaring support for a version of an interoperability standard per application is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no standards model (grep -rli 'standaard' src/ locales/glpi.pot returns nothing); software versions (install/mysql/glpi-empty.sql:6900) carry no supported standard."
},
@@ -5415,6 +5943,7 @@
"stackiq": "lib/Controller/AanbodController.php:200 acceptAanbod and :303 denyAanbod, lib/Service/AanbodService.php:289 checks the active organisation is aanbieder or afnemer then re-owns the object; routes appinfo/routes.php PUT /api/aanbod/{uuid}/accept, DELETE /api/aanbod/{uuid}/deny; also /api/aangeboden-gebruik/{id}/set-self and /deny",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: suppliers see \"Mijn gemeenten\" (who registered their packages) but accepting or declining a usage is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; suppliers have no role in a customer tenant, so accepting a claimed usage is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; suppliers have no role in a customer workspace, so accepting a claimed usage is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers have no login or role (install/mysql/glpi-empty.sql:7067 glpi_suppliers is a plain record; profiles in src/Profile.php:55 are for users), so no supplier can accept or decline a claimed usage."
},
@@ -5446,6 +5975,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle gemeenten helpt bijvoorbeeld in het verkrijgen van inzicht welke gemeenten dezelfde pakketten gebruiken ... Ook met betrekking tot een bepaald beleidsthema, referentiecomponent of standaard\" (read 2026-09-26). Reached on: Inlogmenu > Alle gemeenten / Alle pakketoverzichten.",
"stackiq": "lib/Controller/ViewController.php (routes GET /api/views, /api/views/{viewId}) enriches GEMMA views with shared usage (deelnames); src/store/modules/view.js:89 calls it but no component imports that store",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; comparison with other customers' landscapes is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; comparison with other customers' landscapes is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: no reference components (grep -rli 'reference component' src/ returns nothing) and no data from comparable organisations, since each instance is standalone (src/Entity.php:58 entities are internal)."
},
@@ -5458,7 +5988,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
@@ -5477,6 +6007,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Marktscans: \"kunnen ingelogde gemeenten of samenwerkingen zien bij welke collega-gemeenten betreffende pakketversie in het applicatielandschap staat (klik daarvoor op het getal boven Ingevuld door)\" (read 2026-09-26). Reached on: Package page > Ingevuld door.",
"stackiq": "register :2656 usage (consumer, module); usage read rule lets aanbod-beheerder read usages where provider = own organisation (:3137); ModuleDetail md-related widget src/manifest.json:491; GET /api/koppelingen-gebruik/{uuid} and /api/gebruik in lib/Controller/AangebodenGebruikController.php, lib/Controller/GebruikController.php",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967550-working-with-object-relationships: an application's Relationships tab shows related actors and business units, inside one customer's tenant; which outside organisations use a product is not documented (read 2026-09-26). Reached on: Application object > Relationships tab.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/organization-modeling-guidelines: 'Organizations are intended to address who is using certain applications', within one customer's own business units, regions and legal entities, not across outside organisations (read 2026-09-26). Reached on: Application fact sheet > Organizations relation.",
"glpi": "source read at 11.0.9: within one instance the version Summary tab shows installations per entity, src/Item_SoftwareVersion.php:850 showForVersionByEntity, and the installation list carries the entity column (src/Item_SoftwareVersion.php:484); organisations outside the instance are not visible. Reached on: Assets > Software > version > Summary tab."
},
@@ -5508,6 +6039,7 @@
"stackiq": "lib/Service/ReviewService.php:232 forces pending; lib/Controller/ModerationController.php:81 AuthorizedAdminSetting; src/views/settings/StackiqSettings.vue:98 ModerationQueue type=software-review via src/utils/adminApi.js; lib/Settings/register.d/catalog-ratings.json public read only matches status approved but every catalogue group reads all reviews and may create them",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no reviews are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; there are no reviews, so no review moderation is documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; there are no reviews, so no review moderation is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: there are no product reviews (see mkt-reviews); the only moderation is knowledge base publication by rights on src/KnowbaseItem.php:57, unrelated to reviews."
},
@@ -5520,7 +6052,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "unknown",
"stackiq": "partial",
@@ -5538,6 +6070,7 @@
"stackiq": "register usage authorization (:3137) reads scoped to _organisation or consumer; aanbod-beheerder also reads usages where provider = own organisation; connection read (:3855) public when published and by provider; openspec/specs/vendor-visibility-rbac",
"topdesk": "unknown: TOPdesk is a single-organisation tool; cross-organisation market functions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E2: \"Leveranciers kunnen alleen hun eigen applicatieversies die in gebruik zijn bij gemeenten en samenwerkingen zien ... overigens ziet de leverancier geen status-informatie. Die is vertrouwelijk\" (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967624-manage-roles-and-permissions: 'BlueDolphin uses Role-Based Access Control (RBAC)' within the customer's own tenant; users are added only by admins (https://help.bluedolphin.io/en/articles/11967616-user-management) (read 2026-09-26). Reached on: Admin > Users and Roles.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/manage-workspace-access: 'If a workspace has activated Invitation Only: Visible if the user is invited to this workspace and has a role'; the workspace is 'a self-contained, customer-specific environment' (https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf) (read 2026-09-26). Reached on: Administration > Workspace access.",
"glpi": "source read at 11.0.9: suppliers are records without accounts (install/mysql/glpi-empty.sql:7067 glpi_suppliers) and all data is visible only through the profiles and entities assigned to users (install/mysql/glpi-empty.sql:5917 glpi_profiles_users), so a supplier sees nothing unless given an account. Reached on: Administration > Profiles."
},
@@ -5550,7 +6083,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "no",
- "bluedolphin": "unknown",
+ "bluedolphin": "no",
"glpi": "yes",
"topdesk": "no",
"stackiq": "partial",
@@ -5569,7 +6102,8 @@
"sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf: usage metric 'Application' counted for the subscription, add on products 'subject to additional subscription fees'; https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Application fact sheets are counted for pricing calculations' (read 2026-09-26)",
"glpi": "source read at 11.0.9: LICENSE:1 GNU General Public License version 3, so any municipality or supplier can run it without licence fees; there is no free hosted public service, the paid cloud is GLPI Network by Teclib. Reached on: self hosted install.",
"stackiq": "LICENSE (EUPL-1.2) and appinfo/info.xml: the app is free open source; catalogService and organization carry public read rules for published entries; module's public read also admits every object with registeredBy Supplier, a rule with no publication-date or status condition (lib/Settings/softwarecatalogus_register.json:7322-7327, corrected 2026-09-26); public intake POST /api/intake/register",
- "topdesk": "https://www.topdesk.com/en/pricing/: \"Essential ... £51 Per agent/month\", \"Engaged ... £72\", \"Excellent ... £101\" (read 2026-09-26)"
+ "topdesk": "https://www.topdesk.com/en/pricing/: \"Essential ... £51 Per agent/month\", \"Engaged ... £72\", \"Excellent ... £101\" (read 2026-09-26)",
+ "bluedolphin": "https://bluedolphin.io/pricing/: plans 'Tactical', 'Strategic' and 'Enterprise', with 'Contact sales for pricing' and a free trial only on the Strategic plan, after which 'your workspace continues with limited access unless upgraded' (read 2026-09-26)"
},
"pendingQuestion": "Is a hosted, free-of-charge stackiq instance offered to municipalities and suppliers (the competitor offer is a public service, not software)?"
},
@@ -5600,6 +6134,7 @@
"sap-leanix": "https://help.sap.com/docs/leanix/ea/obsolescence-risk-management-monitor-mitigation: 'You can use automation features to initiate an end-of-life process for applications and alert the responsible individuals well before the end-of-life of an IT component' (read 2026-09-26). Reached on: Administration > Automations (end of life process).",
"stackiq": "src/views/LifecycleRoadmapView.vue:73-86 EOL passed/approaching/withdrawn badges with EOL_WINDOW_DAYS=180 (:143); lib/Settings/softwarecatalogus_register.json moduleVersion x-openregister-notifications eol-approaching (scheduled, dateEndSupport withinNext P180D, recipients software-catalog-admins + object-acl manage) is a declaration only; no notification code in lib (no INotificationManager use)",
"topdesk": "https://docs.topdesk.com/en/events-that-trigger-actions.html: \"…when a card date will be reached within a particular period of time\" (read 2026-09-26). Works on any date field, e.g. a self-defined end-of-support date; no built-in end-of-support. Reached on: Action Management > events.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; end of life dates appear only in an import example (https://help.bluedolphin.io/en/articles/11967633-datacollector-select-tricks '[End-of-Life Date]'), warnings before end of support are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: alerts exist for dates GLPI stores, licence expiry (src/NotificationTargetSoftwareLicense.php:46 'Alarms on expired licenses'), contract end and notice (src/NotificationTargetContract.php:47) and warranty expiry (src/Infocom.php:651 cronInfocom); no end of support date exists on an application or version (install/mysql/glpi-empty.sql:6900 glpi_softwareversions). Reached on: Setup > Notifications; Setup > Automatic actions."
},
"pendingQuestion": "Does the installed OpenRegister dispatch the scheduled x-openregister-notifications rule 'eol-approaching' on moduleVersion, and to whom?"
@@ -5631,6 +6166,7 @@
"stackiq": "lib/BackgroundJob/EolSyncJob.php (registered appinfo/info.xml:101) + appinfo/routes.php:292-295 /api/eol-sync/* -> lib/Service/EolSyncService.php:145 run() reads eol_cycle objects via OpenRegister ObjectService (:328), stamps dateEndSupport on module versions via EolMatcherService; enabled defaults to false (lib/Service/SettingsService.php:7211); lib/Settings/connections.json eol-feed is a switch, off until enabled; the cycles are fetched by integriq's endoflife-date source",
"topdesk": "unknown: no end-of-life feed is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: end-of-support comes from supplier input; no public feed is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; filling end of support dates from a public feed is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -i 'end_of_support\\|endoflife' over install/mysql/glpi-empty.sql and src/ returns nothing; no external lifecycle feed is read (the only outbound catalogues are the plugin marketplace, src/Glpi/Marketplace/). The marketplace client, the only outbound catalogue, is src/Glpi/Marketplace/Controller.php:64."
},
"pendingQuestion": "Is integriq's endoflife-date source (eol_product/eol_cycle register) provisioned on a default install, so that switching the sync on actually finds cycles?"
@@ -5661,6 +6197,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json usage.plannedReplacement ($ref module) + plannedReplacementDate; read by src/views/LifecycleRoadmapView.vue:400; no usage page in src/manifest.json and navigationStore.setModal('usage') is never called (src/modals/Modals.vue:38 lists usage but nothing opens it)",
"topdesk": "unknown: no replacement link is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"geplande harmonisaties ... status gepland met bijbehorende datum ... de uit te faseren applicaties van die status worden voorzien inclusief datum\" (read 2026-09-26). No explicit replaces link. Reached on: Mijn softwarecatalogus > Pakketten > Planning.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; future state objects exist (https://help.bluedolphin.io/en/articles/11967531-object-lifecycle-state), but a replaced by relation between applications is not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/advanced-filter-options: 'analyze your target architecture landscape, provided that you have also modeled successors effectively'; roadmap report option 'showSuccessors' (https://help.sap.com/docs/leanix/ea/report-url-parameter-reference) (read 2026-09-26). Reached on: Fact sheet > Successor relation; Roadmap Report.",
"glpi": "source read at 11.0.9: a software can be flagged as an 'Upgrade from' another software, templates/pages/assets/software.html.twig:46 to :50 (is_update with softwares_id, install/mysql/glpi-empty.sql:6864 and :6865); this records succession after the fact, with no planned replacement link for appliances. Reached on: Assets > Software form, Upgrade from."
},
@@ -5673,7 +6210,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "unknown",
"stackiq": "partial",
@@ -5691,6 +6228,7 @@
"stackiq": "lib/Settings/softwarecatalogus_register.json usage.timeClassification enum Tolerate/Invest/Migrate/Eliminate + timeRationale + timeReviewDate; read by lib/Service/PortfolioReportService.php and rendered in src/views/organisaties/PortfolioReport.vue:112 quadrant chart; src/modals/object/ObjectModal.vue:178 has the enum select but is never opened for usage",
"topdesk": "unknown: no TIME classification is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no TIME classification is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://bluedolphin.io/application-portfolio-management-application-rationalization/: 'TIME powered application lifecycle management' and 'TIME analysis across your entire application portfolio' (read 2026-09-26). Reached on: APM, TIME analysis.",
"glpi": "source read at 11.0.9: grep -rli 'tolerate\\|eliminate' over src/ locales/glpi.pot returns nothing; a TIME class can only be held in a repurposed single choice dropdown such as the appliance status (install/mysql/glpi-empty.sql:8950 states_id, values from src/State.php:45) or type (install/mysql/glpi-empty.sql:8941). Reached on: Management > Appliances, Status or Type field."
},
"pendingQuestion": "Is the external VNG frontend or OpenRegister's generic object editor the intended place to set timeClassification, and does it count here?"
@@ -5702,7 +6240,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -5722,6 +6260,7 @@
"glpi": "source read at 11.0.9: install/mysql/glpi-empty.sql:1483 glpi_contracts with name, num (contract number), contracttypes_id, begin_date, duration, notice and renewal, and costs in install/mysql/glpi-empty.sql:1458 glpi_contractcosts. Reached on: Management > Contracts. Driven on the lab at 11.0.9 (2026-09-26): created \"Lab contract\" with number C-001, start date, 12 month duration and 1 month notice.",
"topdesk": "https://docs.topdesk.com/en/creating-a-contract.html: \"Contract Number (mandatory) ... Type ... Start Date (mandatory) ... End Date (mandatory) ... Costs (Services)\" (read 2026-09-26). Reached on: Modules > Contract Management and SLM > New.",
"stackiq": "src/manifest.json:527 Contracten type:index over catalogContract (contractNumber, contractType, startDate, endDate, cost, status); register :3252 catalogContract requires service AND usage; no manifest page has schema usage (grep src/manifest.json)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967596-archimate-annotation-translation-en-nl lists the object definition 'Contract', which takes admin defined questionnaire fields (https://help.bluedolphin.io/en/articles/11967603-manage-object-questionnaires); an import example carries contract start and end dates (https://help.bluedolphin.io/en/articles/11967633-datacollector-select-tricks) (read 2026-09-26). Reached on: Objects > Contract object.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model: contract fact sheet with 'Contract Number', 'Contract Pricing Type', lifecycle phases for start, notice and end, and licensing, maintenance and support costs, linked to applications and providers (read 2026-09-26). Reached on: Inventory > Contract fact sheet (contract extension)."
},
"pendingQuestion": "Does the installed OpenRegister accept a catalogContract without the required usage (schema hardValidation false), and can the related-object picker create a usage inline?"
@@ -5754,6 +6293,7 @@
"sap-leanix": "https://help.sap.com/docs/leanix/ea/step-2-set-up-contract-lifecycle-automations: 'Prevent missed renewals through proactive notification workflows ... Enable timely decisions with escalation alerts before notice periods' (read 2026-09-26). Reached on: Administration > Automations (contract lifecycle).",
"stackiq": "lib/Settings/softwarecatalogus_register.json:3255 x-openregister-notifications contract-expiry filters status equals 'Actief' but the status enum is Active/Expired/In negotiation (:3428), and the subject uses {{contractNummer}}/{{eindDatum}} while fields are contractNumber/endDate; Contracten quick filter 'Expiring / expired' filters status Expired only (src/manifest.json:527)",
"topdesk": "https://docs.topdesk.com/en/managing-your-service-and-supplier-contracts.html: \"To prevent the accidental extension of unwanted contracts, TOPdesk warns you when contracts are about to expire\" (read 2026-09-26); https://docs.topdesk.com/en/creating-a-contract.html: \"Reminder date Date on which an operator should be reminded about the contract, e.g. ahead of expiry\" (read 2026-09-26). Reached on: Contract card > Reminder date.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; notifications cover mentions and project deliverables (https://help.bluedolphin.io/en/articles/11967481-user-profile), contract expiry warnings are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: src/Contract.php:1092 cronContract computes end and notice dates and sends the events of src/NotificationTargetContract.php:47 (end of contract, notice, periodicity, periodicity notice); install/mysql/glpi-empty.sql:1508 glpi_contracts.alert sets which alerts apply. Reached on: Management > Contracts, Email alarms field; Setup > Notifications."
},
"pendingQuestion": "Does the installed OpenRegister dispatch scheduled x-openregister-notifications, and does it compare the filter value case/locale-insensitively (it cannot map 'Actief' to 'Active')?"
@@ -5785,6 +6325,7 @@
"stackiq": "lib/Service/ContractApprovalService.php:254 submitForApproval dispatches OCA\\Decidiq\\Event\\DecisionRequestedEvent (fail-closed), :412 projectOutcome sets status Active only on approved; src/manifest.json:579 ContractApprovalPanel on ContractDetail; but register :3428 status enum incl. Active is an editable form field and approvalState (register.d/contracts-to-decidesk.json) is not readOnly; the declared x-openregister-lifecycle uses Dutch states 'In onderhandeling'/'Actief' that match no enum value",
"topdesk": "https://docs.topdesk.com/en/registering-and-validating-contracts.html: \"Create a new Preliminary Contract card ... Validate the contract. You have created an active contract\" (read 2026-09-26). A validation step, no recorded approval decision. Reached on: Contract card > Validate Contract.",
"vng-softwarecatalogus": "unknown: contracts are not described in the public docs; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; approval gating of a contract is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; contracts carry a renewal decision field and fact sheets a quality seal approval (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model), but gating a contract's activation on a recorded approval is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: grep -n 'alidation' src/Contract.php returns nothing and no ContractValidation class exists; approvals exist only for ITIL objects (src/ChangeValidation.php:39), and the contract status is a free dropdown (install/mysql/glpi-empty.sql:1512 states_id)."
},
@@ -5814,6 +6355,7 @@
"stackiq": "src/utils/vulnerabilityExposure.js:54 in-production join vulnerability.modules -> usage.module -> usage.consumer; count shown in the list (src/views/KwetsbaarhedenView.vue:111); per-organisation rows in VulnerabilityExposurePanel on KwetsbaarheidDetail tab (src/manifest.json:997), but a list row opens the edit modal, not the detail page (KwetsbaarhedenView.vue:417)",
"topdesk": "unknown: vulnerabilities are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for vulnerability, no hits (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/searching-for-sbom-library-components-by-package-url: 'Vulnerability remediation tracking: Retrieve the business applications linked to a vulnerable component ... assess the blast radius of a pkg:maven/org.apache.logging.log4j/log4j-core vulnerability'. Only for self-built software with SBOMs (read 2026-09-26). Reached on: SBOM explorer and component search API (Technology Risk and Compliance).",
"glpi": "source read at 11.0.9: no vulnerability data exists (grep -rli 'cve' src/ hits only src/Glpi/System/Requirement/PhpSupportedVersion.php:74), so exposure cannot be derived even though installations per entity are known (src/Item_SoftwareVersion.php:850)."
},
@@ -5845,6 +6387,7 @@
"stackiq": "register.json:1622 x-openregister-notifications 'vulnerability-reported' on vulnerability, trigger created, channels nc-notification + email, recipients group software-catalog-admins and object-acl manage (a declaration only)",
"topdesk": "unknown: vulnerabilities are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no vulnerability functions are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for vulnerability and CVE, no hits (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/api-updates-sbom-async-processing: asynchronous SBOM processing 'will allow us to add additional post-processing mechanisms in the future, such as vulnerability checks. Though there's no established timeline' (read 2026-09-26)",
"glpi": "source read at 11.0.9: no vulnerability events among notification targets; software notifications are licence expiry only (src/NotificationTargetSoftwareLicense.php:46)."
},
@@ -5876,6 +6419,7 @@
"stackiq": "lib/Controller/IntakeController.php:74 PublicPage + AnonRateLimit(5/h) on POST /api/intake/register; lib/Service/IntakeService.php:146 forces registrationStatus pending, publicationDate null; no caller in src/. Separately, organization authorization.create includes 'public' (register :2467)",
"topdesk": "unknown: organisations signing themselves up is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-leverancier-aanmelden: \"Als leverancier kunt u zich aanmelden door de volgende gegevens te sturen naar softwarecatalogus@vng.nl\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-kan-ik-me-als-gemeente-aanmelden: cooperations without an account \"vraag deze dan aan door een mail te sturen\" (read 2026-09-26). Sign-up by e-mail, no online form.",
+ "bluedolphin": "unknown: https://bluedolphin.io/pricing/ offers a free trial workspace on the Strategic plan, which is a customer tenant sign up; organisations signing themselves into a shared catalogue is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; workspaces are provisioned per customer (https://help.sap.com/docs/leanix/ea/sap-for-me-super-cloud-admin-for-workspace-provisioning), self sign up of organisations is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: suppliers are created by staff only (src/Supplier.php:75 sets is_active on add from the staff form) and there is no public sign up page among front/ pages (front/lostpassword.php and front/initpassword.php are the only anonymous account pages)."
},
@@ -5907,6 +6451,7 @@
"stackiq": "lib/Controller/ContactpersonenController.php:393 convertToUser -> lib/Service/Stackiq/ContactPersonHandler.php:292 createUserAccount reads objectData['email'] (:299); automatic path lib/EventListener/StackiqEventListener.php -> lib/Service/ContactpersoonService.php:128 also reads contactData['email']; contactPerson schema (:1788) declares no email (identity moved to Nextcloud Contacts via contactsUid); UI: src/components/ContactpersonenList.vue:97 'Convert to User' inside OrganisatieCard",
"topdesk": "https://docs.topdesk.com/en/step-2, operator-import-with-a-linked-person.html: \"To create operators with a person card linked via the Supporting Files import\" (read 2026-09-26); https://docs.topdesk.com/en/assigning-or-editing-self-service-portal-login-data.html: \"select the TOPdesk field Has access to Self-Service Portal and map it\" (read 2026-09-26). Reached on: Supporting Files imports.",
"vng-softwarecatalogus": "unknown: no conversion of contact persons into accounts is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/gebruikersbeheer (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; users are added by admins or SCIM (https://help.bluedolphin.io/en/articles/11967616-user-management), turning a contact person into an account is not documented (read 2026-09-26)",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/users-overview: 'You can also invite contacts from the Subscriptions tab on a specific fact sheet'; roles come from the invitation or SSO, not automatically from the contact's role (read 2026-09-26). Reached on: Fact sheet > Subscriptions > Invite.",
"glpi": "source read at 11.0.9: contacts (src/Contact.php:45) and users are separate itemtypes with no conversion action; user accounts come from manual creation, LDAP import (src/AuthLDAP.php:59) or authorisation rules (src/RuleRight.php:297 profile action)."
},
@@ -5938,6 +6483,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/19703: \"Handleiding beheer gemeente-samenwerking ... Samenwerkingsverbanden die als doel hebben om de applicatielandschappen van de aangesloten gemeenten te harmoniseren\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30355: cooperation selects the member municipalities per package (read 2026-09-26). Reached on: Samenwerking account > Pakketten.",
"stackiq": "register organization.type 'Collaboration' + participants/deelnames (:2236); usage.participants (:2718); shared landscape endpoint GET /api/aangeboden-gebruik/deelnemers (lib/Controller/AangebodenGebruikController.php) has no caller in src/",
"topdesk": "unknown: cooperations of organisations are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; cooperations of organisations sharing a landscape are not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; cooperations of separate organisations sharing a landscape are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: entities form a tree (src/Entity.php:58 extends CommonTreeDropdown) and records flagged recursive are shared with all child entities (src/Appliance.php:325 is_recursive), so a parent entity can hold a landscape shared by several subordinate units; there is no cooperation of independent organisations. Reached on: Administration > Entities; Appliance Child entities field."
},
@@ -5950,7 +6496,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "partial",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "partial",
@@ -5969,6 +6515,7 @@
"stackiq": "register authorization.read rules with {match: {_organisation: $organisation}} on catalogContract (:3474), contactPerson (:1788), usage (:3137), connection (:3855); public reads only for published entries; lib/Controller/ContactpersonenController.php:293 org guard on the custom endpoint",
"topdesk": "https://docs.topdesk.com/en/details-about-certain-permissions.html: \"To restrict access to specific data, link the operator to branch, operator, or category filters\" (read 2026-09-26). Reached on: Operator card > filters.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E6: \"Alle gegevens ingevoerd door de gemeenten en samenwerkingen zijn alleen zichtbaar voor gemeentelijke raadplegers en beheerders\"; E2 \"Ingelogde gemeenten en samenwerkingsverbanden kunnen de applicatielandschappen en koppelingen van collega-gemeenten ... bekijken\" (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967491-business-units: business units 'organize content (objects and views)' and 'The selected business unit then acts as a filter for navigation'; role permissions apply per object definition (https://help.bluedolphin.io/en/articles/11967624-manage-roles-and-permissions) and views can be private. Per organisation record isolation is not documented (read 2026-09-26). Reached on: Business units; roles; private views.",
"sap-leanix": "https://www.leanix.net/hubfs/Legal/Metrics-and-Feature-List-EAM-SAP-LeanIX-v3.1.pdf: 'Virtual workspaces to control users' read and edit permissions for fact sheets and their content in a federated organization'; https://help.sap.com/docs/leanix/ea/virtual-workspaces-configuration (read 2026-09-26). Reached on: Administration > Virtual Workspaces."
},
"pendingQuestion": "Does the installed OpenRegister evaluate authorization.read match rules with $organisation on the generic object list and detail endpoints the stackiq pages use?"
@@ -5999,6 +6546,7 @@
"stackiq": "lib/Service/Stackiq/ContactPersonHandler.php:646 first contact of an organisation gets the organisation-admin groups; lib/Service/Stackiq/HierarchyHandler.php:79 ensureOrganizationBeheerder and :130 setupManagerRelationships make later users report to the primary beheerder",
"topdesk": "unknown: first-user administrator rules are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/17042: \"Vanuit de gemeente is minimaal één gebruiker aangewezen als beheerder. Deze gebruiker kan nieuwe accounts aanmaken voor collega's\" (read 2026-09-26). Reached on: Gebruikersbeheer.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; making an organisation's first user its administrator is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; admins invite and manage users (https://help.sap.com/docs/leanix/ea/managing-users), but making an organisation's first user its administrator is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: an administrator can delegate user management per entity with a profile holding user rights, and GLPI stops a delegate from granting a profile stronger than their own, src/Profile.php:744 currentUserHaveMoreRightThan and src/Profile.php:679 getUnderActiveProfileRestrictCriteria; nothing makes the first user of an organisation its administrator automatically. Reached on: Administration > Users > Authorizations tab."
},
@@ -6011,7 +6559,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
@@ -6030,6 +6578,7 @@
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/16564: E6: \"Iedereen kan de softwarecatalogus raadplegen ... De gegevens ingevoerd door de leveranciers zijn openbaar\" (read 2026-09-26); https://www.softwarecatalogus.nl/pakketten: package list readable without login (read 2026-09-26). Reached on: Alle pakketten.",
"stackiq": "lib/Settings/softwarecatalogus_register.json:7307 module authorization.read grants group public on publicationDate<=$now (and, separately, on registeredBy=Supplier); lib/Settings/softwarecatalogus_register.json:1559 catalogService same; suite read is plain 'public' (lib/Settings/softwarecatalogus_register.json:1270). No stackiq route is #[PublicPage] except intake/review aggregate/gebruik (lib/Controller/GebruikController.php:102 returns an empty envelope to anonymous callers). The app's pages are all behind Nextcloud login (appinfo/routes.php:313 SPA catch-all).",
"topdesk": "unknown: the Self-Service Portal requires a login per the SSP login settings; public browsing of assets is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967628-guest-login-for-process-publications: 'SSO login works for non-BlueDolphin users in the Process Portal (Published BPMN 2.0 diagrams)'. Readers without an account still sign in through the organisation's SSO, and only processes are published (read 2026-09-26). Reached on: Process Portal (guest SSO).",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/portal-faqs: portals make data 'available to a broad audience outside the IT organization ... an Application Portal that is accessible to everyone'. Whether portal visitors must sign in is not stated (read 2026-09-26). Reached on: Administration > Self Service Portal.",
"glpi": "source read at 11.0.9: the only anonymous content is the public FAQ, gated by use_public_faq (src/KnowbaseItem.php:131, src/Document.php:717); asset, appliance and software lists all require a session (src/Glpi/Controller/GenericListController.php checks canView)."
},
@@ -6060,6 +6609,7 @@
"stackiq": "Anonymous read of the supplier offering depends on declared rules: lib/Settings/softwarecatalogus_register.json:7307 module read includes public on publicationDate<=$now and on registeredBy=Supplier; lib/Settings/softwarecatalogus_register.json:1559 catalogService public on publicationDate. Stackiq's own offering endpoint lib/Controller/AanbodController.php (routes.php:202) is authenticated-only (@NoAdminRequired + in-body guard). Rate limit only on GebruikController (#[AnonRateLimit]).",
"topdesk": "unknown: the REST API requires an operator or API account; a public API is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no public API is documented; public data is offered as CSV downloads; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/api, https://www.softwarecatalogus.nl/Beschikbare%20downloads (read 2026-09-26)",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; all API calls need an x-api-key and tenant (https://help.bluedolphin.io/en/articles/11967730-about-the-bluedolphin-api), a public API over a supplier offering is not documented (read 2026-09-26)",
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea; all APIs authenticate with workspace tokens (https://help.sap.com/docs/leanix/ea/authentication-to-sap-leanix-services), a public API over a supplier offering is not documented (read 2026-09-26)"
},
"pendingQuestion": "Does the installed OpenRegister execute the module/catalogService public read rules for anonymous API callers, and is any API key or rate limit applied to that public surface?"
@@ -6071,7 +6621,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
@@ -6088,6 +6638,7 @@
"stackiq": "lib/Portal/PortalContributionProvider.php:130 getContribution() declares read-only, organisation-scoped collections (catalogService, usage, catalogContract, compliancy) for the vendor-org and participant-org audiences. Portaliq discovers it by FQCN from the Stackiq in appinfo/info.xml (portaliq lib/Contribution/PortalProviderLocator.php:49/77). No info.xml dependency; inert without portaliq.",
"topdesk": "unknown: no shared external portal is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no external portal integration is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967500-getting-started-with-process-publication-portal: the process portal shows processes and, 'For each application, you will find different processes in which the selected application is involved'. Process content on BlueDolphin's own portal, not embedded in a shared external portal (read 2026-09-26). Reached on: Process Portal.",
"sap-leanix": "https://updates.leanix.net/announcements/embed-reports-diagrams-into-portals (2025-12-22): 'Portals can also serve as the primary entry point for business users ... diagrams and reports ... can now be added to portals'; https://help.sap.com/docs/leanix/ea/portals (read 2026-09-26). Reached on: Portals.",
"glpi": "source read at 11.0.9: no embeddable widget or external portal integration for catalogue content; the self service interface (src/Glpi/Form/ServiceCatalog/ServiceCatalog.php:45) is GLPI's own helpdesk portal and grep -rli 'iframe embed\\|oembed' over src/ returns nothing."
},
@@ -6100,7 +6651,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "no",
"topdesk": "no",
"stackiq": "partial",
@@ -6117,6 +6668,7 @@
"stackiq": "No MCP, tool-provider, TaskProcessing or ContextChat code in stackiq lib/ or src/ (grep 'mcp|ToolProvider|assistant|TaskProcessing|ContextChat' in lib/ finds nothing). OpenRegister ships a generic MCP endpoint (openregister appinfo/routes.php:1969 /api/mcp/v1/discover and the JSON-RPC endpoint) over all registers.",
"topdesk": "https://tip.topdesk.com/c/200-ai-mcp-based-service-: roadmap card in column \"Building\", \"Model Context Protocol (MCP-based service) allows secure, controlled connectivity between your TOPdesk environment and LLM-powered assistants\" (read 2026-09-26); the shipped TOPdesk Robin works inside tickets (https://docs.topdesk.com/en/td-robin-for-operators.html).",
"vng-softwarecatalogus": "unknown: no assistant or tool interface is described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/15602927-add-bluedolphin-mcp-server-to-an-ai-assistant: 'This feature enables the third-party AI assistant to query data from BlueDolphin. BlueDolphin MCP can only retrieve data. It cannot create, update, or delete anything' (read 2026-09-26). Reached on: System settings > Integration > MCP API key.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/mcp-server-toolsets: toolset 'inventory ... Get fact sheet information', with create tools for surveys, architecture decisions, diagrams and automations; no tool to update fact sheet fields is listed (read 2026-09-26). Reached on: MCP server (https://mcp.leanix.net/services/mcp-server/v1/mcp).",
"glpi": "source read at 11.0.9: grep -rli 'mcp\\|model context\\|openai\\|llm' over src/ returns nothing; AI tool access would go through the generic v2 API (src/Glpi/Api/HL/Controller/AssetController.php:149) with no tool interface of its own."
},
@@ -6129,7 +6681,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -6146,6 +6698,7 @@
"stackiq": "Stackiq has no webhook code. The Flows page (src/manifest.json:1057, settings-section menu entry FlowsMenu) authors OpenRegister's native flows scoped to app stackiq; OpenRegister's flow event catalogue has object.created/object.updated (openregister lib/Service/Flow/EventCatalogService.php:53-54), and OpenRegister has its own webhooks admin (openregister appinfo/routes.php:1909).",
"topdesk": "https://docs.topdesk.com/en/let-your-topdesk-talk-to-other-applications.html: \"Send a request from TOPdesk to another program ... This way you can create an integration with almost any software that has an API\" (read 2026-09-26) triggered by card events (https://docs.topdesk.com/en/events-that-trigger-actions.html). Reached on: Action Management > action sequences.",
"vng-softwarecatalogus": "unknown: notifications go to people by mail and inbox, no system webhooks are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/12310569-introduction-to-subscriptions: 'Subscriptions provide webhook functionality that allows the notification of external services about specific events in BlueDolphin via HTTP requests', for ObjectCreated, ObjectUpdated and ObjectArchived (read 2026-09-26). Reached on: Public API > subscriptions.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/webhooks: 'Webhooks let you receive updates about events as they happen in near real time ... PUSH webhooks : As events occur in SAP LeanIX , they're sent through HTTP POST requests to the specified target URL' (read 2026-09-26). Reached on: Administration > Webhooks.",
"glpi": "source read at 11.0.9: src/Webhook.php:64 Webhook sends HTTP calls on new, update and delete events (src/Webhook.php:311 getDefaultEventsList) for management itemtypes including Appliance, Budget, Contact and others (src/Webhook.php:398). Reached on: Setup > Webhooks (src/Html.php:1331). Driven on the lab at 11.0.9 (2026-09-26): Setup > Webhooks (/front/webhook.php) lists webhooks with type, event and category."
},
@@ -6158,7 +6711,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "yes",
"topdesk": "yes",
"stackiq": "partial",
@@ -6178,6 +6731,7 @@
"topdesk": "https://docs.topdesk.com/en/designing-templates-for-assets.html: \"History widget : shows both present and past changes that have been made to an asset\" (read 2026-09-26); https://docs.topdesk.com/en/cards-in-call-management.html: \"Audit trail tab Previous events while processing this call\" (read 2026-09-26). Reached on: Asset card > History widget.",
"stackiq": "src/manifest.json:436 (and 10 more detail pages: ContactpersoonDetail, ModuleDetail, ContractDetail, SuiteDetail, StandaardDetail, BioMaatregelDetail, ReviewDetail, KompliantieDetail, ModuleversieDetail, KwetsbaarheidDetail) declare a sidebar tab History with widget type audit, which reads OpenRegister's audit trail for that one object.",
"vng-softwarecatalogus": "unknown: only a \"Laatst gewijzigd\" date on supplier pages and a mutation date in exports are shown; who changed what is not described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier, https://www.softwarecatalogus.nl/Beschrijving%20exportbestanden (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967537-object-history: 'The History tab shows the information about when the object was created, changed, or deleted. It is also made clear by whom the change was made'; view history at https://help.bluedolphin.io/en/articles/11967523-view-history (read 2026-09-26). Reached on: Object > History tab.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/collaborating-and-managing-data-in-fact-sheets: the fact sheet change log shows 'Old Value / New Value', 'User', 'Time' and 'Entries in the log cannot be deleted manually' (read 2026-09-26). Reached on: Fact sheet > History log."
},
"pendingQuestion": "Is OpenRegister's audit trail enabled for the voorzieningen register on a default install, so the History tab shows entries?"
@@ -6189,7 +6743,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
- "bluedolphin": "partial",
+ "bluedolphin": "unknown",
"glpi": "no",
"topdesk": "unknown",
"stackiq": "partial",
@@ -6204,7 +6758,7 @@
"providerHow": "read-from-code",
"note": "Five custom pages subscribe to collection events and refetch on a change. Whether the event ever arrives depends on OpenRegister and the push transport, which this repo cannot show.",
"evidence": {
- "bluedolphin": "docs, intelligence competitor_features#48969 'Real-time collaboration' (2026-07-23): Multiple stakeholders collaborate on models. | Rated partial because real-time collaboration on models.",
+ "bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; views can be shared for collaboration (https://help.bluedolphin.io/en/articles/11967512-collaborate-on-an-architecture-view), but a list that refreshes by itself when another user changes an entry is not documented; the earlier intelligence citation alone is a claim (read 2026-09-26)",
"stackiq": "src/composables/useLiveCollections.js:40 subscribes via the library's useObjectSubscription; used in src/views/KwetsbaarhedenView.vue:197, LicensePostureView.vue:209, LifecycleRoadmapView.vue:184, ComplianceMatrixView.vue:326, PortfolioReport.vue:323. The standard index pages (Contracts, Organisations and others) rely on whatever the library's CnIndexPage does.",
"topdesk": "unknown: live list updates are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: no live list updates are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
@@ -6220,7 +6774,7 @@
"origin": "own-code",
"vng-softwarecatalogus": "yes",
"sap-leanix": "partial",
- "bluedolphin": "unknown",
+ "bluedolphin": "yes",
"glpi": "partial",
"topdesk": "partial",
"stackiq": "partial",
@@ -6240,6 +6794,7 @@
"stackiq": "Only declarations: x-openregister-notifications on vulnerability (lib/Settings/softwarecatalogus_register.json:1622), usage (:2662), catalogContract (:3253), software-review (:3962), module (:6781), moduleVersion (:7652). Stackiq has no INotifier or notification code of its own (grep in lib/). The contract-expiry rule filters status equals 'Actief' (lib/Settings/softwarecatalogus_register.json:3255) while the enum is Active/Expired/In negotiation, so it can never match.",
"topdesk": "https://docs.topdesk.com/en/topdesk-mobile.html: \"change your notification settings\" in the mobile app (read 2026-09-26); https://docs.topdesk.com/en/action-management.html: \"specific mobile alerts for operators\" (read 2026-09-26). Mostly email and mobile alerts, no in-app inbox described. Reached on: TOPdesk Mobile; Action Management.",
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1: \"Gemeenten, samenwerkingen, en leveranciers hebben nu rechtsboven bij het inlogmenu een inbox-symbool met daarbij het aantal nieuwe berichten\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/16564: E17 \"De softwarecatalogus bevat een notificatievoorziening en een inbox voor gemeenten en samenwerkingen\" (read 2026-09-26). Reached on: Inlogmenu > Inbox.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967493-notification-bell: 'The notification bell alerts you when a message on an object or a view has been placed for you'; email notices on deliverable status changes (https://help.bluedolphin.io/en/articles/11967481-user-profile) (read 2026-09-26). Reached on: Top bar > notification bell.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/notifications: 'Notification Channels ... Email : This is the primary channel for notifications ... Microsoft Teams', for fact sheet updates, subscriptions, to-dos and surveys; no in-app channel is listed (read 2026-09-26). Reached on: User menu > My Settings > Notifications."
},
"pendingQuestion": "Does the installed OpenRegister dispatch the x-openregister-notifications rules on vulnerability, software-review, moduleVersion and the scheduled rules on catalogContract/usage/module, as Nextcloud notifications to the listed recipients?"
@@ -6251,7 +6806,7 @@
"origin": "competitor",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
- "bluedolphin": "unknown",
+ "bluedolphin": "partial",
"glpi": "yes",
"topdesk": "partial",
"stackiq": "partial",
@@ -6269,6 +6824,7 @@
"topdesk": "https://marketplace.topdesk.com/: \"Showing all 133 results\" of integrations (read 2026-09-26); https://docs.topdesk.com/en/exporting-and-importing.html: \"import an action sequence example from the TOPdesk Marketplace\" (read 2026-09-26). Integrations and action-sequence templates, not installable plugins. Reached on: TOPdesk Marketplace.",
"stackiq": "src/manifest.json:225 Store page (type store, footer menu StoreMenu) over the OpenRegister store plane, with store.types openregister.configset and openregister.flows; its own note says that with no registry configured it shows only the app's built-in items.",
"vng-softwarecatalogus": "unknown: no plugins are described; searched https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967779-add-an-integration-in-bluedolphin: 'Click Add integration in the bottom right corner of the Marketplace page', with 'Marketplace (Integration) is a paid add-on'. The marketplace holds vendor connectors, not third party plugins (read 2026-09-26). Reached on: System settings > Marketplace.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/extension-hub: 'The SAP LeanIX extension hub is a centralized location where you can discover and install ready-to-use extensions for your SAP LeanIX workspace. These include meta model extensions, surveys, and custom reports'; public hub at https://exthub.leanix.net/en (read 2026-09-26). Reached on: Extension Hub."
},
"pendingQuestion": "Is a store registry configured on a default install, and are any stackiq configuration sets published to it?"
@@ -6293,14 +6849,14 @@
"evidence": {
"topdesk": "Card 'Permission for fields and/or widgets' in Under consideration: 'User can set up permission for any fields or widgets'. (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: field-level permissions are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
- "sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "sap-leanix": "https://help.sap.com/docs/leanix/ea/tags-and-custom-fields: custom attributes when data 'Needs access control, allowing you to restrict read or write permissions to specific users or roles'; https://help.sap.com/docs/leanix/ea/using-reports: 'if a user lacks permission to view or edit a specific field in the metamodel' (read 2026-09-26). Reached on: Administration > Meta Model Configuration > field permissions.",
+ "bluedolphin": "https://help.bluedolphin.io/en/articles/11967624-manage-roles-and-permissions: each role defines 'which actions the user with this role is allowed to perform with the objects and their properties, relationships, questionnaires, and views, for each object definition'. Scoped per object definition and questionnaire, not per single field (read 2026-09-26). Reached on: Admin > Roles > Permissions.",
"glpi": "source read at 11.0.9: custom fields of custom asset types can be made read only or hidden per profile, src/Glpi/Asset/CustomFieldType/AbstractType.php:79 'Readonly for these profiles' and :80 'Hidden for these profiles'; ITIL templates hide or lock ticket fields (src/ITILTemplateHiddenField.php:43, src/ITILTemplateReadonlyField.php:43). Core Appliance and Software fields have rights per itemtype only (src/Appliance.php:59 rightname). Reached on: Setup > Asset definitions > Fields; Assistance templates."
},
"note": "Mined from topdesk (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
- "sap-leanix": "unknown",
- "bluedolphin": "unknown",
+ "sap-leanix": "yes",
+ "bluedolphin": "partial",
"glpi": "partial"
}
]
From 1a807f88fe1dd59bc0e3039694d98d82758c8d70 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:55:52 +0200
Subject: [PATCH 27/45] chore(parity): batch-2 back-fill VNG and TOPdesk
---
openspec/parity/capabilities.json | 96 +++++++++++++++----------------
1 file changed, 48 insertions(+), 48 deletions(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index de87c34c0..deaa4175d 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -5286,15 +5286,15 @@
"sap-leanix": "yes",
"evidence": {
"sap-leanix": "Announcement of 2026-05-12: 'We have expanded the AI Agent Hub ... New discovery sources: ServiceNow and SAP AI Core ... automatically populate your workspace with AI assets'; AI agent is an application subtype and AI model an IT component subtype (https://help.sap.com/docs/leanix/ea/application-modeling-guidelines) (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: AI agents and models are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: no AI system itemtype (grep -rli 'artificial intelligence' over src/ locales/glpi.pot returns nothing); an admin can define an 'AI model' custom asset type (src/Html.php:1330 Setup > Asset definitions, src/Glpi/Asset/AssetDefinition.php) and link it to applications as an Appliance item (src/Appliance_Item.php:45) or impact relation (install/mysql/glpi-empty.sql:1247). There is no process model to link to. Reached on: Setup > Asset definitions, then Appliance > Items tab.",
+ "topdesk": "unknown: AI agents and models as registered items are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from sap-leanix (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "partial",
"topdesk": "unknown"
},
{
@@ -5316,15 +5316,15 @@
"sap-leanix": "yes",
"evidence": {
"sap-leanix": "Announcement of 2026-07-13: admins 'add single-select and multi-select dropdown fields to architecture decision templates'; https://help.sap.com/docs/leanix/ea/architecture-decisions: 'Document decisions about enterprise architecture in a structured, template-driven format ... Track decisions through a review process with defined statuses', shown on linked fact sheets (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: architecture decisions are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: grep -rli 'architecture decision' over src/ locales/glpi.pot returns nothing; the only status and review flow is ITIL approval on changes (src/ChangeValidation.php:39), not a decision record linked to applications.",
+ "topdesk": "unknown: architecture decisions are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from sap-leanix (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -5347,15 +5347,15 @@
"evidence": {
"sap-leanix": "Announcement of 2026-06-23: 'Ask a question in plain language, and the assistant provides a sourced answer from your workspace ... Every answer is attributed to its source'. A premium AI feature needing AI units (read 2026-09-26)",
"bluedolphin": "Product news entry of 2026-09-01 'Communicate in natural language to find business information in BlueDolphin'; https://help.bluedolphin.io/en/articles/12528662-ai-capabilities-of-bluedolphin: 'AI Navigator answers questions asked in plain language ... Answers are grounded in your BlueDolphin repository and include direct links to relevant content' (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "vng-softwarecatalogus": "unknown: no plain-language question function is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
+ "glpi": "source read at 11.0.9: grep -rli 'openai\\|llm\\|artificial intelligence' over src/ returns nothing; search is criteria based only (src/Glpi/Search/Input/QueryBuilder.php:72).",
+ "topdesk": "https://docs.topdesk.com/en/td-robin-for-operators.html: \"Chat: Ask TOPdesk Robin a question. TOPdesk Robin searches your organization's knowledge base for an answer\" (read 2026-09-26); https://docs.topdesk.com/en/ai-answer-assistant.html: \"The Knowledge Base is the only source for the AI\" (read 2026-09-26). Answers cite knowledge items, not asset or landscape entries. Reached on: Call card > TOPdesk Robin panel."
},
"note": "Mined from sap-leanix (changelog) on 2026-09-26. Also mined from bluedolphin (changelog, https://bluedolphin.io/product-news/).",
"bluedolphin": "yes",
"vng-softwarecatalogus": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown"
+ "glpi": "no",
+ "topdesk": "partial"
},
{
"id": "comp-ai-act-classification",
@@ -5376,15 +5376,15 @@
"sap-leanix": "partial",
"evidence": {
"sap-leanix": "Roadmap card 'Meta model: EU AI Act extension' is In progress (read from the portal data on 2026-09-26); today the legacy AI agent extension already has an 'AI Risk ... according to the EU AI Act' single select (https://help.sap.com/docs/leanix/ea/ai-agent-extension-to-meta-model), so a basic risk field exists but the full extension is not shipped (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: the EU AI Act is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: grep -rli 'ai act\\|artificial intelligence' over src/ locales/glpi.pot returns nothing; appliances have no risk category field (install/mysql/glpi-empty.sql:8935 glpi_appliances).",
+ "topdesk": "unknown: the AI Act is mentioned only for TOPdesk's own AI features (\"post-market monitoring procedures ... in accordance with the AI Act\"), not for classifying the customer's AI systems; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from sap-leanix (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -5406,15 +5406,15 @@
"sap-leanix": "no",
"evidence": {
"sap-leanix": "Roadmap card 'EA Assistant: Technology Successor Planning' is On roadmap; https://updates.leanix.net/announcements/work-with-complete-technology-version-coverage-without-raising-manual-requests (2026-09-17): 'version concurrency management, which we plan to implement in Q4. You will be able to define version tolerance windows' (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: no version tolerance rule is described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: software versions have no order or release date to measure distance from the latest (install/mysql/glpi-empty.sql:6900 glpi_softwareversions: name, states_id, arch, comment); grep -rli 'releases behind' over src/ returns nothing.",
+ "topdesk": "unknown: no version tolerance rule is described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from sap-leanix (roadmap) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -5436,15 +5436,15 @@
"sap-leanix": "yes",
"evidence": {
"sap-leanix": "Announcement of 2025-09-03: 'Selecting Compare Changes ... on a prior diagram version shows color-coded highlighting (green for additions, red for removals, yellow for modifications), a side-by-side view of differences, and an additional text-based summary' (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: diagram versions are not described; maps are generated on request; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: impact graphs are not versioned; src/ImpactRelation.php:39, src/ImpactItem.php:42 and src/ImpactContext.php:40 set no dohistory, so no saved diagram versions exist to compare.",
+ "topdesk": "unknown: architecture diagrams are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from sap-leanix (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"bluedolphin": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -5466,16 +5466,16 @@
"bluedolphin": "yes",
"evidence": {
"bluedolphin": "November 2025 update (2025-11-13): 'Conditional Syncing for Integrations and Webhooks' lets teams 'control exactly what data syncs to third-party systems based on lifecycle state' (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: no outgoing sync to other systems is described, only CSV and AMEFF exports; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: webhooks carry search criteria filters (src/Webhook.php:64 implements FilterableInterface, src/Glpi/Search/FilterableTrait.php:45) and are only sent when the changed item matches them, src/Webhook.php:1228 itemMatchFilter; filtering on the Status field (src/Appliance.php:350) sends an appliance only once it reaches the chosen state. Reached on: Setup > Webhooks > Filter tab.",
+ "topdesk": "https://docs.topdesk.com/en/creating-events.html: \"Edit card is triggered when a card is modified. Fill in the conditions ... Conditions check the current value of the card\" (read 2026-09-26); https://docs.topdesk.com/en/let-your-topdesk-talk-to-other-applications.html: \"Send a request from TOPdesk to another program\" (read 2026-09-26). The customer builds it as an automated action; no ready-made lifecycle sync. Reached on: Action Management > events and action sequences."
},
"note": "Mined from bluedolphin (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown"
+ "glpi": "yes",
+ "topdesk": "partial"
},
{
"id": "ins-usage-analytics",
@@ -5496,16 +5496,16 @@
"bluedolphin": "yes",
"evidence": {
"bluedolphin": "February 2026 update (2026-02-10): new reports show 'which guest users have access to BlueDolphin' and 'which views are being used across the platform'; https://help.bluedolphin.io/en/articles/13868249-usage-insights (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "https://www.softwarecatalogus.nl/rapportages: per month \"Aantal actieve gemeenten\", \"Aantal ingelogde gebruikers van gemeenten\", \"Aantal zoekopdrachten door gemeenten\" (read 2026-09-26). Usage totals only; which pages or views are used and guest reach are not shown. Reached on: Rapportages.",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: the event log (src/Glpi/Event.php:63) records logins and item actions, not which lists or pages are viewed; grep -rli 'page view' over src/ returns nothing, and there are no guest users apart from the public FAQ (src/KnowbaseItem.php:131).",
+ "topdesk": "https://docs.topdesk.com/en/setting-up-the-self-service-portal.html: \"Only when users click Allow analytics, their page usage is synchronized with your Google Analytics account\" (read 2026-09-26). Self-Service Portal page usage in an outside tool only. Reached on: Self-Service Portal settings > Analytics."
},
"note": "Mined from bluedolphin (changelog) on 2026-09-26.",
- "vng-softwarecatalogus": "unknown",
+ "vng-softwarecatalogus": "partial",
"sap-leanix": "unknown",
- "glpi": "unknown",
- "topdesk": "unknown"
+ "glpi": "no",
+ "topdesk": "partial"
},
{
"id": "land-move-between-workspaces",
@@ -5526,15 +5526,15 @@
"bluedolphin": "yes",
"evidence": {
"bluedolphin": "June 2026 update (2026-06-11): 'You can move one or multiple objects to another workspace directly from the Repository without leaving your current view', skipping objects already in the target (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: workspaces are not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: selected records are moved to another entity with their links by src/Transfer.php:50 Transfer, queued through the massive action add_transfer_list (src/MassiveAction.php:598), for one or many entries at once. Reached on: any list, Actions > Add to transfer list; Administration > Entities > transfer.",
+ "topdesk": "unknown: workspaces are not described; changing an asset's type is still an idea at https://tip.topdesk.com/c/89-changing-the-type-of-an-asset; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from bluedolphin (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
- "glpi": "unknown",
+ "glpi": "yes",
"topdesk": "unknown"
},
{
@@ -5556,15 +5556,15 @@
"bluedolphin": "yes",
"evidence": {
"bluedolphin": "July 2026 update (2026-07-09): customers can 'define questionnaires directly on BPMN elements such as tasks and events'; https://help.bluedolphin.io/en/articles/15874771-questionnaires-for-bpmn-elements: 'centralize documentation like risk levels, compliance checks, and technical specifications' (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: processes are not modelled; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: grep -rli 'business process\\|process step' over src/ locales/glpi.pot returns nothing; 'Processes' in inventory (src/Glpi/Inventory/Asset/Process.php) are operating system processes, not business process steps.",
+ "topdesk": "unknown: process modelling is not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from bluedolphin (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
},
{
@@ -5586,15 +5586,15 @@
"bluedolphin": "yes",
"evidence": {
"bluedolphin": "Product news entry of 2026-09-08 'Bring structure to your Views list with tags' (https://bluedolphin.io/product-news/); the linked article lists view filters 'Owner Contributors Tags Favorited Private Project Status Type' (read 2026-09-26)",
- "vng-softwarecatalogus": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
+ "vng-softwarecatalogus": "unknown: the GEMMA maps are chosen from a fixed list; tagging views is not described; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"sap-leanix": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "topdesk": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet"
+ "glpi": "source read at 11.0.9: saved searches, the only saved views, have type, itemtype, owner and privacy but no tags (install/mysql/glpi-empty.sql:232 glpi_savedsearches, :237 users_id, :238 is_private), and impact graphs are not saved as named views (src/ImpactContext.php:40 holds display settings only). The list can be filtered by owner, not by tag.",
+ "topdesk": "unknown: saved overviews can be renamed and shared, but tagging them is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from bluedolphin (changelog) on 2026-09-26.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
- "glpi": "unknown",
+ "glpi": "no",
"topdesk": "unknown"
}
],
From e33196224911f79b18562060e7ceb7f36a5a996b Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sat, 26 Sep 2026 23:56:11 +0200
Subject: [PATCH 28/45] chore(parity): batch-2 back-fill GLPI
---
openspec/parity/capabilities.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index deaa4175d..fc289e17a 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -5438,7 +5438,7 @@
"sap-leanix": "Announcement of 2025-09-03: 'Selecting Compare Changes ... on a prior diagram version shows color-coded highlighting (green for additions, red for removals, yellow for modifications), a side-by-side view of differences, and an additional text-based summary' (read 2026-09-26)",
"vng-softwarecatalogus": "unknown: diagram versions are not described; maps are generated on request; searched the public manuals and FAQ at https://www.softwarecatalogus.nl/node/16564, https://www.softwarecatalogus.nl/node/13683, https://www.softwarecatalogus.nl/node/19703, https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier (read 2026-09-26)",
"bluedolphin": "not checked: row added in wave 5 (2026-09-26), no reading of this system for it yet",
- "glpi": "source read at 11.0.9: impact graphs are not versioned; src/ImpactRelation.php:39, src/ImpactItem.php:42 and src/ImpactContext.php:40 set no dohistory, so no saved diagram versions exist to compare.",
+ "glpi": "source read at 11.0.9: impact graphs are not versioned; src/ImpactContext.php:40 stores only positions, zoom and colours (install/mysql/glpi-empty.sql:1293 glpi_impactcontexts) and CommonDBTM defaults dohistory to false (src/CommonDBTM.php:104). Relation adds and removals (src/ImpactRelation.php:39 extends CommonDBRelation) appear in each linked item's history (src/CommonDBRelation.php:844), but there is no saved diagram version and no compare view.",
"topdesk": "unknown: architecture diagrams are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
"note": "Mined from sap-leanix (changelog) on 2026-09-26.",
From 49e65cb48670705aa385f05bb051ea4e7d05fff9 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sun, 27 Sep 2026 18:07:23 +0200
Subject: [PATCH 29/45] chore(deps): move @conduction/nextcloud-vue to 2.57.1
(Dexie loads on first use) (#1092)
2.57.1 imports Dexie on first use of the offline database instead of at
import time, so this app's bundle no longer evaluates Dexie on every page.
---
package-lock.json | 8 ++++----
package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 2f65f7188..be0ff2666 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,7 @@
"dependencies": {
"@babel/core": "^7.22.9",
"@codemirror/lang-json": "^6.0.0",
- "@conduction/nextcloud-vue": "^2.55.1",
+ "@conduction/nextcloud-vue": "^2.57.1",
"@nextcloud/auth": "^2.6.0",
"@nextcloud/axios": "^2.5.0",
"@nextcloud/capabilities": "^1.2.1",
@@ -2165,9 +2165,9 @@
}
},
"node_modules/@conduction/nextcloud-vue": {
- "version": "2.55.1",
- "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.55.1.tgz",
- "integrity": "sha512-QIM7xZHg3odrULrB+AUPq4uDLQ2eBKcpRf3dsMCBSjmLA58RQTj25EC3nlfR/AJzr4KuvS3Ai95UPM4E/2tfIw==",
+ "version": "2.57.1",
+ "resolved": "https://registry.npmjs.org/@conduction/nextcloud-vue/-/nextcloud-vue-2.57.1.tgz",
+ "integrity": "sha512-yYN+ZZZqeN8Aj+ncgcMv4P3XWrU69vBDFnYDX4ZIHpGfC9pYpXXuLd+kDKiveap/ingjkD5Ign3miK+dutHhQA==",
"license": "EUPL-1.2",
"dependencies": {
"@ckpack/vue-color": "^1.6.0",
diff --git a/package.json b/package.json
index 1e7d13474..6ac9928c2 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
"dependencies": {
"@babel/core": "^7.22.9",
"@codemirror/lang-json": "^6.0.0",
- "@conduction/nextcloud-vue": "^2.55.1",
+ "@conduction/nextcloud-vue": "^2.57.1",
"@nextcloud/auth": "^2.6.0",
"@nextcloud/axios": "^2.5.0",
"@nextcloud/capabilities": "^1.2.1",
From 9a5ece6a329d4660188e6def69d52105a7a2cf61 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sun, 27 Sep 2026 20:04:54 +0200
Subject: [PATCH 30/45] docs(openspec): OpenSpec pass batch 1, landscape and
connections changes with the gap decisions (#1094)
* docs(openspec): connections-catalogue-pages, connection index, detail and application-page lists
* docs(openspec): connections-diagram-and-graph-export, application map, list diagram and connections in the ArchiMate export
* docs(openspec): connections-api-catalogue, record the APIs an application offers
* docs(openspec): connections-derived-dependencies, suggest known and carried-over connections
* docs(openspec): landscape-application-page, correct keys, usages, contracts and opening from the list
* docs(openspec): landscape-usage-registration, usage pages, owners and a working usage lifecycle
* docs(openspec): landscape-application-components, partOf relation and a components list
* docs(openspec): landscape-change-entry-type, change type through OpenRegister's identity-keeping move
* docs(openspec): landscape-move-between-organisations, transfer chosen entries with a dry run
* docs(openspec): landscape-dependent-field-options, dependent option tables enforced by OpenRegister
* docs(openspec): landscape-completeness-score, OpenRegister quality rules, confirm action and report
* docs(openspec): landscape-owner-attestation, confirmation rounds for owners
* docs(openspec): landscape-ai-system-inventory, AI systems with AI Act classification and evidence
* chore(parity): OpenSpec-pass decisions and matrix states for the first 13 changes
* docs(openspec): landscape-ai-system-inventory, FRIA as a reference field like the DPIA
---
.../connections-api-catalogue/.openspec.yaml | 2 +
.../connections-api-catalogue/design.md | 55 ++
.../connections-api-catalogue/proposal.md | 42 ++
.../specs/application-interfaces/spec.md | 46 ++
.../connections-api-catalogue/tasks.md | 35 +
.../.openspec.yaml | 2 +
.../connections-catalogue-pages/design.md | 59 ++
.../connections-catalogue-pages/proposal.md | 52 ++
.../specs/catalogue-connection-pages/spec.md | 74 ++
.../connections-catalogue-pages/tasks.md | 47 ++
.../.openspec.yaml | 2 +
.../design.md | 55 ++
.../proposal.md | 44 ++
.../specs/derived-connections/spec.md | 61 ++
.../connections-derived-dependencies/tasks.md | 53 ++
.../.openspec.yaml | 2 +
.../design.md | 45 ++
.../proposal.md | 45 ++
.../connection-diagram-and-export/spec.md | 58 ++
.../tasks.md | 53 ++
.../.openspec.yaml | 2 +
.../landscape-ai-system-inventory/design.md | 52 ++
.../landscape-ai-system-inventory/proposal.md | 42 ++
.../specs/ai-system-inventory/spec.md | 46 ++
.../landscape-ai-system-inventory/tasks.md | 43 ++
.../.openspec.yaml | 2 +
.../design.md | 38 +
.../proposal.md | 40 ++
.../specs/application-components/spec.md | 42 ++
.../landscape-application-components/tasks.md | 35 +
.../landscape-application-page/.openspec.yaml | 2 +
.../landscape-application-page/design.md | 54 ++
.../landscape-application-page/proposal.md | 48 ++
.../specs/application-page/spec.md | 64 ++
.../landscape-application-page/tasks.md | 44 ++
.../.openspec.yaml | 2 +
.../landscape-change-entry-type/design.md | 39 +
.../landscape-change-entry-type/proposal.md | 39 +
.../specs/entry-type-change/spec.md | 43 ++
.../landscape-change-entry-type/tasks.md | 35 +
.../.openspec.yaml | 2 +
.../landscape-completeness-score/design.md | 64 ++
.../landscape-completeness-score/proposal.md | 44 ++
.../specs/catalogue-data-quality/spec.md | 54 ++
.../landscape-completeness-score/tasks.md | 51 ++
.../.openspec.yaml | 2 +
.../design.md | 42 ++
.../proposal.md | 39 +
.../specs/dependent-field-options/spec.md | 45 ++
.../tasks.md | 34 +
.../.openspec.yaml | 2 +
.../design.md | 42 ++
.../proposal.md | 41 ++
.../specs/move-between-organisations/spec.md | 47 ++
.../tasks.md | 42 ++
.../.openspec.yaml | 2 +
.../landscape-owner-attestation/design.md | 61 ++
.../landscape-owner-attestation/proposal.md | 45 ++
.../specs/owner-attestation/spec.md | 65 ++
.../landscape-owner-attestation/tasks.md | 53 ++
.../.openspec.yaml | 2 +
.../landscape-usage-registration/design.md | 57 ++
.../landscape-usage-registration/proposal.md | 45 ++
.../specs/application-usage-pages/spec.md | 64 ++
.../landscape-usage-registration/tasks.md | 43 ++
openspec/parity/capabilities.json | 190 ++---
openspec/parity/gap-decisions.json | 674 ++++++++++++++++++
67 files changed, 3301 insertions(+), 95 deletions(-)
create mode 100644 openspec/changes/connections-api-catalogue/.openspec.yaml
create mode 100644 openspec/changes/connections-api-catalogue/design.md
create mode 100644 openspec/changes/connections-api-catalogue/proposal.md
create mode 100644 openspec/changes/connections-api-catalogue/specs/application-interfaces/spec.md
create mode 100644 openspec/changes/connections-api-catalogue/tasks.md
create mode 100644 openspec/changes/connections-catalogue-pages/.openspec.yaml
create mode 100644 openspec/changes/connections-catalogue-pages/design.md
create mode 100644 openspec/changes/connections-catalogue-pages/proposal.md
create mode 100644 openspec/changes/connections-catalogue-pages/specs/catalogue-connection-pages/spec.md
create mode 100644 openspec/changes/connections-catalogue-pages/tasks.md
create mode 100644 openspec/changes/connections-derived-dependencies/.openspec.yaml
create mode 100644 openspec/changes/connections-derived-dependencies/design.md
create mode 100644 openspec/changes/connections-derived-dependencies/proposal.md
create mode 100644 openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md
create mode 100644 openspec/changes/connections-derived-dependencies/tasks.md
create mode 100644 openspec/changes/connections-diagram-and-graph-export/.openspec.yaml
create mode 100644 openspec/changes/connections-diagram-and-graph-export/design.md
create mode 100644 openspec/changes/connections-diagram-and-graph-export/proposal.md
create mode 100644 openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md
create mode 100644 openspec/changes/connections-diagram-and-graph-export/tasks.md
create mode 100644 openspec/changes/landscape-ai-system-inventory/.openspec.yaml
create mode 100644 openspec/changes/landscape-ai-system-inventory/design.md
create mode 100644 openspec/changes/landscape-ai-system-inventory/proposal.md
create mode 100644 openspec/changes/landscape-ai-system-inventory/specs/ai-system-inventory/spec.md
create mode 100644 openspec/changes/landscape-ai-system-inventory/tasks.md
create mode 100644 openspec/changes/landscape-application-components/.openspec.yaml
create mode 100644 openspec/changes/landscape-application-components/design.md
create mode 100644 openspec/changes/landscape-application-components/proposal.md
create mode 100644 openspec/changes/landscape-application-components/specs/application-components/spec.md
create mode 100644 openspec/changes/landscape-application-components/tasks.md
create mode 100644 openspec/changes/landscape-application-page/.openspec.yaml
create mode 100644 openspec/changes/landscape-application-page/design.md
create mode 100644 openspec/changes/landscape-application-page/proposal.md
create mode 100644 openspec/changes/landscape-application-page/specs/application-page/spec.md
create mode 100644 openspec/changes/landscape-application-page/tasks.md
create mode 100644 openspec/changes/landscape-change-entry-type/.openspec.yaml
create mode 100644 openspec/changes/landscape-change-entry-type/design.md
create mode 100644 openspec/changes/landscape-change-entry-type/proposal.md
create mode 100644 openspec/changes/landscape-change-entry-type/specs/entry-type-change/spec.md
create mode 100644 openspec/changes/landscape-change-entry-type/tasks.md
create mode 100644 openspec/changes/landscape-completeness-score/.openspec.yaml
create mode 100644 openspec/changes/landscape-completeness-score/design.md
create mode 100644 openspec/changes/landscape-completeness-score/proposal.md
create mode 100644 openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md
create mode 100644 openspec/changes/landscape-completeness-score/tasks.md
create mode 100644 openspec/changes/landscape-dependent-field-options/.openspec.yaml
create mode 100644 openspec/changes/landscape-dependent-field-options/design.md
create mode 100644 openspec/changes/landscape-dependent-field-options/proposal.md
create mode 100644 openspec/changes/landscape-dependent-field-options/specs/dependent-field-options/spec.md
create mode 100644 openspec/changes/landscape-dependent-field-options/tasks.md
create mode 100644 openspec/changes/landscape-move-between-organisations/.openspec.yaml
create mode 100644 openspec/changes/landscape-move-between-organisations/design.md
create mode 100644 openspec/changes/landscape-move-between-organisations/proposal.md
create mode 100644 openspec/changes/landscape-move-between-organisations/specs/move-between-organisations/spec.md
create mode 100644 openspec/changes/landscape-move-between-organisations/tasks.md
create mode 100644 openspec/changes/landscape-owner-attestation/.openspec.yaml
create mode 100644 openspec/changes/landscape-owner-attestation/design.md
create mode 100644 openspec/changes/landscape-owner-attestation/proposal.md
create mode 100644 openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md
create mode 100644 openspec/changes/landscape-owner-attestation/tasks.md
create mode 100644 openspec/changes/landscape-usage-registration/.openspec.yaml
create mode 100644 openspec/changes/landscape-usage-registration/design.md
create mode 100644 openspec/changes/landscape-usage-registration/proposal.md
create mode 100644 openspec/changes/landscape-usage-registration/specs/application-usage-pages/spec.md
create mode 100644 openspec/changes/landscape-usage-registration/tasks.md
create mode 100644 openspec/parity/gap-decisions.json
diff --git a/openspec/changes/connections-api-catalogue/.openspec.yaml b/openspec/changes/connections-api-catalogue/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/connections-api-catalogue/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/connections-api-catalogue/design.md b/openspec/changes/connections-api-catalogue/design.md
new file mode 100644
index 000000000..218aeba42
--- /dev/null
+++ b/openspec/changes/connections-api-catalogue/design.md
@@ -0,0 +1,55 @@
+# Design: connections-api-catalogue
+
+Read at development `49e65cb4`.
+
+## Context
+
+Stackiq's catalogue schemas live in `lib/Settings/softwarecatalogus_register.json`. Per ADR-037 a change adds its schema in a fragment under `lib/Settings/register.d/`, which `SettingsService::loadSettings()` deep-merges into the monolith at load (`lib/Service/SettingsService.php:1653-1680`). Lists append in that merge (`deepMergeConfig`, :7338), so a fragment can add a schema to the register's list.
+
+## D1. A new schema in a fragment
+
+File `lib/Settings/register.d/application-interfaces.json` with:
+
+- `components.schemas.applicationInterface`, schema.org type `WebAPI`:
+
+| property | type | notes |
+|---|---|---|
+| `name` | string, required | |
+| `shortDescription`, `longDescription` | string, markdown for the long one | |
+| `module` | `$ref` module, required | the application that offers the API, `inversedBy: interfaces` |
+| `style` | enum `REST`, `SOAP`, `GraphQL`, `event or message`, `file`, `other` | facetable |
+| `version` | string | |
+| `specificationUrl` | string, format uri | an OpenAPI, WSDL or AsyncAPI document |
+| `documentationUrl` | string, format uri | |
+| `standardVersions` | array of `$ref` element, `queryParams: gemmaType=standaardversie` | the same picker as `connection.standardVersions` |
+| `status` | enum `in development`, `in use`, `end of support`, `withdrawn` | the connection's values, with an `x-openregister-lifecycle` on those exact values |
+| `publicationDate`, `depublicationDate` | date-time | |
+
+- `authorization` copied from `module` (`register.json` module schema): organisation-scoped read for `aanbod-beheerder`, read for `gebruik-beheerder`, public read after `publicationDate`; create and update for the groups that may edit a module.
+- `components.registers.stackiq.schemas: ["applicationInterface"]` and `components.registers.stackiq.configuration.schemas.applicationInterface: { "magicMapping": true, "autoCreateTable": true }`, like every other catalogue schema (`register.json:853` onwards).
+- On `connection`, a new optional property `interface` (`$ref` applicationInterface, `x-relation-filter` on `module` equal to the connection's `moduleB`), added through the same fragment.
+
+Rejected: a `subtype` value on `connection`. An API exists before anyone connects to it, has its own version and specification, and serves many connections; LeanIX models it as its own fact sheet for that reason.
+
+## D2. Pages
+
+In `src/manifest.d/application-interfaces.json`:
+
+- `Apis`, route `/apis`, `type: index`, schema `applicationInterface`, columns name, module, style, version, status; `filterMenu: true`.
+- `ApiDetail`, route `/apis/:id`, `type: detail`: data widget, files, related (connections that name it), history tab.
+- A menu child `APIs` under the `Modules` (Applications) entry, next to Connections from `connections-catalogue-pages`. No new top-level entry (ADR-097).
+
+On `ModuleDetail` (`src/manifest.json:491`) an `object-list` widget `md-apis` with filter `{ "module": "@objectId" }`, `rowRoute: ApiDetail`, and `allowCreate: true` with the application prefilled.
+
+## Declarative versus imperative
+
+All declarative: a schema with a lifecycle and relations, manifest pages, one object-list widget (ADR-031). No PHP.
+
+## Seed data
+
+`lib/Settings/stackiq_mock_register.json` gains two demo APIs on one demo application: a REST API with a specification URL pointing at a placeholder `https://example.org/openapi.json`, and an event API.
+
+## Risks
+
+- `ModuleDetail` also changes in `connections-catalogue-pages` and `landscape-application-page`; the widgets stack below each other.
+- A schema added through a fragment has never been tried for a brand-new schema in this app (the two existing fragments modify schemas). Task 1 proves the merge with a unit test before any page work.
diff --git a/openspec/changes/connections-api-catalogue/proposal.md b/openspec/changes/connections-api-catalogue/proposal.md
new file mode 100644
index 000000000..f7d84e850
--- /dev/null
+++ b/openspec/changes/connections-api-catalogue/proposal.md
@@ -0,0 +1,42 @@
+---
+kind: code
+depends_on:
+ - connections-catalogue-pages
+---
+
+# Record the APIs an application exposes
+
+## Summary
+
+A supplier or an information manager records the APIs an application offers, next to that application: the style, the version, where the specification lives, the standards it follows and its status. A connection can name the API it calls. The application page lists its APIs, and an APIs list shows them across the catalogue.
+
+## Why
+
+Row from the stackiq matrix:
+
+- `stackiq:conn-api-catalogue`, "Keep the APIs an application exposes in the catalogue next to the application." Rated no. SAP LeanIX rates yes: https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines, interface subtype "API ... APIs provide functionalities accessible to external applications", related to the providing application. The row sits in the product's core area (connections), which is why it is built with one competitor.
+
+No tender, feature request or roadmap row names it.
+
+## What stackiq has today
+
+- No schema describes an API. The register's catalogue schemas are listed at `lib/Settings/softwarecatalogus_register.json:817` onwards (sector, suite, module, catalogService, vulnerability, contactPerson, organization, usage, catalogContract, connection, software-review, compliancy, moduleVersion, sbomComponent, bioMeasure).
+- `connection.type` has the value `api` (`register.json:3565` schema), but it only labels the transport of one connection; it says nothing about the API itself.
+- Standards live as GEMMA elements with `gemmaType` standaard and standaardversie; `module.standardVersions` and `connection.standardVersions` already point at them.
+
+## What this change builds
+
+1. A schema `applicationInterface` (title "API") in a register fragment: name, descriptions, the providing application, style, version, specification URL, documentation URL, standard versions, status and publication dates.
+2. An optional `interface` field on `connection`, so a connection names the API it calls.
+3. An APIs list page and an API detail page, reached under Applications in the menu.
+4. An APIs section on the application page, with an Add button that fills in the application.
+
+## Out of scope
+
+- A developer portal: keys, subscriptions, a try-it console. The matrix category says stackiq is not a developer portal; integriq's open change `access-developer-portal-and-subscriptions` covers that for its gateway.
+- Importing APIs from an OpenAPI file or a gateway (integriq's `gateway-openapi-import-and-publish` covers publishing through integriq).
+- Checking an API against the NLGov REST API design rules (integriq's `gateway-api-design-rules-check`).
+
+## Risks
+
+- Suppliers and municipalities may both register the same API. The detail page shows the providing application and its supplier, and `operations-record-reconciliation` covers merging duplicates.
diff --git a/openspec/changes/connections-api-catalogue/specs/application-interfaces/spec.md b/openspec/changes/connections-api-catalogue/specs/application-interfaces/spec.md
new file mode 100644
index 000000000..37d9cc689
--- /dev/null
+++ b/openspec/changes/connections-api-catalogue/specs/application-interfaces/spec.md
@@ -0,0 +1,46 @@
+# application-interfaces specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- connections-api-catalogue
+
+## Purpose
+
+The catalogue records the APIs an application offers, next to the application, so an architect sees what can be connected to and how. Matrix row `stackiq:conn-api-catalogue`.
+
+## ADDED Requirements
+
+### Requirement: REQ-AIF-001 A user can record an API that an application offers
+
+Stackiq SHALL store an API as an `applicationInterface` object with a name, the providing application, a style, a version, a specification URL, a documentation URL, the standard versions it follows and a status. The status SHALL move through `in development`, `in use`, `end of support` and `withdrawn` by declared transitions.
+
+#### Scenario: A supplier adds a REST API to its application
+@e2e tests/e2e/workflows/application-interfaces.spec.ts
+
+- **GIVEN** a supplier with edit rights on application X
+- **WHEN** they open the page of application X, click Add in the APIs section and save name "Zaken API", style `REST`, version `1.2` and a specification URL
+- **THEN** the APIs section of application X lists "Zaken API" with style REST and version 1.2
+- **AND** the APIs list at `/apis` shows it too
+
+### Requirement: REQ-AIF-002 The application page lists its APIs
+
+The application page `ModuleDetail` SHALL list the APIs whose providing application is that application, and each row SHALL open the API's detail page.
+
+#### Scenario: An architect checks what an application offers
+@e2e tests/e2e/workflows/application-interfaces.spec.ts
+
+- **GIVEN** application X offers a REST API and an event API
+- **WHEN** an architect opens the page of application X
+- **THEN** the APIs section lists both APIs with their style and status
+
+### Requirement: REQ-AIF-003 A connection can name the API it calls
+
+The `connection` schema SHALL carry an optional `interface` field that points at an API of the connection's application B, and the API's detail page SHALL list the connections that name it.
+
+#### Scenario: An information manager links a connection to an API
+@e2e exclude The field is a related-object picker in the library form; tests/Unit/Settings/ApplicationInterfaceFragmentTest.php asserts the property and its relation filter.
+
+- **GIVEN** a connection from application A to application X, and X offers "Zaken API"
+- **WHEN** the information manager sets the connection's API to "Zaken API"
+- **THEN** the detail page of "Zaken API" lists that connection
diff --git a/openspec/changes/connections-api-catalogue/tasks.md b/openspec/changes/connections-api-catalogue/tasks.md
new file mode 100644
index 000000000..8abb73477
--- /dev/null
+++ b/openspec/changes/connections-api-catalogue/tasks.md
@@ -0,0 +1,35 @@
+# Tasks: connections-api-catalogue
+
+## Implementation tasks
+
+### Task 1: The applicationInterface schema
+- **spec_ref**: openspec/changes/connections-api-catalogue/specs/application-interfaces/spec.md#requirement-req-aif-001-a-user-can-record-an-api-that-an-application-offers
+- **files**: `lib/Settings/register.d/application-interfaces.json`, `lib/Settings/stackiq_mock_register.json`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it is imported THEN the stackiq register lists applicationInterface and its table exists
+ - GIVEN a connection WHEN its interface field is set THEN it holds an API of the connection's application B
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Settings/ApplicationInterfaceFragmentTest.php`: the merged register carries the schema, the register list entry and the lifecycle on enum values)
+
+### Task 2: APIs pages and the application page section
+- **spec_ref**: openspec/changes/connections-api-catalogue/specs/application-interfaces/spec.md#requirement-req-aif-002-the-application-page-lists-its-apis
+- **files**: `src/manifest.d/application-interfaces.json`, `src/manifest.json` (ModuleDetail), `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN an application with two APIs WHEN its page opens THEN the APIs section lists both
+ - GIVEN the APIs list WHEN the user filters on style REST THEN only REST APIs remain
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/application-interfaces.spec.ts`)
+
+### Task 3: Documentation
+- **spec_ref**: openspec/changes/connections-api-catalogue/specs/application-interfaces/spec.md#requirement-req-aif-001-a-user-can-record-an-api-that-an-application-offers
+- **files**: `docs/features/application-interfaces.md`, `docs/images/application-apis.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens APIs THEN it explains how to record an API and link a connection to it, with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate connections-api-catalogue --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/connections-catalogue-pages/.openspec.yaml b/openspec/changes/connections-catalogue-pages/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/connections-catalogue-pages/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/connections-catalogue-pages/design.md b/openspec/changes/connections-catalogue-pages/design.md
new file mode 100644
index 000000000..749c118f5
--- /dev/null
+++ b/openspec/changes/connections-catalogue-pages/design.md
@@ -0,0 +1,59 @@
+# Design: connections-catalogue-pages
+
+Read at development `49e65cb4`. Every path and line below was opened for this design.
+
+## Context
+
+A connection (`koppeling`) is a catalogue object: an application A talks to an application B, or to a national provision, over a transport, in a direction. The schema is complete (`lib/Settings/softwarecatalogus_register.json:3565`) and the ArchiMate import fills it, but the app shows it nowhere. The pages are declarative manifest pages over OpenRegister (ADR-001, ADR-024), so no PHP controller or service is added.
+
+## D1. Pages live in a manifest fragment
+
+New file `src/manifest.d/connections.json` (ADR-037), merged at build like `src/manifest.d/connection-registry.json`. It holds:
+
+- `Koppelingen`, route `/koppelingen`, `type: index`, `register: @resolve:voorzieningen_register`, `schema: connection`. Columns: `name`, `type`, `status`, `moduleA`, `moduleB`, `nonMunicipalProvision`, `dataExchangeDirection`. `filterMenu: true`, so the table header lists the values of every enum column as toggleable filters (`CnIndexPage.vue:2236` in `@conduction/nextcloud-vue` 2.57.1). `quickFilters` on status: All, In use, In development, End of support, Withdrawn, the way `Contracten` does it (`src/manifest.json:540`).
+- `KoppelingDetail`, route `/koppelingen/:id`, `type: detail`. Widgets: `kp-data` (type `data`, all visible fields), `kp-files` (files integration, the schema already allows files), `kp-related` (type `related`), and a History tab in the sidebar like every other detail page. `lifecycleActions` on, so `CnLifecycleActions` (`CnDetailPage.vue:158`) offers release, sunset and withdraw once D3 lands.
+
+Rejected: adding the pages to `src/manifest.json` directly. That file is already 1,000+ lines, and ADR-037 puts a change's pages in its own fragment so two changes do not conflict on one file.
+
+## D2. The application page gets two connection lists
+
+`ModuleDetail` (`src/manifest.json:491`) gains two `object-list` widgets:
+
+| id | filter | title |
+|---|---|---|
+| `md-connections-out` | `{ "moduleA": "@objectId" }` | Connections from this application |
+| `md-connections-in` | `{ "moduleB": "@objectId" }` | Connections to this application |
+
+Both set `rowRoute: KoppelingDetail`, `viewAllRoute: Koppelingen` with the same filter in `viewAllQuery`, and columns `type`, `status`, the other side of the connection. `CnObjectListWidget` takes one filter object with AND semantics (`CnObjectListWidget.vue:503`), so one list with "A or B" is not possible declaratively; two lists also say which way the data flows.
+
+Rejected: a custom widget that calls `GET /api/koppelingen-gebruik/{uuid}` (`AangebodenGebruikController.php:208`). That endpoint is public, mixes usages into the answer, and would add the first caller of a custom endpoint where OpenRegister's own list already serves the need (ADR-022).
+
+## D3. Register fixes in the same change
+
+All in `lib/Settings/softwarecatalogus_register.json`, schema `connection`:
+
+1. **Lifecycle states.** Replace the Dutch states in `x-openregister-lifecycle` (:3926) with the enum values: initial `in development`, final `withdrawn`, transitions release (`in development` to `in use`), sunset (`in use` to `end of support`), withdraw (`in use`, `end of support` to `withdrawn`). The rows already hold the English values (`lib/Repair/RenameDutchCatalogValues.php:87-90`).
+2. **Picker.** Change `objectConfiguration.queryParams` on `nonMunicipalProvision` (:3720) to `gemmaType=Buitengemeentelijke voorziening`, the spelling the GEMMA model uses.
+3. **Name template.** `objectNameField` names `gegevensuitwisselingRichting` and `buitengemeentelijkVoorziening`, keys the schema renamed to `dataExchangeDirection` and `nonMunicipalProvision`, and maps `AnaarB`, `BnaarA`, `bi-directioneel` where the enum holds `AtoB`, `BtoA`, `bi-directional`. Rewrite it on the current keys and values, so a connection reads "Application A to Application B" in lists and pickers.
+4. **Facets.** Set `facetable: true` on `type`, `status` and `dataExchangeDirection`, so the index page can count and filter them.
+5. **Version.** Bump the `connection` schema version to 0.3.2 and the register version, and add a changelog line. The register changelog entry 2.4.4 (`register.json:7`) records why: OpenRegister skips an import whose deployed version is not lower, and its content check ignores `configuration`.
+
+## D4. Menu
+
+Add `Connections` as a child of the `Modules` (Applications) menu entry, in the fragment. `CnAppNav` supports one level of `children[]` (`CnAppNav.vue:6`). ADR-097 decision 1 caps the main menu at six top-level entries and asks an amendment for more. Stackiq already carries fifteen, so this change adds none.
+
+Rejected: a top-level `Connections` entry. It would need an ADR-097 amendment that this change has no standing to make.
+
+## Declarative versus imperative
+
+Everything here is declarative: manifest pages, `object-list` widgets, the schema's own lifecycle and facets (ADR-031). No service, controller or route is added. Access follows the schema's existing `authorization` block (`register.json:3565` area): organisation-scoped read and public read after `publicationDate`.
+
+## Seed data
+
+No new schema. The demo register `lib/Settings/stackiq_mock_register.json` gains three connections (an API between two demo applications, a file transfer, and one to a national provision) so the pages show rows on a fresh install.
+
+## Risks
+
+- `ModuleDetail` is also edited by `landscape-application-page`. Both add rows to the same grid. The second change to land moves its widgets below the first.
+- Existing connections whose `nonMunicipalProvision` points at an element still resolve; only the picker's query changes.
+- A connection readable by the public group shows on the public frontend already; the pages add no new read path.
diff --git a/openspec/changes/connections-catalogue-pages/proposal.md b/openspec/changes/connections-catalogue-pages/proposal.md
new file mode 100644
index 000000000..248e72298
--- /dev/null
+++ b/openspec/changes/connections-catalogue-pages/proposal.md
@@ -0,0 +1,52 @@
+---
+kind: code
+depends_on: []
+---
+
+# Connections get their own pages
+
+## Summary
+
+Stackiq stores the connections (koppelingen) between applications, but no page lists them, opens one, or shows them on the application they belong to. This change adds a Connections index page and a connection detail page, a filter on transport type, a connections section on the application page, and a working picker for the national provision a connection reaches.
+
+## Why
+
+Rows from the stackiq matrix (`openspec/parity/capabilities.json`):
+
+- `stackiq:conn-list-page`, "Browse all connections in the catalogue in one list and open each one." Rated no and marked specified with no change directory, so this is the missing change. GEMMA Softwarecatalogus rates yes: https://www.softwarecatalogus.nl/node/13683, "Alle koppelingen ... staan de koppelingen van alle gemeenten en samenwerkingsverbanden". SAP LeanIX rates yes: https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines, interfaces are fact sheets listed in the inventory.
+- `stackiq:conn-type-filter`, "Filter connections by type, such as an API, a file exchange or a message." Rated no, marked specified with no change directory. SAP LeanIX rates yes on the same page: interface subtypes and transfer type are filterable in the inventory. Core area (connections).
+- `stackiq:conn-per-application`, "See every connection an application has, from that application's own page." Rated partial, built. Three competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/circle-map-report, relations on the fact sheet), BlueDolphin (https://help.bluedolphin.io/en/articles/11967550-working-with-object-relationships, the Relationships tab) and GLPI (source read at 11.0.9, `src/Impact.php:91`, an impact analysis tab listing related items in both directions). The missing half is a connections section on the application page that opens each connection.
+- `stackiq:conn-external-provision`, "Record a connection from an application to a national provision such as a basisregistratie." Rated partial, built, one competitor yes: GEMMA Softwarecatalogus (https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo). It rides with `conn-list-page`: its missing half is a page to fill the field, and the connection form on the new page shows it.
+
+No tender, feature request or roadmap row names these rows. `conn-list-page` and `conn-type-filter` sit in the product's core area.
+
+## What stackiq has today
+
+- The `connection` schema (`lib/Settings/softwarecatalogus_register.json:3565`, version 0.3.1) holds name, transport `type`, `status`, four lifecycle dates, `dataExchangeDirection` (:3676), `moduleA` (:3689), `moduleB` (:3705), `nonMunicipalProvision` (:3720), `standardVersions` and `realisedWithIntermediaryModule`.
+- No manifest page uses this schema. The Integrations page (`src/manifest.d/connection-registry.json:23`) lists integriq's `app_connection`, which its `_note` says is a different thing.
+- The application page `ModuleDetail` (`src/manifest.json:491`) shows connections only as untyped entries in the generic related panel `md-related` (:502).
+- `GET /api/koppelingen-gebruik/{uuid}` (`appinfo/routes.php:269`, `lib/Controller/AangebodenGebruikController.php:208`) returns an application's connections and usages. Nothing in `src/` calls it.
+- Two register defects would break the pages even once they exist:
+ - The connection lifecycle (`register.json:3926`) names `in ontwikkeling`, `in gebruik`, `einde ondersteuning` and `teruggetrokken`. The status enum and the migrated rows (`lib/Repair/RenameDutchCatalogValues.php:87-90`) hold `in development`, `in use`, `end of support` and `withdrawn`, so no transition matches any row.
+ - The `nonMunicipalProvision` picker filters on `gemmaType=Buitengemeentenlijke voorziening` (`register.json:3720`). The GEMMA model spells it `Buitengemeentelijke voorziening` (59 times in `lib/Settings/GEMMA_release.xml`), so the picker finds nothing.
+
+## What this change builds
+
+1. A Connections index page (`Koppelingen`, `/koppelingen`) over the `connection` schema, with a filter on transport type and quick filters on status.
+2. A connection detail page (`KoppelingDetail`, `/koppelingen/:id`) with the connection data, both applications, the national provision, standards, documents, history and the status transitions.
+3. A connections section on the application page: the connections that start at the application and the ones that end there, each row opening the detail page.
+4. Register fixes: lifecycle states that match the enum, the picker's GEMMA type, `type` and `status` marked facetable, and the schema version bumped so the edit deploys.
+5. A menu entry for Connections under Applications, without a new top-level entry (ADR-097).
+
+## Out of scope
+
+- Drawing connections as a diagram and exporting the link graph: `connections-diagram-and-graph-export`.
+- The APIs an application exposes: `connections-api-catalogue`.
+- Deriving connections automatically: `connections-derived-dependencies`.
+- integriq's `app_connection` and the Integrations page: open change `adopt-connection-registry`.
+- The public frontend's own connection form (`README.md:273`, a separate repository).
+
+## Risks
+
+- `landscape-application-page` also edits the `ModuleDetail` grid. Whichever change lands second rebases the layout rows.
+- A lifecycle edit without a schema version bump never deploys (register changelog 2.4.4, `register.json:7`).
diff --git a/openspec/changes/connections-catalogue-pages/specs/catalogue-connection-pages/spec.md b/openspec/changes/connections-catalogue-pages/specs/catalogue-connection-pages/spec.md
new file mode 100644
index 000000000..c19d9aca2
--- /dev/null
+++ b/openspec/changes/connections-catalogue-pages/specs/catalogue-connection-pages/spec.md
@@ -0,0 +1,74 @@
+# catalogue-connection-pages specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- connections-catalogue-pages
+
+## Purpose
+
+A connection records that one application exchanges data with another, or with a national provision. Users browse connections, filter them by transport, open one, and see an application's connections on its own page. Matrix rows `stackiq:conn-list-page`, `stackiq:conn-type-filter`, `stackiq:conn-per-application` and `stackiq:conn-external-provision`.
+
+## ADDED Requirements
+
+### Requirement: REQ-CCP-001 A user can browse every connection they may read in one list
+
+Stackiq SHALL offer an index page `Koppelingen` at `/koppelingen` over the `connection` schema, reached from the Applications menu entry. It SHALL list every connection the user may read under the schema's authorization, with its name, transport type, status, both applications and the national provision, and each row SHALL open the connection's detail page.
+
+#### Scenario: A municipal information manager opens the connections list
+@e2e tests/e2e/workflows/connections.spec.ts
+
+- **GIVEN** an information manager of a municipality whose organisation registered two connections
+- **WHEN** they open Applications, then Connections
+- **THEN** the page `/koppelingen` lists both connections with type, status and the two applications
+- **AND** clicking a row opens `/koppelingen/`
+
+#### Scenario: A connection of another municipality stays hidden
+@e2e exclude The read rule is OpenRegister's schema RBAC; tests/Unit/Settings/SchemaRbacTest.php asserts the connection read rule.
+
+- **GIVEN** a connection owned by another organisation with no publication date
+- **WHEN** the information manager opens the connections list
+- **THEN** that connection is not listed
+
+### Requirement: REQ-CCP-002 A user can filter connections by transport type
+
+The connections list SHALL let the user narrow the rows to one or more transport types (`api`, `file transfer`, `digikoppeling`, `message que`, `upload to portal`, `webservices`, `n/a`) and to one status, and SHALL show how many rows each value holds.
+
+#### Scenario: Only API connections remain
+@e2e tests/e2e/workflows/connections.spec.ts
+
+- **GIVEN** the connections list shows one `api` and one `file transfer` connection
+- **WHEN** the information manager picks type `api` in the table's filter menu
+- **THEN** only the `api` connection remains in the list
+
+### Requirement: REQ-CCP-003 The application page lists the connections that start and end there
+
+The application page `ModuleDetail` SHALL show the connections in which the application is application A, and separately the connections in which it is application B. Each row SHALL open the connection's detail page, and each list SHALL link to the connections list filtered on that application.
+
+#### Scenario: An application owner sees both directions
+@e2e tests/e2e/workflows/connections.spec.ts
+
+- **GIVEN** application X is application A in connection 1 and application B in connection 2
+- **WHEN** the application owner opens the page of application X
+- **THEN** "Connections from this application" lists connection 1
+- **AND** "Connections to this application" lists connection 2
+- **AND** clicking connection 2 opens its detail page
+
+### Requirement: REQ-CCP-004 The connection schema offers transitions and a picker that match its data
+
+The `connection` schema SHALL declare its lifecycle on the status values its rows hold (`in development`, `in use`, `end of support`, `withdrawn`), SHALL filter the national provision picker on the GEMMA type `Buitengemeentelijke voorziening`, and SHALL build a connection's display name from `moduleA`, `dataExchangeDirection` and `moduleB` or `nonMunicipalProvision`.
+
+#### Scenario: A supplier releases a connection from its detail page
+@e2e tests/e2e/workflows/connections.spec.ts
+
+- **GIVEN** a connection with status `in development`
+- **WHEN** a supplier with update rights opens its detail page
+- **THEN** the page offers the release action
+- **AND** after release the status reads `in use`
+
+#### Scenario: The national provision picker lists GEMMA provisions
+@e2e exclude The picker is the library's related-object field; tests/Unit/Settings/ConnectionSchemaTest.php asserts the queryParams value and that GEMMA_release.xml uses the same spelling.
+
+- **GIVEN** the GEMMA model is imported
+- **WHEN** a user edits a connection and opens the national provision field
+- **THEN** it offers the GEMMA elements of type Buitengemeentelijke voorziening, such as a basisregistratie
diff --git a/openspec/changes/connections-catalogue-pages/tasks.md b/openspec/changes/connections-catalogue-pages/tasks.md
new file mode 100644
index 000000000..737f099ad
--- /dev/null
+++ b/openspec/changes/connections-catalogue-pages/tasks.md
@@ -0,0 +1,47 @@
+# Tasks: connections-catalogue-pages
+
+## Implementation tasks
+
+### Task 1: Fix the connection schema
+- **spec_ref**: openspec/changes/connections-catalogue-pages/specs/catalogue-connection-pages/spec.md#requirement-req-ccp-004-the-connection-schema-offers-transitions-and-a-picker-that-match-its-data
+- **files**: `lib/Settings/softwarecatalogus_register.json`, `lib/Settings/stackiq_mock_register.json`
+- **acceptance_criteria**:
+ - GIVEN the imported register WHEN a connection in `in development` is opened THEN the release transition is offered
+ - GIVEN the connection form WHEN the national provision picker opens THEN it lists GEMMA elements of type Buitengemeentelijke voorziening
+ - GIVEN the schema version bump WHEN the repair step imports the register THEN the new configuration is deployed
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Settings/ConnectionSchemaTest.php`: lifecycle states are enum values, queryParams spelling, name template keys exist)
+
+### Task 2: Connections index and detail pages
+- **spec_ref**: openspec/changes/connections-catalogue-pages/specs/catalogue-connection-pages/spec.md#requirement-req-ccp-001-a-user-can-browse-every-connection-they-may-read-in-one-list
+- **files**: `src/manifest.d/connections.json`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN connections exist WHEN the user opens Applications, Connections THEN the list shows them with type and status
+ - GIVEN the list WHEN the user filters on type api THEN only API connections remain
+ - GIVEN a row WHEN the user opens it THEN the detail page shows both applications and the national provision
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/connections.spec.ts`, manifest validation in `npm run lint`)
+
+### Task 3: Connections on the application page
+- **spec_ref**: openspec/changes/connections-catalogue-pages/specs/catalogue-connection-pages/spec.md#requirement-req-ccp-003-the-application-page-lists-the-connections-that-start-and-end-there
+- **files**: `src/manifest.json` (ModuleDetail widgets and layout)
+- **acceptance_criteria**:
+ - GIVEN an application that is A in one connection and B in another WHEN its page opens THEN each list shows its connection
+ - GIVEN a connection row WHEN the user clicks it THEN KoppelingDetail opens
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/connections.spec.ts`, application page case)
+
+### Task 4: Documentation
+- **spec_ref**: openspec/changes/connections-catalogue-pages/specs/catalogue-connection-pages/spec.md#requirement-req-ccp-001-a-user-can-browse-every-connection-they-may-read-in-one-list
+- **files**: `docs/features/connections.md`, `docs/images/connections-index.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Connections THEN it explains the list, the filters and the application page section with a screenshot
+- [ ] Implement
+- [ ] Test (docs build `npm run build` in `docs/`, screenshot taken with Playwright)
+
+## Verification
+
+- `openspec validate connections-catalogue-pages --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the new PHPUnit test and the Playwright spec pass.
+- English and Dutch strings exist for every new label (ADR-005).
+- Feature documentation with a screenshot is in `docs/features/` (ADR-010).
diff --git a/openspec/changes/connections-derived-dependencies/.openspec.yaml b/openspec/changes/connections-derived-dependencies/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/connections-derived-dependencies/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/connections-derived-dependencies/design.md b/openspec/changes/connections-derived-dependencies/design.md
new file mode 100644
index 000000000..7d6ad0fdf
--- /dev/null
+++ b/openspec/changes/connections-derived-dependencies/design.md
@@ -0,0 +1,55 @@
+# Design: connections-derived-dependencies
+
+Read at development `49e65cb4`.
+
+## Context
+
+A connection lives between two applications (`connection.moduleA`, `moduleB`, `lib/Settings/softwarecatalogus_register.json:3689`, `:3705`). What an organisation runs is a usage (`usage` schema, `register.json:2656`) with `module`, `moduleVersion`, `koppelingen` (the connections this usage uses) and `plannedReplacement` (a successor application). `landscape-usage-registration` gives usages their own index and detail pages; this change adds a panel to that detail page.
+
+## D1. A suggestion service, computed on demand
+
+New `lib/Service/ConnectionSuggestionService.php` (ADR-008: controller, service, OpenRegister's ObjectService as the mapper). `suggestFor(string $usageUuid): array` does:
+
+1. Load the usage and its organisation (`consumer`).
+2. Load the organisation's other usages and collect their applications: the organisation's landscape.
+3. Load the connections where `moduleA` or `moduleB` is the usage's application, that the caller may read (OpenRegister RBAC stays on).
+4. Keep the connections whose other end is in the landscape, or is a national provision, and that are not already in `usage.koppelingen` and not dismissed for this usage.
+5. Return each with a reason: `shared-landscape`.
+
+Carry-over (`land-version-carry-connections`) adds a second source in the same method:
+
+- If another usage of the organisation has the same `module` and an older `moduleVersion`, or has this usage's `module` as its `plannedReplacement`, its `koppelingen` are offered with reason `carry-over`.
+- For a successor, each offered connection is a draft: same other end, same type and direction, application A or B set to the successor, status `in development`, and `longDescription` naming the connection it came from.
+
+Rejected: storing suggestions as objects. They go stale the moment someone adds a usage; computing them on each open is cheap because every query is scoped to one organisation.
+
+## D2. Endpoints
+
+In `appinfo/routes.php`, next to the offer routes (:202-204):
+
+| verb | url | controller method |
+|---|---|---|
+| GET | `/api/usages/{uuid}/connection-suggestions` | `ConnectionSuggestionController::index` |
+| POST | `/api/usages/{uuid}/connection-suggestions/accept` | `::accept` (body: suggestion ids) |
+| POST | `/api/usages/{uuid}/connection-suggestions/dismiss` | `::dismiss` (body: suggestion ids) |
+
+All `#[NoAdminRequired]` with a per-object guard: the caller must be allowed to update the usage (the usage's `consumer` or a participant is the active organisation), the same rule `AanbodService` applies before it changes a usage. Accept appends existing connections to `usage.koppelingen`, and for a draft creates the connection first. Dismiss records the connection id in a new usage property `dismissedConnectionSuggestions` (array of uuid, `hideOnForm: true`).
+
+Rejected: reusing the offer endpoints (`/api/aanbod/{uuid}/accept`). An offer is an object a supplier made; a suggestion is derived and has no owner to accept from.
+
+## D3. The panel
+
+A custom component `ConnectionSuggestionsPanel` (`src/components/connections/ConnectionSuggestionsPanel.vue`), registered in `src/customComponents.js`, placed on the usage detail page as a body widget. It lists suggestions with the other application, type, direction and reason, and offers Accept, Dismiss and Accept all. Empty state: "No suggestions. Every known connection of this application is already in your usage."
+
+## Declarative versus imperative
+
+Imperative: deriving suggestions joins three queries and a rule, which no `x-openregister-*` block describes (ADR-031 allows code where the dialect has no construct). The accepted result is plain data on the usage.
+
+## Seed data
+
+The usage schema gains `dismissedConnectionSuggestions` (array, hidden on the form), added in `lib/Settings/register.d/derived-connections.json`. The demo register gets two usages of one organisation whose applications share a demo connection, so the panel shows one suggestion.
+
+## Risks
+
+- The per-object guard must match the usage's update rule exactly; `hydra-gate-no-admin-idor` checks each method has one.
+- Draft connections created for a successor are real objects; a dismissed draft is never created, only an accepted one.
diff --git a/openspec/changes/connections-derived-dependencies/proposal.md b/openspec/changes/connections-derived-dependencies/proposal.md
new file mode 100644
index 000000000..ab45a63f9
--- /dev/null
+++ b/openspec/changes/connections-derived-dependencies/proposal.md
@@ -0,0 +1,44 @@
+---
+kind: code
+depends_on:
+ - connections-catalogue-pages
+ - landscape-usage-registration
+---
+
+# Suggest connections from what the catalogue already knows
+
+## Summary
+
+When an organisation records that it uses an application, stackiq suggests the connections that application already has with other applications the organisation uses, so nobody draws each link by hand. When a usage is replaced by a newer version or by its planned successor, stackiq offers to carry the old usage's connections over. The organisation accepts or dismisses each suggestion.
+
+## Why
+
+Rows from the stackiq matrix:
+
+- `stackiq:conn-auto-populate-dependencies`, "Fill in an application's dependencies automatically from what is already known about connected items, instead of drawing each link by hand." Rated no. Feature request: https://github.com/glpi-project/roadmap/discussions/336. Two competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/jira-service-management-integration, "Dependencies and relationships identified in Jira Service Management are automatically documented", and discovered flows that suggest missing interfaces) and BlueDolphin (https://help.bluedolphin.io/en/articles/11967645-use-datasource-to-create-relationships, "automatically create relationships between objects based on a loaded datasource"). Core area (connections).
+- `stackiq:land-version-carry-connections`, "Carry an application's connections over automatically when a new version replaces the old one." Rated no. Feature request from the VNG user research: https://www.softwarecatalogus.nl/gebruikersonderzoek%202021. Core area (landscape).
+
+## What stackiq has today
+
+- A connection links applications, not versions: `connection.moduleA` and `moduleB` are `$ref module` (`lib/Settings/softwarecatalogus_register.json:3689`, `:3705`). Registering a new version never drops a catalogue connection.
+- What an organisation runs is a usage: `usage.module`, `usage.moduleVersion` and `usage.koppelingen`, "the connections used within this usage" (usage schema, `register.json:2656`). `usage.plannedReplacement` names a successor application.
+- A replacing usage starts with an empty `koppelingen`. Nothing copies connections from the usage it replaces, and nothing fills `koppelingen` from the connections the application already has.
+- Suppliers can already offer usages and connections that a municipality accepts or denies (`lib/Service/AanbodService.php:289` acceptAanbod, `:438` denyAanbod; `appinfo/routes.php:203-204`). That flow handles one offered object; it does not derive anything.
+
+## What this change builds
+
+1. A suggestion service that, for one usage, lists the connections of its application whose other end is an application the same organisation uses, and that are not yet in the usage.
+2. A carry-over suggestion: when a usage of the same application at a newer version, or of the old usage's planned successor, is created for the organisation, stackiq offers the old usage's connections. For a successor, it offers draft connections from the successor to the same other ends.
+3. A Suggested connections panel on the usage page (from `landscape-usage-registration`) with Accept and Dismiss per suggestion and Accept all.
+4. Dismissed suggestions stay dismissed for that usage.
+
+## Out of scope
+
+- Discovering connections from network traffic, logs or a service desk. The matrix category says stackiq is not a discovery agent.
+- Suggestions pulled from outside systems through integriq (`sharing-itsm-exchange` covers the service desk exchange).
+- The offer workflow for suppliers (`AanbodService`), which stays as it is.
+
+## Risks
+
+- A popular application has many connections. Suggestions only list connections whose other end the organisation actually uses, which keeps the list short.
+- A draft connection for a successor may be wrong. It starts with status `in development` and names its origin, so the user reviews it.
diff --git a/openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md b/openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md
new file mode 100644
index 000000000..9f98b4bf4
--- /dev/null
+++ b/openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md
@@ -0,0 +1,61 @@
+# derived-connections specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- connections-derived-dependencies
+
+## Purpose
+
+An organisation's usages get their connections filled in from what the catalogue already knows, instead of by hand. Matrix rows `stackiq:conn-auto-populate-dependencies` and `stackiq:land-version-carry-connections`.
+
+## ADDED Requirements
+
+### Requirement: REQ-DCN-001 Stackiq suggests the known connections of an application inside the organisation's landscape
+
+For a usage, stackiq SHALL suggest every readable connection of the usage's application whose other end is an application the same organisation uses, or a national provision, and that is not yet in the usage's connections and was not dismissed for this usage.
+
+#### Scenario: A municipality gets its connections suggested
+@e2e tests/e2e/workflows/connection-suggestions.spec.ts
+
+- **GIVEN** a published connection between application X and application Y, and a municipality that has a usage of Y
+- **WHEN** the municipality's information manager records a usage of X and opens it
+- **THEN** the Suggested connections panel lists the connection between X and Y
+- **AND** after Accept the usage's connections include it
+
+#### Scenario: A connection outside the landscape is not suggested
+@e2e exclude Rule-level case; tests/Unit/Service/ConnectionSuggestionServiceTest.php covers an other end the organisation does not use.
+
+- **GIVEN** a connection between X and Z, and the municipality does not use Z
+- **WHEN** the information manager opens the usage of X
+- **THEN** that connection is not suggested
+
+### Requirement: REQ-DCN-002 A replacing usage is offered the connections of the usage it replaces
+
+When an organisation has a usage of the same application at an older version, or a usage whose planned replacement is the new usage's application, stackiq SHALL suggest the older usage's connections for the new usage. For a successor application it SHALL suggest draft connections from the successor to the same other ends, with status `in development` and a description naming the original connection.
+
+#### Scenario: A new version keeps its connections
+@e2e tests/e2e/workflows/connection-suggestions.spec.ts
+
+- **GIVEN** a usage of X at version 1 with connections to Y and to a national provision
+- **WHEN** the information manager records a usage of X at version 2
+- **THEN** both connections are suggested with the reason that they carry over from version 1
+
+#### Scenario: A successor gets draft connections
+@e2e exclude Rule-level case; tests/Unit/Service/ConnectionSuggestionServiceTest.php covers the successor path.
+
+- **GIVEN** a usage of X whose planned replacement is Z, with a connection from X to Y
+- **WHEN** the information manager records a usage of Z and accepts the suggestion
+- **THEN** a connection from Z to Y exists with status `in development`
+
+### Requirement: REQ-DCN-003 Only the organisation that owns the usage accepts or dismisses its suggestions
+
+`POST /api/usages/{uuid}/connection-suggestions/accept` and `/dismiss` SHALL refuse with 403 a caller whose active organisation is neither the usage's consumer nor one of its participants, and SHALL change nothing then.
+
+#### Scenario: Another organisation cannot accept
+@e2e exclude API guard; tests/Unit/Controller/ConnectionSuggestionControllerTest.php asserts the 403 and that no object was written.
+
+- **GIVEN** a usage of municipality A
+- **WHEN** a user whose active organisation is municipality B posts accept for it
+- **THEN** the answer is 403
+- **AND** the usage's connections are unchanged
diff --git a/openspec/changes/connections-derived-dependencies/tasks.md b/openspec/changes/connections-derived-dependencies/tasks.md
new file mode 100644
index 000000000..430cfefd0
--- /dev/null
+++ b/openspec/changes/connections-derived-dependencies/tasks.md
@@ -0,0 +1,53 @@
+# Tasks: connections-derived-dependencies
+
+## Implementation tasks
+
+### Task 1: Suggestion service
+- **spec_ref**: openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md#requirement-req-dcn-001-stackiq-suggests-the-known-connections-of-an-application-inside-the-organisations-landscape
+- **files**: `lib/Service/ConnectionSuggestionService.php`, `lib/Settings/register.d/derived-connections.json`
+- **acceptance_criteria**:
+ - GIVEN applications X and Y share a connection and the organisation uses both WHEN suggestions are asked for its usage of X THEN the connection is suggested with reason shared-landscape
+ - GIVEN the organisation does not use Y WHEN suggestions are asked THEN that connection is not suggested
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Service/ConnectionSuggestionServiceTest.php` with an ObjectService double built on the real interface)
+
+### Task 2: Carry-over suggestions
+- **spec_ref**: openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md#requirement-req-dcn-002-a-replacing-usage-is-offered-the-connections-of-the-usage-it-replaces
+- **files**: `lib/Service/ConnectionSuggestionService.php`
+- **acceptance_criteria**:
+ - GIVEN an old usage of X at version 1 with two connections WHEN a usage of X at version 2 is created THEN both connections are suggested with reason carry-over
+ - GIVEN an old usage whose planned replacement is Z WHEN a usage of Z is created THEN draft connections from Z to the same ends are suggested
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Service/ConnectionSuggestionServiceTest.php`, carry-over cases)
+
+### Task 3: Endpoints with a per-object guard
+- **spec_ref**: openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md#requirement-req-dcn-003-only-the-organisation-that-owns-the-usage-accepts-or-dismisses-its-suggestions
+- **files**: `lib/Controller/ConnectionSuggestionController.php`, `appinfo/routes.php`, `lib/AppInfo/Application.php`
+- **acceptance_criteria**:
+ - GIVEN a user of another organisation WHEN they post accept for this usage THEN the answer is 403 and nothing changes
+ - GIVEN the owning organisation WHEN it accepts a suggestion THEN the connection is in usage.koppelingen
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Controller/ConnectionSuggestionControllerTest.php`; Newman collection `postman/` request for the three routes)
+
+### Task 4: Suggested connections panel
+- **spec_ref**: openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md#requirement-req-dcn-001-stackiq-suggests-the-known-connections-of-an-application-inside-the-organisations-landscape
+- **files**: `src/components/connections/ConnectionSuggestionsPanel.vue`, `src/customComponents.js`, the usage detail page in `src/manifest.d/`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN one suggestion WHEN the user clicks Accept THEN it leaves the panel and appears in the usage's connections
+ - GIVEN one suggestion WHEN the user clicks Dismiss and reloads THEN it stays gone
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/connection-suggestions.spec.ts`)
+
+### Task 5: Documentation
+- **spec_ref**: openspec/changes/connections-derived-dependencies/specs/derived-connections/spec.md#requirement-req-dcn-002-a-replacing-usage-is-offered-the-connections-of-the-usage-it-replaces
+- **files**: `docs/features/connection-suggestions.md`, `docs/images/connection-suggestions.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Connection suggestions THEN both sources of suggestions are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate connections-derived-dependencies --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; PHPUnit, Newman and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/connections-diagram-and-graph-export/.openspec.yaml b/openspec/changes/connections-diagram-and-graph-export/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/connections-diagram-and-graph-export/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/connections-diagram-and-graph-export/design.md b/openspec/changes/connections-diagram-and-graph-export/design.md
new file mode 100644
index 000000000..caf3790b7
--- /dev/null
+++ b/openspec/changes/connections-diagram-and-graph-export/design.md
@@ -0,0 +1,45 @@
+# Design: connections-diagram-and-graph-export
+
+Read at development `49e65cb4`, with `@conduction/nextcloud-vue` 2.57.1 (`package.json:45`).
+
+## Context
+
+The connection data is complete in the `connection` schema (`lib/Settings/softwarecatalogus_register.json:3565`): `moduleA` (:3689), `moduleB` (:3705), `nonMunicipalProvision` (:3720), `type`, `dataExchangeDirection` (:3676) and `status`. `connections-catalogue-pages` gives it an index page, a detail page and two lists on the application page. This change draws and exports what those pages list.
+
+## D1. The application map uses CnRelationshipGraph
+
+A new custom widget `ConnectionMapWidget` (`src/components/connections/ConnectionMapWidget.vue`), registered in `src/customComponents.js` and placed on `ModuleDetail` (`src/manifest.json:491`) as a body widget. It reads the application's connections through the object store (two queries, `moduleA` and `moduleB` equal to the application, as `connections-catalogue-pages` D2 does) and hands nodes and edges to `CnRelationshipGraph` (`src/components/CnRelationshipGraph/CnRelationshipGraph.vue` in the library) with `layout: 'radial'` and the application as root. Edge labels carry the transport type; the arrow direction follows `dataExchangeDirection`.
+
+Rejected: a new graph library. `CnRelationshipGraph` covers one hop, which is what "what is this application linked to" asks (ADR-012).
+
+## D2. The list diagram uses CnGraphCanvas read-only
+
+The `Koppelingen` index page gets a "Diagram" toggle next to the table, rendered by a custom component `ConnectionsDiagram` (`src/components/connections/ConnectionsDiagram.vue`). It takes the rows the index page fetched (same filters, same page) and draws them with `CnGraphCanvas` with `interactive: false`. Node positions come from a small layered layout in `src/utils/connectionLayout.js`: applications that only send on the left, that only receive on the right, the rest in the middle, sorted by name. No new dependency: Vue Flow already ships with the library.
+
+Rejected: a force layout. It moves nodes on every render and needs a layout engine the library chose not to carry (`CnRelationshipGraph.vue:90`).
+
+## D3. Downloads are client-side
+
+The map widget's action menu offers "Download as SVG", "Download as PNG" and "Download links as CSV". SVG serialises the rendered `svg` element; PNG draws it on a canvas; CSV lists one line per connection with application A, direction, application B or national provision, type and status. Nothing goes to the server, so the download follows exactly what the user may read.
+
+## D4. Connections in the organisation ArchiMate export
+
+- `SettingsController::exportOrgArchiMate()` (`lib/Controller/SettingsController.php:1685`) reads a fourth option `connections` next to `modules`, `deelnames` and `usage` (:1698-1700), default false.
+- `ArchiMateService::exportOrgArchiMate()` (`lib/Service/ArchiMateService.php:302`) passes it on. A new private method in `lib/Service/ArchiMateExportService.php` loads the connections whose `moduleA` or `moduleB` is an application of the organisation, and writes each as an ArchiMate `Flow` relationship in the model's `relationships` section (the section writer at `:1160` and `:1197`), source and target by the exported application component identifiers, with properties for transport type, direction and status. A bi-directional connection writes two flows. A connection to a national provision targets that element's identifier.
+- A flow whose end is not in the exported model is skipped and counted in the export result.
+- `src/views/settings/sections/ArchiMateImportExport.vue:571` gains a fourth checkbox, "Connections".
+
+Rejected: a new export endpoint for connections only. The GEMMA Softwarecatalogus exports "pakketten én koppelingen in 1 model", and one file is what Archi opens.
+
+## Declarative versus imperative
+
+The map and the diagram are views over data the schema already holds; they add no relation or lifecycle behaviour. The export is imperative because it is: the ArchiMate writer is a PHP service today.
+
+## Seed data
+
+No schema change. The three demo connections from `connections-catalogue-pages` are enough to draw a map.
+
+## Risks
+
+- `ArchiMateExportService.php` is large (the export path around `:2734`). The new method stays separate and is unit tested against a fixture.
+- The list diagram draws only the fetched page; the toggle says so.
diff --git a/openspec/changes/connections-diagram-and-graph-export/proposal.md b/openspec/changes/connections-diagram-and-graph-export/proposal.md
new file mode 100644
index 000000000..71f803ec8
--- /dev/null
+++ b/openspec/changes/connections-diagram-and-graph-export/proposal.md
@@ -0,0 +1,45 @@
+---
+kind: code
+depends_on:
+ - connections-catalogue-pages
+---
+
+# See connections as a diagram and export the link graph
+
+## Summary
+
+An application owner can see an application's connections drawn as a map on its page, and an information manager can see the filtered connections list as a diagram. The link graph leaves stackiq in two forms: the application map as an image and a CSV of its links, and the connections inside the organisation's ArchiMate export, so Archi and other modelling tools receive them.
+
+## Why
+
+Rows from the stackiq matrix:
+
+- `stackiq:conn-diagram`, "See the connections between applications drawn as a diagram." Rated no. Four competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/data-flow, data flow diagrams "understand how applications are connected"), BlueDolphin (https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin, "visualize chains and information flows"), GLPI (source read at 11.0.9, `src/Impact.php:252` displayGraphView draws the relation network) and TOPdesk (https://docs.topdesk.com/en/linking-assets-to-other-assets.html, "the graphical overview to see a visual representation of their relationship"). Core area (connections).
+- `stackiq:conn-export-graph`, "Export the graph of what an application is linked to, for use elsewhere." Rated no. Two competitors rate yes: GEMMA Softwarecatalogus (https://www.softwarecatalogus.nl/Handleiding%20koppeling%20architectuurtools, "Pakketten én koppelingen worden in 1 model geëxporteerd ... AMEFF-export") and GLPI (source read at 11.0.9, CSV export in `front/impactcsv.php` and PNG or JPEG download at `js/impact.js:2528`). Core area.
+
+No tender, feature request or roadmap row names these rows.
+
+## What stackiq has today
+
+- No page draws connections. `src/store/modules/view.js` calls `GET /api/views` and nothing imports it.
+- The organisation ArchiMate export (`GET /api/archimate/export/organization/{organizationUuid}`, `appinfo/routes.php:98`, `lib/Controller/SettingsController.php:1685`) takes the options `modules`, `deelnames` and `usage` (:1698-1700) and writes GEMMA view copies with the organisation's applications (`lib/Service/ArchiMateExportService.php:2734`). It writes no catalogue connection: the only `connection` handling in the export service is a diagram line inside a copied view (`:632-634`, `:742`).
+- The export is reached from the admin settings section (`src/views/settings/sections/ArchiMateImportExport.vue:571`), with checkboxes Modules, Deelnames and Gebruik, for a Nextcloud admin or an organisation admin (`SettingsController.php:1737`).
+- `@conduction/nextcloud-vue` 2.57.1 ships `CnRelationshipGraph` (an SVG graph with radial, grid and manual layouts) and `CnGraphCanvas` (a Vue Flow canvas).
+
+## What this change builds
+
+1. A connection map on the application page: the application in the centre, every application or national provision it connects to around it, each line labelled with transport and direction. Clicking a node opens that application or the connection.
+2. A diagram view on the connections list (`Koppelingen`, from `connections-catalogue-pages`), drawing the rows the current filters return.
+3. Downloads from the application map: the drawing as SVG and PNG, and the links as CSV.
+4. A `connections` option on the organisation ArchiMate export, writing each connection of the organisation as an ArchiMate flow relationship between the application components, with transport type, direction and status as properties.
+
+## Out of scope
+
+- Drawing or editing architecture views: `architecture-views-editor`.
+- Making the organisation export reachable outside admin settings (`stackiq:arch-export-org`, deferred as partial, built, no demand).
+- Impact analysis before retiring an application (`stackiq:conn-impact-analysis`, owned by openregister).
+
+## Risks
+
+- A large landscape gives an unreadable diagram. The list diagram caps at the page size and asks the user to filter.
+- Archi reads flow relationships only between elements it knows. The export writes a flow only when both ends are in the exported model, and counts the ones it skipped.
diff --git a/openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md b/openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md
new file mode 100644
index 000000000..97206822e
--- /dev/null
+++ b/openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md
@@ -0,0 +1,58 @@
+# connection-diagram-and-export specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- connections-diagram-and-graph-export
+
+## Purpose
+
+Users see how applications connect as a picture, and take the link graph to other tools. Matrix rows `stackiq:conn-diagram` and `stackiq:conn-export-graph`.
+
+## ADDED Requirements
+
+### Requirement: REQ-CDX-001 The application page draws the application's connections as a map
+
+The application page `ModuleDetail` SHALL show a map with the application in the centre and every application or national provision it has a readable connection with around it. Each line SHALL carry the transport type and point in the connection's data exchange direction. Clicking a node SHALL open that application, and clicking a line SHALL open the connection.
+
+#### Scenario: An application owner reads the map
+@e2e tests/e2e/workflows/connections.spec.ts
+
+- **GIVEN** application X has an `api` connection to application Y and a `file transfer` connection to a national provision
+- **WHEN** the application owner opens the page of application X
+- **THEN** the connection map shows X in the centre with Y and the national provision around it
+- **AND** the line to Y reads `api`
+
+### Requirement: REQ-CDX-002 The connections list can be shown as a diagram of the filtered rows
+
+The connections list `Koppelingen` SHALL offer a diagram view that draws exactly the rows the current filters return, with a stable layout: the same rows SHALL give the same positions.
+
+#### Scenario: An information manager draws only the API connections
+@e2e tests/e2e/workflows/connections.spec.ts
+
+- **GIVEN** the connections list filtered on transport type `api`
+- **WHEN** the information manager switches to Diagram
+- **THEN** the diagram shows only the `api` connections and their applications
+
+### Requirement: REQ-CDX-003 A user can download an application's map and its links
+
+The connection map SHALL let the user download the drawing as SVG and as PNG, and the links as a CSV with one line per connection: application A, direction, application B or national provision, transport type and status. The download SHALL hold only connections the user may read.
+
+#### Scenario: An architect takes the links to a spreadsheet
+@e2e exclude The download is built client-side; tests/vitest/connectionExport.spec.js asserts the CSV columns, one line per connection and quoting.
+
+- **GIVEN** the map of application X with two connections
+- **WHEN** the architect picks Download links as CSV
+- **THEN** a CSV downloads with a header line and two connection lines
+
+### Requirement: REQ-CDX-004 The organisation ArchiMate export can carry the organisation's connections
+
+`GET /api/archimate/export/organization/{organizationUuid}` SHALL accept `connections=true`. The export SHALL then write every connection between applications in the export as an ArchiMate flow relationship, and a connection to a national provision as a flow to that element, with the transport type, direction and status as properties. A connection whose other end is not in the exported model SHALL be skipped and counted in the result.
+
+#### Scenario: An organisation admin exports applications and connections in one file
+@e2e tests/e2e/org-archimate-export.spec.ts
+
+- **GIVEN** an organisation whose two applications share one `api` connection
+- **WHEN** the organisation admin runs the organisation export with Applications and Connections ticked
+- **THEN** the downloaded file holds a flow relationship between the two application components
+- **AND** the relationship carries the property transport type `api`
diff --git a/openspec/changes/connections-diagram-and-graph-export/tasks.md b/openspec/changes/connections-diagram-and-graph-export/tasks.md
new file mode 100644
index 000000000..4eb83425e
--- /dev/null
+++ b/openspec/changes/connections-diagram-and-graph-export/tasks.md
@@ -0,0 +1,53 @@
+# Tasks: connections-diagram-and-graph-export
+
+## Implementation tasks
+
+### Task 1: Connection map on the application page
+- **spec_ref**: openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md#requirement-req-cdx-001-the-application-page-draws-the-applications-connections-as-a-map
+- **files**: `src/components/connections/ConnectionMapWidget.vue`, `src/customComponents.js`, `src/manifest.json` (ModuleDetail bodyWidgets), `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN an application with three connections WHEN its page opens THEN the map shows the application in the centre and three linked nodes with transport labels
+ - GIVEN a node on the map WHEN the user clicks it THEN the linked application or connection opens
+- [ ] Implement
+- [ ] Test (vitest `tests/vitest/connectionMap.spec.js` for nodes and edges from connections; Playwright `tests/e2e/workflows/connections.spec.ts` map case)
+
+### Task 2: Diagram view on the connections list
+- **spec_ref**: openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md#requirement-req-cdx-002-the-connections-list-can-be-shown-as-a-diagram-of-the-filtered-rows
+- **files**: `src/components/connections/ConnectionsDiagram.vue`, `src/utils/connectionLayout.js`, `src/manifest.d/connections.json`
+- **acceptance_criteria**:
+ - GIVEN the connections list filtered on type api WHEN the user switches to Diagram THEN only the api connections are drawn
+ - GIVEN the same rows WHEN the diagram renders twice THEN every node keeps its position
+- [ ] Implement
+- [ ] Test (vitest `tests/vitest/connectionLayout.spec.js` for a stable layered layout)
+
+### Task 3: Downloads from the map
+- **spec_ref**: openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md#requirement-req-cdx-003-a-user-can-download-an-applications-map-and-its-links
+- **files**: `src/components/connections/ConnectionMapWidget.vue`, `src/utils/connectionExport.js`
+- **acceptance_criteria**:
+ - GIVEN the map of an application WHEN the user picks Download links as CSV THEN a CSV with one line per connection downloads
+ - GIVEN the same map WHEN the user picks Download as SVG THEN an SVG with the drawn nodes downloads
+- [ ] Implement
+- [ ] Test (vitest `tests/vitest/connectionExport.spec.js` for CSV columns and escaping)
+
+### Task 4: Connections in the organisation ArchiMate export
+- **spec_ref**: openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md#requirement-req-cdx-004-the-organisation-archimate-export-can-carry-the-organisations-connections
+- **files**: `lib/Controller/SettingsController.php`, `lib/Service/ArchiMateService.php`, `lib/Service/ArchiMateExportService.php`, `src/views/settings/sections/ArchiMateImportExport.vue`
+- **acceptance_criteria**:
+ - GIVEN an organisation with two connections between its applications WHEN the export runs with connections on THEN the file holds two flow relationships with transport properties
+ - GIVEN a connection whose other end is outside the export WHEN the export runs THEN it is skipped and counted
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Service/ArchiMateExportConnectionsTest.php` against a fixture model; Playwright `tests/e2e/org-archimate-export.spec.ts` extended with the checkbox)
+
+### Task 5: Documentation
+- **spec_ref**: openspec/changes/connections-diagram-and-graph-export/specs/connection-diagram-and-export/spec.md#requirement-req-cdx-001-the-application-page-draws-the-applications-connections-as-a-map
+- **files**: `docs/features/connections.md`, `docs/images/connection-map.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Connections THEN the map, the diagram and the export option are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate connections-diagram-and-graph-export --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit, vitest and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/landscape-ai-system-inventory/.openspec.yaml b/openspec/changes/landscape-ai-system-inventory/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-ai-system-inventory/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-ai-system-inventory/design.md b/openspec/changes/landscape-ai-system-inventory/design.md
new file mode 100644
index 000000000..3aff7e287
--- /dev/null
+++ b/openspec/changes/landscape-ai-system-inventory/design.md
@@ -0,0 +1,52 @@
+# Design: landscape-ai-system-inventory
+
+Read at development `49e65cb4`.
+
+## Context
+
+The catalogue holds applications (`module`, `lib/Settings/softwarecatalogus_register.json:6779` schema) and organisations' usages of them (`usage`, `:2656`). An AI system either is a product of its own or runs inside an application; in both cases the organisation needs to see it next to the application and classify it. New schemas go in a fragment (ADR-037) that appends them to the `stackiq` register (`SettingsService::loadSettings()`, `lib/Service/SettingsService.php:1653-1680`).
+
+## D1. The aiSystem schema
+
+`lib/Settings/register.d/ai-system-inventory.json`, schema.org type `SoftwareApplication` with `applicationCategory` AI:
+
+| property | type | notes |
+|---|---|---|
+| `name` | string, required | |
+| `description` | string, markdown | |
+| `kind` | enum `AI agent`, `AI model`, `AI feature` | facetable |
+| `module` | `$ref module` | the application it runs in or supports, `inversedBy: aiSystems` |
+| `provider` | `$ref organization` | the supplier |
+| `purpose` | string | what it decides or produces |
+| `aiActRiskCategory` | enum `prohibited`, `high risk`, `limited risk`, `minimal risk`, `not yet assessed`, default `not yet assessed` | facetable |
+| `aiActRole` | enum `provider`, `deployer` | |
+| `algorithmRegisterUrl` | string, format uri | the entry at algoritmes.overheid.nl |
+| `assessedOn` | date | |
+| `friaDocumentRef` | string | reference to the fundamental rights impact assessment, the same pattern as `module.dpiaDocumentRef` |
+| `status` | enum `in development`, `in use`, `withdrawn`, with an `x-openregister-lifecycle` on those exact values | |
+
+Configuration: `allowFiles: true`, `allowedTags`: `FRIA`, `Technical documentation`, `Human oversight`, `Logging`. Authorization copied from `usage`: the organisation reads and edits its own AI systems (`_organisation` match); suppliers read those whose `provider` is their organisation.
+
+Rejected: a new value `AI system` in `module.type`. The act's fields (category, role, assessment) do not belong on every application, and one application can carry several AI features.
+
+## D2. Pages
+
+`src/manifest.d/ai-systems.json`: `AiSystems` (`/ai-systems`, index, columns name, kind, module, aiActRiskCategory, status, `filterMenu: true`, quick filters per risk category) and `AiSystemDetail` (`/ai-systems/:id`: data, files with the four tags, related, history). A menu child "AI systems" under Applications (ADR-097). On `ModuleDetail` (`src/manifest.json:491`) an `object-list` `md-ai-systems` with filter `{ "module": "@objectId" }`.
+
+## D3. The missing assessment warning
+
+The warning follows the pattern the module schema already uses for its DPIA (`module.dpiaDocumentRef`): the assessment is a reference field, `friaDocumentRef`, filled when the file is attached. The AI systems list gets a quick filter "High risk without FRIA" (`aiActRiskCategory` high risk and `friaDocumentRef` empty) and a warning badge column on the same rule. A body widget `AiActChecklist` (`src/components/ai/AiActChecklist.vue`) on the detail page lists the four evidence tags and marks which have a file, reading the entry's files through the library's files API.
+
+Rejected: a flag written by a file listener. OpenRegister raises no event when a file is added to an object (its `lib/Event` holds copy, lock, move, rename, unlock and version-restore events only), so a listener would miss the case that matters.
+
+## Declarative versus imperative
+
+All declarative (ADR-031): the schema, lifecycle, tags, the quick filter and the pages. The checklist widget only reads.
+
+## Seed data
+
+Two demo AI systems: a chat assistant (AI agent, limited risk) inside a demo application, and a scoring model (AI model, high risk) without a FRIA, so the badge shows.
+
+## Risks
+
+- A supplier may register the same AI feature for its product that a municipality registered for its usage. The detail page shows provider and organisation; `operations-record-reconciliation` merges duplicates.
diff --git a/openspec/changes/landscape-ai-system-inventory/proposal.md b/openspec/changes/landscape-ai-system-inventory/proposal.md
new file mode 100644
index 000000000..50f41d019
--- /dev/null
+++ b/openspec/changes/landscape-ai-system-inventory/proposal.md
@@ -0,0 +1,42 @@
+---
+kind: config
+depends_on:
+ - landscape-usage-registration
+---
+
+# Register the AI systems you use and classify them under the AI Act
+
+## Summary
+
+An information manager registers the AI agents, AI models and AI features the organisation uses, links each to the application it runs in, and records its EU AI Act risk category, the organisation's role under the act and the documents the act asks for. The application page shows its AI systems, and an AI systems list filters on risk category, so a privacy officer sees which high-risk systems still lack their assessment.
+
+## Why
+
+Rows from the stackiq matrix:
+
+- `stackiq:land-ai-agent-inventory`, "Register the AI agents and AI models the organisation uses and link them to the applications and processes they support." Rated no. SAP LeanIX rates yes: https://help.sap.com/docs/leanix/ea/application-modeling-guidelines (AI agent is an application subtype, AI model an IT component subtype), with the changelog row https://updates.leanix.net/announcements/discover-verify-and-govern-ai-assets-with-sap-ai-agent-hub. Core area (landscape).
+- `stackiq:comp-ai-act-classification`, "Classify the AI systems in the landscape by EU AI Act risk category and keep the evidence the act requires." Rated no, no competitor yes. Roadmap demand: https://roadmap.leanix.net/c/812-meta-model-eu-ai-act-extension. It rides with `land-ai-agent-inventory`: its whole capability is a risk category and evidence on the AI system record that change adds.
+
+## What stackiq has today
+
+- No schema for AI agents, models or systems; the register's catalogue schemas are listed at `lib/Settings/softwarecatalogus_register.json:817` onwards.
+- `module.type` distinguishes Application from System software only.
+- Evidence documents already hang on records through Nextcloud files (`allowFiles`, for example `usage` with tags DPIA, Contract, Verwerkingsovereenkomst), and `module.dpiaDocumentRef` links a DPIA.
+
+## What this change builds
+
+1. A schema `aiSystem`: name, description, kind (AI agent, AI model, AI feature), the application it runs in or supports, the supplier, the purpose, the EU AI Act risk category (prohibited, high risk, limited risk, minimal risk, not yet assessed), the organisation's role (provider or deployer), a link to the entry in the Dutch algorithm register, the date of the last assessment, and a status.
+2. File tags on `aiSystem` for the documents the act asks of a deployer of a high-risk system: fundamental rights impact assessment, technical documentation from the provider, human oversight procedure, logging arrangement.
+3. An AI systems list with filters on kind and risk category, and an AI systems section on the application page.
+4. A warning on a high-risk AI system that has no fundamental rights impact assessment, and a quick filter that lists them.
+
+## Out of scope
+
+- Discovering AI systems automatically. The matrix category says stackiq is not a discovery agent.
+- Publishing to the Dutch algorithm register (algoritmes.overheid.nl). Stackiq stores the link; exchange with that register is integriq's.
+- Linking AI systems to business processes: `architecture-process-mapping` adds processes; a relation from `aiSystem` follows once that schema exists.
+- Legal advice on the category. The field records the organisation's own classification.
+
+## Risks
+
+- The AI Act's categories and deployer duties may be refined by guidance. The enum and the file tags live in the fragment and change with a pull request.
diff --git a/openspec/changes/landscape-ai-system-inventory/specs/ai-system-inventory/spec.md b/openspec/changes/landscape-ai-system-inventory/specs/ai-system-inventory/spec.md
new file mode 100644
index 000000000..197c6d641
--- /dev/null
+++ b/openspec/changes/landscape-ai-system-inventory/specs/ai-system-inventory/spec.md
@@ -0,0 +1,46 @@
+# ai-system-inventory specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-ai-system-inventory
+
+## Purpose
+
+The organisation keeps its AI agents, models and features next to the applications they run in, with their EU AI Act classification and evidence. Matrix rows `stackiq:land-ai-agent-inventory` and `stackiq:comp-ai-act-classification`.
+
+## ADDED Requirements
+
+### Requirement: REQ-AIS-001 An organisation registers the AI systems it uses next to their applications
+
+Stackiq SHALL store an AI system with its name, kind (AI agent, AI model or AI feature), the application it runs in or supports, the supplier, its purpose and a status, and the application page SHALL list the AI systems linked to it.
+
+#### Scenario: An information manager registers a chat assistant
+@e2e tests/e2e/workflows/ai-systems.spec.ts
+
+- **GIVEN** the municipality uses application X, which has a built-in chat assistant
+- **WHEN** the information manager opens AI systems, clicks Add and saves "Chat assistant" of kind AI feature linked to X
+- **THEN** the page of X lists "Chat assistant" in its AI systems section
+
+### Requirement: REQ-AIS-002 An AI system carries its AI Act classification and evidence
+
+An AI system SHALL record its EU AI Act risk category (prohibited, high risk, limited risk, minimal risk or not yet assessed), the organisation's role under the act, the date of the last assessment and a link to its algorithm register entry, and SHALL hold evidence files tagged FRIA, Technical documentation, Human oversight and Logging. The AI systems list SHALL filter on risk category.
+
+#### Scenario: A privacy officer lists the high-risk systems
+@e2e tests/e2e/workflows/ai-systems.spec.ts
+
+- **GIVEN** two AI systems, one high risk and one minimal risk
+- **WHEN** the privacy officer filters the AI systems list on high risk
+- **THEN** only the high-risk system remains
+
+### Requirement: REQ-AIS-003 A high-risk AI system without a fundamental rights impact assessment is flagged
+
+The detail page of an AI system SHALL show which of the four evidence tags have a file. A high-risk AI system whose FRIA reference is empty SHALL show a warning in the list, and the list SHALL offer a filter for exactly those systems.
+
+#### Scenario: The missing assessment shows
+@e2e tests/e2e/workflows/ai-systems.spec.ts
+
+- **GIVEN** a high-risk AI system with technical documentation but no FRIA
+- **WHEN** the privacy officer filters the AI systems list on High risk without FRIA
+- **THEN** that system is listed with a warning
+- **AND** its page marks FRIA as missing in the evidence checklist
diff --git a/openspec/changes/landscape-ai-system-inventory/tasks.md b/openspec/changes/landscape-ai-system-inventory/tasks.md
new file mode 100644
index 000000000..9f3be00de
--- /dev/null
+++ b/openspec/changes/landscape-ai-system-inventory/tasks.md
@@ -0,0 +1,43 @@
+# Tasks: landscape-ai-system-inventory
+
+## Implementation tasks
+
+### Task 1: The aiSystem schema
+- **spec_ref**: openspec/changes/landscape-ai-system-inventory/specs/ai-system-inventory/spec.md#requirement-req-ais-001-an-organisation-registers-the-ai-systems-it-uses-next-to-their-applications
+- **files**: `lib/Settings/register.d/ai-system-inventory.json`, `lib/Settings/stackiq_mock_register.json`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it is imported THEN the stackiq register lists aiSystem with its lifecycle and file tags
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Settings/AiSystemFragmentTest.php`)
+
+### Task 2: Pages and the application page section
+- **spec_ref**: openspec/changes/landscape-ai-system-inventory/specs/ai-system-inventory/spec.md#requirement-req-ais-002-an-ai-system-carries-its-ai-act-classification-and-evidence
+- **files**: `src/manifest.d/ai-systems.json`, `src/manifest.json` (ModuleDetail list), `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN an application with one AI feature WHEN its page opens THEN the AI systems section lists it with its risk category
+ - GIVEN the AI systems list WHEN the user filters on high risk THEN only high-risk systems remain
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/ai-systems.spec.ts`)
+
+### Task 3: Evidence checklist and missing FRIA flag
+- **spec_ref**: openspec/changes/landscape-ai-system-inventory/specs/ai-system-inventory/spec.md#requirement-req-ais-003-a-high-risk-ai-system-without-a-fundamental-rights-impact-assessment-is-flagged
+- **files**: `src/components/ai/AiActChecklist.vue`, `src/customComponents.js`, `src/manifest.d/ai-systems.json` (quick filter and badge column)
+- **acceptance_criteria**:
+ - GIVEN a high-risk AI system without a FRIA reference WHEN the list is filtered on High risk without FRIA THEN it is listed with a warning
+ - GIVEN its FRIA reference is filled WHEN the list reloads THEN it is no longer listed
+- [ ] Implement
+- [ ] Test (vitest `tests/vitest/aiActChecklist.spec.js`; Playwright case in `tests/e2e/workflows/ai-systems.spec.ts`)
+
+### Task 4: Documentation
+- **spec_ref**: openspec/changes/landscape-ai-system-inventory/specs/ai-system-inventory/spec.md#requirement-req-ais-001-an-organisation-registers-the-ai-systems-it-uses-next-to-their-applications
+- **files**: `docs/features/ai-systems.md`, `docs/images/ai-systems.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens AI systems THEN registering, classifying and the evidence checklist are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate landscape-ai-system-inventory --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit, vitest and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/landscape-application-components/.openspec.yaml b/openspec/changes/landscape-application-components/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-application-components/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-application-components/design.md b/openspec/changes/landscape-application-components/design.md
new file mode 100644
index 000000000..fa0942a16
--- /dev/null
+++ b/openspec/changes/landscape-application-components/design.md
@@ -0,0 +1,38 @@
+# Design: landscape-application-components
+
+Read at development `49e65cb4`.
+
+## Context
+
+`module` (`lib/Settings/softwarecatalogus_register.json:6779` schema, version 0.3.3) is the application. It has versions (`moduleVersion.module`), usages (`usage.module`), connections (`connection.moduleA` and `moduleB`), standards and reference components. `suite` (`register.json:1137` schema) groups applications that are sold together. LeanIX models components as child applications, and GEMMA reference components apply to components as much as to whole applications, so a component stays a `module`.
+
+## D1. One self relation on module
+
+Through `lib/Settings/register.d/application-components.json`:
+
+| property | type | notes |
+|---|---|---|
+| `partOf` | `$ref module` | title "Part of", `x-relation-filter: { "provider": "@object.provider" }` so a component belongs to an application of the same supplier; `inversedBy: components` |
+
+and a computed inverse `components` (array of `$ref module`, `hideOnForm: true`, `x-relation-filter: { "partOf": "@objectId" }`), the same pattern `moduleVersion.usages` uses (`register.json:7651` schema).
+
+A module whose `partOf` points at itself, or at one of its own components, is refused: a `x-openregister-validation` rule if OpenRegister's dialect supports a not-self check, else a check in `ModuleRegistrationService` before save (the service that already hooks module saves, `lib/Service/ModuleRegistrationService.php`).
+
+Rejected: a separate `applicationComponent` schema. A component would then lose versions, usages, connections and compliance claims, which all point at `module`.
+
+## D2. Pages
+
+- `ModuleDetail` (`src/manifest.json:491`): an `object-list` widget `md-components`, filter `{ "partOf": "@objectId" }`, `rowRoute: ModuleDetail`, `allowCreate: true` with `partOf` and `provider` filled in. `partOf` joins the data widget's `include` list, so a component shows its parent.
+- `Modules` page (`src/manifest.json`, component `FacetedCatalogIndexView`): a quick filter "Whole applications" (default) with `partOf` empty, and "All, including components". The page's quick filters already compose with the facet narrowing (its `_note`).
+
+## Declarative versus imperative
+
+A relation, a filter and page widgets (ADR-031). The only imperative part is the cycle check, and only if the dialect has no rule for it.
+
+## Seed data
+
+The demo register gains one demo application with two components.
+
+## Risks
+
+- `x-relation-filter` on `provider` means a component of another supplier's product cannot be recorded; LeanIX allows it. Suppliers register their own products, so this matches who may edit.
diff --git a/openspec/changes/landscape-application-components/proposal.md b/openspec/changes/landscape-application-components/proposal.md
new file mode 100644
index 000000000..8608f348f
--- /dev/null
+++ b/openspec/changes/landscape-application-components/proposal.md
@@ -0,0 +1,40 @@
+---
+kind: config
+depends_on:
+ - landscape-application-page
+---
+
+# Break an application into its components
+
+## Summary
+
+A supplier or an information manager records that an application consists of components, such as a case system with a separate portal and a document module. A component is an application in its own right, with its own versions, standards and connections, and it names the application it belongs to. The application page lists its components, and a component's page shows the application it is part of.
+
+## Why
+
+Row from the stackiq matrix:
+
+- `stackiq:land-application-modules`, "Break an application into modules and see which module belongs to which product." Rated partial, built. Two competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/application-modeling-guidelines, "Applications often consist of multiple entities or modules within a common ecosystem or platform", modelled as a parent and child hierarchy) and BlueDolphin (https://help.bluedolphin.io/en/articles/11967518-grouping-and-child-objects-in-architecture-views, "breaking down a system into its components"). The missing half: breaking one application into its components. Core area (landscape).
+
+No tender, feature request or roadmap row names it.
+
+## What stackiq has today
+
+- Stackiq's `module` is the whole application (`lib/Settings/softwarecatalogus_register.json:6779` schema, title Application). Nothing breaks one application into parts.
+- A suite (`register.json:1137` schema) lists applications that are sold together (`suite.applications`), with a wizard (`src/dialogs/SuiteWizardDialog.vue`) and a page (`SuiteDetail`, `src/manifest.json` around :676). That answers "which application belongs to which product", not what one application is made of.
+
+## What this change builds
+
+1. A `partOf` field on `module` pointing at the application it is a component of, limited to applications of the same supplier.
+2. A Components list on the application page, with an Add component action, and the parent application in the component's data.
+3. A column filter on the Applications list to hide components, so the list shows whole applications by default.
+
+## Out of scope
+
+- More than one level of nesting (a component of a component). The field allows it, but the pages show one level.
+- Suites and the suite wizard, which stay as they are.
+- Drawing the composition in an architecture view: `architecture-views-editor`.
+
+## Risks
+
+- A component that is also registered as a separate application in usages keeps its own usages; nothing moves usages to the parent.
diff --git a/openspec/changes/landscape-application-components/specs/application-components/spec.md b/openspec/changes/landscape-application-components/specs/application-components/spec.md
new file mode 100644
index 000000000..d6239b018
--- /dev/null
+++ b/openspec/changes/landscape-application-components/specs/application-components/spec.md
@@ -0,0 +1,42 @@
+# application-components specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-application-components
+
+## Purpose
+
+An application can be broken into components, each an application of its own that names the application it belongs to. Matrix row `stackiq:land-application-modules`.
+
+## ADDED Requirements
+
+### Requirement: REQ-ACM-001 An application can name the application it is a component of
+
+The `module` schema SHALL carry `partOf`, pointing at another application of the same supplier, and SHALL expose the inverse list of components. A module SHALL NOT be part of itself or of one of its own components.
+
+#### Scenario: A supplier records a component
+@e2e tests/e2e/workflows/application-components.spec.ts
+
+- **GIVEN** a supplier's application "Zaaksysteem"
+- **WHEN** the supplier opens its page, clicks Add component and saves "Zaaksysteem portaal"
+- **THEN** "Zaaksysteem portaal" names "Zaaksysteem" as the application it is part of
+
+#### Scenario: A cycle is refused
+@e2e exclude Save-time guard; tests/Unit/Settings/ApplicationComponentsFragmentTest.php or tests/Unit/Service/ModuleRegistrationServiceTest.php asserts the refusal.
+
+- **GIVEN** application A with component C
+- **WHEN** a user sets A to be part of C
+- **THEN** the save is refused and A keeps no parent
+
+### Requirement: REQ-ACM-002 The application page lists its components
+
+The application page SHALL list the application's components, each opening its own page, and a component's page SHALL show the application it is part of. The Applications list SHALL show whole applications by default and SHALL let the user include components.
+
+#### Scenario: A buyer reads what an application is made of
+@e2e tests/e2e/workflows/application-components.spec.ts
+
+- **GIVEN** "Zaaksysteem" has components "Zaaksysteem portaal" and "Zaaksysteem documenten"
+- **WHEN** a municipal buyer opens the page of "Zaaksysteem"
+- **THEN** the Components list shows both components
+- **AND** the Applications list shows "Zaaksysteem" but not its components until the buyer picks All, including components
diff --git a/openspec/changes/landscape-application-components/tasks.md b/openspec/changes/landscape-application-components/tasks.md
new file mode 100644
index 000000000..cedab0f75
--- /dev/null
+++ b/openspec/changes/landscape-application-components/tasks.md
@@ -0,0 +1,35 @@
+# Tasks: landscape-application-components
+
+## Implementation tasks
+
+### Task 1: The partOf relation and its guard
+- **spec_ref**: openspec/changes/landscape-application-components/specs/application-components/spec.md#requirement-req-acm-001-an-application-can-name-the-application-it-is-a-component-of
+- **files**: `lib/Settings/register.d/application-components.json`, `lib/Service/ModuleRegistrationService.php` (only if the dialect lacks a not-self rule), `lib/Settings/stackiq_mock_register.json`
+- **acceptance_criteria**:
+ - GIVEN component C of application A WHEN A is read THEN its components list holds C
+ - GIVEN application A WHEN a user sets A part of A THEN the save is refused with a message
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Settings/ApplicationComponentsFragmentTest.php`; `tests/Unit/Service/ModuleRegistrationServiceTest.php` cycle case if the service check is used)
+
+### Task 2: Components on the application page and the list filter
+- **spec_ref**: openspec/changes/landscape-application-components/specs/application-components/spec.md#requirement-req-acm-002-the-application-page-lists-its-components
+- **files**: `src/manifest.json` (ModuleDetail widget, Modules quick filters), `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN application A with two components WHEN its page opens THEN the Components list shows both
+ - GIVEN the Applications list WHEN it opens THEN components are hidden until the user picks All, including components
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/application-components.spec.ts`)
+
+### Task 3: Documentation
+- **spec_ref**: openspec/changes/landscape-application-components/specs/application-components/spec.md#requirement-req-acm-002-the-application-page-lists-its-components
+- **files**: `docs/features/application-components.md`, `docs/images/application-components.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Application components THEN recording a component and the list filter are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate landscape-application-components --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/landscape-application-page/.openspec.yaml b/openspec/changes/landscape-application-page/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-application-page/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-application-page/design.md b/openspec/changes/landscape-application-page/design.md
new file mode 100644
index 000000000..84b8e5377
--- /dev/null
+++ b/openspec/changes/landscape-application-page/design.md
@@ -0,0 +1,54 @@
+# Design: landscape-application-page
+
+Read at development `49e65cb4`, `@conduction/nextcloud-vue` 2.57.1.
+
+## Context
+
+`ModuleDetail` is a manifest detail page (`src/manifest.json:491`) with a grid of widgets (:500-511) and body widgets (:514). The Applications list is a custom page, `FacetedCatalogIndexView` (`src/manifest.json` page `Modules`, component at `src/views/FacetedCatalogIndexView.vue`), which wraps a standalone `CnIndexPage` beside a GEMMA facet sidebar.
+
+## D1. Field keys
+
+In `src/manifest.json`:
+
+- `md-data.content.include` (:500): `beschrijvingKort` becomes `shortDescription`, `beschrijvingLang` becomes `longDescription`, `contactpersoon` becomes `contactPerson`.
+- `suite-data.content.include` (:683): the same three renames.
+- `md-compliance.content.columns` (:503): `bioMaatregel` becomes `bioMeasure`.
+
+`tests/vitest/manifestFilterEnumParity.spec.js` already checks enum filters against the schema; a new `tests/vitest/manifestIncludeKeys.spec.js` asserts every `include` key and every `object-list` column key of a detail page exists on its schema, so a rename cannot leave a page blank again.
+
+## D2. Usages list
+
+A new `object-list` widget `md-usages`: register `@resolve:voorzieningen_register`, schema `usage`, filter `{ "module": "@objectId" }`, columns consumer, moduleVersion, status. The `usage` read rule (`register.json:2656` schema) already scopes rows: a municipality sees its own usages, a supplier sees usages of its products. No row route until `landscape-usage-registration` adds the usage detail page; that change sets `rowRoute`.
+
+## D3. Contracts list
+
+`catalogContract` reaches an application in two ways: through `usage` (a usage of the application) or through `service` (a service whose `modules` include the application, `catalogService.modules`). A single `object-list` filter cannot follow a hop (`CnObjectListWidget.vue:503`, one filter object).
+
+A small custom widget `ApplicationContractsWidget` (`src/components/contracts/ApplicationContractsWidget.vue`, registered in `src/customComponents.js`, placed as a grid widget) does it with the object store:
+
+1. Fetch the application's usages (`usage`, `module` equals the id) and the services that offer it (`catalogService`, `modules` contains the id).
+2. Fetch `catalogContract` with `usage` in the usage ids, and with `service` in the service ids, and merge by id.
+3. Render the rows with the library's `CnObjectRow`, columns contract number, type, end date and status, each opening `ContractDetail`.
+
+Rejected: a denormalised `module` field on `catalogContract`. It would go stale when a usage or service changes its application, and needs a save hook to fill it.
+
+## D4. Open from the Applications list
+
+`FacetedCatalogIndexView.vue` gains a `detailRoute` prop and binds `@row-click` on its `CnIndexPage` (:108) to `$router.push({ name: detailRoute, params: { id } })`. The `Modules` page config passes `detailRoute: "ModuleDetail"`; the `Diensten` page passes none, and its rows stay as they are. `CnIndexPage` emits `row-click` for register and schema pages (`CnIndexPage.vue:5500` onwards); only a named source routes by itself.
+
+## D5. Layout
+
+The grid becomes: data 8 wide with files and related at the right, then versions and usages side by side, then contracts and compliance side by side. Body widgets (reviews) stay at the end. The layout follows ADR-062 (detail page grid discipline).
+
+## Declarative versus imperative
+
+D1, D2 and D5 are manifest edits. D3 is one custom widget because the relation is two hops; it reads through the object store and adds no endpoint (ADR-022).
+
+## Seed data
+
+No schema change.
+
+## Risks
+
+- `connections-catalogue-pages` and `connections-api-catalogue` add widgets to the same page; they append below this layout.
+- The contract widget fires three queries per page view; each is scoped by ids and paged.
diff --git a/openspec/changes/landscape-application-page/proposal.md b/openspec/changes/landscape-application-page/proposal.md
new file mode 100644
index 000000000..aced1c8da
--- /dev/null
+++ b/openspec/changes/landscape-application-page/proposal.md
@@ -0,0 +1,48 @@
+---
+kind: code
+depends_on: []
+---
+
+# One application page with versions, usages, contracts and compliance
+
+## Summary
+
+The application page becomes the one place to read an application: its data with the right field names, the supplier's contact person, its versions, the organisations' usages, the contracts behind it and its compliance claims. It also opens from the Applications list, which it does not today.
+
+## Why
+
+Rows from the stackiq matrix:
+
+- `stackiq:land-detail-page`, "Open one application and see its versions, usages, contracts and compliance on one page." Rated partial, built. Two competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/application-modeling-guidelines, the application fact sheet with relations and cost on one page) and BlueDolphin (https://help.bluedolphin.io/en/articles/11967521-object-viewer, "shows all the object properties ... relationships, history"). The missing half: contracts on the page, opening it from the Applications list, and the stale field keys. Core area (landscape).
+- `stackiq:ctr-per-application`, "See the contracts behind an application from that application's page." Rated no. Two competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/contract-extension-to-meta-model, "Attached to Contract - Application Many-to-Many") and GLPI (source read at 11.0.9, `src/Appliance.php:99` adds the Contracts tab listing every contract of the application).
+- `stackiq:mkt-contacts-per-product`, "Name different contact persons per product a supplier offers." Rated partial, built, no competitor yes and no demand. It rides with `land-detail-page`: its missing half is the stale `contactpersoon` key on the application page, which this change corrects.
+
+No tender, feature request or roadmap row names these rows.
+
+## What stackiq has today
+
+- `ModuleDetail` (`src/manifest.json:491`) has a data widget, files, a generic related panel, compliance claims and versions (:500-504), and a reviews panel.
+- The data widget includes `beschrijvingKort`, `beschrijvingLang` and `contactpersoon` (:500). The module schema renamed them to `shortDescription`, `longDescription` and `contactPerson` (`lib/Settings/softwarecatalogus_register.json:6779` schema), so the descriptions and the contact person do not render. SuiteDetail carries the same stale keys (:683).
+- The compliance list's column `bioMaatregel` (:503) names a key the `compliancy` schema calls `bioMeasure`, so that column stays empty.
+- Usages show only as untyped entries in the related panel (:502).
+- No contract list: `catalogContract` points at a `service` and a `usage` (`register.json:3252` schema), not at the application, so a one-hop list cannot reach it.
+- The Applications list (`src/views/FacetedCatalogIndexView.vue:108`) renders `CnIndexPage` with no `@row-click` handler, so clicking a row or View does nothing. The page opens only from an organisation's list (`src/manifest.json:417`, `rowRoute: ModuleDetail`).
+
+## What this change builds
+
+1. Correct field keys on ModuleDetail and SuiteDetail, and the compliance column key.
+2. A Usages list on the application page, filtered on `usage.module`.
+3. A Contracts list on the application page: contracts whose usage is a usage of this application, or whose service offers this application.
+4. Opening the application page from the Applications list, by row click and by the View action.
+
+## Out of scope
+
+- Registering a usage and its status on a usage page: `landscape-usage-registration`.
+- Business and technical owners: `landscape-usage-registration`.
+- Connections and APIs on the page: `connections-catalogue-pages`, `connections-api-catalogue`.
+- A detail page for services (the Services list has none today); no matrix row asks for it in this pass.
+
+## Risks
+
+- Three changes in this pass add widgets to `ModuleDetail`. This one reorders the grid first; the others stack below.
+- A contract visible through a service may belong to another organisation. The list shows only contracts the user may read under the `catalogContract` read rule.
diff --git a/openspec/changes/landscape-application-page/specs/application-page/spec.md b/openspec/changes/landscape-application-page/specs/application-page/spec.md
new file mode 100644
index 000000000..a965256aa
--- /dev/null
+++ b/openspec/changes/landscape-application-page/specs/application-page/spec.md
@@ -0,0 +1,64 @@
+# application-page specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-application-page
+
+## Purpose
+
+One page per application shows its data, contact person, versions, usages, contracts and compliance, and opens from the Applications list. Matrix rows `stackiq:land-detail-page`, `stackiq:ctr-per-application` and `stackiq:mkt-contacts-per-product`.
+
+## ADDED Requirements
+
+### Requirement: REQ-APG-001 The application page shows every field it lists under the schema's current keys
+
+The application page `ModuleDetail` and the suite page `SuiteDetail` SHALL list only keys that exist on their schema, so the short description, long description and the supplier's contact person of a product render. The compliance list SHALL show the BIO measure of each claim.
+
+#### Scenario: A buyer reads a product's contact person
+@e2e tests/e2e/workflows/application-page.spec.ts
+
+- **GIVEN** a supplier registered product X with a short description and contact person Anna
+- **WHEN** a municipal buyer opens the page of product X
+- **THEN** the data widget shows the short description and contact person Anna
+
+#### Scenario: A stale key cannot ship again
+@e2e exclude Build-time guard; tests/vitest/manifestIncludeKeys.spec.js fails when a detail page lists a key its schema lacks.
+
+- **GIVEN** a detail page whose data widget lists a key the schema does not have
+- **WHEN** the vitest suite runs
+- **THEN** the test fails and names the page and the key
+
+### Requirement: REQ-APG-002 The application page lists the usages of the application
+
+The application page SHALL list the usages of the application the user may read, with the using organisation, the version and the status.
+
+#### Scenario: A supplier sees which organisations use its product
+@e2e tests/e2e/workflows/application-page.spec.ts
+
+- **GIVEN** two municipalities have a usage of product X
+- **WHEN** the supplier of X opens its page
+- **THEN** the Usages list shows both usages with version and status
+
+### Requirement: REQ-APG-003 The application page lists the contracts behind the application
+
+The application page SHALL list every readable contract whose usage is a usage of the application, or whose service offers the application, once each, with contract number, type, end date and status, and each row SHALL open the contract page.
+
+#### Scenario: An information manager finds the contract behind an application
+@e2e tests/e2e/workflows/application-page.spec.ts
+
+- **GIVEN** the municipality has a usage of application X and a contract on that usage
+- **WHEN** the information manager opens the page of X
+- **THEN** the Contracts list shows that contract with its end date
+- **AND** clicking it opens the contract page
+
+### Requirement: REQ-APG-004 The Applications list opens the application page
+
+Clicking a row, or its View action, on the Applications list SHALL open that application's page.
+
+#### Scenario: A user opens an application from the list
+@e2e tests/e2e/workflows/application-page.spec.ts
+
+- **GIVEN** the Applications list at `/modules`
+- **WHEN** the user clicks the row of application X
+- **THEN** the page `/modules/` opens
diff --git a/openspec/changes/landscape-application-page/tasks.md b/openspec/changes/landscape-application-page/tasks.md
new file mode 100644
index 000000000..675aa4c05
--- /dev/null
+++ b/openspec/changes/landscape-application-page/tasks.md
@@ -0,0 +1,44 @@
+# Tasks: landscape-application-page
+
+## Implementation tasks
+
+### Task 1: Correct field keys and guard them
+- **spec_ref**: openspec/changes/landscape-application-page/specs/application-page/spec.md#requirement-req-apg-001-the-application-page-shows-every-field-it-lists-under-the-schemas-current-keys
+- **files**: `src/manifest.json` (ModuleDetail, SuiteDetail), `tests/vitest/manifestIncludeKeys.spec.js`
+- **acceptance_criteria**:
+ - GIVEN an application with a short description and a contact person WHEN its page opens THEN both show in the data widget
+ - GIVEN a detail page include key that is not on its schema WHEN vitest runs THEN the test fails
+- [ ] Implement
+- [ ] Test (vitest `tests/vitest/manifestIncludeKeys.spec.js`)
+
+### Task 2: Usages and contracts on the application page
+- **spec_ref**: openspec/changes/landscape-application-page/specs/application-page/spec.md#requirement-req-apg-003-the-application-page-lists-the-contracts-behind-the-application
+- **files**: `src/manifest.json` (ModuleDetail widgets and layout), `src/components/contracts/ApplicationContractsWidget.vue`, `src/customComponents.js`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN a contract on a usage of application X WHEN the page of X opens THEN the Contracts list shows it
+ - GIVEN a contract on a service that offers X WHEN the page of X opens THEN the Contracts list shows it once
+- [ ] Implement
+- [ ] Test (vitest `tests/vitest/applicationContracts.spec.js` for the merge; Playwright `tests/e2e/workflows/application-page.spec.ts`)
+
+### Task 3: Open the page from the Applications list
+- **spec_ref**: openspec/changes/landscape-application-page/specs/application-page/spec.md#requirement-req-apg-004-the-applications-list-opens-the-application-page
+- **files**: `src/views/FacetedCatalogIndexView.vue`, `src/manifest.json` (Modules page config)
+- **acceptance_criteria**:
+ - GIVEN the Applications list WHEN the user clicks a row THEN ModuleDetail of that application opens
+ - GIVEN the Services list WHEN the user clicks a row THEN nothing navigates away
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/application-page.spec.ts`)
+
+### Task 4: Documentation
+- **spec_ref**: openspec/changes/landscape-application-page/specs/application-page/spec.md#requirement-req-apg-002-the-application-page-lists-the-usages-of-the-application
+- **files**: `docs/features/application-page.md`, `docs/images/application-page.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens the application page article THEN every section of the page is explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate landscape-application-page --type change --strict` passes.
+- `npm run lint` passes; the vitest and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/landscape-change-entry-type/.openspec.yaml b/openspec/changes/landscape-change-entry-type/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-change-entry-type/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-change-entry-type/design.md b/openspec/changes/landscape-change-entry-type/design.md
new file mode 100644
index 000000000..0e8035e24
--- /dev/null
+++ b/openspec/changes/landscape-change-entry-type/design.md
@@ -0,0 +1,39 @@
+# Design: landscape-change-entry-type
+
+Read at development `49e65cb4`, OpenRegister development `4fee776`.
+
+## Context
+
+Stackiq keeps applications in `module` and services in `catalogService` (`lib/Settings/softwarecatalogus_register.json:6779` and `:1326` schemas). Both share `name`, `shortDescription`, `longDescription`, `website`, `contactPerson`, `provider`, `logo`, `koppelingen`, `publicationDate` and `depublicationDate`. A module also holds licence, hosting, reference components, standards and versions; a service holds `modules` and a service `type`. OpenRegister's `MoveObject` moves an object between schemas without a copy: the uuid, audit trail, versions, files, notes and watchers stay keyed on the same uuid (`openregister lib/Service/Object/MoveObject.php:3-24`), and the endpoint answers 422 when the object does not fit (`ObjectsController.php:5219-5223`).
+
+## D1. A type-change service
+
+New `lib/Service/EntryTypeService.php`:
+
+- `preview(string $uuid, string $targetType): array` returns `carried` (fields both schemas declare), `dropped` (fields only the source has, with their values), and `blockers`: incoming references the target cannot hold. For Application to Service the blockers are usages (`usage.module`), versions (`moduleVersion.module`) and connections (`connection.moduleA`, `moduleB`); for Service to Application, contracts (`catalogContract.service`).
+- `change(string $uuid, string $targetType): array` refuses when `blockers` is not empty, clears the dropped fields with one update, then calls the move (`POST /api/objects/{register}/{schema}/{id}/move`, in process through OpenRegister's `MoveObject` service resolved from the container) and returns the outcome.
+- Application to System software and back is not a move: it sets `module.type`.
+
+Routes in `appinfo/routes.php`: `GET /api/entries/{uuid}/type-change?target=` (preview) and `POST /api/entries/{uuid}/type-change` (change), both `#[NoAdminRequired]`. The service reads the object under the caller's own permissions, and OpenRegister's move authorises both sides again, so a caller who cannot edit the entry or create in the target gets a 403 or 422.
+
+Rejected: create in the target and delete the source. It mints a second uuid and orphans the audit trail, files and relations, which is the problem the row names.
+
+## D2. The action and the preview
+
+A dialog `ChangeEntryTypeDialog` in `src/dialogs/` (ADR-004: dialogs live in their own file), opened from a header action on `ModuleDetail` (`src/manifest.json:491`) and from a row action on the Services list. It shows the preview in three lists (carried, dropped, blockers), disables Confirm while there are blockers, and after the move opens the entry at its new page.
+
+## D3. module.type on the form
+
+`module.type` (`register.json` module schema) becomes `visible: true`, so the form and the data widget show Application or System software. No dialog is needed for that switch.
+
+## Declarative versus imperative
+
+The move itself is OpenRegister's. The preview and the guard are stackiq code because they depend on stackiq's schema pairs; there is no `x-openregister-*` construct for "which schemas may an object move between".
+
+## Seed data
+
+No schema added. `module.type` changes visibility only.
+
+## Risks
+
+- A future schema that references `module` would be missed by the blocker list. The list is built from the register's `$ref` properties at runtime, not hard-coded.
diff --git a/openspec/changes/landscape-change-entry-type/proposal.md b/openspec/changes/landscape-change-entry-type/proposal.md
new file mode 100644
index 000000000..574cdc0db
--- /dev/null
+++ b/openspec/changes/landscape-change-entry-type/proposal.md
@@ -0,0 +1,39 @@
+---
+kind: code
+depends_on: []
+---
+
+# Change the type of an entry without recreating it
+
+## Summary
+
+A supplier or a functional administrator turns an application into a service, a service into an application, or an application into system software, without deleting the entry and typing it again. The entry keeps its identity: its history, files, relations and links stay attached, because OpenRegister moves the object instead of copying it.
+
+## Why
+
+Row from the stackiq matrix:
+
+- `stackiq:land-change-entry-type`, "Change the type of an existing entry without recreating it." Rated no, no competitor rates yes. Roadmap demand: https://tip.topdesk.com/c/89-changing-the-type-of-an-asset (TOPdesk). It sits in the product's core area (landscape), which is why it is built.
+
+## What stackiq has today
+
+- An entry lives in one schema: `module` (`lib/Settings/softwarecatalogus_register.json:6779` schema), `catalogService` (`:1326`) or `suite` (`:1137`). Nothing moves an object to another schema; the only route is delete and recreate, which loses its uuid and everything keyed on it.
+- `module.type` (Application or System software) exists but is `visible: false` with default Application, so nobody can change it from a page.
+- OpenRegister ships a move that keeps identity: `POST /api/objects/{register}/{schema}/{id}/move` (openregister `appinfo/routes.php:1245`, `lib/Controller/ObjectsController.php:5176`, `lib/Service/Object/MoveObject.php`). It authorises both sides and answers 422 when the object does not fit the target schema.
+
+## What this change builds
+
+1. A "Change type" action on the application page, and on the service rows of the Services list, offering: Application to Service, Service to Application, and Application to System software and back.
+2. A preview of what carries over: the fields both schemas share, and the fields that would be dropped, before the user confirms.
+3. A stackiq service that prepares the object for the target schema and calls OpenRegister's move, so the uuid, history, files and relations survive.
+4. `module.type` shown and editable on the application form.
+
+## Out of scope
+
+- Suites: a suite groups applications and has no counterpart to turn into.
+- Moving entries to another organisation: `landscape-move-between-organisations`.
+- Bulk type changes.
+
+## Risks
+
+- Relations that point at the old schema by `$ref` (for example `usage.module`) keep the uuid but now point at an object in another schema. The preview lists incoming references that would no longer resolve, and the action refuses when the entry has usages or connections the target type cannot hold.
diff --git a/openspec/changes/landscape-change-entry-type/specs/entry-type-change/spec.md b/openspec/changes/landscape-change-entry-type/specs/entry-type-change/spec.md
new file mode 100644
index 000000000..9a2e13e0e
--- /dev/null
+++ b/openspec/changes/landscape-change-entry-type/specs/entry-type-change/spec.md
@@ -0,0 +1,43 @@
+# entry-type-change specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-change-entry-type
+
+## Purpose
+
+An entry registered as the wrong type changes type in place and keeps its identity. Matrix row `stackiq:land-change-entry-type`.
+
+## ADDED Requirements
+
+### Requirement: REQ-ETC-001 An entry changes type and keeps its identity
+
+Stackiq SHALL change an application into a service, or a service into an application, by moving the object with OpenRegister's move, so the uuid, history, files and links stay. It SHALL refuse the change while the entry has incoming references the target type cannot hold, and SHALL switch an application between Application and System software by its type field.
+
+#### Scenario: A supplier turns an application into a service
+@e2e tests/e2e/workflows/change-entry-type.spec.ts
+
+- **GIVEN** a supplier registered "Hosting en beheer" as an application, with no usages, versions or connections, and one file attached
+- **WHEN** the supplier opens its page, picks Change type, Service, and confirms
+- **THEN** "Hosting en beheer" opens as a service with the same identifier
+- **AND** the attached file and the history are still there
+
+#### Scenario: A change that would break usages is refused
+@e2e exclude Guard case; tests/Unit/Service/EntryTypeServiceTest.php asserts the blocker list and that no move is called.
+
+- **GIVEN** an application with one usage by a municipality
+- **WHEN** a functional administrator asks to change it into a service
+- **THEN** the dialog lists the usage as a blocker and Confirm stays disabled
+- **AND** `POST /api/entries/{uuid}/type-change` answers 409 with the blocker
+
+### Requirement: REQ-ETC-002 The user sees what carries over before confirming
+
+Before a type change, stackiq SHALL show which fields carry over, which fields and values would be dropped, and which references block the change.
+
+#### Scenario: The preview names the dropped licence field
+@e2e tests/e2e/workflows/change-entry-type.spec.ts
+
+- **GIVEN** an application with a licence type filled in
+- **WHEN** the supplier picks Change type, Service
+- **THEN** the dialog lists the licence type under fields that will be dropped, with its value
diff --git a/openspec/changes/landscape-change-entry-type/tasks.md b/openspec/changes/landscape-change-entry-type/tasks.md
new file mode 100644
index 000000000..16c673677
--- /dev/null
+++ b/openspec/changes/landscape-change-entry-type/tasks.md
@@ -0,0 +1,35 @@
+# Tasks: landscape-change-entry-type
+
+## Implementation tasks
+
+### Task 1: Entry type service with preview and guard
+- **spec_ref**: openspec/changes/landscape-change-entry-type/specs/entry-type-change/spec.md#requirement-req-etc-001-an-entry-changes-type-and-keeps-its-identity
+- **files**: `lib/Service/EntryTypeService.php`, `lib/Controller/EntryTypeController.php`, `appinfo/routes.php`, `lib/AppInfo/Application.php`
+- **acceptance_criteria**:
+ - GIVEN an application without usages, versions or connections WHEN it is changed to a service THEN the same uuid answers as a catalogService with its history intact
+ - GIVEN an application with a usage WHEN a change to service is asked THEN the preview lists the usage as a blocker and the change is refused
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Service/EntryTypeServiceTest.php` with an ObjectService double on the real interface; `tests/Unit/Controller/EntryTypeControllerTest.php` for 403, 409 and 422)
+
+### Task 2: Change type dialog and module type on the form
+- **spec_ref**: openspec/changes/landscape-change-entry-type/specs/entry-type-change/spec.md#requirement-req-etc-002-the-user-sees-what-carries-over-before-confirming
+- **files**: `src/dialogs/ChangeEntryTypeDialog.vue`, `src/manifest.json` (ModuleDetail header action, Diensten row action), `lib/Settings/softwarecatalogus_register.json` (module.type visible), `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the application page WHEN the user picks Change type, Service THEN the dialog lists carried and dropped fields
+ - GIVEN the application form WHEN it opens THEN the type field offers Application and System software
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/change-entry-type.spec.ts`)
+
+### Task 3: Documentation
+- **spec_ref**: openspec/changes/landscape-change-entry-type/specs/entry-type-change/spec.md#requirement-req-etc-001-an-entry-changes-type-and-keeps-its-identity
+- **files**: `docs/features/change-entry-type.md`, `docs/images/change-entry-type.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Change entry type THEN the preview, the blockers and what survives are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate landscape-change-entry-type --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/landscape-completeness-score/.openspec.yaml b/openspec/changes/landscape-completeness-score/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-completeness-score/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-completeness-score/design.md b/openspec/changes/landscape-completeness-score/design.md
new file mode 100644
index 000000000..37f9ded03
--- /dev/null
+++ b/openspec/changes/landscape-completeness-score/design.md
@@ -0,0 +1,64 @@
+# Design: landscape-completeness-score
+
+Read at development `49e65cb4`, OpenRegister development `4fee776`.
+
+## Context
+
+OpenRegister computes a weighted data quality score on every save when a schema's `configuration` carries `x-openregister-quality` (`openregister lib/Listener/QualityScoreOnSaveListener.php:223-233` reads it). Rule types are `required`, `format` (named `email`, `url`, `date`, or a `pattern`) and `freshness` (exponential decay on a date field with `halfLifeDays`, default 180) (`lib/Service/Quality/QualityScorer.php`). `good` and `fair` thresholds default to 0.8 and 0.5 (`QualityScorer.php:134-147`). The score always lands in `@self.quality` and also in body fields the schema declares (`QualityScoreOnSaveListener.php:153-191`). The statistics endpoint reads the body field (`QualityStatisticsService.php:154`, default `qualityScore`).
+
+## D1. The rule set, in a fragment
+
+`lib/Settings/register.d/data-quality.json`:
+
+`module.configuration["x-openregister-quality"]`:
+
+| type | field | weight |
+|---|---|---|
+| required | name | 1 |
+| required | shortDescription | 2 |
+| required | longDescription | 1 |
+| required | provider | 2 |
+| required | contactPerson | 2 |
+| required | referenceComponents | 3 |
+| required | licentietype | 1 |
+| required | cloudDienstverleningsmodel | 1 |
+| required | hostingLocation | 1 |
+| required | bbnLevel | 1 |
+| format (url) | website | 1 |
+| freshness (halfLifeDays 365) | lastConfirmedAt | 3 |
+
+`usage.configuration["x-openregister-quality"]`: required `module`, `moduleVersion`, `status`, `businessOwner`, `technicalOwner` (from `landscape-usage-registration`), `usedForReferenceComponents`, and freshness on `lastConfirmedAt`. Thresholds good 0.8, fair 0.5 on both.
+
+Plus, on both schemas: `lastConfirmedAt` (date-time, visible, editable only through the action in D3), `qualityScore` (number) and `qualityStatus` (string, enum good, fair, poor), both `hideOnForm: true`, so the form never shows a number the platform overwrites.
+
+Rejected: a stackiq scoring service. OpenRegister already scores on save and serves the statistics; a second scorer would drift from it (ADR-022, ADR-031).
+
+## D2. Where the score shows
+
+- Applications list (`FacetedCatalogIndexView`, `Modules` page columns) and Applications in use (`src/manifest.d/usages.json` from `landscape-usage-registration`): a `qualityStatus` column rendered as a status badge.
+- `ModuleDetail` (`src/manifest.json:491`): a `stat` widget showing `qualityScore` as a percentage with its status.
+
+## D3. Confirm this entry is current
+
+A header action on `ModuleDetail` and on the usage detail page that saves `lastConfirmedAt = now` and nothing else. The save triggers the rescore, so the freshness part goes back to full. The action shows for users who may update the entry.
+
+## D4. The report
+
+`Reports` (`src/manifest.json:1021`) gets a second card, "Data quality", routing to a new page `DataQualityReport` (`/data-quality`), a custom view `src/views/DataQualityReportView.vue` that calls the two OpenRegister endpoints per schema (`module`, `usage`): the score spread (good, fair, poor counts, from `stats`) and the twenty lowest entries (from the listing), each row opening its page.
+
+## D5. Existing rows
+
+A repair step `lib/Repair/RescoreDataQuality.php`, run after the register import, saves every module and usage once through the object service so each gets a score. It logs the count and is idempotent.
+
+## Declarative versus imperative
+
+The rules and the scoring are declarative (ADR-031); the report is a read view over OpenRegister's endpoints; the rescore is a one-off repair.
+
+## Seed data
+
+`lastConfirmedAt` is set on the demo modules and usages so the demo shows good, fair and poor entries.
+
+## Risks
+
+- The rescore saves every row once; on a catalogue of 6,000 modules it runs as a background job rather than inside the repair step if it exceeds the step's time budget.
+- Weights encode a judgement. They are in the fragment where a pull request can change them.
diff --git a/openspec/changes/landscape-completeness-score/proposal.md b/openspec/changes/landscape-completeness-score/proposal.md
new file mode 100644
index 000000000..4bf27d6a0
--- /dev/null
+++ b/openspec/changes/landscape-completeness-score/proposal.md
@@ -0,0 +1,44 @@
+---
+kind: config
+depends_on:
+ - landscape-usage-registration
+---
+
+# Score how complete and current each entry is
+
+## Summary
+
+Every application, and every organisation's usage of one, gets a data quality score from a declared rule set: which fields must be filled, which must have the right format, and how recently the entry was confirmed. The score shows on the Applications list and the application page, and a Data quality report lists the weakest entries per type, so an information manager knows what to fix first.
+
+## Why
+
+Rows from the stackiq matrix:
+
+- `stackiq:land-completeness-score`, "See how complete and up to date each application's entry is, as a score." Rated no. Two competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/fact-sheet-completeness, "The fact sheet completion score measures how much of the required data has been filled out ... in the fact sheet's header") and BlueDolphin (https://help.bluedolphin.io/en/articles/11967713-governance-insights, "Object completeness: Lists all objects and the completeness score of each object"). Core area (landscape).
+- `stackiq:comp-health-scoring`, "Score the correctness and completeness of the register against a rule set." Rated no. Two competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/application-portfolio-management-dashboard, "Data Quality KPI ... Overall Completion of Applications", weights set by admins) and BlueDolphin (the same governance insights page).
+
+No tender, feature request or roadmap row names these rows.
+
+## What stackiq has today
+
+- No completeness, quality or freshness score in `lib/` or `src/`.
+- OpenRegister scores data quality from a declared annotation: `configuration.x-openregister-quality` with `rules` of type `required`, `format` and `freshness`, weights and `good` and `fair` thresholds (`openregister lib/Service/Quality/QualityScorer.php`, `QualityAnnotationValidator.php:42`). A save listener writes the score to `@self.quality` and to the body fields `qualityScore` and `qualityStatus` where the schema declares them (`lib/Listener/QualityScoreOnSaveListener.php:153-191`). Read-only statistics and a lowest-first listing sit at `GET /api/objects/quality/{register}/{schema}/stats` and `GET /api/objects/quality/{register}/{schema}` (openregister `appinfo/routes.php:628-629`), and they read the body field (`QualityStatisticsService.php:154`).
+- No stackiq schema declares the annotation.
+
+## What this change builds
+
+1. A declared rule set on `module` and on `usage`: required fields with weights, a URL format check on websites, and a freshness rule on a new `lastConfirmedAt` date.
+2. Hidden `qualityScore` and `qualityStatus` fields on both schemas, so OpenRegister's statistics and listing work.
+3. A Data quality column on the Applications list and on Applications in use, and a score tile on the application page.
+4. A "Confirm this entry is current" action on the application and usage pages that sets `lastConfirmedAt`.
+5. A Data quality report, a card on the Reports page, with the score spread per type and the twenty weakest entries.
+
+## Out of scope
+
+- Asking owners to confirm their entries by survey: `landscape-owner-attestation`, which sets the same `lastConfirmedAt`.
+- Scores for contracts, connections and compliance claims; the same annotation can be added per schema later.
+- An admin screen for the rule set. The rules live in the register fragment and are edited like code, or in OpenRegister's schema editor.
+
+## Risks
+
+- Existing rows have no score until they are saved. The design adds a one-off rescore after the import.
diff --git a/openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md b/openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md
new file mode 100644
index 000000000..66c5beca2
--- /dev/null
+++ b/openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md
@@ -0,0 +1,54 @@
+# catalogue-data-quality specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-completeness-score
+
+## Purpose
+
+Applications and usages carry a data quality score from a declared rule set, so users see what to fix and whether entries are current. Matrix rows `stackiq:land-completeness-score` and `stackiq:comp-health-scoring`.
+
+## ADDED Requirements
+
+### Requirement: REQ-CDQ-001 Every application and usage carries a data quality score from a declared rule set
+
+The `module` and `usage` schemas SHALL declare `x-openregister-quality` with weighted `required`, `format` and `freshness` rules and `good` and `fair` thresholds, so OpenRegister scores each entry on save. Stackiq SHALL show the resulting status (good, fair or poor) on the Applications list, on Applications in use and on the application page.
+
+#### Scenario: An incomplete application scores poor
+@e2e tests/e2e/workflows/data-quality.spec.ts
+
+- **GIVEN** a supplier saves an application with only a name and a supplier
+- **WHEN** a municipal information manager opens the Applications list
+- **THEN** that application shows data quality poor
+
+#### Scenario: The rule set is valid for OpenRegister
+@e2e exclude Config check; tests/Unit/Settings/DataQualityFragmentTest.php asserts the annotation shape and that every rule names an existing field.
+
+- **GIVEN** the merged register
+- **WHEN** OpenRegister validates the `x-openregister-quality` annotation of `module` and `usage`
+- **THEN** it reports no errors
+
+### Requirement: REQ-CDQ-002 A user confirms an entry is current and its freshness resets
+
+The application page and the usage page SHALL offer "Confirm this entry is current" to a user who may edit the entry. Confirming SHALL set `lastConfirmedAt` to now and nothing else, and the score SHALL be recomputed.
+
+#### Scenario: An application owner confirms a stale entry
+@e2e tests/e2e/workflows/data-quality.spec.ts
+
+- **GIVEN** an application last confirmed 14 months ago with status fair
+- **WHEN** its owner opens the page and clicks Confirm this entry is current
+- **THEN** the page shows today as last confirmed
+- **AND** the data quality score is higher than before
+
+### Requirement: REQ-CDQ-003 A data quality report shows the spread and the weakest entries
+
+The Reports page SHALL offer a Data quality report that shows, for applications and for usages, how many entries are good, fair and poor, and lists the twenty weakest entries first, each opening its page.
+
+#### Scenario: An information manager finds what to fix first
+@e2e tests/e2e/workflows/data-quality.spec.ts
+
+- **GIVEN** the catalogue has good, fair and poor applications
+- **WHEN** the information manager opens Reports, then Data quality
+- **THEN** the page shows the three counts for applications
+- **AND** the first rows of the weakest list are poor entries
diff --git a/openspec/changes/landscape-completeness-score/tasks.md b/openspec/changes/landscape-completeness-score/tasks.md
new file mode 100644
index 000000000..6aa5cc815
--- /dev/null
+++ b/openspec/changes/landscape-completeness-score/tasks.md
@@ -0,0 +1,51 @@
+# Tasks: landscape-completeness-score
+
+## Implementation tasks
+
+### Task 1: Rule set and fields
+- **spec_ref**: openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md#requirement-req-cdq-001-every-application-and-usage-carries-a-data-quality-score-from-a-declared-rule-set
+- **files**: `lib/Settings/register.d/data-quality.json`, `lib/Settings/stackiq_mock_register.json`
+- **acceptance_criteria**:
+ - GIVEN an application with every weighted field filled and confirmed today WHEN it is saved THEN its status is good
+ - GIVEN an application without reference components and never confirmed WHEN it is saved THEN its status is poor or fair
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Settings/DataQualityFragmentTest.php`: annotation passes OpenRegister's shape rules, every rule field exists on its schema)
+
+### Task 2: Score on lists and the application page, and the confirm action
+- **spec_ref**: openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md#requirement-req-cdq-002-a-user-confirms-an-entry-is-current-and-its-freshness-resets
+- **files**: `src/manifest.json` (Modules columns, ModuleDetail stat widget and action), `src/manifest.d/usages.json`, `src/views/FacetedCatalogIndexView.vue` if the column needs a renderer, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the Applications list WHEN it opens THEN each row shows good, fair or poor
+ - GIVEN an application confirmed a year ago WHEN its owner clicks Confirm this entry is current THEN lastConfirmedAt is today and the score rises
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/data-quality.spec.ts`)
+
+### Task 3: Data quality report
+- **spec_ref**: openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md#requirement-req-cdq-003-a-data-quality-report-shows-the-spread-and-the-weakest-entries
+- **files**: `src/views/DataQualityReportView.vue`, `src/customComponents.js`, `src/manifest.json` (Reports card, DataQualityReport page)
+- **acceptance_criteria**:
+ - GIVEN applications with mixed scores WHEN the information manager opens Reports, Data quality THEN the page shows the good, fair and poor counts and the weakest entries first
+- [ ] Implement
+- [ ] Test (vitest `tests/vitest/dataQualityReport.spec.js` for the view model; Playwright case in `tests/e2e/workflows/data-quality.spec.ts`)
+
+### Task 4: Rescore existing rows
+- **spec_ref**: openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md#requirement-req-cdq-001-every-application-and-usage-carries-a-data-quality-score-from-a-declared-rule-set
+- **files**: `lib/Repair/RescoreDataQuality.php`, `appinfo/info.xml`
+- **acceptance_criteria**:
+ - GIVEN modules without a score WHEN the repair step runs THEN each has a score and the count is logged
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Repair/RescoreDataQualityTest.php`)
+
+### Task 5: Documentation
+- **spec_ref**: openspec/changes/landscape-completeness-score/specs/catalogue-data-quality/spec.md#requirement-req-cdq-003-a-data-quality-report-shows-the-spread-and-the-weakest-entries
+- **files**: `docs/features/data-quality.md`, `docs/images/data-quality-report.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Data quality THEN the rules, the score, the confirm action and the report are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate landscape-completeness-score --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit, vitest and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/landscape-dependent-field-options/.openspec.yaml b/openspec/changes/landscape-dependent-field-options/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-dependent-field-options/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-dependent-field-options/design.md b/openspec/changes/landscape-dependent-field-options/design.md
new file mode 100644
index 000000000..8951fab03
--- /dev/null
+++ b/openspec/changes/landscape-dependent-field-options/design.md
@@ -0,0 +1,42 @@
+# Design: landscape-dependent-field-options
+
+Read at development `49e65cb4`, OpenRegister development `4fee776`, `@conduction/nextcloud-vue` 2.57.1.
+
+## Context
+
+OpenRegister reads `x-openregister-dependent-values` from a property: `{ "controlledBy": "", "allowed": { "": ["", ...] } }` (`openregister lib/Service/Rules/DependentValueTable.php:55`, the shape at :106-128). A controlling value the table does not list leaves the property unconstrained (:30-40). `DependentValueListener` refuses an object save with code `dependent-value-not-allowed` when a value is outside its row. The library form narrows relation pickers by `x-relation-filter` (`CnFormDialog.vue:1183`), but nothing in `@conduction/nextcloud-vue` 2.57.1 reads the dependent-values annotation (a search of `src/` finds none).
+
+## D1. Two tables in a register fragment
+
+`lib/Settings/register.d/dependent-field-options.json`:
+
+- `components.schemas.module.properties.licence["x-openregister-dependent-values"]`: `controlledBy: licentietype`, `allowed: { "Open source": [the five licences of the enum], "Closed source": [] }`.
+- `components.schemas.organization.properties.samenwerkingtype["x-openregister-dependent-values"]`: `controlledBy: type`, `allowed: { "Collaboration": [the collaboration types], "Municipality": [], "Supplier": [], "Community": [] }`.
+
+The fragment adds a key to existing property objects; the deep merge unions object keys (`lib/Service/SettingsService.php:7338`), so nothing else in those properties changes.
+
+## D2. The stray enum value
+
+`organization.samenwerkingtype.enum` in `lib/Settings/softwarecatalogus_register.json` loses `samenwerkingtype`. That edit goes in the monolith, because a fragment can only append to a list (lists merge by `array_merge`, `SettingsService.php:7352`). The organization schema version is bumped with it.
+
+## D3. Existing rows
+
+A repair step `lib/Repair/ClearDisallowedDependentValues.php`, registered in `appinfo/info.xml` before the register import, clears `licence` on closed-source modules and `samenwerkingtype` on organisations that are not a collaboration, and logs how many it cleared. Without it the first edit of such a row after the import would be refused for a field the user did not touch.
+
+## D4. The form half lives in the library
+
+`CnFormDialog` gains the same treatment for `x-openregister-dependent-values` that `relationFilterDecls` gives `x-relation-filter`: when the controlling field changes, the dependent field's options become the table row, and a value outside it is cleared. That is a change in ConductionNL/nextcloud-vue; this change bumps `package.json` to the release that ships it, and until then the save-time refusal from OpenRegister is shown as the form error.
+
+Rejected: a stackiq-only form wrapper. ADR-012 keeps form behaviour in the shared library, and every app with an enum pair gains from it.
+
+## Declarative versus imperative
+
+Declarative: two annotations OpenRegister already enforces (ADR-031). The repair step is the one imperative piece, a one-off data fix.
+
+## Seed data
+
+The demo register's modules and organisations already satisfy both tables; the repair step's test uses its own fixtures.
+
+## Risks
+
+- A future licence value added to the enum must also be added to the table, or it is refused for open-source modules. The unit test compares the enum with the table's Open source row.
diff --git a/openspec/changes/landscape-dependent-field-options/proposal.md b/openspec/changes/landscape-dependent-field-options/proposal.md
new file mode 100644
index 000000000..cebd0ec48
--- /dev/null
+++ b/openspec/changes/landscape-dependent-field-options/proposal.md
@@ -0,0 +1,39 @@
+---
+kind: config
+depends_on: []
+---
+
+# Let the options of one field depend on another
+
+## Summary
+
+The catalogue's forms already narrow a picker by another field: the version picker follows the chosen application and the contact person picker follows the chosen supplier. Plain option lists do not: a closed-source application can still pick an open-source licence, and a municipality can pick a collaboration type. This change declares which values of one list are allowed for each value of another, so OpenRegister refuses a wrong pair on save and the form offers only the allowed options.
+
+## Why
+
+Row from the stackiq matrix:
+
+- `stackiq:land-dependent-fields`, "Make the options of one field depend on another, such as model depending on brand." Rated no, no competitor rates yes. Roadmap demand: https://tip.topdesk.com/c/87-field-dependencies-brand-type-model- (TOPdesk). Core area (landscape), which is why it is built.
+
+Re-reading the code for this change showed the rating is too low, so the matrix is corrected to partial in the same pull request: relation pickers already depend on another field (see below). What this change builds is the missing half, dependent option lists.
+
+## What stackiq has today
+
+- Relation pickers that follow another field: `usage.moduleVersion` with `x-relation-filter: { module: @object.module }`, `module.contactPerson` and `catalogService.contactPerson` and `catalogService.modules` on `@object.provider` (`lib/Settings/softwarecatalogus_register.json`, usage, module and catalogService schemas). The library form honours `@object.` filters (`@conduction/nextcloud-vue` 2.57.1, `src/components/CnFormDialog/CnFormDialog.vue:1183`).
+- Plain option lists that do not: `module.licence` (five open-source licences) is offered whatever `module.licentietype` says, and `organization.samenwerkingtype` is offered whatever `organization.type` says. The `samenwerkingtype` enum also holds the stray value `samenwerkingtype`, its own name.
+- OpenRegister declares dependent option lists as a table, `x-openregister-dependent-values` with `controlledBy` and `allowed`, and refuses a pair outside the table on save (`openregister lib/Service/Rules/DependentValueTable.php:55`, `lib/Listener/DependentValueListener.php`). No stackiq property uses it, and the library form does not read it.
+
+## What this change builds
+
+1. `x-openregister-dependent-values` on `module.licence` (controlled by `licentietype`: open-source licences only for Open source) and on `organization.samenwerkingtype` (controlled by `type`: collaboration types only for Collaboration).
+2. The stray `samenwerkingtype` value removed from its own enum.
+3. A form that offers only the allowed options, by asking `@conduction/nextcloud-vue` to read the annotation in `CnFormDialog`, the way it reads `x-relation-filter`.
+
+## Out of scope
+
+- The library change itself lives in ConductionNL/nextcloud-vue; this change names it and pins the release that carries it. Until then, OpenRegister's save-time refusal is the guard and the form shows every option.
+- An admin screen to edit the tables. The tables live in the register fragment, reviewed like code.
+
+## Risks
+
+- Existing rows may hold a pair the table now refuses (a closed-source application with a licence set). The design adds a repair step that clears such values before the table is imported.
diff --git a/openspec/changes/landscape-dependent-field-options/specs/dependent-field-options/spec.md b/openspec/changes/landscape-dependent-field-options/specs/dependent-field-options/spec.md
new file mode 100644
index 000000000..f73c4ecb7
--- /dev/null
+++ b/openspec/changes/landscape-dependent-field-options/specs/dependent-field-options/spec.md
@@ -0,0 +1,45 @@
+# dependent-field-options specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-dependent-field-options
+
+## Purpose
+
+The allowed values of one option list follow the value of another, both on save and in the form. Matrix row `stackiq:land-dependent-fields`.
+
+## ADDED Requirements
+
+### Requirement: REQ-DFO-001 A value outside its dependent list is refused on save
+
+The `module` schema SHALL allow a `licence` only when `licentietype` is Open source, and the `organization` schema SHALL allow a `samenwerkingtype` only when `type` is Collaboration, declared with `x-openregister-dependent-values` so OpenRegister refuses any other pair.
+
+#### Scenario: A supplier cannot give a closed-source application an open-source licence
+@e2e exclude Enforced by OpenRegister's save listener; tests/Unit/Settings/DependentFieldOptionsTest.php asserts both tables and the enum match.
+
+- **GIVEN** an application with licence type Closed source
+- **WHEN** the supplier saves it with licence EUPL 1.2
+- **THEN** the save is refused with a message that the licence is not allowed for Closed source
+
+### Requirement: REQ-DFO-002 Existing rows that break a table are cleaned before it applies
+
+Before the tables are imported, stackiq SHALL clear `licence` on closed-source applications and `samenwerkingtype` on organisations that are not a collaboration, and SHALL log how many values it cleared.
+
+#### Scenario: An old row does not block the next edit
+@e2e exclude Repair step; tests/Unit/Repair/ClearDisallowedDependentValuesTest.php covers it.
+
+- **GIVEN** a municipality whose collaboration type was filled in by an old import
+- **WHEN** the repair step runs and an administrator then edits the municipality's name
+- **THEN** the save succeeds and the collaboration type is empty
+
+### Requirement: REQ-DFO-003 The form offers only the allowed options
+
+The create and edit forms SHALL offer, for a dependent field, only the values its table allows for the current value of the controlling field, and SHALL clear a value that becomes disallowed when the controlling field changes.
+
+#### Scenario: Switching an application to open source opens the licence list
+@e2e tests/e2e/workflows/dependent-field-options.spec.ts
+
+- **GIVEN** the edit form of an application with licence type Closed source and an empty licence list
+- **WHEN** the supplier sets licence type to Open source
+- **THEN** the licence field offers the five open-source licences
diff --git a/openspec/changes/landscape-dependent-field-options/tasks.md b/openspec/changes/landscape-dependent-field-options/tasks.md
new file mode 100644
index 000000000..2085ad456
--- /dev/null
+++ b/openspec/changes/landscape-dependent-field-options/tasks.md
@@ -0,0 +1,34 @@
+# Tasks: landscape-dependent-field-options
+
+## Implementation tasks
+
+### Task 1: Dependent value tables and the enum fix
+- **spec_ref**: openspec/changes/landscape-dependent-field-options/specs/dependent-field-options/spec.md#requirement-req-dfo-001-a-value-outside-its-dependent-list-is-refused-on-save
+- **files**: `lib/Settings/register.d/dependent-field-options.json`, `lib/Settings/softwarecatalogus_register.json` (samenwerkingtype enum, organization version)
+- **acceptance_criteria**:
+ - GIVEN a closed-source module WHEN a licence is saved on it THEN OpenRegister refuses with dependent-value-not-allowed
+ - GIVEN the merged register WHEN the licence enum and the Open source row are compared THEN they hold the same values
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Settings/DependentFieldOptionsTest.php`)
+
+### Task 2: Clear disallowed values in existing rows
+- **spec_ref**: openspec/changes/landscape-dependent-field-options/specs/dependent-field-options/spec.md#requirement-req-dfo-002-existing-rows-that-break-a-table-are-cleaned-before-it-applies
+- **files**: `lib/Repair/ClearDisallowedDependentValues.php`, `appinfo/info.xml`
+- **acceptance_criteria**:
+ - GIVEN a closed-source module with a licence WHEN the repair step runs THEN its licence is empty and the count is logged
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Repair/ClearDisallowedDependentValuesTest.php`)
+
+### Task 3: Adopt the library form support
+- **spec_ref**: openspec/changes/landscape-dependent-field-options/specs/dependent-field-options/spec.md#requirement-req-dfo-003-the-form-offers-only-the-allowed-options
+- **files**: `package.json`, `package-lock.json`
+- **acceptance_criteria**:
+ - GIVEN the application form WHEN the licence type is Closed source THEN the licence field offers no options
+- [ ] Implement (after ConductionNL/nextcloud-vue releases CnFormDialog support for x-openregister-dependent-values)
+- [ ] Test (Playwright `tests/e2e/workflows/dependent-field-options.spec.ts`)
+
+## Verification
+
+- `openspec validate landscape-dependent-field-options --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit and Playwright cases above pass.
+- No new user-facing strings beyond the error text OpenRegister already translates.
diff --git a/openspec/changes/landscape-move-between-organisations/.openspec.yaml b/openspec/changes/landscape-move-between-organisations/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-move-between-organisations/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-move-between-organisations/design.md b/openspec/changes/landscape-move-between-organisations/design.md
new file mode 100644
index 000000000..d979a813d
--- /dev/null
+++ b/openspec/changes/landscape-move-between-organisations/design.md
@@ -0,0 +1,42 @@
+# Design: landscape-move-between-organisations
+
+Read at development `49e65cb4`.
+
+## Context
+
+Ownership in stackiq has two layers. OpenRegister multitenancy stamps `@self.organisation` on every object, and read rules match on it (`{"_organisation": "$organisation"}` throughout `lib/Settings/softwarecatalogus_register.json`). Domain fields name the organisation too: `module.provider`, `catalogService.provider`, `usage.consumer` and `participants`, `connection.provider`, `contactPerson.organization`. `MergeOrganisatieService` already knows both layers per type (`FIELD_RELATION_TYPES` :111, `SELF_ORGANISATION_RELATION_TYPES` :122) and saves the full object so unrelated fields survive (`repointBySelfOrganisation` :442, reading the owner through `readOwningOrganisation`).
+
+## D1. A transfer service on the merge primitives
+
+New `lib/Service/OwnershipTransferService.php`:
+
+- `plan(array $objectRefs, string $targetOrganisation, IUser $caller): array` returns, per object, `move` or `skip` with a reason (not owned by the source, caller cannot edit, target unknown), plus linked objects of the source organisation that stay behind (for a usage: its connections; for an application: its versions).
+- `execute(...)` runs the plan's `move` items: sets `@self.organisation` to the target and the type's owning field (from the same map the merge uses), saving the full object.
+
+The per-type map and the owner reader move out of `MergeOrganisatieService` into a small shared class `lib/Service/Organisation/OwnershipMap.php`, used by both services, so the merge and the transfer cannot drift.
+
+Rejected: calling the merge with a filter. The merge tombstones the source organisation at the end; a transfer must never do that.
+
+## D2. Endpoints and authorisation
+
+`POST /api/ownership-transfers/plan` and `POST /api/ownership-transfers/execute` in `appinfo/routes.php`, body `{ objects: [{ schema, id }], targetOrganisation }`, controller `lib/Controller/OwnershipTransferController.php`, `#[NoAdminRequired]` with an explicit guard: the caller is a Nextcloud admin, or is in an organisation admin group (`SettingsService::getOrganizationAdminGroups()`, as `SettingsController::verifyOrgExportPermission()` uses at `lib/Controller/SettingsController.php:1737`) AND is a member of both organisations (the multi-org membership from the archived change `multi-org-membership`). Anything else is a 403 before any read.
+
+## D3. The action
+
+A dialog `MoveToOrganisationDialog` (`src/dialogs/`) with an organisation picker, the dry-run list and Confirm. It opens from:
+
+- a mass action on the list pages that support selection (Applications, Services, Applications in use, Connections, Contracts), through `CnIndexPage` mass actions (`CnMassActionBar` in the library);
+- a header action on each of their detail pages.
+
+## Declarative versus imperative
+
+Imperative: a transfer rewrites ownership across types with a guard, which no `x-openregister-*` construct expresses. The per-type map is data in one class.
+
+## Seed data
+
+None.
+
+## Risks
+
+- Extracting the map touches the merge service; its existing tests (`tests/Unit/Service/MergeOrganisatieServiceTest.php` and the merge e2e) must stay green.
+- `@self.organisation` is written through a full save. The archived merge change recorded why a partial write drops fields; the transfer uses the same full save.
diff --git a/openspec/changes/landscape-move-between-organisations/proposal.md b/openspec/changes/landscape-move-between-organisations/proposal.md
new file mode 100644
index 000000000..fa6dc87e3
--- /dev/null
+++ b/openspec/changes/landscape-move-between-organisations/proposal.md
@@ -0,0 +1,41 @@
+---
+kind: code
+depends_on:
+ - landscape-usage-registration
+---
+
+# Move entries to another organisation without recreating them
+
+## Summary
+
+A functional administrator moves one entry, or a selection of entries, to another organisation: an application that belongs to a sister municipality, usages registered under the wrong organisation, or a contact person who changed employer. The entries keep their identity and relations; only who owns them changes. A dry run shows what will move before anything does.
+
+## Why
+
+Row from the stackiq matrix:
+
+- `stackiq:land-move-between-workspaces`, "Move one or many entries to another workspace or section without recreating them." Rated no. Two competitors rate yes: BlueDolphin (June 2026 update, https://bluedolphin.io/blog/june-2026-bluedolphin-updates/, "You can move one or multiple objects to another workspace directly from the Repository without leaving your current view", also the changelog demand row) and GLPI (source read at 11.0.9, `src/Transfer.php:50` moves selected records to another entity with their links, queued through `src/MassiveAction.php:598`). Core area (landscape).
+
+In stackiq the workspace is the organisation: every record belongs to one through OpenRegister multitenancy (`@self.organisation`), and the domain fields `module.provider`, `usage.consumer`, `connection.provider` and `contactPerson.organization` say the same thing in the data.
+
+## What stackiq has today
+
+- No page or action moves an entry to another organisation.
+- The organisation merge moves everything of one organisation into another (`lib/Service/MergeOrganisatieService.php`): it re-points domain fields per type (`FIELD_RELATION_TYPES`, :111) and `@self.organisation` for contracts and compliance claims (`repointBySelfOrganisation`, :442), with a dry run and an execute (`lib/Controller/MergeController.php:82`, `:106`), for a Nextcloud admin only (:142). It moves all of an organisation, never a chosen set.
+
+## What this change builds
+
+1. A transfer service that moves a chosen set of entries (applications, services, usages, connections, contracts, compliance claims, contact persons) from one organisation to another, re-pointing `@self.organisation` and the type's owning field, reusing the merge service's per-type map.
+2. A dry run that lists what will move and what will not (entries of another organisation, entries the caller may not edit).
+3. A "Move to organisation" action on the list pages for the selected rows, and on each detail page.
+4. Authorisation: a Nextcloud admin, or a user who is organisation admin in both the source and the target organisation.
+
+## Out of scope
+
+- Moving between registers or schemas: `landscape-change-entry-type`.
+- Merging whole organisations, which stays in the merge panel.
+- Moving files between Nextcloud folders; files stay attached to the entry's uuid.
+
+## Risks
+
+- A usage moved to another organisation keeps its connections, which may belong to the old organisation. The dry run lists such links so the administrator moves them together.
diff --git a/openspec/changes/landscape-move-between-organisations/specs/move-between-organisations/spec.md b/openspec/changes/landscape-move-between-organisations/specs/move-between-organisations/spec.md
new file mode 100644
index 000000000..7d69b3bf4
--- /dev/null
+++ b/openspec/changes/landscape-move-between-organisations/specs/move-between-organisations/spec.md
@@ -0,0 +1,47 @@
+# move-between-organisations specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-move-between-organisations
+
+## Purpose
+
+Entries registered under the wrong organisation move to the right one, one or many at a time, keeping their identity. Matrix row `stackiq:land-move-between-workspaces`.
+
+## ADDED Requirements
+
+### Requirement: REQ-MBO-001 An administrator moves chosen entries to another organisation and they keep their identity
+
+Stackiq SHALL move a chosen set of applications, services, usages, connections, contracts, compliance claims and contact persons from one organisation to another by re-pointing `@self.organisation` and the type's owning field, keeping each entry's uuid, history, files and relations.
+
+#### Scenario: A functional administrator moves two applications
+@e2e tests/e2e/workflows/move-to-organisation.spec.ts
+
+- **GIVEN** a functional administrator who administers supplier A and supplier B, and two applications registered under A that belong to B
+- **WHEN** they select both on the Applications list, pick Move to organisation, choose B and confirm
+- **THEN** both applications show supplier B
+- **AND** their pages open at the same addresses with their history
+
+### Requirement: REQ-MBO-002 Only an administrator of both organisations moves entries
+
+`POST /api/ownership-transfers/plan` and `/api/ownership-transfers/execute` SHALL answer 403 unless the caller is a Nextcloud admin, or an organisation admin who is a member of both the source and the target organisation. A refused call SHALL change nothing.
+
+#### Scenario: An administrator of one side is refused
+@e2e exclude API guard; tests/Unit/Controller/OwnershipTransferControllerTest.php asserts the 403 and that no object was saved.
+
+- **GIVEN** a user who administers organisation A only
+- **WHEN** they post a transfer of an A entry to organisation B
+- **THEN** the answer is 403
+
+### Requirement: REQ-MBO-003 The dry run shows what moves and what stays behind
+
+Before a transfer, stackiq SHALL list each chosen entry as moving or skipped with the reason, and SHALL list linked entries of the source organisation that stay behind.
+
+#### Scenario: Connections that stay behind are named
+@e2e tests/e2e/workflows/move-to-organisation.spec.ts
+
+- **GIVEN** a usage of organisation A with one connection owned by A
+- **WHEN** the administrator opens Move to organisation for that usage and picks organisation B
+- **THEN** the dialog lists the usage under moving
+- **AND** lists the connection under staying with organisation A
diff --git a/openspec/changes/landscape-move-between-organisations/tasks.md b/openspec/changes/landscape-move-between-organisations/tasks.md
new file mode 100644
index 000000000..c75f41626
--- /dev/null
+++ b/openspec/changes/landscape-move-between-organisations/tasks.md
@@ -0,0 +1,42 @@
+# Tasks: landscape-move-between-organisations
+
+## Implementation tasks
+
+### Task 1: Shared ownership map
+- **spec_ref**: openspec/changes/landscape-move-between-organisations/specs/move-between-organisations/spec.md#requirement-req-mbo-001-an-administrator-moves-chosen-entries-to-another-organisation-and-they-keep-their-identity
+- **files**: `lib/Service/Organisation/OwnershipMap.php`, `lib/Service/MergeOrganisatieService.php`
+- **acceptance_criteria**:
+ - GIVEN the merge service WHEN it runs after the extraction THEN its dry run and execute give the same counts as before
+- [ ] Implement
+- [ ] Test (PHPUnit merge tests unchanged and green; `tests/Unit/Service/Organisation/OwnershipMapTest.php`)
+
+### Task 2: Transfer service and endpoints
+- **spec_ref**: openspec/changes/landscape-move-between-organisations/specs/move-between-organisations/spec.md#requirement-req-mbo-002-only-an-administrator-of-both-organisations-moves-entries
+- **files**: `lib/Service/OwnershipTransferService.php`, `lib/Controller/OwnershipTransferController.php`, `appinfo/routes.php`, `lib/AppInfo/Application.php`
+- **acceptance_criteria**:
+ - GIVEN two applications of organisation A WHEN an admin of A and B executes a transfer to B THEN both carry organisation B and provider B with the same uuids
+ - GIVEN a user who administers only A WHEN they post a transfer to B THEN the answer is 403 and nothing changes
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Service/OwnershipTransferServiceTest.php`, `tests/Unit/Controller/OwnershipTransferControllerTest.php`; Newman request in `postman/stackiq-tests.json`)
+
+### Task 3: Move to organisation dialog
+- **spec_ref**: openspec/changes/landscape-move-between-organisations/specs/move-between-organisations/spec.md#requirement-req-mbo-003-the-dry-run-shows-what-moves-and-what-stays-behind
+- **files**: `src/dialogs/MoveToOrganisationDialog.vue`, `src/manifest.json` and `src/manifest.d/*.json` (mass and header actions), `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN three selected usages WHEN the admin picks Move to organisation THEN the dialog lists the three and their connections that stay behind
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/move-to-organisation.spec.ts`)
+
+### Task 4: Documentation
+- **spec_ref**: openspec/changes/landscape-move-between-organisations/specs/move-between-organisations/spec.md#requirement-req-mbo-003-the-dry-run-shows-what-moves-and-what-stays-behind
+- **files**: `docs/features/move-to-organisation.md`, `docs/images/move-to-organisation.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Move to organisation THEN who may move, the dry run and what stays are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate landscape-move-between-organisations --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit, Newman and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/landscape-owner-attestation/.openspec.yaml b/openspec/changes/landscape-owner-attestation/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-owner-attestation/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-owner-attestation/design.md b/openspec/changes/landscape-owner-attestation/design.md
new file mode 100644
index 000000000..565a602c1
--- /dev/null
+++ b/openspec/changes/landscape-owner-attestation/design.md
@@ -0,0 +1,61 @@
+# Design: landscape-owner-attestation
+
+Read at development `49e65cb4`, OpenRegister development `4fee776`.
+
+## Context
+
+The entries to confirm are usages (an organisation's applications in use, owners from `landscape-usage-registration`) and modules (a supplier's products, contact from `module.contactPerson`). `landscape-completeness-score` gives both `lastConfirmedAt` and a freshness rule. Owners act as Nextcloud users; contact persons get accounts through `ContactPersonHandler::createUserAccount()` (called from `lib/Controller/ContactpersonenController.php:393` onwards).
+
+## D1. Two schemas in a fragment
+
+`lib/Settings/register.d/owner-attestation.json`, both added to the `stackiq` register list:
+
+`attestationRound`: `name`, `deadline` (date), `scopeSchema` (enum `usage`, `module`), `scopeOrganisation` (`$ref organization`), `startedBy` (string, uid), `status` (enum `open`, `closed`) with an `x-openregister-lifecycle` (open to closed), `requestCount`, `answeredCount` (numbers written by the service).
+
+`attestationRequest`: `round` (`$ref attestationRound`), `entrySchema`, `entryId`, `entryName` (string, for lists), `assigneeUserId` (string, Nextcloud uid), `assigneeContact` (`$ref contactPerson`), `status` (enum `pending`, `confirmed`, `corrected`, `overdue`), `respondedAt`.
+
+Authorization: an organisation reads its own rounds and requests (`_organisation` match); a request is also readable and updatable by its assignee (`{"match": {"assigneeUserId": "$userId"}}` in the read and update rules).
+
+## D2. Creating a round
+
+`lib/Service/AttestationService.php`, `start(string $scopeSchema, string $organisationId, string $deadline, IUser $caller)`:
+
+1. Load the entries: usages whose `consumer` is the organisation, or modules whose `provider` is the organisation.
+2. For each entry pick owners: `businessOwner` and `technicalOwner` for a usage, `contactPerson` for a module. Resolve each contact person to a Nextcloud uid through `ContactPersonHandler`; entries whose owner has no account are returned as `unassigned`.
+3. Create the round and one request per entry and owner.
+
+Route `POST /api/attestation-rounds` (`#[NoAdminRequired]`), guarded: the caller is an organisation admin of the scope organisation (`SettingsService::getOrganizationAdminGroups()`). The response lists the unassigned entries.
+
+## D3. Answering
+
+- Confirm: `POST /api/attestation-requests/{id}/confirm` sets the entry's `lastConfirmedAt` to now (a normal update under the caller's rights, so OpenRegister rescores it) and the request's status to `confirmed`.
+- Correct: the owner edits the entry through its normal page; a listener on `ObjectUpdatedEvent` for `usage` and `module` marks an open pending request for that entry and that user `corrected` and sets `lastConfirmedAt`.
+- Overdue: a daily `TimedJob` (`lib/BackgroundJob/AttestationOverdueJob.php`, registered in `appinfo/info.xml`) sets pending requests past the round's deadline to `overdue` and updates the round's counts.
+
+## D4. Notifications, declared
+
+`attestationRequest.configuration["x-openregister-notifications"]`:
+
+- `request-created`: trigger `created`, channels `nc-notification` and `email`, recipient `{ "kind": "field", "field": "assigneeUserId" }`, subject "Please confirm your entry {{entryName}}".
+- `deadline-near`: trigger `scheduled` daily with filter on the round deadline within three days and status `pending`, same recipient.
+
+## D5. Pages
+
+`src/manifest.d/owner-attestation.json`:
+
+- `MyAttestations` (`/my-confirmations`), an index over `attestationRequest` filtered on `assigneeUserId` of the current user and status `pending`, with row actions Confirm and Open entry.
+- `AttestationRounds` (`/confirmation-rounds`) and `AttestationRoundDetail`, with a Start round action (dialog `src/dialogs/StartAttestationRoundDialog.vue`), the counts as stat widgets and the requests as an object list grouped by status.
+- Menu: both as children of an existing entry (Organisations), not new top-level entries (ADR-097).
+
+## Declarative versus imperative
+
+Schemas, lifecycle, notifications and pages are declarative (ADR-031). Creating requests from a scope, resolving owners to users and the overdue sweep are imperative: they join several schemas and Nextcloud users.
+
+## Seed data
+
+None beyond the schemas; the demo shows a round only after an administrator starts one.
+
+## Risks
+
+- The update listener must only mark requests of the user who saved; a colleague's edit must not answer someone else's request.
+- The overdue job must stay idempotent; it only moves `pending` to `overdue`.
diff --git a/openspec/changes/landscape-owner-attestation/proposal.md b/openspec/changes/landscape-owner-attestation/proposal.md
new file mode 100644
index 000000000..82b5ce5ea
--- /dev/null
+++ b/openspec/changes/landscape-owner-attestation/proposal.md
@@ -0,0 +1,45 @@
+---
+kind: code
+depends_on:
+ - landscape-usage-registration
+ - landscape-completeness-score
+---
+
+# Ask owners to confirm or correct their entries
+
+## Summary
+
+An information manager starts a confirmation round: every owner of an application in use, or every supplier contact of a product, gets a request to confirm the entry is current or to correct it, by a deadline. Owners answer from a notification, see exactly which entries are theirs, and confirm or edit each. The round shows who answered, who corrected and who is overdue, and a confirmed entry's data quality score goes back to fresh.
+
+## Why
+
+Row from the stackiq matrix:
+
+- `stackiq:land-data-quality-survey`, "Ask application owners through a survey to confirm or correct their entries." Rated no. Two competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/application-modernization-collect-data, "Create a new survey to get key information from application or business owners", and https://help.sap.com/docs/leanix/ea/reviewing-responses, "Review and approve survey responses before they are saved") and BlueDolphin (https://help.bluedolphin.io/en/articles/11967524-create-a-survey, surveys "allowing external stakeholders to contribute directly to the Enterprise Architecture repository"). Core area (landscape).
+
+No tender, feature request or roadmap row names it.
+
+## What stackiq has today
+
+- Nothing asks owners to confirm or correct entries: no survey, attestation or confirmation code in `lib/` or `src/`.
+- `landscape-usage-registration` adds `businessOwner` and `technicalOwner` to a usage; `module.contactPerson` names the supplier's contact per product. Contact persons become Nextcloud users through `ContactpersonenController::convertToUser()` (`lib/Controller/ContactpersonenController.php:393`).
+- `landscape-completeness-score` adds `lastConfirmedAt` and a freshness rule, and a manual Confirm action.
+- OpenRegister notifications resolve a recipient from an object field (`kind: field`, `openregister lib/Service/Notification/NotificationRecipientResolver.php:187`), and stackiq already declares notification rules in its register (for example the usage phase-out rule, `lib/Settings/softwarecatalogus_register.json:2662`).
+
+## What this change builds
+
+1. Two schemas: a confirmation round (name, deadline, which entries, who started it) and a confirmation request per entry and owner (status pending, confirmed, corrected or overdue).
+2. A service that creates a round's requests from a scope (the organisation's usages, or a supplier's products), resolving each owner to a Nextcloud user.
+3. A notification to each owner when a request is created and a reminder three days before the deadline, declared with `x-openregister-notifications`.
+4. A "My confirmation requests" page for the owner with Confirm and Edit per entry; confirming sets the entry's `lastConfirmedAt`, editing and saving marks the request corrected.
+5. A round page for the information manager with the answer counts and the overdue owners.
+
+## Out of scope
+
+- Free-form survey questions. A request asks one thing: is this entry right. Custom questions per object type belong to a later change.
+- An approval step before an owner's correction is saved. Owners already have edit rights on their entries; the round records that they changed it.
+- Owners without a Nextcloud account: portaliq's contribution contract covers outside parties (open change `portal-contribution`).
+
+## Risks
+
+- An entry without an owner cannot be asked. The round lists those entries separately so the information manager assigns owners first.
diff --git a/openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md b/openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md
new file mode 100644
index 000000000..0d47ca6bd
--- /dev/null
+++ b/openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md
@@ -0,0 +1,65 @@
+# owner-attestation specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-owner-attestation
+
+## Purpose
+
+Owners confirm or correct their catalogue entries in rounds an information manager starts and follows. Matrix row `stackiq:land-data-quality-survey`.
+
+## ADDED Requirements
+
+### Requirement: REQ-OAT-001 An information manager starts a confirmation round for a scope
+
+An organisation admin SHALL start a round for the organisation's usages or for its products, with a deadline. Stackiq SHALL create one request per entry and owner, resolved to a Nextcloud user, and SHALL report the entries that have no owner with an account.
+
+#### Scenario: A round over the applications in use
+@e2e tests/e2e/workflows/owner-attestation.spec.ts
+
+- **GIVEN** a municipality with four usages that have owners and one usage without
+- **WHEN** its information manager starts a confirmation round for applications in use with a deadline in two weeks
+- **THEN** the round shows four pending requests
+- **AND** it lists the one usage without an owner under unassigned
+
+### Requirement: REQ-OAT-002 Each owner is notified and reminded
+
+Stackiq SHALL notify an owner in Nextcloud and by email when a request for them is created, and SHALL remind them three days before the deadline while the request is pending.
+
+#### Scenario: An application owner gets the request
+@e2e exclude Delivered by OpenRegister's notification engine; tests/Unit/Settings/OwnerAttestationFragmentTest.php asserts the rule, its trigger and its field recipient.
+
+- **GIVEN** a round with a request for application owner Anna
+- **WHEN** the request is created
+- **THEN** Anna receives a Nextcloud notification naming the entry
+
+### Requirement: REQ-OAT-003 An owner confirms or corrects each entry
+
+An owner SHALL confirm an entry from My confirmation requests, which sets the entry's `lastConfirmedAt` and marks the request confirmed. When the owner edits and saves the entry instead, the request SHALL be marked corrected. An edit by someone else SHALL NOT answer the owner's request. A request still pending after the deadline SHALL become overdue.
+
+#### Scenario: Confirming from the list
+@e2e tests/e2e/workflows/owner-attestation.spec.ts
+
+- **GIVEN** Anna has a pending request for the usage of application X
+- **WHEN** she opens My confirmation requests and clicks Confirm
+- **THEN** the request reads confirmed
+- **AND** the usage shows today as last confirmed
+
+#### Scenario: Correcting by editing
+@e2e exclude Listener behaviour; tests/Unit/Listener/AttestationCorrectionListenerTest.php covers the owner's edit and a colleague's edit with the real event class.
+
+- **GIVEN** Anna has a pending request for the usage of application X
+- **WHEN** she changes its version and saves
+- **THEN** the request reads corrected
+
+### Requirement: REQ-OAT-004 The round shows who answered and who is overdue
+
+The round page SHALL show how many requests are pending, confirmed, corrected and overdue, and list the requests grouped by status with their owners.
+
+#### Scenario: Following up overdue owners
+@e2e tests/e2e/workflows/owner-attestation.spec.ts
+
+- **GIVEN** a round past its deadline with one request still pending
+- **WHEN** the overdue job has run and the information manager opens the round
+- **THEN** the round shows one overdue request with its owner
diff --git a/openspec/changes/landscape-owner-attestation/tasks.md b/openspec/changes/landscape-owner-attestation/tasks.md
new file mode 100644
index 000000000..3b1fb8c06
--- /dev/null
+++ b/openspec/changes/landscape-owner-attestation/tasks.md
@@ -0,0 +1,53 @@
+# Tasks: landscape-owner-attestation
+
+## Implementation tasks
+
+### Task 1: Round and request schemas with notifications
+- **spec_ref**: openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md#requirement-req-oat-002-each-owner-is-notified-and-reminded
+- **files**: `lib/Settings/register.d/owner-attestation.json`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it is imported THEN attestationRound and attestationRequest exist with their lifecycle and notification rules
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Settings/OwnerAttestationFragmentTest.php`)
+
+### Task 2: Start a round
+- **spec_ref**: openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md#requirement-req-oat-001-an-information-manager-starts-a-confirmation-round-for-a-scope
+- **files**: `lib/Service/AttestationService.php`, `lib/Controller/AttestationController.php`, `appinfo/routes.php`, `lib/AppInfo/Application.php`
+- **acceptance_criteria**:
+ - GIVEN four usages with owners and one without WHEN an organisation admin starts a round THEN four requests exist and one entry is reported unassigned
+ - GIVEN a user who is not an organisation admin WHEN they post a round THEN the answer is 403
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Service/AttestationServiceTest.php`, `tests/Unit/Controller/AttestationControllerTest.php`)
+
+### Task 3: Confirm, correct and overdue
+- **spec_ref**: openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md#requirement-req-oat-003-an-owner-confirms-or-corrects-each-entry
+- **files**: `lib/Controller/AttestationController.php`, `lib/Listener/AttestationCorrectionListener.php`, `lib/BackgroundJob/AttestationOverdueJob.php`, `appinfo/info.xml`
+- **acceptance_criteria**:
+ - GIVEN a pending request WHEN its owner confirms THEN the entry's lastConfirmedAt is today and the request is confirmed
+ - GIVEN a pending request WHEN another user edits the entry THEN the request stays pending
+ - GIVEN a pending request past its deadline WHEN the job runs THEN it is overdue
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Listener/AttestationCorrectionListenerTest.php` with the real ObjectUpdatedEvent class, `tests/Unit/BackgroundJob/AttestationOverdueJobTest.php`)
+
+### Task 4: Owner and round pages
+- **spec_ref**: openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md#requirement-req-oat-004-the-round-shows-who-answered-and-who-is-overdue
+- **files**: `src/manifest.d/owner-attestation.json`, `src/dialogs/StartAttestationRoundDialog.vue`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN an owner with two pending requests WHEN they open My confirmation requests THEN both show with Confirm
+ - GIVEN a round with answers WHEN the information manager opens it THEN it shows confirmed, corrected, pending and overdue counts
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/owner-attestation.spec.ts`)
+
+### Task 5: Documentation
+- **spec_ref**: openspec/changes/landscape-owner-attestation/specs/owner-attestation/spec.md#requirement-req-oat-001-an-information-manager-starts-a-confirmation-round-for-a-scope
+- **files**: `docs/features/owner-attestation.md`, `docs/images/confirmation-round.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Confirmation rounds THEN starting a round, answering and following it are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate landscape-owner-attestation --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit and Playwright cases above pass.
+- English and Dutch strings for every new label and notification (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/changes/landscape-usage-registration/.openspec.yaml b/openspec/changes/landscape-usage-registration/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/landscape-usage-registration/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/landscape-usage-registration/design.md b/openspec/changes/landscape-usage-registration/design.md
new file mode 100644
index 000000000..e3692eb9e
--- /dev/null
+++ b/openspec/changes/landscape-usage-registration/design.md
@@ -0,0 +1,57 @@
+# Design: landscape-usage-registration
+
+Read at development `49e65cb4`.
+
+## Context
+
+A usage (`gebruik`) is an organisation's use of an application: `consumer` (the organisation), `module`, `moduleVersion`, `status`, phase dates, connections and replacement (`usage` schema, `lib/Settings/softwarecatalogus_register.json:2656`). Its read rule shows a usage to the using organisation (`consumer` or `_organisation` equals the active organisation) and to the supplier (`provider`). Everything the portfolio views compute (`src/views/LifecycleRoadmapView.vue:397`, `lib/Service/PortfolioReportService.php`) starts from usages, but no page creates them.
+
+## D1. Pages in a fragment
+
+`src/manifest.d/usages.json` (ADR-037):
+
+- `Gebruik`, route `/gebruik`, `type: index`, schema `usage`. Title "Applications in use". Columns: module, moduleVersion, status, businessOwner, technicalOwner, timeClassification. Quick filters on status. `filterMenu: true`.
+- `GebruikDetail`, route `/gebruik/:id`, `type: detail`. Widgets: data (application, version, status, phase dates, owners, cloud model, annotation), files (the schema has `allowFiles` and tags DPIA, Contract, Verwerkingsovereenkomst), related, and a History tab. `lifecycleActions` on.
+- Menu child "Applications in use" under the `Modules` entry. No new top-level entry (ADR-097).
+
+`landscape-application-page` added a usages list to `ModuleDetail` without a row route; this change sets its `rowRoute: GebruikDetail`. `OrganisatieDetail` (`src/manifest.json:403`) gets an `object-list` `org-usages` with filter `{ "consumer": "@objectId" }`, next to `org-modules` (:417), which lists what an organisation offers.
+
+## D2. "Add to our landscape"
+
+`ModuleDetail` gets a header action "Add to our landscape" that opens the library's create form for `usage` with `module` set to the page's object and `consumer` set to the active organisation. The action shows only when the user may create a usage. It mirrors the GEMMA Softwarecatalogus "+" behind a package (the row's evidence).
+
+Rejected: a wizard. The usage form has five fields a user must decide on; a dialog is enough, and `CnFormDialog` already renders the schema.
+
+## D3. Owners
+
+Two new properties on `usage`, added through `lib/Settings/register.d/usage-owners.json`:
+
+| property | type | notes |
+|---|---|---|
+| `businessOwner` | `$ref contactPerson` | `x-relation-filter: { "organization": "@object.consumer" }` |
+| `technicalOwner` | `$ref contactPerson` | same filter |
+
+The existing hidden `contactPerson` stays as it is. The contact person read rule (`register.json:1788` schema) scopes a supplier to its own organisation's contact persons, so a supplier reading a usage of its product sees an owner reference it cannot open.
+
+Rejected: owner fields on `module`. A module is the supplier's product; the business owner is a person of the organisation that uses it, and two municipalities using one product have two owners.
+
+## D4. Register fixes
+
+In `lib/Settings/softwarecatalogus_register.json`, schema `usage`:
+
+1. `x-openregister-lifecycle` on the enum values: initial `Acquisition`, final `Phased out`, transitions plan (Acquisition to Planned), goLive (Planned to In production), phaseOut (In production to To be phased out), retire (To be phased out to Phased out). The rows already hold these (`lib/Repair/RenameDutchCatalogValues.php:80-84`).
+2. `objectNameField` becomes `{{ module }} ({{ consumer }})`.
+3. The schema version goes to 1.5.1 with a register changelog line, for the reason the 2.4.4 entry records (`register.json:7`).
+
+## Declarative versus imperative
+
+Declarative only: pages, relations, lifecycle and a header action that opens the library form (ADR-031). No PHP.
+
+## Seed data
+
+`lib/Settings/stackiq_mock_register.json`: two demo usages of demo applications by the demo municipality, one In production with a version and both owners, one Planned.
+
+## Risks
+
+- The default status stays In production, which the lifecycle treats as a valid state. A usage created as In production starts there; the lifecycle's initial state only applies when no status is sent.
+- `ModuleDetail` gains a header action and a row route; `landscape-application-page` lands first.
diff --git a/openspec/changes/landscape-usage-registration/proposal.md b/openspec/changes/landscape-usage-registration/proposal.md
new file mode 100644
index 000000000..1d9d6e59e
--- /dev/null
+++ b/openspec/changes/landscape-usage-registration/proposal.md
@@ -0,0 +1,45 @@
+---
+kind: code
+depends_on:
+ - landscape-application-page
+---
+
+# Record the applications your organisation uses, with status, version and owners
+
+## Summary
+
+An information manager records that the organisation uses an application: which version it runs, where it stands in its lifecycle, and who owns it on the business side and the technical side. Today this record (a usage, `gebruik`) exists in the data but no stackiq page creates or edits it. This change adds the pages, fixes the usage lifecycle so its transitions work, and adds the two owner fields.
+
+## Why
+
+Rows from the stackiq matrix:
+
+- `stackiq:land-register-application`, "Register an application your organisation uses, with its supplier, description and status." Rated partial, built. Four competitors rate yes, among them GEMMA Softwarecatalogus (https://www.softwarecatalogus.nl/node/30355, "klik dan op de knop + achter de beschrijving van het pakket om het pakket toe te voegen aan je omgeving ... Vul onder Planning bij Status in gebruik in"), SAP LeanIX (https://help.sap.com/docs/leanix/ea/application-modeling-guidelines), BlueDolphin (https://help.bluedolphin.io/en/articles/11967529-welcome-to-the-objects) and GLPI (source read at 11.0.9, `src/Appliance.php:350` search option Status). The missing half: a lifecycle status for the application an organisation uses, set on a usage page. Core area (landscape).
+- `stackiq:life-version-in-use`, "Record which version of an application your organisation currently runs." Rated partial, built. Two competitors rate yes: GEMMA Softwarecatalogus (https://www.softwarecatalogus.nl/node/30355, "Pakketversie - selecteer de versie die in gebruik is") and GLPI (source read at 11.0.9, `src/Item_SoftwareVersion.php:39`). The missing half: a usage page where the organisation sets the version.
+- `stackiq:land-application-owner`, "Name the business owner and the technical owner responsible for an application." Rated partial, built. Two competitors rate yes: SAP LeanIX (https://help.sap.com/docs/leanix/ea/subscription-roles, "roles that map to your organization's positions, such as application owner") and GLPI (source read at 11.0.9, `glpi_appliances` holds `users_id` and `users_id_tech`, `src/Appliance.php:186` and `:240`). The missing half: a separate business owner and technical owner for the organisation that uses the application, on its usage. Core area.
+
+## What stackiq has today
+
+- The `usage` schema (`lib/Settings/softwarecatalogus_register.json:2656`, version 1.5.0) holds `consumer`, `module`, `moduleVersion` (filtered to the module's versions), `status` (Acquisition, Planned, In production, To be phased out, Phased out; default In production), five phase dates, `contactPerson` (hidden), `koppelingen`, `plannedReplacement` and the TIME classification.
+- No manifest page uses the schema. `LifecycleRoadmapView.vue:397` and the portfolio report read usages, and the EOL badges depend on `usage.moduleVersion`, but nobody can set it in stackiq.
+- The usage lifecycle names Verwerving, Gepland, In productie, Uit te faseren and Uitgefaseerd, while the enum and the migrated rows (`lib/Repair/RenameDutchCatalogValues.php:80-84`) hold the English values, so no transition matches a row.
+- `usage.objectNameField` is `consumer`, so every usage of one organisation carries the same name in lists and pickers.
+
+## What this change builds
+
+1. A usage index page (`Gebruik`, `/gebruik`, "Applications in use") and a usage detail page, under Applications in the menu.
+2. An "Add to our landscape" action on the application page that opens the usage form with the application and the active organisation filled in.
+3. Business owner and technical owner fields on the usage, picked from the organisation's contact persons.
+4. The usage lifecycle on the enum values, so Plan, Go live, Phase out and Retire work from the detail page.
+5. A usage name built from the application and the organisation.
+6. An "Applications in use" list on the organisation page.
+
+## Out of scope
+
+- Filling phase dates when the status changes (`stackiq:life-dates-follow-status`, deferred: feature request without a competitor yes).
+- Suggested connections for a usage: `connections-derived-dependencies`.
+- A status on the product itself: a product's own status is its versions' status (`moduleVersion.status`).
+
+## Risks
+
+- Suppliers can read usages of their products (`provider` read rule). The owner fields name people of the using organisation; the design keeps them readable only for that organisation.
diff --git a/openspec/changes/landscape-usage-registration/specs/application-usage-pages/spec.md b/openspec/changes/landscape-usage-registration/specs/application-usage-pages/spec.md
new file mode 100644
index 000000000..37b71c2e5
--- /dev/null
+++ b/openspec/changes/landscape-usage-registration/specs/application-usage-pages/spec.md
@@ -0,0 +1,64 @@
+# application-usage-pages specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- landscape-usage-registration
+
+## Purpose
+
+An organisation records the applications it uses, with the version it runs, its lifecycle status and its owners. Matrix rows `stackiq:land-register-application`, `stackiq:life-version-in-use` and `stackiq:land-application-owner`.
+
+## ADDED Requirements
+
+### Requirement: REQ-UAP-001 An organisation records and browses the applications it uses
+
+Stackiq SHALL offer a page "Applications in use" at `/gebruik` over the `usage` schema that lists the usages the user may read, with application, version, status and owners, and a detail page at `/gebruik/:id` where the user edits them. The organisation page SHALL list the organisation's usages.
+
+#### Scenario: An information manager lists the organisation's applications
+@e2e tests/e2e/workflows/usages.spec.ts
+
+- **GIVEN** the municipality uses application X at version 2.1 in production and application Y as planned
+- **WHEN** its information manager opens Applications, then Applications in use
+- **THEN** the list shows X with version 2.1 and status In production, and Y with status Planned
+
+### Requirement: REQ-UAP-002 An organisation adds an application to its landscape from the application page
+
+The application page SHALL offer "Add to our landscape" to a user who may create a usage. It SHALL open the usage form with the application and the user's active organisation filled in, and the version picker SHALL offer only versions of that application.
+
+#### Scenario: Adding an application with its version
+@e2e tests/e2e/workflows/usages.spec.ts
+
+- **GIVEN** application X has versions 2.0 and 2.1
+- **WHEN** the information manager opens the page of X, clicks Add to our landscape, picks version 2.1 and saves
+- **THEN** a usage of X by their municipality with version 2.1 exists
+- **AND** it shows on Applications in use
+
+### Requirement: REQ-UAP-003 A usage names a business owner and a technical owner
+
+A usage SHALL carry a business owner and a technical owner, each picked from the contact persons of the using organisation.
+
+#### Scenario: Setting both owners
+@e2e tests/e2e/workflows/usages.spec.ts
+
+- **GIVEN** the municipality has contact persons Anna and Bram
+- **WHEN** the information manager edits its usage of X and sets business owner Anna and technical owner Bram
+- **THEN** the usage page shows Anna as business owner and Bram as technical owner
+
+#### Scenario: A supplier cannot open the owners
+@e2e exclude Read rule of the contact person schema; tests/Unit/Settings/SchemaRbacTest.php asserts a supplier reads only its own organisation's contact persons.
+
+- **GIVEN** a usage of the supplier's product with both owners set
+- **WHEN** the supplier opens that usage
+- **THEN** the owner contact persons do not open for the supplier
+
+### Requirement: REQ-UAP-004 A usage moves through its lifecycle from its page
+
+The usage schema SHALL declare its lifecycle on the status values its rows hold, so the detail page offers Plan, Go live, Phase out and Retire from the matching status.
+
+#### Scenario: Going live
+@e2e tests/e2e/workflows/usages.spec.ts
+
+- **GIVEN** a usage with status Planned
+- **WHEN** the information manager opens it and clicks Go live
+- **THEN** its status reads In production
diff --git a/openspec/changes/landscape-usage-registration/tasks.md b/openspec/changes/landscape-usage-registration/tasks.md
new file mode 100644
index 000000000..532ad2186
--- /dev/null
+++ b/openspec/changes/landscape-usage-registration/tasks.md
@@ -0,0 +1,43 @@
+# Tasks: landscape-usage-registration
+
+## Implementation tasks
+
+### Task 1: Usage schema fixes and owner fields
+- **spec_ref**: openspec/changes/landscape-usage-registration/specs/application-usage-pages/spec.md#requirement-req-uap-003-a-usage-names-a-business-owner-and-a-technical-owner
+- **files**: `lib/Settings/softwarecatalogus_register.json`, `lib/Settings/register.d/usage-owners.json`, `lib/Settings/stackiq_mock_register.json`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN a usage in Planned is opened THEN Go live is offered
+ - GIVEN a usage WHEN its business owner field opens THEN it lists contact persons of the consumer organisation only
+- [ ] Implement
+- [ ] Test (PHPUnit `tests/Unit/Settings/UsageSchemaTest.php`: lifecycle states are enum values, owner filters, name template keys exist)
+
+### Task 2: Usage index and detail pages
+- **spec_ref**: openspec/changes/landscape-usage-registration/specs/application-usage-pages/spec.md#requirement-req-uap-001-an-organisation-records-and-browses-the-applications-it-uses
+- **files**: `src/manifest.d/usages.json`, `src/manifest.json` (ModuleDetail row route, OrganisatieDetail list), `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN two usages of the organisation WHEN the user opens Applications in use THEN both show with version and status
+ - GIVEN a usage row WHEN the user opens it THEN the detail page shows version, status and owners
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/usages.spec.ts`)
+
+### Task 3: Add to our landscape
+- **spec_ref**: openspec/changes/landscape-usage-registration/specs/application-usage-pages/spec.md#requirement-req-uap-002-an-organisation-adds-an-application-to-its-landscape-from-the-application-page
+- **files**: `src/manifest.json` (ModuleDetail header action), `src/customComponents.js` if the action needs a handler
+- **acceptance_criteria**:
+ - GIVEN application X WHEN an information manager clicks Add to our landscape and saves version 2.1 THEN a usage of X by their organisation exists with version 2.1
+- [ ] Implement
+- [ ] Test (Playwright `tests/e2e/workflows/usages.spec.ts`, add case)
+
+### Task 4: Documentation
+- **spec_ref**: openspec/changes/landscape-usage-registration/specs/application-usage-pages/spec.md#requirement-req-uap-004-a-usage-moves-through-its-lifecycle-from-its-page
+- **files**: `docs/features/applications-in-use.md`, `docs/images/applications-in-use.png`
+- **acceptance_criteria**:
+ - GIVEN the docs site WHEN a reader opens Applications in use THEN adding, the lifecycle and the owners are explained with a screenshot
+- [ ] Implement
+- [ ] Test (docs build, screenshot with Playwright)
+
+## Verification
+
+- `openspec validate landscape-usage-registration --type change --strict` passes.
+- `composer check:strict` and `npm run lint` pass; the PHPUnit and Playwright cases above pass.
+- English and Dutch strings for every new label (ADR-005); docs with a screenshot (ADR-010).
diff --git a/openspec/parity/capabilities.json b/openspec/parity/capabilities.json
index fc289e17a..5c51959fa 100644
--- a/openspec/parity/capabilities.json
+++ b/openspec/parity/capabilities.json
@@ -366,7 +366,7 @@
"topdesk": "partial",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "specified",
"evidence": "src/manifest.json:592 Modules page (FacetedCatalogIndexView, schema module) with the library CnIndexPage create form at src/views/FacetedCatalogIndexView.vue:108; lib/Settings/softwarecatalogus_register.json:6777 module schema has name, shortDescription/longDescription and provider (Supplier) but NO status property; status lives on usage (register.json:2654, enum Acquisition..In production) which has no page",
"owner": "ConductionNL/stackiq"
},
@@ -375,7 +375,7 @@
"providerHow": "read-from-code",
"feature": "software-landscape-register",
"featureConfidence": "high",
- "note": "An application with supplier and description can be registered on the Modules page, but the module schema has no status field, and the per-organisation usage that carries a status has no page to create it on. The Modules list also cannot open ModuleDetail: its standalone CnIndexPage (FacetedCatalogIndexView.vue:108-117) binds no @view/@row-click, so the View action is inert.",
+ "note": "An application with supplier and description can be registered on the Modules page, but the module schema has no status field, and the per-organisation usage that carries a status has no page to create it on. The Modules list also cannot open ModuleDetail: its standalone CnIndexPage (FacetedCatalogIndexView.vue:108-117) binds no @view/@row-click, so the View action is inert. Specified in openspec/changes/landscape-usage-registration (OpenSpec pass 2026-09-27).",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/30355: \"klik dan op de knop + achter de beschrijving van het pakket om het pakket toe te voegen aan je omgeving ... Pakketversie ... Referentiecomponenten ... Vul onder Planning bij Status in gebruik in\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus: \"Wanneer Gemeenten en samenwerkingen hun applicatielandschap hebben ingevoerd, wordt deze automatisch geplot op de GEMMA referentiecomponentenkaart\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Pakketten > Voeg pakket toe.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Applications are software systems or programs that process or analyze business data'; application fact sheet with description and lifecycle, supplier via 'provider -> IT component -> application relation' (https://help.sap.com/docs/leanix/ea/provider-modeling-guidelines) (read 2026-09-26). Reached on: Inventory > Application fact sheet.",
@@ -397,7 +397,7 @@
"topdesk": "unknown",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "specified",
"evidence": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')",
"owner": "ConductionNL/stackiq"
},
@@ -406,7 +406,7 @@
"providerHow": "read-from-code",
"feature": "software-landscape-register",
"featureConfidence": "low",
- "note": "Stackiq's 'module' is the whole application, so there is no breakdown of one application into modules. The nearest thing is a suite (product) listing its applications, which answers 'which module belongs to which product' but not the decomposition.",
+ "note": "Stackiq's 'module' is the whole application, so there is no breakdown of one application into modules. The nearest thing is a suite (product) listing its applications, which answers 'which module belongs to which product' but not the decomposition. Specified in openspec/changes/landscape-application-components (OpenSpec pass 2026-09-27).",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines: 'Applications often consist of multiple entities or modules within a common ecosystem or platform', modeled as parent/child hierarchy, e.g. Adobe Photoshop as child of Adobe Creative Cloud (read 2026-09-26). Reached on: Application fact sheet > parent/child relations.",
"stackiq": "register.json:1135 suite schema with applications[] (register.json:1231); src/manifest.json:674 SuiteDetail with suite-related panel; no schema breaks one application into sub-modules (module IS the application, register.json:6777 title 'Application')",
@@ -521,14 +521,14 @@
"topdesk": "unknown",
"stackiq": "no",
"built": {
- "state": "specified",
+ "state": "decided-no",
"evidence": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "A sector schema exists, but no application, service or organisation can be tagged with a sector and no page lists sectors.",
+ "note": "A sector schema exists, but no application, service or organisation can be tagged with a sector and no page lists sectors. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: aanvullende-informatie.md:511 lists VNG issue #4 (classify packages on the reference architectures of the relevant sectors, so buyers from several sectors find them) with the analysis \"Classificeren op meerdere sectorale referentiearchitecturen, buiten scope\", and issues/4.md carries the label \"Buiten scope oplevering\" and is closed. Tagging applications with sectors is the entry to that out-of-scope classification. The unused sector schema (lib/Settings/softwarecatalogus_register.json:1036) is what the specified state pointed at; no change directory existed.",
"evidence": {
"stackiq": "register.json:1034 sector schema (name, description only); no schema property references #/components/schemas/sector (grep found none), no manifest page for sector; only the admin schema mapping in src/views/settings/sections/OpenRegisterIntegration.vue:395",
"topdesk": "unknown: the TOPdesk documentation is about service management and does not cover this; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -550,7 +550,7 @@
"topdesk": "partial",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "specified",
"evidence": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')",
"owner": "ConductionNL/stackiq"
},
@@ -559,7 +559,7 @@
"providerHow": "read-from-code",
"feature": "software-landscape-register",
"featureConfidence": "low",
- "note": "One contact person per application can be set, but there is no separate business owner and technical owner. ModuleDetail's data widget includes 'contactpersoon', a key the schema no longer has, so the contact may not show there.",
+ "note": "One contact person per application can be set, but there is no separate business owner and technical owner. ModuleDetail's data widget includes 'contactpersoon', a key the schema no longer has, so the contact may not show there. Specified in openspec/changes/landscape-usage-registration (OpenSpec pass 2026-09-27).",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/subscription-roles: 'Define roles that map to your organization's positions, such as application owner', with subscription types 'Responsible, Accountable, Observer' per fact sheet (read 2026-09-26). Reached on: Fact sheet > Subscriptions; Administration > Subscription Roles.",
"stackiq": "register.json:6856 module.contactPerson is a single related contactPerson; register.json:1786 contactPerson has free-text role (job title) and a roles enum of catalogue roles (Aanbod-beheerder, Gebruik-beheerder, ...), no business/technical owner distinction; shown on ModuleDetail md-data (src/manifest.json:500 lists the stale key 'contactpersoon', not 'contactPerson')",
@@ -640,7 +640,7 @@
"topdesk": "partial",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "specified",
"evidence": "src/manifest.json:491 ModuleDetail: md-versions (:504), md-compliance (:503), md-related generic Related panel (:502); no contract widget (catalogContract links to service/usage, register.json:3250, not to module); md-data include lists stale keys beschrijvingKort/beschrijvingLang/contactpersoon (:500)",
"owner": "ConductionNL/stackiq"
},
@@ -649,7 +649,7 @@
"providerHow": "read-from-code",
"feature": "software-landscape-register",
"featureConfidence": "medium",
- "note": "The application page shows versions and compliance claims, and usages only as untyped entries in the generic Related panel. Contracts are not shown. The page cannot be opened from the Applications list itself, and its data widget asks for three field names the schema no longer has, so the descriptions do not render.",
+ "note": "The application page shows versions and compliance claims, and usages only as untyped entries in the generic Related panel. Contracts are not shown. The page cannot be opened from the Applications list itself, and its data widget asks for three field names the schema no longer has, so the descriptions do not render. Specified in openspec/changes/landscape-application-page (OpenSpec pass 2026-09-27).",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/pakket/archi: package page shows versions with status and start dates, \"Pakket geschikt voor (GEMMA 2) Ingevuld door (28)\", and per version the mandatory and recommended standards with support, compliancy and testrapport (read 2026-09-26). No contracts on the page. Reached on: Alle pakketten > package name.",
"sap-leanix": "https://help.sap.com/docs/leanix/ea/application-modeling-guidelines and https://help.sap.com/docs/leanix/ea/adding-and-editing-data-in-fact-sheets: the application fact sheet holds lifecycle, relations to IT components, organizations, interfaces, cost on relations, and a Relations Explorer on one fact sheet (read 2026-09-26). Reached on: Inventory > Application fact sheet.",
@@ -731,14 +731,14 @@
"topdesk": "unknown",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "No survey, attestation or owner-confirmation code in lib/ or src/ (searched survey/enquete/confirm entry)",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "Nothing asks owners to confirm or correct their entries.",
+ "note": "Nothing asks owners to confirm or correct their entries. Specified in openspec/changes/landscape-owner-attestation (OpenSpec pass 2026-09-27).",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/reviewing-responses: 'Review and approve survey responses before they are saved to fact sheets'; https://help.sap.com/docs/leanix/ea/application-modernization-collect-data: 'Create a new survey to get key information from application or business owners' (read 2026-09-26). Reached on: Surveys.",
"bluedolphin": "https://help.bluedolphin.io/en/articles/11967524-create-a-survey: surveys 'gather input from stakeholders outside your core BlueDolphin users ... allowing external stakeholders to contribute directly to the Enterprise Architecture repository' on an object's questionnaire (read 2026-09-26). Reached on: Object > Questionnaire tab > Create survey.",
@@ -760,14 +760,14 @@
"topdesk": "unknown",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "No page scores how complete or current an entry is.",
+ "note": "No page scores how complete or current an entry is. Specified in openspec/changes/landscape-completeness-score (OpenSpec pass 2026-09-27).",
"evidence": {
"stackiq": "No completeness or data-quality score in lib/ or src/ (searched completeness/volledigheid/score outside reviews)",
"topdesk": "unknown: the only readiness score described is the AI readiness score for the knowledge base; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -907,7 +907,7 @@
"topdesk": "unknown",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "specified",
"evidence": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection",
"owner": "ConductionNL/stackiq"
},
@@ -916,7 +916,7 @@
"providerHow": "read-from-code",
"feature": "software-landscape-register",
"featureConfidence": "low",
- "note": "The field for a national provision exists on the connection schema, but with no connection page nobody can fill it in stackiq.",
+ "note": "The field for a national provision exists on the connection schema, but with no connection page nobody can fill it in stackiq. Specified in openspec/changes/connections-catalogue-pages (OpenSpec pass 2026-09-27).",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Opvoeren%20koppeling%20iJw%20en%20iWmo: \"De richting van het berichtenverkeer, de landelijke voorziening waarmee gekoppeld is/wordt, in dit geval GGK\" (read 2026-09-26); https://www.softwarecatalogus.nl/hoe-werkt-de-catalogus: \"kunnen koppelingen tussen applicaties onderling en met Landelijke Voorzieningen vastgelegd worden\" (read 2026-09-26). Reached on: Mijn softwarecatalogus > Koppelingen > koppeling toevoegen.",
"stackiq": "register.json:3720 connection.nonMunicipalProvision -> element filtered gemmaType 'Buitengemeentenlijke voorziening'; no page for connection",
@@ -947,7 +947,7 @@
"providerHow": "read-from-code",
"feature": "software-landscape-register",
"featureConfidence": "medium",
- "note": "There is no list of connections in the catalogue. The Integrations page lists outside integrations, a different thing.",
+ "note": "There is no list of connections in the catalogue. The Integrations page lists outside integrations, a different thing. Specified in openspec/changes/connections-catalogue-pages (OpenSpec pass 2026-09-27).",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Alle koppelingen ... staan de koppelingen van alle gemeenten en samenwerkingsverbanden ... Door te klikken op het icoontje rechts van een koppeling, krijg je nog enige detail informatie\" (read 2026-09-26). Reached on: Inlogmenu > Alle koppelingen (logged-in municipal users).",
"stackiq": "No manifest page with schema connection (src/manifest.json and src/manifest.d/*.json); the Integrations page (src/manifest.d/connection-registry.json:23) lists integriq app_connection, explicitly not stackiq's connection schema (its _note)",
@@ -969,7 +969,7 @@
"topdesk": "partial",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "specified",
"evidence": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/",
"owner": "ConductionNL/stackiq"
},
@@ -978,7 +978,7 @@
"providerHow": "read-from-code",
"feature": "software-landscape-register",
"featureConfidence": "low",
- "note": "Connections that reference an application should appear among the untyped related objects on its page, but there is no connections section and nothing to open. The dedicated per-application endpoint is API only.",
+ "note": "Connections that reference an application should appear among the untyped related objects on its page, but there is no connections section and nothing to open. The dedicated per-application endpoint is API only. Specified in openspec/changes/connections-catalogue-pages (OpenSpec pass 2026-09-27).",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/node/13683: \"Mijn pakketoverzicht ... Onder het eerste tabblad zitten de pakketten en onder het tweede tabblad de koppelingen\" (read 2026-09-26); https://www.softwarecatalogus.nl/node/30890: \"Door op een applicatienaam in het Models venster te klikken, zie je in de Visualiser alle koppelingen tussen die applicatie met andere applicaties\" (in Archi after export) (read 2026-09-26). No per-application connection view inside the catalogue is described. Reached on: Mijn softwarecatalogus > Koppelingen.",
"stackiq": "src/manifest.json:502 ModuleDetail md-related generic Related panel (OpenRegister /uses + /used merged into an Objects tab); register.json:7064 module.koppelingen is hideOnForm and not in md-data include (:500); lib/Controller/AangebodenGebruikController.php:208 GET /api/koppelingen-gebruik/{uuid} (public) has no caller in src/",
@@ -1000,7 +1000,7 @@
"topdesk": "yes",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "No diagram rendering in src/ (no graph library; src/store/modules/view.js GET /api/views has no importer outside itself); lib/Service/ArchiMateExportService.php exports GEMMA views as ArchiMate XML without koppeling objects (no 'koppeling' in lib/Service/ArchiMate*)",
"owner": "ConductionNL/stackiq"
},
@@ -1009,7 +1009,7 @@
"providerHow": "read-from-code",
"feature": "archimate-import-and-export",
"featureConfidence": "low",
- "note": "No page draws connections. The ArchiMate export can be opened in Archi, but it carries GEMMA views and usages, not the catalogue's connections.",
+ "note": "No page draws connections. The ArchiMate export can be opened in Archi, but it carries GEMMA views and usages, not the catalogue's connections. Specified in openspec/changes/connections-diagram-and-graph-export (OpenSpec pass 2026-09-27).",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/data-flow: data flow diagrams help 'understand how applications are connected, identify dependencies, and trace data movement between systems' (read 2026-09-26). Reached on: Diagrams > Data Flow Diagram.",
"bluedolphin": "https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin: 'insight into connections between business processes, applications, and their underlying infrastructure. This way, you can visualize chains and information flows'; https://help.bluedolphin.io/en/articles/11967545-spider-tool adds related objects with 'all existing relationships' to a view (read 2026-09-26). Reached on: Views > architecture view.",
@@ -1067,7 +1067,7 @@
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "The type field exists but there is no connection list to filter.",
+ "note": "The type field exists but there is no connection list to filter. Specified in openspec/changes/connections-catalogue-pages (OpenSpec pass 2026-09-27).",
"evidence": {
"stackiq": "register.json:3563 connection.type enum (file transfer, digikoppeling, message que, webservices, api, ...) exists, but no connection list page to filter",
"topdesk": "unknown: custom link types exist, but filtering relations by type is not described; https://tip.topdesk.com/c/90-graphical-overview-improvements is still under consideration; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -1089,14 +1089,14 @@
"topdesk": "unknown",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "Stackiq has no record for an API an application exposes.",
+ "note": "Stackiq has no record for an API an application exposes. Specified in openspec/changes/connections-api-catalogue (OpenSpec pass 2026-09-27).",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/interface-modeling-guidelines: interface subtype 'API ... APIs provide functionalities accessible to external applications ... Examples: Metrics API, Import API', related to the providing application (read 2026-09-26). Reached on: Inventory > Interface fact sheet, subtype API.",
"stackiq": "No API/interface schema in register.json (schemas listed at register.json:1034-7920); connection.type 'api' is only a transport label",
@@ -1118,7 +1118,7 @@
"topdesk": "unknown",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*",
"owner": "ConductionNL/stackiq"
},
@@ -1127,7 +1127,7 @@
"providerHow": "read-from-code",
"feature": "archimate-import-and-export",
"featureConfidence": "low",
- "note": "The organisation ArchiMate export carries modules and usages but not connections, so an application's link graph cannot be exported.",
+ "note": "The organisation ArchiMate export carries modules and usages but not connections, so an application's link graph cannot be exported. Specified in openspec/changes/connections-diagram-and-graph-export (OpenSpec pass 2026-09-27).",
"evidence": {
"glpi": "source read at 11.0.9: front/impactcsv.php streams Glpi\\Csv\\ImpactCsvExport for an item, linked from the impact list view at src/Impact.php:393; the graph Download button src/Impact.php:1165 calls js/impact.js:2528 download, which writes PNG (js/impact.js:2539) or JPEG (js/impact.js:2546). Reached on: Appliance > Impact analysis tab, Download and CSV export.",
"stackiq": "src/views/settings/sections/ArchiMateImportExport.vue:571 org export options are Modules, Deelnames, Gebruik only; lib/Controller/SettingsController.php:1685 exportOrgArchiMate; no koppeling handling in lib/Service/ArchiMate*",
@@ -1817,14 +1817,14 @@
"topdesk": "unknown",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "grep for completeness/health score/quality score in lib and src: no hits; lib/Command/ReferencesAuditCommand.php:34 (occ stackiq:references:audit) only audits cross-app uuid references, it is not a scored rule set",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "No rule-based score of register correctness or completeness exists on any page.",
+ "note": "No rule-based score of register correctness or completeness exists on any page. Specified in openspec/changes/landscape-completeness-score (OpenSpec pass 2026-09-27).",
"evidence": {
"stackiq": "grep for completeness/health score/quality score in lib and src: no hits; lib/Command/ReferencesAuditCommand.php:34 (occ stackiq:references:audit) only audits cross-app uuid references, it is not a scored rule set",
"topdesk": "unknown: standards compliance of applications, BIO and DPIA are not covered; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -2088,14 +2088,14 @@
"topdesk": "unknown",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "specified",
"evidence": "register :6856 module.contactPerson -> contactPerson with x-relation-filter organization = @object.provider; catalogService and suite also carry contactPerson; src/manifest.json:500 ModuleDetail md-data include lists 'contactpersoon', 'beschrijvingKort', 'beschrijvingLang', which are not module properties (renamed to contactPerson/shortDescription/longDescription)",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "Applications /modules create/edit form; not shown on ModuleDetail /modules/:id",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "Each product can point at its own contact person of the supplier through the form. The application page's data widget names the old Dutch keys, so the product's contact person (and its descriptions) do not show there; the same stale keys are on SuiteDetail (src/manifest.json:683).",
+ "note": "Each product can point at its own contact person of the supplier through the form. The application page's data widget names the old Dutch keys, so the product's contact person (and its descriptions) do not show there; the same stale keys are on SuiteDetail (src/manifest.json:683). Specified in openspec/changes/landscape-application-page (OpenSpec pass 2026-09-27).",
"evidence": {
"stackiq": "register :6856 module.contactPerson -> contactPerson with x-relation-filter organization = @object.provider; catalogService and suite also carry contactPerson; src/manifest.json:500 ModuleDetail md-data include lists 'contactpersoon', 'beschrijvingKort', 'beschrijvingLang', which are not module properties (renamed to contactPerson/shortDescription/longDescription)",
"topdesk": "unknown: supplier contacts are registered per supplier (\"Registering a supplier contact\"); contacts per product are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -2266,7 +2266,7 @@
"topdesk": "unknown",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "specified",
"evidence": "lib/Settings/softwarecatalogus_register.json usage.moduleVersion ($ref moduleVersion); read by src/views/LifecycleRoadmapView.vue:397 for EOL state; ModuleversieDetail mv-related shows related usages; no usage create/edit page in src/manifest.json",
"owner": "ConductionNL/stackiq"
},
@@ -2275,7 +2275,7 @@
"providerHow": "read-from-code",
"feature": "lifecycle-and-end-of-support",
"featureConfidence": "low",
- "note": "The version an organisation runs is a field on its usage and drives the EOL badges, but no stackiq page lets the organisation set or change it.",
+ "note": "The version an organisation runs is a field on its usage and drives the EOL badges, but no stackiq page lets the organisation set or change it. Specified in openspec/changes/landscape-usage-registration (OpenSpec pass 2026-09-27).",
"evidence": {
"stackiq": "lib/Settings/softwarecatalogus_register.json usage.moduleVersion ($ref moduleVersion); read by src/views/LifecycleRoadmapView.vue:397 for EOL state; ModuleversieDetail mv-related shows related usages; no usage create/edit page in src/manifest.json",
"topdesk": "unknown: versions in use are only possible as a self-defined field; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)",
@@ -2480,7 +2480,7 @@
"topdesk": "partial",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it",
"owner": "ConductionNL/stackiq"
},
@@ -2489,7 +2489,7 @@
"providerHow": "read-from-code",
"feature": "contract-administration",
"featureConfidence": "medium",
- "note": "The application page has no contracts list, and a contract links to a usage and a service rather than the application, so there is no path from an application to its contracts in the UI.",
+ "note": "The application page has no contracts list, and a contract links to a usage and a service rather than the application, so there is no path from an application to its contracts in the UI. Specified in openspec/changes/landscape-application-page (OpenSpec pass 2026-09-27).",
"evidence": {
"glpi": "source read at 11.0.9: src/Appliance.php:99 and src/Software.php:131 add the Contract_Item tab (src/Contract_Item.php:43, install/mysql/glpi-empty.sql:1536 glpi_contracts_items) listing every contract of the application. Reached on: Management > Appliances > Contracts tab. Driven on the lab at 11.0.9 (2026-09-26): after linking the contract, the appliance Contracts tab showed \"Lab contract, 2025-01-01, 12 months -> 2025-12-31\".",
"stackiq": "src/manifest.json:491 ModuleDetail widgets: md-data, md-files, md-related, md-compliance, md-versions, ReviewsPanel; no catalogContract list. catalogContract points at service and usage (register :3252), not at module, so the one-hop related panel cannot reach it",
@@ -3249,14 +3249,14 @@
"topdesk": "yes",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "No OIDC/SAML code in lib/ or src/; stackiq creates local Nextcloud users with a password (lib/Service/Stackiq/ContactPersonHandler.php:292)",
- "owner": "ConductionNL/stackiq"
+ "owner": "nextcloud/server"
},
"reachedOn": "nothing reaches it in stackiq; Nextcloud's own user_oidc/user_saml apps would apply platform-wide",
"provider": "nextcloud",
"providerHow": "read-from-code",
- "note": "Stackiq does nothing for single sign-on. A Nextcloud admin can add an identity provider app, but that is the platform, not a stackiq page.",
+ "note": "Stackiq does nothing for single sign-on. A Nextcloud admin can add an identity provider app, but that is the platform, not a stackiq page. Decided no (OpenSpec pass 2026-09-27): Platform capability: Nextcloud signs users in through its identity provider apps (user_oidc, user_saml) for every app, and stackiq users are Nextcloud users. built.owner corrected to nextcloud/server.",
"evidence": {
"glpi": "source read at 11.0.9: src/Auth.php:106 EXTERNAL (web server provided identity, for example a SAML or OIDC module in front of GLPI), src/Auth.php:107 CAS with phpCAS::client at src/Auth.php:557, and src/Auth.php:108 X509 certificates, next to LDAP at src/Auth.php:105. Reached on: Setup > Authentication > Other authentication methods.",
"topdesk": "https://docs.topdesk.com/en/automatic-login-methods.html: \"Single Sign-on via SAML requirements TOPdesk uses OpenSAML 3 for authentication. You can connect all common IdP solutions which support SAML 2.0\" (read 2026-09-26). Reached on: Settings > Login Settings.",
@@ -3278,14 +3278,14 @@
"topdesk": "yes",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/",
- "owner": "ConductionNL/stackiq"
+ "owner": "nextcloud/server"
},
"reachedOn": "nothing reaches it in stackiq; Nextcloud's user_ldap would apply platform-wide",
"provider": "nextcloud",
"providerHow": "read-from-code",
- "note": "Stackiq has no directory sync for users or groups. Nextcloud's LDAP app could do it platform-wide, outside stackiq.",
+ "note": "Stackiq has no directory sync for users or groups. Nextcloud's LDAP app could do it platform-wide, outside stackiq. Decided no (OpenSpec pass 2026-09-27): Platform capability: Nextcloud user_ldap keeps users and groups in step with a directory for every app, and stackiq users and groups are Nextcloud users and groups. built.owner corrected to nextcloud/server.",
"evidence": {
"glpi": "source read at 11.0.9: src/AuthLDAP.php:59 LDAP directories with user import and group import (src/AuthLDAP.php:2816 ldapImportGroup), and the CLI src/Glpi/Console/Ldap/SynchronizeUsersCommand.php:79 ldap:synchronize_users (alias ldap:sync at :80). Reached on: Administration > Users > LDAP directory link; Setup > Authentication > LDAP directories. Driven on the lab at 11.0.9 (2026-09-26): /front/ldap.php offers \"Bulk import users from a LDAP directory\" and \"Synchronizing already imported users\".",
"stackiq": "lib/Service/OrganizationSyncService.php and the 'Organization synchronization' admin section sync catalogue organisations to OpenRegister organisation entities, not users from a directory; no LDAP code in lib/",
@@ -3307,14 +3307,14 @@
"topdesk": "yes",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "decided-no",
"evidence": "src/components/ContactpersonenList.vue:115 'Change Password' opens src/dialogs/ChangePasswordDialog.vue -> POST /api/contactpersonen/change-password -> lib/Controller/ContactpersonenController.php:718, self-reset allowed at :753; GET /api/me (:1578) used only by src/App.vue and OrganisationSwitcher",
- "owner": "ConductionNL/stackiq"
+ "owner": "nextcloud/server"
},
"reachedOn": "Organisations /organisaties card -> contact persons view -> Change Password on your own row",
- "provider": "stackiq",
+ "provider": "nextcloud",
"providerHow": "read-from-code",
- "note": "A user can change their own password from their contact row in the organisation card, which is hard to find. There is no 'my account' page in stackiq; /api/me feeds only the organisation switcher. Nextcloud's personal settings do both natively.",
+ "note": "A user can change their own password from their contact row in the organisation card, which is hard to find. There is no 'my account' page in stackiq; /api/me feeds only the organisation switcher. Nextcloud's personal settings do both natively. Decided no (OpenSpec pass 2026-09-27): Platform capability: Nextcloud personal settings let every user change their password and see their account details. The stackiq half (change password from your own contact row) stays as built evidence. built.owner corrected to nextcloud/server, provider nextcloud.",
"evidence": {
"stackiq": "src/components/ContactpersonenList.vue:115 'Change Password' opens src/dialogs/ChangePasswordDialog.vue -> POST /api/contactpersonen/change-password -> lib/Controller/ContactpersonenController.php:718, self-reset allowed at :753; GET /api/me (:1578) used only by src/App.vue and OrganisationSwitcher",
"topdesk": "https://docs.topdesk.com/en/editing-your-personal-profile.html: \"Click on Personal Profile . In the General and Private section, you can edit your personal information. In the Change password section, you can change your password\" (read 2026-09-26). Reached on: Profile picture > Personal Profile.",
@@ -4024,14 +4024,14 @@
"topdesk": "partial",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "No discovery agent or agent-ingest endpoint in lib/ or appinfo/routes.php. The nearest capability is SBOM import per module version (lib/Controller/SbomController.php:129), which records components of a known release, not installed software.",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "Stackiq is a catalogue, and nothing discovers installed software.",
+ "note": "Stackiq is a catalogue, and nothing discovers installed software. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Agent-based discovery of installed software is a discovery agent.",
"evidence": {
"glpi": "source read at 11.0.9: native inventory receives glpi-agent submissions at src/Glpi/Controller/InventoryController.php:61 /Inventory (legacy :62 /front/inventory.php), processed by src/Glpi/Inventory/Inventory.php:106 with src/Glpi/Inventory/Asset/Software.php creating software and installations. The agent is the separate glpi-project/glpi-agent repository. Reached on: Administration > Inventory; Assets > Software.",
"stackiq": "No discovery agent or agent-ingest endpoint in lib/ or appinfo/routes.php. The nearest capability is SBOM import per module version (lib/Controller/SbomController.php:129), which records components of a known release, not installed software.",
@@ -4053,14 +4053,14 @@
"topdesk": "partial",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "No network scanning code in lib/ or routes (appinfo/routes.php).",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "No device discovery.",
+ "note": "No device discovery. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Network device discovery is a discovery agent.",
"evidence": {
"glpi": "source read at 11.0.9: src/Glpi/Inventory/Request.php:97 NETDISCOVERY_ACTION calls src/Glpi/Inventory/Request.php:237 networkDiscovery, importing devices found by the agent's network discovery; scheduling discovery tasks from the server goes through the HANDLE_NETDISCOVERY_TASK hook (src/Glpi/Inventory/Request.php:448), which the separate glpiinventory plugin implements. Reached on: Administration > Inventory; Assets > Network devices.",
"stackiq": "No network scanning code in lib/ or routes (appinfo/routes.php).",
@@ -4082,14 +4082,14 @@
"topdesk": "unknown",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "No SaaS or SSO-log discovery code in lib/; lib/Settings/connections.json has no such source.",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "No discovery of unregistered SaaS use.",
+ "note": "No discovery of unregistered SaaS use. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Discovering unregistered SaaS use is a discovery agent.",
"evidence": {
"sap-leanix": "https://help.sap.com/docs/leanix/ea/saas-discovery: 'SaaS discovery identifies your organization's SaaS applications through integrations with third-party systems like Single-Sign-on (SSO) ... Eliminate shadow IT and business-managed IT' (read 2026-09-26). Reached on: Discovery > SaaS discovery inbox.",
"stackiq": "No SaaS or SSO-log discovery code in lib/; lib/Settings/connections.json has no such source.",
@@ -4198,14 +4198,14 @@
"topdesk": "yes",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "No incident or request schema or endpoint in lib/Settings/softwarecatalogus_register.json or appinfo/routes.php.",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "No ticketing.",
+ "note": "No ticketing. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Logging incidents and requests is a service desk. Exchange with the organisation's service desk is specified under share-itsm-integration.",
"evidence": {
"glpi": "source read at 11.0.9: src/autoload/CFG_GLPI.php:301 ticket_types includes Appliance (line 305), so tickets link to an application through src/Item_Ticket.php:41, shown on the appliance Tickets tab (src/Appliance.php:105). Reached on: Assistance > Tickets; Appliance > Tickets tab. Driven on the lab at 11.0.9 (2026-09-26): the default Super-Admin profile lists Computer, Monitor, NetworkEquipment, Peripheral, Phone, Printer, Software, DCRoom, Rack, Enclosure and Database as associable to tickets, not Appliance, so an appliance shows no Tickets tab until an administrator adds it in the profile; rating kept.",
"topdesk": "https://docs.topdesk.com/en/linking-assets-to-cards.html: \"On Call, Change (Activity) ... cards, you can link multiple assets\" (read 2026-09-26). Reached on: Call card > Links > Assets.",
@@ -4227,14 +4227,14 @@
"topdesk": "yes",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "No change-request workflow for applications. The only approval flow is for contracts: src/components/contracts/ContractApprovalPanel.vue on ContractDetail via /api/contracts/{uuid}/approval (routes.php:35-37), delegated to decidiq.",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "Contracts go through an approval, but changes to an application do not.",
+ "note": "Contracts go through an approval, but changes to an application do not. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Change approval workflows are service desk change management.",
"evidence": {
"glpi": "source read at 11.0.9: changes link to the appliance (src/Appliance.php:107 Change_Item tab) and go through approvals, src/ChangeValidation.php:39 ChangeValidation extends CommonITILValidation. Reached on: Assistance > Changes; Appliance > Changes tab.",
"topdesk": "https://docs.topdesk.com/en/requesting-a-change.html: \"A Preliminary Request for Change can only be dealt with as a Request for Change after it is authorized\" (read 2026-09-26). Reached on: Modules > Change Management.",
@@ -4256,14 +4256,14 @@
"topdesk": "yes",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "catalogContract.contractType enum includes 'SLA' (lib/Settings/softwarecatalogus_register.json:3344) as a label only; no service-level target, measurement or breach fields in any schema.",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "A contract can be typed as SLA, but no service level targets are recorded or tracked.",
+ "note": "A contract can be typed as SLA, but no service level targets are recorded or tracked. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" The competitor evidence tracks service desk response and resolution targets on calls and tickets.",
"evidence": {
"glpi": "source read at 11.0.9: src/SLM.php:42 service level management with src/SLA.php:44 SLA and OLA targets on tickets (install/mysql/glpi-empty.sql:7304 glpi_tickets.slas_id_ttr), assigned by business rules (src/RuleCommonITILObject.php:73) that can key on the linked appliance (src/RuleCommonITILObject.php:305 assign_appliance). Reached on: Setup > Service levels.",
"topdesk": "https://docs.topdesk.com/en/track-when-you-respond-to-calls, response-times.html: \"you register and track how quickly your operators need to respond ... you need a Contract Management and SLM license\" (read 2026-09-26). Reached on: Contract Management and SLM.",
@@ -4285,14 +4285,14 @@
"topdesk": "yes",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls.",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
"provider": "stackiq",
"providerHow": "read-from-code",
- "note": "End users cannot request software.",
+ "note": "End users cannot request software. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" A self-service portal where end users request software is a service desk.",
"evidence": {
"topdesk": "https://docs.topdesk.com/en/mobile-access-to-the-self-service-portal.html: \"The SSP layout is suited to be displayed in a mobile interface\" (read 2026-09-26); https://tip.topdesk.com/c/86-webshop-is-connected-with-asset-management: roadmap card in column \"Building\", \"End-user can order items which are in Asset Management\" (read 2026-09-26); pricing lists \"Self-Service Portal\" and \"Webshop\". Reached on: Self-Service Portal.",
"stackiq": "No software-request flow. The only public intake is organisation self-registration (lib/Controller/IntakeController.php, POST /api/intake/register, routes.php:214), which no src/ page calls.",
@@ -4523,7 +4523,7 @@
"originUrl": "https://www.tenderned.nl/aankondigingen/overzicht/418890",
"stackiq": "partial",
"built": {
- "state": "built",
+ "state": "decided-no",
"evidence": "lib/Settings/softwarecatalogus_register.json:7307 module authorization.read grants group public once publicationDate has passed (same rule as share-public-browse); no stackiq route or page serves it anonymously, the public surface is OpenRegister's objects API and the external VNG frontend",
"owner": "ConductionNL/stackiq"
},
@@ -4532,7 +4532,7 @@
"providerHow": "read-from-code",
"feature": "offering-and-usage-listings",
"featureConfidence": "medium",
- "note": "Standard municipal tender text (Noordwijk 418890, Reimerswaal 417169, FUMO 415897, HLT Samen 383984): a supplier inside the GEMMA scope can make its product information transparent through the Softwarecatalogus. stackiq publishes the data; the page a buyer opens lives in the external frontend.",
+ "note": "Standard municipal tender text (Noordwijk 418890, Reimerswaal 417169, FUMO 415897, HLT Samen 383984): a supplier inside the GEMMA scope can make its product information transparent through the Softwarecatalogus. stackiq publishes the data; the page a buyer opens lives in the external frontend. Decided no (OpenSpec pass 2026-09-27): Recorded design: README.md:266 says stackiq runs \"with a separate React-based public frontend\", and README.md:273 names it (ConductionNL/tilburg-woo-ui) as the public search and detail pages. The missing half is the public page a buyer opens, which that frontend serves; stackiq publishes the data (module read rule for group public after publicationDate).",
"vng-softwarecatalogus": "yes",
"evidence": {
"vng-softwarecatalogus": "https://www.softwarecatalogus.nl/Gebruikershandleiding_leverancier: \"De leveranciersinformatie in de Softwarecatalogus is openbaar\" (read 2026-09-26); https://www.softwarecatalogus.nl/inkoopondersteuning%20standaarden: \"De gegenereerde bestekstekst kunt u gebruiken in uw offerte-uitvraag ... Als informatiebron is de GEMMA softwarecatalogus gebruikt\" (read 2026-09-26). Reached on: Supplier login > Productportfolio; Inkoopondersteuning.",
@@ -4765,12 +4765,12 @@
"originUrl": "https://github.com/VNG-Realisatie/Softwarecatalogus/issues/104",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "no impersonation in lib/ or src/ (grep impersonat); stackiq relies on Nextcloud users",
- "owner": "ConductionNL/stackiq"
+ "owner": "nextcloud/server"
},
"reachedOn": "nothing reaches it",
- "provider": "stackiq",
+ "provider": "nextcloud",
"providerHow": "read-from-code",
"featureConfidence": "medium",
"vng-softwarecatalogus": "unknown",
@@ -4781,7 +4781,7 @@
"glpi": "source read at 11.0.9: src/Session.php:2054 startImpersonating and :2113 stopImpersonating, allowed by src/Session.php:1995 canImpersonate for users with fewer rights and the Impersonate right (src/User.php:6235); the button 'Impersonate' is on the user form (src/User.php:2974). CHANGELOG.md 11.0.0 adds the dedicated right. Reached on: Administration > Users > user form, Impersonate.",
"topdesk": "unknown: acting as another user is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26. Decided no (OpenSpec pass 2026-09-27): Platform capability: the Nextcloud Impersonate app lets an administrator sign in as another account, and stackiq relies on Nextcloud users. built.owner corrected to nextcloud/server, provider nextcloud.",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
"glpi": "yes",
@@ -4825,7 +4825,7 @@
"originUrl": "https://www.softwarecatalogus.nl/gebruikersonderzoek%202021",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "moduleVersion (lib/Settings/softwarecatalogus_register.json) is created on the Moduleversies index form; no copy of a version with its connections and no carry-over logic in lib/Service/ModuleVersionService.php",
"owner": "ConductionNL/stackiq"
},
@@ -4841,7 +4841,7 @@
"glpi": "source read at 11.0.9: installations can be moved to another version by the massive action src/Item_SoftwareVersion.php:179 move_version, but impact relations (install/mysql/glpi-empty.sql:1247 glpi_impactrelations) point at the item and are never copied to a replacing version or appliance; grep -n 'Impact' src/SoftwareVersion.php returns nothing.",
"topdesk": "unknown: versions of applications are not modelled; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26.",
+ "note": "Mined from vng-softwarecatalogus (featureRequest) on 2026-09-26. Specified in openspec/changes/connections-derived-dependencies (OpenSpec pass 2026-09-27).",
"sap-leanix": "partial",
"bluedolphin": "unknown",
"glpi": "no",
@@ -4883,10 +4883,10 @@
"name": "Make the options of one field depend on another, such as model depending on brand.",
"origin": "roadmap",
"originUrl": "https://tip.topdesk.com/c/87-field-dependencies-brand-type-model-",
- "stackiq": "no",
+ "stackiq": "partial",
"built": {
- "state": "none",
- "evidence": "register properties are independent enums; no dependent option lists in lib/Settings/softwarecatalogus_register.json",
+ "state": "specified",
+ "evidence": "Relation pickers already follow another field on the form: module.contactPerson x-relation-filter {organization: @object.provider}, catalogService.modules and contactPerson on @object.provider, usage.moduleVersion on @object.module (lib/Settings/softwarecatalogus_register.json), honoured by the library form (@conduction/nextcloud-vue 2.57.1 src/components/CnFormDialog/CnFormDialog.vue:1183 relationFilterDecls). No enum property declares dependent values (x-openregister-dependent-values, openregister lib/Service/Rules/DependentValueTable.php), and the library form does not read that annotation.",
"owner": "ConductionNL/stackiq"
},
"reachedOn": "nothing reaches it",
@@ -4901,7 +4901,7 @@
"bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; questionnaire field options depending on another field are not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: native forms show or hide questions on conditions (src/Glpi/Form/Condition/Engine.php:138, src/Glpi/Form/Condition/VisibilityStrategy.php:39), but options of one field do not filter by another on item forms; the open requests github.com/glpi-project/roadmap/discussions/414 (cascading filters) and /240 (custom field conditions) ask for it. Reached on: Administration > Forms, question conditions."
},
- "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "note": "Mined from topdesk (roadmap) on 2026-09-26. Corrected 2026-09-27 (OpenSpec pass): partial, not no. Relation pickers depend on another field (the version picker follows the application, the contact person follows the supplier); enum options do not. Missing half specified in landscape-dependent-field-options. Specified in openspec/changes/landscape-dependent-field-options (OpenSpec pass 2026-09-27).",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4915,7 +4915,7 @@
"originUrl": "https://tip.topdesk.com/c/89-changing-the-type-of-an-asset",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "each entry lives in one schema (module, catalogService, suite) and no action moves an object to another schema",
"owner": "ConductionNL/stackiq"
},
@@ -4931,7 +4931,7 @@
"bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; changing the type of a BPMN element is documented (https://help.bluedolphin.io/en/articles/11967561-add-an-object), changing the object definition of an existing repository object is not (read 2026-09-26)",
"glpi": "source read at 11.0.9: the type of an appliance is an editable dropdown (install/mysql/glpi-empty.sql:8941 appliancetypes_id), changeable in place or by massive update (src/MassiveAction.php:666); changing the itemtype itself (for example a custom asset to another definition) is not possible, since each custom asset class is bound to one definition (src/Glpi/Asset/Asset.php:113), and the open request github.com/glpi-project/roadmap/discussions/232 asks for it. Reached on: Management > Appliances, Type field."
},
- "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "note": "Mined from topdesk (roadmap) on 2026-09-26. Specified in openspec/changes/landscape-change-entry-type (OpenSpec pass 2026-09-27).",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4945,7 +4945,7 @@
"originUrl": "https://tip.topdesk.com/c/252-audit-logging-for-topdesk-mcp-server",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "stackiq has no AI or MCP integration of its own (see share-ai-assistant); the History tab (widget type audit, src/manifest.json:436) shows every change per object but does not single out actions an assistant took",
"owner": "ConductionNL/stackiq"
},
@@ -4961,7 +4961,7 @@
"bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; the MCP server is read only (https://help.bluedolphin.io/en/articles/15602927-add-bluedolphin-mcp-server-to-an-ai-assistant) and AI credit usage is reported, but a log of AI actions on records is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: there is no AI assistant in core (grep -rliw 'llm\\|mcp' over src/ returns nothing); the history log (src/Log.php:48) records changes per user or API client, without any AI actor."
},
- "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "note": "Mined from topdesk (roadmap) on 2026-09-26. Specified in open change openspec/changes/mcp-full-action-surface (OpenSpec pass 2026-09-27).",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -4975,7 +4975,7 @@
"originUrl": "https://tip.topdesk.com/c/162-support-multi-factor-authentication-mfa-",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "no sign-in code in stackiq; stackiq creates local Nextcloud users (lib/Service/Stackiq/ContactPersonHandler.php:292) and second factors come from Nextcloud two-factor apps platform-wide, as with org-sso",
"owner": "nextcloud/server"
},
@@ -4991,7 +4991,7 @@
"sap-leanix": "unknown: docs searched at https://help.sap.com/docs/leanix/ea for multi factor and two factor, no hits; strong sign in is left to the identity provider through SSO (https://help.sap.com/docs/leanix/ea/managing-users) (read 2026-09-26)",
"bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/ for multi factor and two factor, no hits; strong sign in is left to the SSO identity provider (read 2026-09-26)"
},
- "note": "Mined from topdesk (roadmap) on 2026-09-26. Also mined from glpi (changelog, https://github.com/glpi-project/glpi/releases/tag/11.0.0).",
+ "note": "Mined from topdesk (roadmap) on 2026-09-26. Also mined from glpi (changelog, https://github.com/glpi-project/glpi/releases/tag/11.0.0). Decided no (OpenSpec pass 2026-09-27): Owed to nextcloud/server: Nextcloud two-factor apps require a second factor at sign-in for every app, and stackiq users are Nextcloud users.",
"glpi": "yes",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
@@ -5005,7 +5005,7 @@
"originUrl": "https://tip.topdesk.com/c/163-enforce-strong-passwords",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "stackiq sets passwords through lib/Controller/ContactpersonenController.php:718 change-password and relies on Nextcloud for rules; a strength policy is the Nextcloud password_policy app, platform-wide",
"owner": "nextcloud/server"
},
@@ -5021,7 +5021,7 @@
"bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; local passwords are managed in 'BlueDolphin's private Active Directory' (https://help.bluedolphin.io/en/articles/11967616-user-management) but no password policy setting is documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: Setup > General > Security enables a password policy (templates/pages/setup/general/security_setup.html.twig:46 use_password_security, :56 password_min_length, :63 password_need_number, :70 password_need_letter), enforced by src/User.php:7187 validatePassword with checks for length, digits, letters, capitals and symbols (src/User.php:7196 onwards), plus expiry settings (install/empty_data.php:380 password_expiration_delay). Reached on: Setup > General > Security."
},
- "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "note": "Mined from topdesk (roadmap) on 2026-09-26. Decided no (OpenSpec pass 2026-09-27): Owed to nextcloud/server: the Nextcloud password_policy app enforces password rules for every local account, including the ones stackiq creates.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "unknown",
@@ -5035,7 +5035,7 @@
"originUrl": "https://tip.topdesk.com/c/241-ai-risk-prediction-",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "decided-no",
"evidence": "stackiq runs no changes and scores no risk (see ops-change)",
"owner": "ConductionNL/stackiq"
},
@@ -5051,7 +5051,7 @@
"bluedolphin": "unknown: docs searched at https://help.bluedolphin.io/en/; change risk scoring is not documented (read 2026-09-26)",
"glpi": "source read at 11.0.9: changes carry manual urgency, impact and priority (install/mysql/glpi-empty.sql:659 urgency, :660 impact, :661 priority) and a free text impact analysis (:663 impactcontent); no score is computed from past outcomes or dependencies, and grep -rli 'risk' over src/Change.php returns nothing."
},
- "note": "Mined from topdesk (roadmap) on 2026-09-26.",
+ "note": "Mined from topdesk (roadmap) on 2026-09-26. Decided no (OpenSpec pass 2026-09-27): Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" A risk score for a planned change belongs to service desk change management, which stackiq does not run.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"bluedolphin": "unknown",
@@ -5065,7 +5065,7 @@
"originUrl": "https://github.com/glpi-project/roadmap/discussions/336",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "connections are registered one at a time or arrive through the ArchiMate import (lib/Service/ArchiMateImportService.php); nothing derives dependencies from known relations",
"owner": "ConductionNL/stackiq"
},
@@ -5081,7 +5081,7 @@
"bluedolphin": "https://help.bluedolphin.io/en/articles/11967645-use-datasource-to-create-relationships: 'how to automatically create relationships between objects based on a loaded datasource', for example application component to node (read 2026-09-26). Reached on: Admin > Sources > relationship creation.",
"topdesk": "unknown: relations are created by hand in the Relationships widget; automatic filling is not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "note": "Mined from glpi (featureRequest) on 2026-09-26.",
+ "note": "Mined from glpi (featureRequest) on 2026-09-26. Specified in openspec/changes/connections-derived-dependencies (OpenSpec pass 2026-09-27).",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "yes",
"bluedolphin": "yes",
@@ -5275,7 +5275,7 @@
"originUrl": "https://updates.leanix.net/announcements/discover-verify-and-govern-ai-assets-with-sap-ai-agent-hub",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "no schema for AI agents or models in lib/Settings/softwarecatalogus_register.json (20 schemas, none for AI systems)",
"owner": "ConductionNL/stackiq"
},
@@ -5291,7 +5291,7 @@
"glpi": "source read at 11.0.9: no AI system itemtype (grep -rli 'artificial intelligence' over src/ locales/glpi.pot returns nothing); an admin can define an 'AI model' custom asset type (src/Html.php:1330 Setup > Asset definitions, src/Glpi/Asset/AssetDefinition.php) and link it to applications as an Appliance item (src/Appliance_Item.php:45) or impact relation (install/mysql/glpi-empty.sql:1247). There is no process model to link to. Reached on: Setup > Asset definitions, then Appliance > Items tab.",
"topdesk": "unknown: AI agents and models as registered items are not described; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "note": "Mined from sap-leanix (changelog) on 2026-09-26.",
+ "note": "Mined from sap-leanix (changelog) on 2026-09-26. Specified in openspec/changes/landscape-ai-system-inventory (OpenSpec pass 2026-09-27).",
"vng-softwarecatalogus": "unknown",
"bluedolphin": "unknown",
"glpi": "partial",
@@ -5335,7 +5335,7 @@
"originUrl": "https://updates.leanix.net/announcements/answer-your-questions-in-seconds-with-the-enterprise-architecture-assistant",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "no assistant in stackiq lib/ or src/ (see share-ai-assistant, where only OpenRegister's generic MCP endpoint exists outside the app)",
"owner": "ConductionNL/stackiq"
},
@@ -5351,7 +5351,7 @@
"glpi": "source read at 11.0.9: grep -rli 'openai\\|llm\\|artificial intelligence' over src/ returns nothing; search is criteria based only (src/Glpi/Search/Input/QueryBuilder.php:72).",
"topdesk": "https://docs.topdesk.com/en/td-robin-for-operators.html: \"Chat: Ask TOPdesk Robin a question. TOPdesk Robin searches your organization's knowledge base for an answer\" (read 2026-09-26); https://docs.topdesk.com/en/ai-answer-assistant.html: \"The Knowledge Base is the only source for the AI\" (read 2026-09-26). Answers cite knowledge items, not asset or landscape entries. Reached on: Call card > TOPdesk Robin panel."
},
- "note": "Mined from sap-leanix (changelog) on 2026-09-26. Also mined from bluedolphin (changelog, https://bluedolphin.io/product-news/).",
+ "note": "Mined from sap-leanix (changelog) on 2026-09-26. Also mined from bluedolphin (changelog, https://bluedolphin.io/product-news/). Specified in open change openspec/changes/stackiq-mcp-adoption (OpenSpec pass 2026-09-27).",
"bluedolphin": "yes",
"vng-softwarecatalogus": "unknown",
"glpi": "no",
@@ -5365,7 +5365,7 @@
"originUrl": "https://roadmap.leanix.net/c/812-meta-model-eu-ai-act-extension",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "no AI system or AI Act risk property on module or any other schema in lib/Settings/softwarecatalogus_register.json",
"owner": "ConductionNL/stackiq"
},
@@ -5381,7 +5381,7 @@
"glpi": "source read at 11.0.9: grep -rli 'ai act\\|artificial intelligence' over src/ locales/glpi.pot returns nothing; appliances have no risk category field (install/mysql/glpi-empty.sql:8935 glpi_appliances).",
"topdesk": "unknown: the AI Act is mentioned only for TOPdesk's own AI features (\"post-market monitoring procedures ... in accordance with the AI Act\"), not for classifying the customer's AI systems; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "note": "Mined from sap-leanix (roadmap) on 2026-09-26.",
+ "note": "Mined from sap-leanix (roadmap) on 2026-09-26. Specified in openspec/changes/landscape-ai-system-inventory (OpenSpec pass 2026-09-27).",
"vng-softwarecatalogus": "unknown",
"bluedolphin": "unknown",
"glpi": "no",
@@ -5453,11 +5453,11 @@
"name": "Send entries to connected outside systems only once they reach a chosen lifecycle state.",
"origin": "changelog",
"originUrl": "https://bluedolphin.io/blog/november-2025-product-updates-effortless-enterprise-architecture-management/",
- "stackiq": "unknown",
+ "stackiq": "yes",
"built": {
- "state": "none",
- "evidence": "stackiq has no sync code of its own; outgoing events go through OpenRegister flows authored on the Flows page (src/manifest.json:1057, see share-webhooks), and whether a flow can gate on a lifecycle status was not traced",
- "owner": "ConductionNL/stackiq"
+ "state": "built",
+ "evidence": "src/manifest.json:1057 Flows page (entitySource flows, app stackiq) and FlowDetail canvas over OpenRegister's flow store; openregister lib/Service/Flow/Nodes/TriggerObjectNode.php:82 object.updated trigger per register and schema; lib/Service/Flow/Nodes/FilterNode.php:10 and :186 per-item condition (for example the status); integriq lib/Flow/SourceCallNode.php (development) calls the outside source.",
+ "owner": "ConductionNL/openregister"
},
"reachedOn": "nothing reaches it",
"provider": "openregister",
@@ -5471,7 +5471,7 @@
"glpi": "source read at 11.0.9: webhooks carry search criteria filters (src/Webhook.php:64 implements FilterableInterface, src/Glpi/Search/FilterableTrait.php:45) and are only sent when the changed item matches them, src/Webhook.php:1228 itemMatchFilter; filtering on the Status field (src/Appliance.php:350) sends an appliance only once it reaches the chosen state. Reached on: Setup > Webhooks > Filter tab.",
"topdesk": "https://docs.topdesk.com/en/creating-events.html: \"Edit card is triggered when a card is modified. Fill in the conditions ... Conditions check the current value of the card\" (read 2026-09-26); https://docs.topdesk.com/en/let-your-topdesk-talk-to-other-applications.html: \"Send a request from TOPdesk to another program\" (read 2026-09-26). The customer builds it as an automated action; no ready-made lifecycle sync. Reached on: Action Management > events and action sequences."
},
- "note": "Mined from bluedolphin (changelog) on 2026-09-26.",
+ "note": "Mined from bluedolphin (changelog) on 2026-09-26. Matrix corrected (OpenSpec pass 2026-09-27): a flow on the Flows page gates on the lifecycle status before integriq sends the entry; rated yes.",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"glpi": "yes",
@@ -5515,7 +5515,7 @@
"originUrl": "https://bluedolphin.io/blog/june-2026-bluedolphin-updates/",
"stackiq": "no",
"built": {
- "state": "none",
+ "state": "specified",
"evidence": "entries belong to an organisation through OpenRegister multitenancy (see org-data-segregation); no stackiq page or action moves an entry to another organisation or register",
"owner": "ConductionNL/stackiq"
},
@@ -5531,7 +5531,7 @@
"glpi": "source read at 11.0.9: selected records are moved to another entity with their links by src/Transfer.php:50 Transfer, queued through the massive action add_transfer_list (src/MassiveAction.php:598), for one or many entries at once. Reached on: any list, Actions > Add to transfer list; Administration > Entities > transfer.",
"topdesk": "unknown: workspaces are not described; changing an asset's type is still an idea at https://tip.topdesk.com/c/89-changing-the-type-of-an-asset; searched the full-text search index of docs.topdesk.com (https://docs.topdesk.com/en/js/fuzzydata.js, 987 pages) (read 2026-09-26)"
},
- "note": "Mined from bluedolphin (changelog) on 2026-09-26.",
+ "note": "Mined from bluedolphin (changelog) on 2026-09-26. Specified in openspec/changes/landscape-move-between-organisations (OpenSpec pass 2026-09-27).",
"vng-softwarecatalogus": "unknown",
"sap-leanix": "unknown",
"glpi": "yes",
diff --git a/openspec/parity/gap-decisions.json b/openspec/parity/gap-decisions.json
new file mode 100644
index 000000000..e9e45b35d
--- /dev/null
+++ b/openspec/parity/gap-decisions.json
@@ -0,0 +1,674 @@
+[
+ {
+ "row": "arch-definitions",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "arch-export-amef",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (1 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "arch-export-org",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (1 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "arch-import-amef",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (1 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-ai-act-classification",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Below the bar on its own (0 competitor yes, no tender, feature request or roadmap demand), and it rides with land-ai-agent-inventory: its whole capability is an AI Act risk category on the AI system record that change adds.",
+ "change": "landscape-ai-system-inventory",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-audit-questionnaire",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, no demand, outside the core areas (compliance).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-bio-assessment",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-bio-measures",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-bulk-sync-standards",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-common-ground-fit",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, featureRequest demand without a competitor yes, outside the core areas (compliance).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-forum-standaardisatie",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, no demand, outside the core areas (compliance).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-health-scoring",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (SAP LeanIX, BlueDolphin).",
+ "change": "landscape-completeness-score",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-processing-register-generate",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, featureRequest demand without a competitor yes, outside the core areas (compliance).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-retention-cleanup",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, changelog only, which counts as the competitor it names, outside the core areas (compliance).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-security-officer-signoff",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, featureRequest demand without a competitor yes, outside the core areas (compliance).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "comp-verified-vs-claimed",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (1 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-api-catalogue",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: core area (connections).",
+ "change": "connections-api-catalogue",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-auto-populate-dependencies",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (SAP LeanIX, BlueDolphin); featureRequest demand; core area (connections).",
+ "change": "connections-derived-dependencies",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-diagram",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 4 competitors rate yes (SAP LeanIX, BlueDolphin, GLPI, TOPdesk); core area (connections).",
+ "change": "connections-diagram-and-graph-export",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-export-graph",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (GEMMA Softwarecatalogus, GLPI); core area (connections).",
+ "change": "connections-diagram-and-graph-export",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-external-provision",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Below the bar on its own (1 competitor yes, no tender, feature request or roadmap demand), and it rides with conn-list-page: its missing half is a page to fill the field, and the connection form on the new connections page shows it.",
+ "change": "connections-catalogue-pages",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-list-page",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (GEMMA Softwarecatalogus, SAP LeanIX); core area (connections). Marked specified with no change directory; this change is the missing change.",
+ "change": "connections-catalogue-pages",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-per-application",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 3 competitors rate yes (SAP LeanIX, BlueDolphin, GLPI); core area (connections). Partial and built: the change builds the missing half, a connections section on the application page that opens each connection.",
+ "change": "connections-catalogue-pages",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-type-filter",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: core area (connections). Marked specified with no change directory; this change is the missing change.",
+ "change": "connections-catalogue-pages",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ctr-budget",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, no demand, outside the core areas (contracts).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ctr-collective-agreements",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, featureRequest demand without a competitor yes, outside the core areas (contracts).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ctr-depreciation",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, no demand, outside the core areas (contracts).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ctr-effective-licence-position",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, no demand, outside the core areas (contracts).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ctr-linked-contracts",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, featureRequest demand without a competitor yes, outside the core areas (contracts).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ctr-per-application",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (SAP LeanIX, GLPI).",
+ "change": "landscape-application-page",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ctr-saas-spend",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ins-ai-action-audit",
+ "matrix": "stackiq",
+ "decision": "existing",
+ "reason": "Open change mcp-full-action-surface, spec mcp-tool-surface, requires every agent tool invocation on stackiq to land in Hermiq's audit trail, which lists what an assistant did, when and on which record.",
+ "change": "mcp-full-action-surface",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ins-concept-orgs-widget",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, no demand, outside the core areas (insight).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ins-cost-report",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (1 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ins-natural-language-query",
+ "matrix": "stackiq",
+ "decision": "existing",
+ "reason": "Open change stackiq-mcp-adoption declares read-only search and get MCP tools on nine catalogue schemas so Hermiq answers questions about the landscape from the entries it read; mcp-full-action-surface design section 6 grounds the chat scenario. The chat, the answer and its citations are Hermiq's (ADR-034).",
+ "change": "stackiq-mcp-adoption",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ins-scheduled-report",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, no demand, outside the core areas (insight).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ins-usage-analytics",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, changelog only, which counts as the competitor it names, outside the core areas (insight).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-ai-agent-inventory",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: core area (landscape).",
+ "change": "landscape-ai-system-inventory",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-application-modules",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (SAP LeanIX, BlueDolphin); core area (landscape). Partial and built: the change builds the missing half, breaking one application into its components.",
+ "change": "landscape-application-components",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-application-owner",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (SAP LeanIX, GLPI); core area (landscape). Partial and built: the change builds the missing half, a separate business owner and technical owner for the organisation that uses the application, on its usage.",
+ "change": "landscape-usage-registration",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-bulk-edit",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (1 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-change-entry-type",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: roadmap demand; core area (landscape).",
+ "change": "landscape-change-entry-type",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-completeness-score",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (SAP LeanIX, BlueDolphin); core area (landscape).",
+ "change": "landscape-completeness-score",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-data-quality-survey",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (SAP LeanIX, BlueDolphin); core area (landscape).",
+ "change": "landscape-owner-attestation",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-dependent-fields",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: roadmap demand (https://tip.topdesk.com/c/87-field-dependencies-brand-type-model-); core area (landscape). Matrix corrected to partial while re-reading the code: relation pickers already follow another field (CnFormDialog relationFilterDecls, usage.moduleVersion on @object.module); the change builds the missing half, dependent enum options declared with OpenRegister x-openregister-dependent-values.",
+ "change": "landscape-dependent-field-options",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-detail-page",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (SAP LeanIX, BlueDolphin); core area (landscape). Partial and built: the change builds the missing half, contracts on the application page, opening it from the Applications list, and the stale field keys.",
+ "change": "landscape-application-page",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-guided-wizard",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-move-between-workspaces",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (BlueDolphin, GLPI); core area (landscape).",
+ "change": "landscape-move-between-organisations",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-register-application",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 4 competitors rate yes (GEMMA Softwarecatalogus, SAP LeanIX, BlueDolphin, GLPI); core area (landscape). Partial and built: the change builds the missing half, a lifecycle status for the application an organisation uses, set on a usage page.",
+ "change": "landscape-usage-registration",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-sectors",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: aanvullende-informatie.md:511 lists VNG issue #4 (classify packages on the reference architectures of the relevant sectors, so buyers from several sectors find them) with the analysis \"Classificeren op meerdere sectorale referentiearchitecturen, buiten scope\", and issues/4.md carries the label \"Buiten scope oplevering\" and is closed. Tagging applications with sectors is the entry to that out-of-scope classification. The unused sector schema (lib/Settings/softwarecatalogus_register.json:1036) is what the specified state pointed at; no change directory existed.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "land-version-carry-connections",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: featureRequest demand; core area (landscape).",
+ "change": "connections-derived-dependencies",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "life-dates-follow-status",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, featureRequest demand without a competitor yes, outside the core areas (lifecycle).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "life-strategy-link",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, no demand, outside the core areas (lifecycle).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "life-version-in-use",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Build: 2 competitors rate yes (GEMMA Softwarecatalogus, GLPI). Partial and built: the change builds the missing half, a usage page where the organisation sets the version it runs.",
+ "change": "landscape-usage-registration",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "life-version-tolerance",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, roadmap demand without a competitor yes, outside the core areas (lifecycle).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "mkt-contact-peers",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, no demand, outside the core areas (market).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "mkt-contacts-per-product",
+ "matrix": "stackiq",
+ "decision": "build",
+ "reason": "Below the bar on its own (0 competitor yes, no tender, feature request or roadmap demand), and it rides with land-detail-page: its missing half is the stale contactpersoon key on the application page, which that change corrects.",
+ "change": "landscape-application-page",
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "mkt-side-by-side-compare",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, featureRequest demand without a competitor yes, outside the core areas (market).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "mkt-tender-product-info",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded design: README.md:266 says stackiq runs \"with a separate React-based public frontend\", and README.md:273 names it (ConductionNL/tilburg-woo-ui) as the public search and detail pages. The missing half is the public page a buyer opens, which that frontend serves; stackiq publishes the data (module read rule for group public after publicationDate).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-agent-inventory",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Agent-based discovery of installed software is a discovery agent.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-change",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Change approval workflows are service desk change management.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-change-risk-score",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" A risk score for a planned change belongs to service desk change management, which stackiq does not run.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-mobile",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, no demand, outside the core areas (operations).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-network-discovery",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Network device discovery is a discovery agent.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-saas-discovery",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Discovering unregistered SaaS use is a discovery agent.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-self-service",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" A self-service portal where end users request software is a service desk.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-sla",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" The competitor evidence tracks service desk response and resolution targets on calls and tickets.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "ops-tickets",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Recorded non-goal: openspec/parity/capabilities.json category: \"It is not a discovery agent, a service desk or a developer portal, and the operations area exists to record that on purpose.\" Logging incidents and requests is a service desk. Exchange with the organisation's service desk is specified under share-itsm-integration.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "org-act-as-user",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Platform capability: the Nextcloud Impersonate app lets an administrator sign in as another account, and stackiq relies on Nextcloud users. built.owner corrected to nextcloud/server, provider nextcloud.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "org-activation-mail",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (1 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "org-assigned-only-rights",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: single competitor, changelog only, which counts as the competitor it names, outside the core areas (organisations).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "org-directory-sync",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Platform capability: Nextcloud user_ldap keeps users and groups in step with a directory for every app, and stackiq users and groups are Nextcloud users and groups. built.owner corrected to nextcloud/server.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "org-merge",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "org-password-change",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Platform capability: Nextcloud personal settings let every user change their password and see their account details. The stackiq half (change password from your own contact row) stays as built evidence. built.owner corrected to nextcloud/server, provider nextcloud.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "org-sso",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Platform capability: Nextcloud signs users in through its identity provider apps (user_oidc, user_saml) for every app, and stackiq users are Nextcloud users. built.owner corrected to nextcloud/server.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "sec-affected-versions",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "sec-patch-status",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, no demand, outside the core areas (security).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "sec-risk-score",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "Defer: no competitor rates yes, no demand, outside the core areas (security).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "share-federation-peers",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "share-lifecycle-conditional-sync",
+ "matrix": "stackiq",
+ "decision": "existing",
+ "reason": "matrix corrected: stackiq's Flows page (src/manifest.json:1057, OpenRegister's flow store scoped to stackiq) composes an object trigger on object.updated (openregister lib/Service/Flow/Nodes/TriggerObjectNode.php:82), a per-item Filter on the lifecycle status (FilterNode.php:10, :186) and integriq's source call node (integriq lib/Flow/SourceCallNode.php on development). Rating set to yes, built.owner ConductionNL/openregister.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "share-publish",
+ "matrix": "stackiq",
+ "decision": "defer",
+ "reason": "partial, built, no demand (0 competitor yes, no tender, feature request or roadmap row).",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "sec-multi-factor-sign-in",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Owed to nextcloud/server: Nextcloud two-factor apps require a second factor at sign-in for every app, and stackiq users are Nextcloud users.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "sec-password-policy",
+ "matrix": "stackiq",
+ "decision": "decided-no",
+ "reason": "Owed to nextcloud/server: the Nextcloud password_policy app enforces password rules for every local account, including the ones stackiq creates.",
+ "change": null,
+ "decidedOn": "2026-09-27"
+ },
+ {
+ "row": "conn-integration-registry",
+ "matrix": "stackiq",
+ "decision": "existing",
+ "reason": "Owned by ConductionNL/integriq. Its open change connection-registry covers the integrations overview; stackiq's half is the open change adopt-connection-registry (19 of 20 tasks). Recorded as instructed by the coordinator; the matrix row is the integriq lane's to set.",
+ "change": "connection-registry (ConductionNL/integriq)",
+ "decidedOn": "2026-09-27"
+ }
+]
From e2d38aa61a64d5681e6b22813a10aa6e20af6869 Mon Sep 17 00:00:00 2001
From: Ruben van der Linde
Date: Sun, 27 Sep 2026 20:25:28 +0200
Subject: [PATCH 31/45] docs(openspec): OpenSpec pass batch 2, architecture and
lifecycle changes (#1109)
* docs(openspec): architecture-views-editor, draw, tag and compare views on CnGraphCanvas
* docs(openspec): architecture-views-editor, readers keep only imported or empty origin
* docs(openspec): architecture-assistant-drafted-views, two MCP tools draft a marked view for review
* docs(openspec): architecture-process-mapping, processes and steps linked to applications in use
* docs(openspec): architecture-data-model-and-ggm, data model pages and GGM entities on applications in use
* docs(openspec): architecture-reference-component-coverage, gaps, overlaps and a coverage map per organisation
* docs(openspec): lifecycle-application-value-assessment, value, fit and risk scores behind the TIME class
* docs(openspec): lifecycle-maintenance-and-supplier-roadmap, maintenance windows, owner notices and a product roadmap
* docs(openspec): architecture-future-state-scenarios, the plan and named scenarios compared with today
* docs(openspec): architecture-decision-register, reviewed decisions as stackiq objects linked to applications
* docs(openspec): architecture-views-editor, guard the single view read that runs without RBAC
* docs(openspec): architecture-views-to-office-documents, SVG from stackiq and office files through filinq
* docs(openspec): architecture-round-trip-check, an admin check that writes nothing replaces the broken round trip
* chore(parity): OpenSpec-pass batch 2 matrix states and decisions
---
.../.openspec.yaml | 2 +
.../design.md | 111 +++++++++++++
.../proposal.md | 47 ++++++
.../architecture-assistant-views/spec.md | 103 ++++++++++++
.../tasks.md | 71 ++++++++
.../.openspec.yaml | 2 +
.../architecture-data-model-and-ggm/design.md | 102 ++++++++++++
.../proposal.md | 45 ++++++
.../specs/data-model-and-ggm/spec.md | 90 +++++++++++
.../architecture-data-model-and-ggm/tasks.md | 70 ++++++++
.../.openspec.yaml | 2 +
.../architecture-decision-register/design.md | 108 +++++++++++++
.../proposal.md | 46 ++++++
.../architecture-decision-register/spec.md | 87 ++++++++++
.../architecture-decision-register/tasks.md | 62 +++++++
.../.openspec.yaml | 2 +
.../design.md | 149 +++++++++++++++++
.../proposal.md | 49 ++++++
.../specs/future-state-scenarios/spec.md | 99 ++++++++++++
.../tasks.md | 72 +++++++++
.../.openspec.yaml | 2 +
.../architecture-process-mapping/design.md | 135 ++++++++++++++++
.../architecture-process-mapping/proposal.md | 48 ++++++
.../specs/business-process-mapping/spec.md | 116 +++++++++++++
.../architecture-process-mapping/tasks.md | 62 +++++++
.../.openspec.yaml | 2 +
.../design.md | 74 +++++++++
.../proposal.md | 47 ++++++
.../reference-component-coverage/spec.md | 97 +++++++++++
.../tasks.md | 80 +++++++++
.../.openspec.yaml | 2 +
.../architecture-round-trip-check/design.md | 69 ++++++++
.../architecture-round-trip-check/proposal.md | 41 +++++
.../specs/archimate-round-trip-check/spec.md | 88 ++++++++++
.../architecture-round-trip-check/tasks.md | 69 ++++++++
.../architecture-views-editor/.openspec.yaml | 2 +
.../architecture-views-editor/design.md | 137 ++++++++++++++++
.../architecture-views-editor/proposal.md | 53 ++++++
.../specs/architecture-views-editor/spec.md | 127 +++++++++++++++
.../architecture-views-editor/tasks.md | 101 ++++++++++++
.../.openspec.yaml | 2 +
.../design.md | 56 +++++++
.../proposal.md | 48 ++++++
.../architecture-view-office-export/spec.md | 77 +++++++++
.../tasks.md | 59 +++++++
.../.openspec.yaml | 2 +
.../design.md | 48 ++++++
.../proposal.md | 41 +++++
.../application-value-assessment/spec.md | 46 ++++++
.../tasks.md | 44 +++++
.../.openspec.yaml | 2 +
.../design.md | 57 +++++++
.../proposal.md | 43 +++++
.../maintenance-and-supplier-roadmap/spec.md | 63 ++++++++
.../tasks.md | 50 ++++++
openspec/parity/capabilities.json | 74 ++++-----
openspec/parity/gap-decisions.json | 152 ++++++++++++++++++
57 files changed, 3498 insertions(+), 37 deletions(-)
create mode 100644 openspec/changes/architecture-assistant-drafted-views/.openspec.yaml
create mode 100644 openspec/changes/architecture-assistant-drafted-views/design.md
create mode 100644 openspec/changes/architecture-assistant-drafted-views/proposal.md
create mode 100644 openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md
create mode 100644 openspec/changes/architecture-assistant-drafted-views/tasks.md
create mode 100644 openspec/changes/architecture-data-model-and-ggm/.openspec.yaml
create mode 100644 openspec/changes/architecture-data-model-and-ggm/design.md
create mode 100644 openspec/changes/architecture-data-model-and-ggm/proposal.md
create mode 100644 openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md
create mode 100644 openspec/changes/architecture-data-model-and-ggm/tasks.md
create mode 100644 openspec/changes/architecture-decision-register/.openspec.yaml
create mode 100644 openspec/changes/architecture-decision-register/design.md
create mode 100644 openspec/changes/architecture-decision-register/proposal.md
create mode 100644 openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md
create mode 100644 openspec/changes/architecture-decision-register/tasks.md
create mode 100644 openspec/changes/architecture-future-state-scenarios/.openspec.yaml
create mode 100644 openspec/changes/architecture-future-state-scenarios/design.md
create mode 100644 openspec/changes/architecture-future-state-scenarios/proposal.md
create mode 100644 openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md
create mode 100644 openspec/changes/architecture-future-state-scenarios/tasks.md
create mode 100644 openspec/changes/architecture-process-mapping/.openspec.yaml
create mode 100644 openspec/changes/architecture-process-mapping/design.md
create mode 100644 openspec/changes/architecture-process-mapping/proposal.md
create mode 100644 openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md
create mode 100644 openspec/changes/architecture-process-mapping/tasks.md
create mode 100644 openspec/changes/architecture-reference-component-coverage/.openspec.yaml
create mode 100644 openspec/changes/architecture-reference-component-coverage/design.md
create mode 100644 openspec/changes/architecture-reference-component-coverage/proposal.md
create mode 100644 openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md
create mode 100644 openspec/changes/architecture-reference-component-coverage/tasks.md
create mode 100644 openspec/changes/architecture-round-trip-check/.openspec.yaml
create mode 100644 openspec/changes/architecture-round-trip-check/design.md
create mode 100644 openspec/changes/architecture-round-trip-check/proposal.md
create mode 100644 openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md
create mode 100644 openspec/changes/architecture-round-trip-check/tasks.md
create mode 100644 openspec/changes/architecture-views-editor/.openspec.yaml
create mode 100644 openspec/changes/architecture-views-editor/design.md
create mode 100644 openspec/changes/architecture-views-editor/proposal.md
create mode 100644 openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md
create mode 100644 openspec/changes/architecture-views-editor/tasks.md
create mode 100644 openspec/changes/architecture-views-to-office-documents/.openspec.yaml
create mode 100644 openspec/changes/architecture-views-to-office-documents/design.md
create mode 100644 openspec/changes/architecture-views-to-office-documents/proposal.md
create mode 100644 openspec/changes/architecture-views-to-office-documents/specs/architecture-view-office-export/spec.md
create mode 100644 openspec/changes/architecture-views-to-office-documents/tasks.md
create mode 100644 openspec/changes/lifecycle-application-value-assessment/.openspec.yaml
create mode 100644 openspec/changes/lifecycle-application-value-assessment/design.md
create mode 100644 openspec/changes/lifecycle-application-value-assessment/proposal.md
create mode 100644 openspec/changes/lifecycle-application-value-assessment/specs/application-value-assessment/spec.md
create mode 100644 openspec/changes/lifecycle-application-value-assessment/tasks.md
create mode 100644 openspec/changes/lifecycle-maintenance-and-supplier-roadmap/.openspec.yaml
create mode 100644 openspec/changes/lifecycle-maintenance-and-supplier-roadmap/design.md
create mode 100644 openspec/changes/lifecycle-maintenance-and-supplier-roadmap/proposal.md
create mode 100644 openspec/changes/lifecycle-maintenance-and-supplier-roadmap/specs/maintenance-and-supplier-roadmap/spec.md
create mode 100644 openspec/changes/lifecycle-maintenance-and-supplier-roadmap/tasks.md
diff --git a/openspec/changes/architecture-assistant-drafted-views/.openspec.yaml b/openspec/changes/architecture-assistant-drafted-views/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-assistant-drafted-views/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-assistant-drafted-views/design.md b/openspec/changes/architecture-assistant-drafted-views/design.md
new file mode 100644
index 000000000..9fcfd90f5
--- /dev/null
+++ b/openspec/changes/architecture-assistant-drafted-views/design.md
@@ -0,0 +1,111 @@
+# Design: architecture-assistant-drafted-views
+
+Read at development 49e65cb4, with the open changes `architecture-views-editor` and `mcp-full-action-surface` as the ground this change stands on.
+
+## Where it fits
+
+| Layer | Touched | Notes |
+|---|---|---|
+| MCP provider | `lib/Mcp/StackiqToolProvider.php` (created by `mcp-full-action-surface`, its `tasks.md` 2.1) | two descriptors and two dispatch entries, no logic |
+| Argument checks | `lib/Mcp/McpArgumentValidator.php` (same change, `tasks.md` 2.3) | reused as is |
+| Service | new `lib/Service/ArchitectureViewDraftService.php` | validation, element resolution, relation reuse, writes |
+| Register | new fragment `lib/Settings/register.d/architecture-assistant-drafted-views.json` | appends `assistant` to `origin` on `view`, `element` and `relation`, adds `draftedFor` and `draftedAt` to `view` |
+| Page | `ViewEditor` from `architecture-views-editor` (`src/views/architecture/ArchitectureViewEditor.vue`) | a notice and a first-open layout |
+| Routes | none | the tools are reached through OpenRegister's MCP server (`openregister-ro/appinfo/routes.php:1990`, `POST /api/mcp`) and Hermiq's facade |
+
+The fragment merges through `SettingsService::loadSettings` (`lib/Service/SettingsService.php:1653-1680`). `deepMergeConfig` (:7338) appends list values, so `"enum": ["assistant"]` under `origin` adds the value to the enum `architecture-views-editor` declares. The fragment bumps `view`, `element` and `relation` once more.
+
+## Decisions
+
+### D1. Two curated tools on the provider `mcp-full-action-surface` creates
+
+| Tool id | Delegates to | Scope | Reach | Hints |
+|---|---|---|---|---|
+| `stackiq.searchArchitectureElements` | `ArchitectureViewDraftService::searchElements(query, types, limit)` | read | user | `readOnlyHint: true` |
+| `stackiq.draftView` | `ArchitectureViewDraftService::draftView(name, description, elements, relations)` | create | instance | `readOnlyHint: false`, `destructiveHint: false`, `idempotentHint: false` |
+
+`draftView` is `reach: instance` because a drafted view is visible to the members of the caller's organisation, not only to the caller. Hermiq fail-closes an undeclared reach to `external` (`mcp-full-action-surface` design section 5), so both tools declare one.
+
+Rejected: an `#[McpTool]` attribute on the service method (ADR-063 Decision 2). `mcp-full-action-surface` builds stackiq's tools as a hand-written provider with one argument validator and per-object gates. A second mechanism in the same app would split where a reviewer looks for stackiq's tools.
+
+Rejected: derived `x-openregister-mcp` writes on `view`, `element` and `relation`. Both open MCP changes exclude the AMEF schemas for good reason (`element` has more than 80 properties, and a raw `view.create` would take the node list as free JSON). A draft is a composite write across three schemas, which is what a curated tool is for.
+
+### D2. The input is structure, not a picture
+
+`draftView` takes:
+
+```json
+{
+ "name": "Zaakgericht werken, concept",
+ "description": "How the case system hands documents to document management.",
+ "elements": [
+ { "key": "a", "uuid": "00000000-0000-0000-0000-000000000000" },
+ { "key": "b", "type": "ApplicationComponent", "name": "Documentbeheer" }
+ ],
+ "relations": [
+ { "source": "a", "target": "b", "type": "Flow" }
+ ]
+}
+```
+
+An element names either an existing AMEF element by `uuid` or a new one by ArchiMate `type` and `name`. A relation names two element keys and an ArchiMate relation type. Types come from closed lists in the service: the ArchiMate 3.2 element types and the eleven relation types. A draft holds at most 60 elements and 120 relations. An unknown type, a dangling key or a list over the cap returns a validation error before anything is written.
+
+The result is `{ "uuid": ..., "url": "/apps/stackiq/views/", "created": { "elements": n, "relations": n } }`, so the assistant can hand the user a link.
+
+### D3. The mark is written with the object (ADR-088)
+
+Every object the tool writes carries `origin: assistant` in the same `saveObject` call that creates it: the view, each new element and each new relation. The view also carries `draftedFor` (the Nextcloud user id of the session the tool ran in) and `draftedAt`. There is no second write that could fail after the first, so an unmarked draft cannot exist (ADR-088 Decisions 1 and 5).
+
+ADR-088 Decision 2 asks for the mark in the object's own metadata. OpenRegister's object metadata has no agent or provenance field (`openregister-ro/lib/Db/ObjectEntity.php:174` to :759 holds `owner`, `application`, `organisation` and the like), and `application` reads stackiq for a human save and a tool save alike. So the mark is the schema field `origin`, which the editor already reads and the Views index already facets.
+
+Rejected: an OpenRegister change that adds an agent field to the object metadata. It is the better long-term home, but it is OpenRegister's to design for every app, and stackiq's field can move there later without losing data.
+
+Stackiq does not record which agent drafted the view. `ToolRegistryFacade::invokeTool` passes no agent identity to a provider (`openregister-ro/lib/Service/Mcp/ToolRegistryFacade.php:351-353`). Hermiq's tool trace records the agent with the tool id and the returned view uuid (ADR-088 Decision 3), and OpenRegister's invocation audit records the call (ADR-063 Decision 8). The mark says "an assistant drafted this", the trace says which one.
+
+A person editing a drafted view keeps the mark. The editor shows "Drafted by an assistant for on " on every open, and the Views index shows `assistant` in its origin facet.
+
+### D4. Drafts carry no positions and are laid out on first open
+
+The service writes nodes without `x` and `y`. `ArchitectureViewEditor.vue` checks the nodes with `needsFullLayout` and places them with `layoutFlowNodes` (`@conduction/nextcloud-vue` 2.57.1, `src/composables/flowGraphLayout.js:129` and :329), a deterministic layered layout. The first human save stores the positions. A draft has no nested nodes, so the flat layout fits.
+
+The package root does not export these two helpers: `src/index.js:438` exports `useFlowStore`, which uses them (`src/composables/useFlowStore.js:28`), but not the helpers themselves. The editor imports them through the package's `./src/*` export (`package.json` `exports`), and the vitest spec imports the same path, so a rename in the library fails the test instead of the page.
+
+Rejected: a layout in PHP. It would be a second layout algorithm next to the one the shared library already ships and tests.
+
+### D5. The caller's rights decide
+
+The tool runs in the caller's session (ADR-034 Decision 7). `ArchitectureViewDraftService` writes through OpenRegister's `ObjectService` with RBAC and multitenancy on, so a caller without create rights on `view` gets a forbidden result and nothing is written. The draft is scoped to the caller's active organisation. `searchArchitectureElements` reads the same way, so it only returns elements the caller may see.
+
+### D6. A draft stays out of shared readers
+
+`architecture-views-editor` makes `GET /api/views`, `GET /api/views/{viewId}` and the full ArchiMate export keep only views whose `origin` is empty or `imported`. `assistant` is neither, so a draft is never cached for all callers and never exported with the GEMMA model. This change adds no filter of its own and adds a test that the existing readers skip `assistant`.
+
+## Declarative versus imperative
+
+The draft is imperative: one call writes up to three kinds of object, resolves keys and reuses relations, which no `x-openregister-*` extension expresses. The status stays under the lifecycle `architecture-views-editor` declares, and the tool cannot move it past draft. No notification, aggregation or widget is added.
+
+## Seed data
+
+The fragment changes the `view`, `element` and `relation` schemas, so it seeds one drafted view next to the drawn examples `architecture-views-editor` seeds. All objects live in the `vng-gemma` register.
+
+### Schema: `view`
+
+| Field | Object 1 |
+|---|---|
+| slug | `seed-view-assistant-zaak-dms` |
+| name | Zaaksysteem en documentbeheer, concept van de assistent |
+| status | draft |
+| origin | assistant |
+| draftedFor | admin |
+| draftedAt | 2026-09-27T09:00:00+00:00 |
+| nodes | `seed-el-zaaksysteem` and `seed-el-dms`, without `x` and `y` |
+| connections | one Flow connection that reuses `seed-rel-zaak-dms` |
+
+The seed reuses the drawn example elements and relation, so it adds no element or relation of its own, and a fresh install shows the notice and the first-open layout on a real object.
+
+## Risks
+
+- **A wrong element.** The assistant may pick a GEMMA element that does not mean what the user meant. The notice and the draft status tell the reviewer the view is unreviewed, and `searchArchitectureElements` returns the GEMMA type and name so the assistant can show its picks.
+- **Duplicate new elements.** An assistant can create "Documentbeheer" when a GEMMA element with that name exists. The service matches a new element's type and name against existing elements in the caller's scope and reuses an exact match.
+- **Dependency order.** `lib/Mcp/StackiqToolProvider.php` does not exist until `mcp-full-action-surface` lands. This change is blocked on it.
+- **A deep import.** The layout helpers come from `@conduction/nextcloud-vue/src/composables/flowGraphLayout.js`, not the package root. A library release that moves the file breaks the import at build time, which the vitest spec catches. Asking the library to export them from the root is the clean fix and can follow.
diff --git a/openspec/changes/architecture-assistant-drafted-views/proposal.md b/openspec/changes/architecture-assistant-drafted-views/proposal.md
new file mode 100644
index 000000000..8623d55ca
--- /dev/null
+++ b/openspec/changes/architecture-assistant-drafted-views/proposal.md
@@ -0,0 +1,47 @@
+---
+kind: code
+depends_on:
+ - architecture-views-editor
+ - mcp-full-action-surface
+---
+
+# Let an assistant draft an architecture view for review
+
+## Summary
+
+A user asks Hermiq's assistant for a view ("draw how our case system talks to document management"). The assistant looks up the GEMMA elements that fit through a stackiq tool, then calls a second stackiq tool that writes the view as a draft. The draft opens in the view editor, marked as drafted by an assistant, and a person reviews, adjusts and saves it. Stackiq owns the two tools and the mark. The chat, the model and the agent's rights are Hermiq's.
+
+## Why
+
+This change builds one row of the stackiq parity matrix: `stackiq:arch-ai-diagram`, "Have a diagram drafted for you by an assistant from a description." No tender, feature request or changelog names it for stackiq.
+
+- SAP LeanIX rates yes: "AI agents connected to your workspace via the MCP server can now create, populate, and edit diagrams ... You describe what you want to see, and the agent adds fact sheets to a canvas" (https://updates.leanix.net/announcements/build-and-edit-architecture-diagrams-with-ai-agents).
+- BlueDolphin rates yes: "Modelling Assistant or BPMN Generator instantly creates BPMN 2.0-compliant process diagrams from a simple prompt or by uploading existing documentation" (https://help.bluedolphin.io/en/articles/12528662-ai-capabilities-of-bluedolphin).
+
+The lane decided build because two competitors rate yes and architecture is a core area. The matrix notes "Nothing drafts diagrams."
+
+## What stackiq has today
+
+- No MCP surface. `grep -rn "IMcpToolProvider\|McpTool" lib appinfo` returns nothing, and `lib/Mcp` does not exist at development 49e65cb4.
+- Two open changes plan one. `stackiq-mcp-adoption` excludes `element`, `view`, `model`, `property-definition` and `relation` (its `design.md` exclusion table and Decision 3). `mcp-full-action-surface` keeps that exclusion for derived tools (its `design.md` section 3, "Excluded from derivation"), adds read-only `stackiq.listViews` and `stackiq.getView` over `ViewService` (its `design.md` section 5), and creates `lib/Mcp/StackiqToolProvider.php` and `lib/Mcp/McpArgumentValidator.php` (its `tasks.md` 2.1 and 2.3). Neither writes a view.
+- OpenRegister's `IMcpToolProvider` (`openregister-ro/lib/Mcp/IMcpToolProvider.php:47`) runs a tool in the caller's Nextcloud session, and `ToolRegistryFacade::invokeTool` (`openregister-ro/lib/Service/Mcp/ToolRegistryFacade.php:350-365`) passes no agent identity to the provider.
+- `architecture-views-editor` adds the editor, the `origin` field on `view`, `element` and `relation`, and the readers that keep only imported views in the shared list and the full export.
+
+## What this change builds
+
+- `stackiq.searchArchitectureElements`, a read tool that returns a short projection of AMEF elements (uuid, identifier, name, ArchiMate type, GEMMA type) so a draft reuses existing elements instead of inventing duplicates.
+- `stackiq.draftView`, a create tool that takes a name, a description, elements (an existing uuid, or a new ArchiMate type and name) and relations (source, target, ArchiMate relation type), and writes a `view` in status draft.
+- `lib/Service/ArchitectureViewDraftService.php`, which validates the input, resolves elements, reuses or creates relations, and writes every object with the assistant mark in the same write (ADR-088).
+- An `assistant` value on `origin`, a notice in the editor on a drafted view, and a first-open layout for drafted nodes.
+
+## Out of scope
+
+- The chat, the prompt, the model call, the agent's tool grants and the human approval gate. Those are Hermiq's (ADR-034, ADR-063 Decision 4).
+- Letting an assistant change an existing view. SAP LeanIX's agents also edit diagrams. This change only drafts new views, and a later change can add an edit tool once drafts have been reviewed in practice.
+- Drafting business processes in BPMN, which is BlueDolphin's evidence. Stackiq models processes in `architecture-process-mapping`, and a process draft tool can follow it.
+- Reading an uploaded document to draft from it.
+
+## Risks
+
+- An agent can create many drafts. Drafts are ordinary organisation objects under OpenRegister RBAC, the tool caps a draft at 60 elements and 120 relations, and Hermiq's approval gate sits in front of every create tool.
+- The relation reuse rule exists twice: in the editor's store (`architecture-views-editor` D5) and in this service. Both are tested against the same fixture.
diff --git a/openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md b/openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md
new file mode 100644
index 000000000..078a390f9
--- /dev/null
+++ b/openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md
@@ -0,0 +1,103 @@
+# architecture-assistant-views specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-assistant-drafted-views
+
+## Purpose
+
+A user asks Hermiq's assistant to draw a view, and the assistant drafts it through two stackiq MCP tools: one finds the AMEF elements that fit, one writes the draft. The draft is an ordinary `view` in status draft, marked as drafted by an assistant in the same write (ADR-088), and a person reviews it in the view editor from `architecture-views-editor`. The chat, the model, the agent's grants and the approval gate are Hermiq's (ADR-034, ADR-063). Stackiq owns the tools, the input checks and the mark.
+
+## ADDED Requirements
+
+### Requirement: REQ-AAV-001 Stackiq SHALL offer a read tool that finds architecture elements for a draft
+
+The provider `lib/Mcp/StackiqToolProvider.php` SHALL list `stackiq.searchArchitectureElements` with scope read, reach user and `readOnlyHint` true. It SHALL take a search text, an optional list of ArchiMate element types and a limit of at most 50, and SHALL return for each match the uuid, the ArchiMate identifier, the name, the ArchiMate type and the GEMMA type. It SHALL read through OpenRegister with RBAC and multitenancy on, so it returns only elements the caller may read.
+
+#### Scenario: A sibling app finds the GEMMA element for a case system
+@e2e exclude The tool is called over MCP, not through a page; tests/Unit/Service/ArchitectureViewDraftServiceTest.php asserts the projection fields and the type filter, and tests/Unit/Mcp/StackiqToolProviderDraftToolsTest.php asserts the descriptor's scope, reach and hints.
+
+- **GIVEN** the imported GEMMA model holds an application component named Zaaksysteem
+- **WHEN** Hermiq, the sibling app, calls `stackiq.searchArchitectureElements` with the text zaak and the type ApplicationComponent in a signed-in user's session
+- **THEN** the result SHALL list Zaaksysteem with its uuid, identifier, name, ArchiMate type and GEMMA type
+- **AND** the result SHALL hold no other element fields
+
+### Requirement: REQ-AAV-002 Stackiq SHALL offer a create tool that writes a draft view from elements and relations
+
+The provider SHALL list `stackiq.draftView` with scope create, reach instance, `readOnlyHint` false, `destructiveHint` false and `idempotentHint` false. It SHALL take a name, a description, a list of elements (an existing element uuid, or a new ArchiMate element type and name, each with a key) and a list of relations (a source key, a target key and an ArchiMate relation type). It SHALL check the whole input before it writes anything: an unknown element or relation type, a key no element declares, more than 60 elements or more than 120 relations SHALL return an error result and SHALL write nothing. On success it SHALL write one `view` in status draft, reuse a `relation` of the same type between the same two elements or create one, reuse an existing element of the same type and exact name in the caller's scope or create one, and SHALL return the view's uuid, its editor link `/apps/stackiq/views/` and the number of elements and relations it created.
+
+#### Scenario: An assistant drafts a view and hands back a link
+@e2e tests/e2e/workflows/architecture-assistant-views.spec.ts
+
+- **GIVEN** an application owner signed in to stackiq and the seeded elements Zaaksysteem and Documentbeheer
+- **WHEN** a tool call to `stackiq.draftView` on OpenRegister's MCP endpoint `POST /apps/openregister/api/mcp` names both elements and a Flow relation between them
+- **THEN** the result SHALL carry a view uuid and the link `/apps/stackiq/views/`
+- **AND** the Views page SHALL list the new view with status draft
+
+#### Scenario: A dangling key writes nothing
+@e2e exclude Input checks are a service concern; tests/Unit/Service/ArchitectureViewDraftServiceTest.php asserts that a relation naming an undeclared key, an unknown type and a list over the cap each return an error and call no save.
+
+- **GIVEN** a draft request whose relation names the target key c while only the keys a and b are declared
+- **WHEN** Hermiq calls `stackiq.draftView`
+- **THEN** the result SHALL be an error that names the key c
+- **AND** no `view`, `element` or `relation` object SHALL be written
+
+#### Scenario: A new element with the name of an existing one is reused
+@e2e exclude The match rule is a service concern; tests/Unit/Service/ArchitectureViewDraftServiceTest.php asserts that a new ApplicationComponent named Documentbeheer resolves to the existing element of that type and name.
+
+- **GIVEN** an element of type ApplicationComponent named Documentbeheer in the caller's scope
+- **WHEN** a draft request asks for a new ApplicationComponent named Documentbeheer
+- **THEN** the view SHALL reference the existing element
+- **AND** the result SHALL report zero created elements
+
+### Requirement: REQ-AAV-003 Every object the draft tool writes SHALL carry the assistant mark in the same write
+
+Every `view`, `element` and `relation` that `stackiq.draftView` creates SHALL carry `origin` set to `assistant` in the save that creates it. The view SHALL also carry `draftedFor`, the Nextcloud user id of the session the tool ran in, and `draftedAt`. A write that fails SHALL return an error result, and no object SHALL be saved first and marked later (ADR-088). A person who edits a drafted view SHALL NOT remove the mark.
+
+#### Scenario: A reviewer sees who the draft was made for
+@e2e tests/e2e/workflows/architecture-assistant-views.spec.ts
+
+- **GIVEN** a view drafted through `stackiq.draftView` in the session of an application owner
+- **WHEN** the application owner opens it in the view editor at `/views/`
+- **THEN** the editor SHALL show the notice "Drafted by an assistant for" with their name and the date
+- **AND** the notice SHALL still show after they move a node and save
+
+#### Scenario: New elements and relations carry the mark
+@e2e exclude The mark sits in the saved objects; tests/Unit/Service/ArchitectureViewDraftServiceTest.php asserts every saveObject call for a new view, element and relation carries origin assistant in the same payload.
+
+- **GIVEN** a draft request with one new element and one new relation
+- **WHEN** `stackiq.draftView` writes it
+- **THEN** the new element and the new relation SHALL each carry `origin` assistant
+- **AND** the reused elements SHALL keep their own `origin`
+
+### Requirement: REQ-AAV-004 A drafted view SHALL be laid out when it is first opened
+
+The draft tool SHALL write nodes without positions. When the view editor opens a view whose nodes need a full layout, it SHALL place them with the shared library's layered layout, and the first save by a person SHALL store the positions. The Views page SHALL offer `assistant` in its origin facet.
+
+#### Scenario: An application owner opens a fresh draft
+@e2e tests/e2e/workflows/architecture-assistant-views.spec.ts
+
+- **GIVEN** a view drafted with three elements and two relations and no positions
+- **WHEN** the application owner opens it in the view editor
+- **THEN** the three nodes SHALL render at distinct positions with both connections drawn
+- **AND** choosing the origin assistant in the Views sidebar SHALL list the draft
+
+### Requirement: REQ-AAV-005 The draft tools SHALL run with the caller's rights and SHALL keep drafts out of shared readers
+
+Both tools SHALL run in the caller's Nextcloud session with no substitute account (ADR-034 Decision 7). A caller without create rights on `view` SHALL get a forbidden result and nothing SHALL be written. A drafted view SHALL belong to the caller's active organisation. `GET /api/views`, `GET /api/views/{viewId}` and the full ArchiMate export SHALL leave out views with `origin` assistant, as they leave out drawn views.
+
+#### Scenario: A caller without create rights gets a forbidden result
+@e2e exclude The CI instance runs as admin; tests/Unit/Service/ArchitectureViewDraftServiceTest.php asserts that a forbidden save from OpenRegister's ObjectService returns a forbidden result and that no later save runs.
+
+- **GIVEN** a signed-in user whose groups may read but not create `view` objects
+- **WHEN** Hermiq calls `stackiq.draftView` in that user's session
+- **THEN** the result SHALL be forbidden
+- **AND** no object SHALL be written
+
+#### Scenario: A draft stays out of the shared views list
+@e2e exclude The shared readers are PHP; tests/Unit/Service/ViewServiceDrawnViewTest.php and tests/Unit/Service/ArchiMateExportServiceDrawnFilterTest.php gain a case with origin assistant and assert it is left out.
+
+- **GIVEN** a view drafted by an assistant
+- **WHEN** another user calls `GET /api/views` or a Nextcloud admin runs the full ArchiMate export
+- **THEN** the drafted view SHALL NOT be in the response or in the exported file
diff --git a/openspec/changes/architecture-assistant-drafted-views/tasks.md b/openspec/changes/architecture-assistant-drafted-views/tasks.md
new file mode 100644
index 000000000..d0e869015
--- /dev/null
+++ b/openspec/changes/architecture-assistant-drafted-views/tasks.md
@@ -0,0 +1,71 @@
+# Tasks: architecture-assistant-drafted-views
+
+## Implementation tasks
+
+### Task 1: Register fragment for the assistant mark
+- **spec_ref**: openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md#requirement-req-aav-003-every-object-the-draft-tool-writes-shall-carry-the-assistant-mark-in-the-same-write
+- **files**: `lib/Settings/register.d/architecture-assistant-drafted-views.json`, `tests/Unit/Service/ArchitectureViewsRegisterShapeTest.php`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it loads THEN `origin` on `view`, `element` and `relation` accepts imported, drawn and assistant
+ - GIVEN the merged register WHEN it loads THEN `view` has `draftedFor` and `draftedAt` and carries a bumped version
+ - GIVEN a fresh install WHEN the seed runs THEN the drafted example view exists with `origin` assistant
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchitectureViewsRegisterShapeTest`, `RegisterFragmentMergeTest`)
+
+### Task 2: Draft service
+- **spec_ref**: openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md#requirement-req-aav-002-stackiq-shall-offer-a-create-tool-that-writes-a-draft-view-from-elements-and-relations
+- **files**: `lib/Service/ArchitectureViewDraftService.php`, `tests/Unit/Service/ArchitectureViewDraftServiceTest.php`
+- **acceptance_criteria**:
+ - GIVEN an unknown type, a dangling key or a list over the cap WHEN `draftView` runs THEN it returns an error and calls no save
+ - GIVEN a new element whose type and exact name match an existing element WHEN `draftView` runs THEN the existing element is referenced
+ - GIVEN a relation of the same type between the same two elements WHEN `draftView` runs THEN it is reused
+ - GIVEN any object the service creates WHEN it is saved THEN `origin` assistant is in the same payload, and the view carries `draftedFor` and `draftedAt`
+ - GIVEN `searchElements` WHEN it runs THEN it returns only uuid, identifier, name, ArchiMate type and GEMMA type, at most 50 rows
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchitectureViewDraftServiceTest`)
+
+### Task 3: Two tools on the stackiq MCP provider
+- **spec_ref**: openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md#requirement-req-aav-001-stackiq-shall-offer-a-read-tool-that-finds-architecture-elements-for-a-draft
+- **files**: `lib/Mcp/StackiqToolProvider.php`, `tests/Unit/Mcp/StackiqToolProviderDraftToolsTest.php`
+- **acceptance_criteria**:
+ - GIVEN the provider WHEN it lists its tools THEN `stackiq.searchArchitectureElements` is scope read, reach user, read-only, and `stackiq.draftView` is scope create, reach instance, not read-only, not destructive, not idempotent
+ - GIVEN a call to either tool WHEN it is dispatched THEN the arguments pass `McpArgumentValidator` and reach the service unchanged
+- [ ] Implement
+- [ ] Test (PHPUnit `StackiqToolProviderDraftToolsTest`)
+
+### Task 4: Caller rights and shared readers
+- **spec_ref**: openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md#requirement-req-aav-005-the-draft-tools-shall-run-with-the-callers-rights-and-shall-keep-drafts-out-of-shared-readers
+- **files**: `lib/Service/ArchitectureViewDraftService.php`, `tests/Unit/Service/ArchitectureViewDraftServiceTest.php`, `tests/Unit/Service/ViewServiceDrawnViewTest.php`, `tests/Unit/Service/ArchiMateExportServiceDrawnFilterTest.php`
+- **acceptance_criteria**:
+ - GIVEN OpenRegister refuses the view save WHEN `draftView` runs THEN the result is forbidden and no later save runs
+ - GIVEN a view with `origin` assistant WHEN `GET /api/views`, `GET /api/views/{viewId}` or the full ArchiMate export runs THEN it is left out
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchitectureViewDraftServiceTest`, `ViewServiceDrawnViewTest`, `ArchiMateExportServiceDrawnFilterTest`)
+
+### Task 5: Draft notice and first-open layout in the editor
+- **spec_ref**: openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md#requirement-req-aav-004-a-drafted-view-shall-be-laid-out-when-it-is-first-opened
+- **files**: `src/views/architecture/ArchitectureViewEditor.vue`, `src/utils/viewGraph.js`, `tests/vitest/viewGraph.spec.js`, `tests/e2e/workflows/architecture-assistant-views.spec.ts`
+- **acceptance_criteria**:
+ - GIVEN a view with `origin` assistant WHEN it opens THEN the notice names the user it was drafted for and the date, also after a save
+ - GIVEN nodes without positions WHEN the editor opens them THEN `layoutFlowNodes` places each at a distinct point, and a save stores the points
+ - GIVEN the Views page WHEN the origin facet is opened THEN assistant is one of its values
+- [ ] Implement
+- [ ] Test (vitest `viewGraph.spec.js` layout case, Playwright `architecture-assistant-views.spec.ts`)
+
+### Task 6: Documentation and translations
+- **spec_ref**: openspec/changes/architecture-assistant-drafted-views/specs/architecture-assistant-views/spec.md#requirement-req-aav-003-every-object-the-draft-tool-writes-shall-carry-the-assistant-mark-in-the-same-write
+- **files**: `docs/features/architecture-views.md`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the feature page WHEN it is read THEN a section shows a drafted view with its notice in a screenshot and names the two tools
+ - GIVEN a Dutch instance WHEN a drafted view opens THEN the notice reads in Dutch
+- [ ] Implement
+- [ ] Test (`tests/l10n` key parity, screenshot captured with Playwright)
+
+## Verification
+
+- `openspec validate architecture-assistant-drafted-views --type change --strict`
+- PHPUnit: `ArchitectureViewDraftServiceTest`, `StackiqToolProviderDraftToolsTest`, `ArchitectureViewsRegisterShapeTest`, `ViewServiceDrawnViewTest`, `ArchiMateExportServiceDrawnFilterTest`
+- vitest: `viewGraph.spec.js`
+- Playwright: `tests/e2e/workflows/architecture-assistant-views.spec.ts`
+- Documentation in `docs/features/architecture-views.md` with a screenshot (ADR-010)
+- English and Dutch strings for the notice and the facet value (ADR-005)
diff --git a/openspec/changes/architecture-data-model-and-ggm/.openspec.yaml b/openspec/changes/architecture-data-model-and-ggm/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-data-model-and-ggm/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-data-model-and-ggm/design.md b/openspec/changes/architecture-data-model-and-ggm/design.md
new file mode 100644
index 000000000..f415c449e
--- /dev/null
+++ b/openspec/changes/architecture-data-model-and-ggm/design.md
@@ -0,0 +1,102 @@
+# Design: architecture-data-model-and-ggm
+
+Read at development 49e65cb4. Line numbers below are from that sha. The `origin` field on `element` and `relation` and the Architecture menu group come from `architecture-views-editor` (its D1 and D8). `GebruikDetail` comes from `landscape-usage-registration` (`src/manifest.d/usages.json` in its design).
+
+## Where it fits
+
+| Layer | Touched | Read at |
+|---|---|---|
+| Register | `usage` (`lib/Settings/softwarecatalogus_register.json:2654`) gains `dataEntities`; `element` (:4130) gains `attributes`; `relation` (:6300) gains `sourceCardinality` and `targetCardinality` | through a new fragment `lib/Settings/register.d/architecture-data-model-and-ggm.json` |
+| Pages | new `src/manifest.d/architecture-data-model.json` with `Gegevensmodel` (index) and `GegevensobjectDetail` (detail) | |
+| Pages | `GebruikDetail` in `src/manifest.d/usages.json` shows `dataEntities` in its data widget | |
+| Menu | `src/menu-layout.json` relocates `Gegevensmodel` under the `Architecture` group | |
+| Views | new `src/views/architecture/DataEntityRelations.vue` and `src/views/architecture/DataEntityAttributes.vue`, registered in `src/customComponents.js` | |
+| Service, controller, routes | none | reads and writes go through OpenRegister's objects API |
+
+The fragment merges through `SettingsService::loadSettings` (`lib/Service/SettingsService.php:1653-1680`, `deepMergeConfig` at :7338). It bumps `usage`, `element` and `relation`.
+
+## Decisions
+
+### D1. A data entity is an AMEF `element` of type `BusinessObject`
+
+The GGM entities are already `element` objects after a GEMMA import: 503 `BusinessObject` elements in `lib/Settings/GEMMA_release.xml` carry `GGM-guid` (propid-6, :121153), and 636 Association and 158 Specialization relationships run between them. The import keeps them all (`lib/Service/ArchiMateImportService.php:973-980`) and stores the guid in `ggm-guid` (register.json:5038, through `convertToCamelCase` at :2256). A municipality's own entity is an `element` of type `BusinessObject` with `origin` drawn, so the view editor can place it next to GGM entities.
+
+Rejected: a new `dataEntity` schema in the `stackiq` register. It would copy 503 GGM entities out of the model they belong to, and a view could no longer place them, because the editor and both exports read the AMEF schemas only.
+
+### D2. The link lives on the application in use
+
+`usage.dataEntities` is a list of related `element` objects, with `objectConfiguration.queryParams` `type=BusinessObject`, so the picker offers only data entities. It is facetable, so the usages index can filter on an entity.
+
+Rejected: the field on `module`, filled by the supplier. Which data an application holds depends on how the municipality uses it: one product serves several reference components, and a municipality may keep only part of its data there. The tender asks for the municipality's own architecture repository. A supplier-declared list can follow as a suggestion when a usage is created.
+
+### D3. The Data model pages
+
+`Gegevensmodel` (`/gegevensmodel`) is a `CnIndexPage` (manifest `type: index`) over `@resolve:amef_register` and `element` with `filter` `{"type": "BusinessObject"}`, columns name, ggm-uml-type, gemmaType and origin, and quick filters All, GGM (`origin` imported) and Own (`origin` drawn). Its add dialog uses `createDefaults` `{"type": "BusinessObject", "origin": "drawn"}` and `includeFields` name, documentation and attributes (`@conduction/nextcloud-vue` 2.57.1 `src/components/CnIndexPage/CnIndexPage.vue`, props at :1817 and :1949), because `element` has 86 properties and the default dialog would show them all.
+
+`GegevensobjectDetail` (`/gegevensmodel/:id`) is a `type: detail` page on the ADR-062 grid with:
+- a `data` widget for name, documentation, ggm-guid, ggm-uml-type and origin,
+- a body widget `DataEntityRelations` (D4),
+- a body widget `DataEntityAttributes` (D5),
+- an `object-list` widget `entity-usages` over `@resolve:voorzieningen_register` and `usage` with filter `{"dataEntities": "@objectId"}`, titled "Applications that hold this data", `rowRoute: GebruikDetail`.
+
+OpenRegister filters an array property on one value with a JSON containment test (`openregister-ro/lib/Db/MagicMapper/MagicSearchHandler.php:1601`).
+
+### D4. The relations of an entity are drawn around it
+
+`DataEntityRelations.vue` loads the `relation` objects whose `source` or `target` is the entity's `identifier` and whose `type` is Association, Aggregation, Composition or Specialization, then the elements at the other end. It passes them to `CnRelationshipGraph` (`@conduction/nextcloud-vue` 2.57.1, `src/components/CnRelationshipGraph/CnRelationshipGraph.vue`, props `nodes`, `edges`, `layout` and `legend` at :123 to :171) with the radial layout, the entity as root, and an edge label of the relation name, its type, and the cardinalities when set. The component's colour props default to hex values (:150 to :158), so the view passes Nextcloud CSS variables for every colour (ADR-003). Under the graph a table lists every relation as text, and choosing a node or a row opens that entity's page.
+
+Rejected: `CnGraphCanvas`. The picture is an entity and its direct neighbours, which is what the relationship graph draws; a canvas with pan and zoom suits a whole view, and the view editor already offers it.
+
+Rejected: a UML class diagram with attribute compartments. GGM entities carry no attributes in the AMEFF file, so the compartments would be empty for 503 of them.
+
+### D5. Attributes and keys on the municipality's own entities
+
+`element.attributes` is a list of objects: `name` (required), `dataType` (enum text, number, date, boolean, reference), `isKey` (boolean) and `description`. `DataEntityAttributes.vue` shows them as a table with the key attributes first and marked "key" in text, and edits them for an entity with `origin` drawn. An imported entity shows "The GGM does not publish attributes in this file".
+
+`relation.sourceCardinality` and `relation.targetCardinality` are enums `0..1`, `1`, `0..*` and `1..*`. They are set on relations with `origin` drawn and shown on the edge label.
+
+Rejected: attributes as separate `element` objects of their own type. ArchiMate has no attribute element, and the export would write them as elements that Archi does not know how to show.
+
+## Declarative versus imperative
+
+- The usage to entity link is a `related-object` list, so OpenRegister keeps it in its relation index, and the entity page's application list is a manifest `object-list` with a filter. No PHP.
+- The attribute list and cardinalities are schema properties. No lifecycle, notification or aggregation is added.
+- `DataEntityRelations.vue` and `DataEntityAttributes.vue` are the imperative pieces: the first only reads, the second writes one property of one object.
+
+## Seed data
+
+`architecture-views-editor` seeds drawn elements in `vng-gemma`. This change adds two own data entities, one relation and one usage link.
+
+### Schema: `element`
+
+| Field | Object 1 | Object 2 |
+|---|---|---|
+| slug | `seed-el-melding` | `seed-el-melder` |
+| identifier | `id-seed-el-melding` | `id-seed-el-melder` |
+| type | `BusinessObject` | `BusinessObject` |
+| name | Melding openbare ruimte | Melder |
+| origin | drawn | drawn |
+| attributes | meldingnummer (text, key), datum melding (date), locatie (text) | e-mailadres (text, key), naam (text) |
+
+### Schema: `relation`
+
+| Field | Object 1 |
+|---|---|
+| slug | `seed-rel-melding-melder` |
+| type | `Association` |
+| name | gedaan door |
+| source | `id-seed-el-melding` |
+| target | `id-seed-el-melder` |
+| sourceCardinality | `0..*` |
+| targetCardinality | `1` |
+| origin | drawn |
+
+### Schema: `usage`
+
+The seeded usage `gebruik-topdesk-gem-leiden-deelnemers` (register.json `components.objects`) gets `dataEntities` with the uuid of `seed-el-melding`, so the entity page shows one application on a fresh install.
+
+## Risks
+
+- **Identifier lookups.** A relation stores ArchiMate identifiers in `source` and `target`, while an imported element's uuid is its GEMMA object id (`ArchiMateImportService.php:4794-4798`). The view queries on the entity's `identifier` field, not its uuid, and its vitest spec covers an imported and a drawn entity.
+- **Two queries per open.** The relations of one entity need a query on `source` and one on `target`. Both are limited to 200 rows, and the text list says when the limit is reached.
+- **Schema versions.** The fragment bumps three schemas. The register changelog entry 2.4.4 (register.json:7) records that a deployed version equal to or above the declared one makes the import skip.
diff --git a/openspec/changes/architecture-data-model-and-ggm/proposal.md b/openspec/changes/architecture-data-model-and-ggm/proposal.md
new file mode 100644
index 000000000..3a20c764e
--- /dev/null
+++ b/openspec/changes/architecture-data-model-and-ggm/proposal.md
@@ -0,0 +1,45 @@
+---
+kind: code
+depends_on:
+ - architecture-views-editor
+ - landscape-usage-registration
+---
+
+# Show the data model and link applications to the entities of the GGM
+
+## Summary
+
+A municipal information manager opens a Data model page in stackiq and finds the entities of the Gemeentelijk Gegevensmodel (GGM), each with its relations to other entities drawn around it. They record which entities an application in use holds data for, and an entity's page lists those applications. The municipality can add its own data entities with attributes and keys, and relate them with a cardinality.
+
+## Why
+
+This change builds two rows of the stackiq parity matrix. Both come from the Helmond architecture repository tender, https://www.tenderned.nl/aankondigingen/overzicht/398728.
+
+- `stackiq:arch-data-model`, "Model data entities and their relations, as an entity relationship or UML diagram, next to the applications." The matrix note: "Helmond REQ54 asks for entity relationship or UML data models." BlueDolphin rates yes: "Primary keys are unique identifiers for a data object and can be used to create a relationship between data objects" (https://help.bluedolphin.io/en/articles/11967570-keys-and-relationships), with a logical data dictionary (https://help.bluedolphin.io/en/articles/11967568-logical-data-dictionary) and views of type Logical Data (https://help.bluedolphin.io/en/articles/11967483-views-button-explanation). SAP LeanIX rates partial. The lane decided build on tender demand and a core area.
+- `stackiq:arch-ggm-link`, "Relate applications to the entities of the Gemeentelijk Gegevensmodel they hold data for." The matrix note: "Helmond's architecture repository tender (REQ3, REQ61) asks to relate the repository to the GGM." BlueDolphin rates partial, through a third-party route: "hiervoor gebruik je het AMEFF-bestand van het GGM uit de GEMMA-repository voor de Architectuur module van BlueDolphin" (https://github.com/Gemeente-Delft/Gemeentelijk-Gegevensmodel/blob/master/README.md). No competitor rates yes. Decided build on tender demand and a core area.
+
+## What stackiq has today
+
+- The GGM is already in the data after a GEMMA import. `lib/Settings/GEMMA_release.xml` defines the property `GGM-guid` (propid-6, :121153) and carries it on 503 `BusinessObject` elements, such as Formatieplaats, Werknemer and Aanvraag, and on the relationships between them. The import keeps every element type (`lib/Service/ArchiMateImportService.php:973-980`) and turns a property name into a key by lowercasing it (`convertToCamelCase`, :2256), so `GGM-guid` lands in `ggm-guid`, which the `element` schema declares (`lib/Settings/softwarecatalogus_register.json:5038`, schema at :4130).
+- No page shows these entities. The only AMEF page, Standaarden (`src/manifest.json:701`), is filtered to `gemmaType` standaard.
+- No application points at a data entity. `module` (register.json:6777) and `usage` (:2654) hold no such field. `usage.amefElements` holds reference component ids that `GebruikSyncService` fills (`lib/Service/GebruikSyncService.php:170-272`).
+- `relation` (:6300) has `source`, `target`, `type` and `name`, and no cardinality. `element` has no attribute list.
+
+## What this change builds
+
+- A field `dataEntities` on `usage`: the data entities an application in use holds data for.
+- A Data model index page over `element` objects of type `BusinessObject`, and a data entity page with its relations drawn around it, its attributes and the applications that hold its data.
+- An attribute list with keys on data entities the municipality adds, and a cardinality on relations it draws.
+- A picker for data entities on the usage page `GebruikDetail`.
+
+## Out of scope
+
+- Importing the GGM separately. The GEMMA release carries it, and a municipality that wants a newer GGM imports that AMEFF file through the existing ArchiMate import.
+- The attributes of GGM entities. The GEMMA AMEFF file has entities and relations but no attributes, so a GGM entity shows none. Loading GGM attributes from its UML source is a later change.
+- Drawing a data model freehand. The view editor from `architecture-views-editor` draws `BusinessObject` elements and their relations on a canvas; this change adds the entity pages and the fields.
+- A field on the catalogue `module` that suppliers fill. See design D2.
+
+## Risks
+
+- A GEMMA re-import updates imported entities. The municipality's own entities carry `origin` drawn and the import never writes them (`architecture-views-editor` D2).
+- An entity with many relations draws a crowded graph. The graph shows direct neighbours only, and the text list under it holds every relation.
diff --git a/openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md b/openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md
new file mode 100644
index 000000000..190551652
--- /dev/null
+++ b/openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md
@@ -0,0 +1,90 @@
+# data-model-and-ggm specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-data-model-and-ggm
+
+## Purpose
+
+A municipality sees the entities of the Gemeentelijk Gegevensmodel (GGM) in stackiq, with their relations, and records which entities each application in use holds data for. It can add its own data entities with attributes and keys. Entities are AMEF `element` objects of type `BusinessObject`, and the link is a field on `usage`, both stored in OpenRegister (ADR-001) and shown with `CnIndexPage`, `CnDetailPage` and `CnRelationshipGraph` (ADR-012).
+
+## ADDED Requirements
+
+### Requirement: REQ-DMG-001 Stackiq SHALL show the data entities of the imported model on a Data model page
+
+Stackiq SHALL offer a Data model page at `/gegevensmodel` (page `Gegevensmodel`) that lists the `element` objects of type `BusinessObject`, with columns name, GGM UML type, GEMMA type and origin, and the quick filters All, GGM and Own. It SHALL offer a data entity page at `/gegevensmodel/:id` (page `GegevensobjectDetail`) with the entity's name, documentation, GGM guid and origin. The page SHALL sit under the Architecture menu group.
+
+#### Scenario: An information manager finds a data entity
+@e2e tests/e2e/workflows/data-model.spec.ts
+
+- **GIVEN** the seeded own data entity Melding openbare ruimte
+- **WHEN** a municipal information manager opens Architecture, then Data model, chooses the quick filter Own and searches Melding
+- **THEN** the list SHALL show Melding openbare ruimte with origin drawn
+- **AND** opening it SHALL show its name and documentation
+
+#### Scenario: GGM entities are listed after a GEMMA import
+@e2e exclude The CI seed (tests/e2e/ci-seed.sh) imports the register but no GEMMA model; tests/validate-manifest.js asserts that the Gegevensmodel page filters element on type BusinessObject and that the quick filter GGM filters on origin imported.
+
+- **GIVEN** a stackiq instance where a Nextcloud admin imported the GEMMA model
+- **WHEN** a municipal information manager opens the Data model page and chooses the quick filter GGM
+- **THEN** the list SHALL show GGM entities such as Werknemer and Aanvraag
+- **AND** no application component SHALL be listed
+
+### Requirement: REQ-DMG-002 A data entity page SHALL draw the entity's relations to other entities
+
+The data entity page SHALL show the entity with every entity it is related to by an Association, Aggregation, Composition or Specialization relation, drawn on `CnRelationshipGraph` with the entity at the centre and each edge labelled with the relation name or type and its cardinalities. A table under the graph SHALL list the same relations as text. Choosing a node or a row SHALL open that entity's page. All colours SHALL be Nextcloud CSS variables.
+
+#### Scenario: An information manager sees what a melding relates to
+@e2e tests/e2e/workflows/data-model.spec.ts
+
+- **GIVEN** the seeded own entities Melding openbare ruimte and Melder with the relation gedaan door
+- **WHEN** a municipal information manager opens the page of Melding openbare ruimte
+- **THEN** the graph SHALL show Melder connected to it with the label gedaan door, 0..* to 1
+- **AND** the relation table SHALL hold the same relation as text
+
+#### Scenario: Relations are found by identifier for imported and drawn entities
+@e2e exclude A lookup detail; tests/vitest/dataEntityRelations.spec.js asserts that an imported entity, whose uuid differs from its identifier, and a drawn entity both find their relations through the identifier field.
+
+- **GIVEN** an imported entity whose uuid is its GEMMA object id and whose identifier starts with id-
+- **WHEN** its relations load
+- **THEN** relations whose source or target is its identifier SHALL be found
+
+### Requirement: REQ-DMG-003 An application in use SHALL record the data entities it holds data for
+
+The `usage` schema SHALL have a facetable list `dataEntities` of related `element` objects, and its picker SHALL offer only elements of type `BusinessObject`. The usage page `GebruikDetail` SHALL show and edit the list. The data entity page SHALL list the usages that name it under "Applications that hold this data".
+
+#### Scenario: An application owner links their application to a data entity
+@e2e tests/e2e/workflows/data-model.spec.ts
+
+- **GIVEN** an application owner on the page of a usage at `/gebruik/:id`
+- **WHEN** they edit the usage, pick the data entity Melding openbare ruimte and save
+- **THEN** the usage page SHALL show the entity under data entities
+- **AND** the page of Melding openbare ruimte SHALL list the usage under "Applications that hold this data"
+
+#### Scenario: The picker offers data entities only
+@e2e exclude A schema setting; tests/Unit/Settings/DataModelRegisterShapeTest.php asserts that usage.dataEntities is a related element list with the query type=BusinessObject and is facetable.
+
+- **GIVEN** the merged register
+- **WHEN** the shape test reads `usage.dataEntities`
+- **THEN** it SHALL relate to `element` filtered on type BusinessObject
+
+### Requirement: REQ-DMG-004 A municipality SHALL add its own data entities with attributes, keys and cardinalities
+
+The Data model page SHALL offer New data entity, which SHALL create an `element` of type `BusinessObject` with `origin` drawn and ask only for name, documentation and attributes. An attribute SHALL have a name, a data type (text, number, date, boolean or reference), a key flag and a description. The entity page SHALL list attributes with key attributes first and marked as key in text, and SHALL let an owner edit the attributes of an entity with `origin` drawn. A relation with `origin` drawn SHALL carry a source and a target cardinality of `0..1`, `1`, `0..*` or `1..*`. An imported entity SHALL show that the GGM file publishes no attributes.
+
+#### Scenario: An information manager adds an entity with a key
+@e2e tests/e2e/workflows/data-model.spec.ts
+
+- **GIVEN** a municipal information manager on the Data model page
+- **WHEN** they choose New data entity, enter the name Vergunning, add the attribute zaaknummer as a text key and save
+- **THEN** the Data model page SHALL list Vergunning under the quick filter Own
+- **AND** its page SHALL show zaaknummer first, marked key
+
+#### Scenario: An imported entity cannot be given attributes
+@e2e exclude A view rule; tests/vitest/dataEntityAttributes.spec.js asserts that an entity with origin imported renders no edit control and shows the notice about the GGM file.
+
+- **GIVEN** an imported GGM entity
+- **WHEN** its page renders
+- **THEN** the attribute section SHALL show no edit control
+- **AND** it SHALL say that the GGM file publishes no attributes
diff --git a/openspec/changes/architecture-data-model-and-ggm/tasks.md b/openspec/changes/architecture-data-model-and-ggm/tasks.md
new file mode 100644
index 000000000..ce280e29e
--- /dev/null
+++ b/openspec/changes/architecture-data-model-and-ggm/tasks.md
@@ -0,0 +1,70 @@
+# Tasks: architecture-data-model-and-ggm
+
+## Implementation tasks
+
+### Task 1: Register fragment for data entities, attributes and the usage link
+- **spec_ref**: openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md#requirement-req-dmg-003-an-application-in-use-shall-record-the-data-entities-it-holds-data-for
+- **files**: `lib/Settings/register.d/architecture-data-model-and-ggm.json`, `tests/Unit/Settings/DataModelRegisterShapeTest.php`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it loads THEN `usage.dataEntities` relates to `element` with the query type=BusinessObject and is facetable
+ - GIVEN the merged register WHEN it loads THEN `element.attributes` has name, dataType, isKey and description, and `relation` has both cardinality enums
+ - GIVEN the fragment WHEN it is compared with development THEN `usage`, `element` and `relation` carry bumped versions
+ - GIVEN a fresh install WHEN the seed runs THEN the two own entities, their relation and the usage link exist
+- [ ] Implement
+- [ ] Test (PHPUnit `DataModelRegisterShapeTest`, `RegisterFragmentMergeTest`)
+
+### Task 2: Data model index and entity page
+- **spec_ref**: openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md#requirement-req-dmg-001-stackiq-shall-show-the-data-entities-of-the-imported-model-on-a-data-model-page
+- **files**: `src/manifest.d/architecture-data-model.json`, `src/menu-layout.json`
+- **acceptance_criteria**:
+ - GIVEN the effective manifest WHEN it is built THEN `Gegevensmodel` filters `element` on type BusinessObject with the quick filters All, GGM and Own
+ - GIVEN the add dialog WHEN it opens THEN it asks only for name, documentation and attributes and creates type BusinessObject with origin drawn
+ - GIVEN the effective menu WHEN it renders THEN Data model sits under the Architecture group
+ - GIVEN an entity page WHEN it renders THEN "Applications that hold this data" lists usages filtered on `dataEntities`
+- [ ] Implement
+- [ ] Test (`tests/validate-manifest.js`, Playwright `tests/e2e/workflows/data-model.spec.ts`)
+
+### Task 3: Relations drawn around an entity
+- **spec_ref**: openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md#requirement-req-dmg-002-a-data-entity-page-shall-draw-the-entitys-relations-to-other-entities
+- **files**: `src/views/architecture/DataEntityRelations.vue`, `src/utils/dataEntityGraph.js`, `src/customComponents.js`, `tests/vitest/dataEntityRelations.spec.js`
+- **acceptance_criteria**:
+ - GIVEN an imported and a drawn entity WHEN their relations load THEN both are found through the identifier field
+ - GIVEN a relation with cardinalities WHEN it is drawn THEN the edge label holds its name and both cardinalities
+ - GIVEN the graph WHEN it renders THEN every colour prop is a CSS variable and a text table lists the same relations
+- [ ] Implement
+- [ ] Test (vitest `dataEntityRelations.spec.js`, Playwright relation scenario)
+
+### Task 4: Attributes with keys
+- **spec_ref**: openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md#requirement-req-dmg-004-a-municipality-shall-add-its-own-data-entities-with-attributes-keys-and-cardinalities
+- **files**: `src/views/architecture/DataEntityAttributes.vue`, `tests/vitest/dataEntityAttributes.spec.js`
+- **acceptance_criteria**:
+ - GIVEN a drawn entity WHEN its page renders THEN key attributes come first, marked key in text, and can be edited
+ - GIVEN an imported entity WHEN its page renders THEN no edit control shows and the notice about the GGM file does
+- [ ] Implement
+- [ ] Test (vitest `dataEntityAttributes.spec.js`, Playwright new entity scenario)
+
+### Task 5: Data entities on the usage page
+- **spec_ref**: openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md#requirement-req-dmg-003-an-application-in-use-shall-record-the-data-entities-it-holds-data-for
+- **files**: `src/manifest.d/usages.json`
+- **acceptance_criteria**:
+ - GIVEN a usage page WHEN it is edited THEN the data entities picker offers business objects only, and the saved list shows on the page
+- [ ] Implement
+- [ ] Test (Playwright usage link scenario)
+
+### Task 6: Documentation and translations
+- **spec_ref**: openspec/changes/architecture-data-model-and-ggm/specs/data-model-and-ggm/spec.md#requirement-req-dmg-001-stackiq-shall-show-the-data-entities-of-the-imported-model-on-a-data-model-page
+- **files**: `docs/features/data-model.md`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the feature page WHEN it is read THEN it shows the Data model page, an entity page with its graph and a usage with data entities, each in a screenshot, and says how to import a newer GGM
+ - GIVEN a Dutch instance WHEN the Data model page renders THEN every new label reads in Dutch
+- [ ] Implement
+- [ ] Test (`tests/l10n` key parity, screenshots captured with Playwright)
+
+## Verification
+
+- `openspec validate architecture-data-model-and-ggm --type change --strict`
+- PHPUnit: `DataModelRegisterShapeTest`, `RegisterFragmentMergeTest`
+- vitest: `dataEntityRelations.spec.js`, `dataEntityAttributes.spec.js`
+- Playwright: `tests/e2e/workflows/data-model.spec.ts`
+- Documentation in `docs/features/data-model.md` with screenshots (ADR-010)
+- English and Dutch strings for every new label and enum value (ADR-005)
diff --git a/openspec/changes/architecture-decision-register/.openspec.yaml b/openspec/changes/architecture-decision-register/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-decision-register/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-decision-register/design.md b/openspec/changes/architecture-decision-register/design.md
new file mode 100644
index 000000000..44499d666
--- /dev/null
+++ b/openspec/changes/architecture-decision-register/design.md
@@ -0,0 +1,108 @@
+# Design: architecture-decision-register
+
+Read at development 49e65cb4. Line numbers below are from that sha. The Architecture menu group comes from `architecture-views-editor` (its D8), and `GebruikDetail` from `landscape-usage-registration`.
+
+## Where it fits
+
+| Layer | Touched | Read at |
+|---|---|---|
+| Register | `stackiq` register (`lib/Settings/softwarecatalogus_register.json:817`), new schema `architectureDecision` | through a new fragment `lib/Settings/register.d/architecture-decision-register.json` |
+| Lifecycle guard | new `lib/Lifecycle/ArchitectureDecisionReviewGuard.php`, implementing `OCA\OpenRegister\Lifecycle\LifecycleGuardInterface` (`openregister-ro/lib/Lifecycle/LifecycleGuardInterface.php:37`) | resolved by OpenRegister through the server container by its class name |
+| Analysis stub | `tests/Stubs` gains the OpenRegister guard interface and `GuardResult` if psalm and phpstan cannot see them | |
+| Pages | new `src/manifest.d/architecture-decision-register.json` with `Architectuurbesluiten` (index) and `ArchitectuurbesluitDetail` (detail) | |
+| Pages | `GebruikDetail` in `src/manifest.d/usages.json` and `StandaardDetail` (`src/manifest.json:724`) each gain an `object-list` widget | |
+| Menu | `src/menu-layout.json` relocates `Architectuurbesluiten` under the `Architecture` group | |
+| Service, controller, routes | none | reads and writes go through OpenRegister's objects API; transitions through OpenRegister's lifecycle actions |
+
+## Decisions
+
+### D1. An architecture decision is a stackiq object, not a decidiq decision
+
+An architecture decision is recorded as an `architectureDecision` object in the `stackiq` register with a lifecycle declared on the schema (ADR-031). When a board formally adopts it in decidiq, the object links to that decidiq decision, in the way `catalogContract.decisions` does (register.json:3450).
+
+Rejected: every architecture decision as a decidiq decision, projected back as contracts are. An architecture decision record is an architecture artefact: context, options, consequences, links to applications and GEMMA elements, and a chain of decisions that supersede each other. Architects review it; most never reach a board. A decidiq decision is a governance act with meetings, voting and signing. Delegating would make recording any architecture decision depend on decidiq being installed, move architecture fields into decidiq, and cost the fail-closed cross-app event path the contracts carry, including the two event class spellings after the rename (`lib/Service/ContractApprovalService.php:64` to :104).
+
+### D2. The schema
+
+`architectureDecision`:
+
+| Field | Type | Notes |
+|---|---|---|
+| title | string, required | |
+| context | string, long text | why a decision is needed |
+| decision | string, long text | what was decided |
+| alternatives | list of objects `{option, reasonRejected}` | the options not chosen |
+| consequences | string, long text | |
+| category | enum application, data, integration, infrastructure, security, standards, facetable | |
+| impact | enum low, medium, high, facetable | |
+| status | enum draft, in review, accepted, rejected, superseded, deprecated, default draft, facetable | lifecycle in the Declarative section |
+| reviewer | string, a Nextcloud user id | required to submit |
+| decidedOn | date | set by the owner when accepted |
+| applications | list of related `usage` | the applications in use it affects |
+| elements | list of related `element` | the GEMMA reference components, standards or other elements it affects |
+| supersedes | related `architectureDecision` | |
+| supersededBy | related `architectureDecision` | |
+| boardDecisions | list of decidiq decision uuids, `x-external-register` decidesk, `referenceType` decision | as `catalogContract.decisions` (register.json:3450) |
+
+The read and write rules follow `usage` (register.json, `usage.authorization`): the catalogue groups create and update, and read is matched on `_organisation`. OpenRegister multitenancy scopes each decision to the organisation that recorded it.
+
+### D3. Fixed classification lists
+
+Category and impact are enums on the schema, so `CnIndexPage` facets and the forms render them without code.
+
+Rejected: dropdown fields an administrator adds to a decision template, as the LeanIX changelog describes. That needs a field-definition schema and a renderer for its answers next to the schema-driven forms (ADR-012), and properties added to the schema in OpenRegister's editor vanish on the next register import with a version bump. Two fixed lists cover the classification the row asks for, and a list can grow in a later register version.
+
+### D4. A second pair of eyes through one guard
+
+`ArchitectureDecisionReviewGuard::check(object, action, userId)` returns:
+
+| Action | Allowed when |
+|---|---|
+| submit | `reviewer` names a Nextcloud user and is not the caller |
+| accept, reject | the caller is the `reviewer` |
+| supersede | `supersededBy` points at a decision in status accepted |
+
+Other actions pass. The guard reads only; it never writes (the interface contract, `LifecycleGuardInterface.php:31` to :35). OpenRegister runs it for a named transition and for a direct edit of `status` alike (`openregister-ro/openspec/specs/object-lifecycle/spec.md:126` to :134), and denies with a 403 and the guard's message.
+
+Rejected: the review rule in a stackiq controller in front of the transition. A direct save of `status` through OpenRegister's objects API would pass around it. The guard sits in the save pipeline.
+
+### D5. Pages
+
+`Architectuurbesluiten` (`/architectuurbesluiten`) is a `CnIndexPage` over `architectureDecision` with columns title, status, category, impact and reviewer, the facets in the sidebar, and quick filters All, In review, Accepted and "To review by me" (`{"reviewer": "@me"}`, resolved by `@conduction/nextcloud-vue` `src/utils/resolveFilterTokens.js:119`).
+
+`ArchitectuurbesluitDetail` (`/architectuurbesluiten/:id`) is a `type: detail` page on the ADR-062 grid with a `data` widget for the text fields, a second `data` widget for classification, reviewer and dates, `object-list` widgets for the linked applications and elements, `lifecycleActions` on, and the History tab.
+
+`GebruikDetail` and `StandaardDetail` each get an `object-list` widget "Architecture decisions" over `architectureDecision` with filter `{"applications": "@objectId"}` or `{"elements": "@objectId"}`, which OpenRegister answers with a JSON containment test (`openregister-ro/lib/Db/MagicMapper/MagicSearchHandler.php:1601`).
+
+## Declarative versus imperative
+
+- The lifecycle is declared as `configuration.x-openregister-lifecycle` on `architectureDecision`: field `status`, initial draft, final rejected, superseded and deprecated, transitions submit (draft to in review, `requires` the guard), accept (in review to accepted, `requires` the guard), reject (in review to rejected, `requires` the guard), rework (in review or rejected to draft), supersede (accepted to superseded, `requires` the guard) and deprecate (accepted to deprecated). Every `from` and `to` value is an enum value exactly (register changelog 2.4.4, register.json:7).
+- Two notifications are declared in `x-openregister-notifications` on the schema, in the shape `usage` uses (register.json:2662): `review-requested`, trigger `updated` with the condition status equals in review, recipient `{"kind": "field", "field": "reviewer"}` (a single user id, which the resolver checks is a real user, `NotificationRecipientResolver.php:187`); and `review-concluded`, trigger `updated` with status in accepted or rejected, recipient `{"kind": "object-acl", "permission": "manage"}`. Both on the channels `nc-notification` and `email`, with Dutch and English subjects.
+- The links are `related-object` properties and manifest `object-list` widgets.
+- The guard is the only PHP, and it is a read-only check the platform calls.
+
+## Seed data
+
+All objects live in the `stackiq` register.
+
+### Schema: `architectureDecision`
+
+| Field | Object 1 | Object 2 |
+|---|---|---|
+| slug | `seed-ab-zaakgericht-werken` | `seed-ab-api-first` |
+| title | Eén zaaksysteem voor alle domeinen | Nieuwe koppelingen alleen via API's |
+| context | Drie domeinen gebruiken elk een eigen zaaksysteem. | Bestandsuitwisseling via FTP is niet te volgen. |
+| decision | We gaan naar één zaaksysteem, domein voor domein. | Een nieuwe koppeling gebruikt een gedocumenteerde API. |
+| category | application | integration |
+| impact | high | medium |
+| status | accepted | in review |
+| reviewer | admin | admin |
+| applications | `gebruik-suite4-gem-delft-eigenaar` | |
+
+The usage slug is one of the three the register seeds (register.json `components.objects`).
+
+## Risks
+
+- **Guard resolution.** OpenRegister resolves a guard by class name through the server container and fails closed when it cannot (`openregister-ro/openspec/specs/object-lifecycle/spec.md:593`). A typo in the `requires` value blocks the transition on every instance, so the register shape test asserts the value equals the guard's class name.
+- **Payload shape.** The guard reads `reviewer`, `supersededBy` and the linked decision's status from the payload OpenRegister passes. Its unit test builds that payload from a saved object, not by hand.
+- **One reviewer.** The notification recipient kind `field` takes one user id, so a decision has one reviewer. A review by a group can follow once the resolver takes a list.
diff --git a/openspec/changes/architecture-decision-register/proposal.md b/openspec/changes/architecture-decision-register/proposal.md
new file mode 100644
index 000000000..a548a7a2c
--- /dev/null
+++ b/openspec/changes/architecture-decision-register/proposal.md
@@ -0,0 +1,46 @@
+---
+kind: code
+depends_on:
+ - architecture-views-editor
+ - landscape-usage-registration
+---
+
+# Record architecture decisions with a review and link them to applications
+
+## Summary
+
+A municipal information manager records an architecture decision in stackiq: the context, the decision, the options they rejected and the consequences, classified by category and impact. They name a reviewer and submit it; the reviewer accepts or rejects it, and a later decision can supersede it. Each decision links to the applications in use and the GEMMA elements it affects, and the page of an application in use lists the decisions about it. When a board formally adopts a decision in decidiq, the architecture decision links to that decidiq decision.
+
+## Why
+
+This change builds one row of the stackiq parity matrix: `stackiq:arch-decision-register`, "Record architecture decisions with a status and review flow, and link each decision to the applications it affects." The demand is a changelog entry, https://updates.leanix.net/announcements/classify-architecture-decisions-with-dropdown-fields.
+
+- SAP LeanIX rates yes: admins "add single-select and multi-select dropdown fields to architecture decision templates", and "Document decisions about enterprise architecture in a structured, template-driven format ... Track decisions through a review process with defined statuses" (https://help.sap.com/docs/leanix/ea/architecture-decisions).
+- GLPI rates no; GEMMA Softwarecatalogus, BlueDolphin and TOPdesk are unknown.
+
+The lane decided build: architecture is a core area.
+
+## What stackiq has today
+
+- The only decisions are contract approvals and renewals, delegated to decidiq. `lib/Service/ContractApprovalService.php:254` (`submitForApproval`) dispatches decidiq's `DecisionRequestedEvent` with the decision type `contract` or `contract-renewal` (:129, :135) and projects the outcome onto `approvalDecisionId` and `approvalState` (`lib/Settings/register.d/contracts-to-decidesk.json`). It must handle two event class spellings after decidiq's rename (:64 to :104) and fails closed when decidiq is absent.
+- `catalogContract.decisions` (`lib/Settings/softwarecatalogus_register.json:3450`) holds decidiq decision uuids with `x-external-register` decidesk and `referenceType` decision: a link, not a copy.
+- No schema holds an architecture decision, and no page lists one.
+- OpenRegister runs a lifecycle transition through `requires` guards that an app can supply (`openregister-ro/openspec/specs/object-lifecycle/spec.md:126` to :134, `openregister-ro/lib/Lifecycle/LifecycleGuardInterface.php:37`), and its notification engine resolves a recipient from a user id held in an object field (`openregister-ro/lib/Service/Notification/NotificationRecipientResolver.php:187`).
+
+## What this change builds
+
+- A schema `architectureDecision` in the `stackiq` register with the decision text, category, impact, reviewer, links to usages and AMEF elements, supersedes and superseded by, and links to decidiq decisions.
+- A declared review lifecycle (draft, in review, accepted, rejected, superseded, deprecated) with one stackiq guard class that enforces a second pair of eyes.
+- Notifications to the reviewer on submit and to the owner on the outcome, declared on the schema.
+- An Architecture decisions index and a decision page under the Architecture menu group, and a list of decisions on the usage page and on the standard page.
+
+## Out of scope
+
+- Making a formal board or council decision. That is decidiq's: its meetings, voting and signing. Stackiq only links to a decidiq decision the organisation already took. Raising an architecture decision in decidiq through `DecisionRequestedEvent` would need decidiq to accept a new decision type, and can follow the contract pattern later.
+- Templates an administrator defines. Category and impact are fixed lists; see design D3.
+- Decisions about a catalogue product for every municipality. A decision belongs to the organisation that records it.
+
+## Risks
+
+- The guard class implements an OpenRegister interface. If OpenRegister cannot resolve the guard, the transition fails closed, so a misconfigured instance blocks acceptance rather than letting anyone accept.
+- A reviewer who leaves the organisation keeps pending decisions. The owner can send the decision back to draft and name a new reviewer.
diff --git a/openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md b/openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md
new file mode 100644
index 000000000..abe18f281
--- /dev/null
+++ b/openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md
@@ -0,0 +1,87 @@
+# architecture-decision-register specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-decision-register
+
+## Purpose
+
+A municipality records its architecture decisions in stackiq with a review by a second person, and links each decision to the applications in use and the GEMMA elements it affects. Decisions are `architectureDecision` objects in the `stackiq` register (ADR-001) with a lifecycle and notifications declared on the schema (ADR-031), shown with `CnIndexPage` and `CnDetailPage` (ADR-012). A formal board decision stays in decidiq, and stackiq links to it.
+
+## ADDED Requirements
+
+### Requirement: REQ-ADREG-001 An information manager SHALL record an architecture decision with its context, options and consequences
+
+Stackiq SHALL offer an Architecture decisions page at `/architectuurbesluiten` (page `Architectuurbesluiten`) and a decision page at `/architectuurbesluiten/:id` (page `ArchitectuurbesluitDetail`) under the Architecture menu group. A decision SHALL have a title, a context, the decision, the rejected alternatives each with a reason, the consequences, a category (application, data, integration, infrastructure, security or standards), an impact (low, medium or high), a status and a reviewer. Category, impact and status SHALL be facetable. Decisions SHALL be scoped to the organisation that recorded them.
+
+#### Scenario: An information manager records a decision
+@e2e tests/e2e/workflows/architecture-decisions.spec.ts
+
+- **GIVEN** a municipal information manager signed in to stackiq
+- **WHEN** they open Architecture, then Architecture decisions, create the decision Nieuwe koppelingen alleen via API's with category integration, impact medium, one rejected alternative and a reviewer, and save
+- **THEN** the page SHALL list the decision with status draft
+- **AND** its page SHALL show the rejected alternative with its reason
+
+#### Scenario: Another municipality does not see the decision
+@e2e exclude The CI instance has one organisation; tests/Unit/Settings/ArchitectureDecisionRegisterShapeTest.php asserts the read rules match on _organisation, as usage does.
+
+- **GIVEN** a decision of municipality A
+- **WHEN** a user of municipality B opens the Architecture decisions page
+- **THEN** the decision SHALL NOT be listed
+
+### Requirement: REQ-ADREG-002 A decision SHALL be reviewed by a second person through a declared lifecycle
+
+The status SHALL move through transitions declared as `x-openregister-lifecycle`: submit (draft to in review), accept and reject (in review to accepted or rejected), rework (in review or rejected to draft), supersede (accepted to superseded) and deprecate (accepted to deprecated), with values that are members of the status enum. Submit SHALL be allowed only when the reviewer is a Nextcloud user other than the caller. Accept and reject SHALL be allowed only for the reviewer. Supersede SHALL be allowed only when the decision names an accepted decision that supersedes it. A denied transition SHALL answer 403 with the reason, whether it was applied as an action or as a direct edit of the status.
+
+#### Scenario: A reviewer accepts a decision
+@e2e tests/e2e/workflows/architecture-decisions.spec.ts
+
+- **GIVEN** a decision in review whose reviewer is a second test user, created by the test fixture
+- **WHEN** that reviewer opens the decision and applies Accept
+- **THEN** the decision SHALL read accepted
+- **AND** the transition SHALL appear in its History tab
+
+#### Scenario: The author cannot accept their own decision
+@e2e exclude A guard rule; tests/Unit/Lifecycle/ArchitectureDecisionReviewGuardTest.php asserts that submit is denied when the reviewer is the caller and that accept and reject are denied for anyone but the reviewer.
+
+- **GIVEN** a decision in review whose reviewer is a colleague
+- **WHEN** the author applies Accept
+- **THEN** the transition SHALL be denied with a 403 naming the reviewer rule
+
+#### Scenario: A decision is superseded only by an accepted one
+@e2e exclude A guard rule; tests/Unit/Lifecycle/ArchitectureDecisionReviewGuardTest.php asserts supersede is allowed when supersededBy points at an accepted decision and denied otherwise.
+
+- **GIVEN** an accepted decision whose supersededBy names a decision still in draft
+- **WHEN** the owner applies Supersede
+- **THEN** the transition SHALL be denied
+
+### Requirement: REQ-ADREG-003 The reviewer and the owner SHALL be notified through declared notifications
+
+The schema SHALL declare in `x-openregister-notifications` a notification to the reviewer when a decision enters in review, and a notification to the owners of the decision when it is accepted or rejected, on the channels Nextcloud notification and email, with Dutch and English subjects.
+
+#### Scenario: A reviewer is told a decision waits for them
+@e2e exclude Delivery runs in OpenRegister's engine; tests/Unit/Settings/ArchitectureDecisionRegisterShapeTest.php asserts the review-requested rule uses the field recipient reviewer and the review-concluded rule the object-acl manage recipient, and that both subjects have nl and en.
+
+- **GIVEN** a decision with a colleague as reviewer
+- **WHEN** the author submits it
+- **THEN** the colleague SHALL receive a Nextcloud notification that links to the decision
+
+### Requirement: REQ-ADREG-004 A decision SHALL link to the applications and elements it affects and to board decisions
+
+A decision SHALL hold a list of the usages it affects, a list of the AMEF elements it affects, the decision it supersedes, the decision that supersedes it, and a list of decidiq decision ids with `x-external-register` decidesk. The usage page `GebruikDetail` and the standard page `StandaardDetail` SHALL each list the architecture decisions that name them.
+
+#### Scenario: An application owner sees the decisions about their application
+@e2e tests/e2e/workflows/architecture-decisions.spec.ts
+
+- **GIVEN** the seeded accepted decision Eén zaaksysteem voor alle domeinen linked to the seeded Suite4 usage
+- **WHEN** an application owner opens that usage at `/gebruik/:id`
+- **THEN** the list Architecture decisions SHALL show the decision with status accepted
+- **AND** choosing it SHALL open the decision page
+
+#### Scenario: A decision links a board decision without copying it
+@e2e exclude The CI instance runs without decidiq; tests/Unit/Settings/ArchitectureDecisionRegisterShapeTest.php asserts boardDecisions is a uuid list with x-external-register decidesk and referenceType decision, as catalogContract.decisions is.
+
+- **GIVEN** a decision adopted by a board in decidiq
+- **WHEN** the owner adds the decidiq decision to the architecture decision
+- **THEN** the architecture decision SHALL store only the decidiq decision id
diff --git a/openspec/changes/architecture-decision-register/tasks.md b/openspec/changes/architecture-decision-register/tasks.md
new file mode 100644
index 000000000..9447ed36e
--- /dev/null
+++ b/openspec/changes/architecture-decision-register/tasks.md
@@ -0,0 +1,62 @@
+# Tasks: architecture-decision-register
+
+## Implementation tasks
+
+### Task 1: Register fragment with lifecycle and notifications
+- **spec_ref**: openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md#requirement-req-adreg-001-an-information-manager-shall-record-an-architecture-decision-with-its-context-options-and-consequences
+- **files**: `lib/Settings/register.d/architecture-decision-register.json`, `tests/Unit/Settings/ArchitectureDecisionRegisterShapeTest.php`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it loads THEN the `stackiq` register lists `architectureDecision` with magic mapping on and read rules matched on `_organisation`
+ - GIVEN the lifecycle WHEN the shape test reads it THEN every `from` and `to` value is a status enum value and every `requires` equals the guard's class name
+ - GIVEN the notifications WHEN the shape test reads them THEN review-requested uses the field recipient reviewer, review-concluded the object-acl manage recipient, and both subjects have nl and en
+ - GIVEN `boardDecisions` WHEN the shape test reads it THEN it matches the shape of `catalogContract.decisions`
+ - GIVEN a fresh install WHEN the seed runs THEN the two demo decisions exist
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchitectureDecisionRegisterShapeTest`, `RegisterFragmentMergeTest`)
+
+### Task 2: Review guard
+- **spec_ref**: openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md#requirement-req-adreg-002-a-decision-shall-be-reviewed-by-a-second-person-through-a-declared-lifecycle
+- **files**: `lib/Lifecycle/ArchitectureDecisionReviewGuard.php`, `tests/Stubs/`, `tests/Unit/Lifecycle/ArchitectureDecisionReviewGuardTest.php`
+- **acceptance_criteria**:
+ - GIVEN submit WHEN the reviewer is empty, unknown or the caller THEN the guard denies with a message
+ - GIVEN accept or reject WHEN the caller is not the reviewer THEN the guard denies
+ - GIVEN supersede WHEN supersededBy is not an accepted decision THEN the guard denies
+ - GIVEN any action WHEN the guard runs THEN it writes nothing
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchitectureDecisionReviewGuardTest`, psalm and phpstan on the guard)
+
+### Task 3: Decision pages and menu
+- **spec_ref**: openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md#requirement-req-adreg-001-an-information-manager-shall-record-an-architecture-decision-with-its-context-options-and-consequences
+- **files**: `src/manifest.d/architecture-decision-register.json`, `src/menu-layout.json`, `tests/e2e/workflows/architecture-decisions.spec.ts`
+- **acceptance_criteria**:
+ - GIVEN the effective manifest WHEN it is built THEN `Architectuurbesluiten` and `ArchitectuurbesluitDetail` exist with the quick filter "To review by me" on `@me`
+ - GIVEN the effective menu WHEN it renders THEN Architecture decisions sits under the Architecture group
+ - GIVEN a decision page WHEN it renders THEN its lifecycle actions and History tab show
+- [ ] Implement
+- [ ] Test (`tests/validate-manifest.js`, Playwright record and accept scenarios)
+
+### Task 4: Decisions on the usage and standard pages
+- **spec_ref**: openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md#requirement-req-adreg-004-a-decision-shall-link-to-the-applications-and-elements-it-affects-and-to-board-decisions
+- **files**: `src/manifest.d/usages.json`, `src/manifest.json`
+- **acceptance_criteria**:
+ - GIVEN a decision that names a usage WHEN the usage page opens THEN Architecture decisions lists it
+ - GIVEN a decision that names a standard WHEN the standard page opens THEN Architecture decisions lists it
+- [ ] Implement
+- [ ] Test (Playwright usage page scenario)
+
+### Task 5: Documentation and translations
+- **spec_ref**: openspec/changes/architecture-decision-register/specs/architecture-decision-register/spec.md#requirement-req-adreg-002-a-decision-shall-be-reviewed-by-a-second-person-through-a-declared-lifecycle
+- **files**: `docs/features/architecture-decisions.md`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the feature page WHEN it is read THEN it shows a decision page, the review step and the list on a usage page, each in a screenshot, and explains when to use decidiq
+ - GIVEN a Dutch instance WHEN the pages render THEN every new label and enum value reads in Dutch
+- [ ] Implement
+- [ ] Test (`tests/l10n` key parity, screenshots captured with Playwright)
+
+## Verification
+
+- `openspec validate architecture-decision-register --type change --strict`
+- PHPUnit: `ArchitectureDecisionRegisterShapeTest`, `ArchitectureDecisionReviewGuardTest`, `RegisterFragmentMergeTest`
+- Playwright: `tests/e2e/workflows/architecture-decisions.spec.ts`
+- Documentation in `docs/features/architecture-decisions.md` with screenshots (ADR-010)
+- English and Dutch strings for every new label, enum value and notification subject (ADR-005)
diff --git a/openspec/changes/architecture-future-state-scenarios/.openspec.yaml b/openspec/changes/architecture-future-state-scenarios/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-future-state-scenarios/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-future-state-scenarios/design.md b/openspec/changes/architecture-future-state-scenarios/design.md
new file mode 100644
index 000000000..3771b1eb2
--- /dev/null
+++ b/openspec/changes/architecture-future-state-scenarios/design.md
@@ -0,0 +1,149 @@
+# Design: architecture-future-state-scenarios
+
+Read at development 49e65cb4. Line numbers below are from that sha. `ReferenceComponentCoverageDerivation`, `ReferenceComponentCoverageService` and `OrganisationReportAccess` come from `architecture-reference-component-coverage` (its D1 and D2); the Architecture menu group from `architecture-views-editor` (its D8); `GebruikDetail` and the usage lifecycle on English values from `landscape-usage-registration`.
+
+## Where it fits
+
+| Layer | Touched | Read at |
+|---|---|---|
+| Register | `stackiq` register (`lib/Settings/softwarecatalogus_register.json:817`), new schemas `scenario` and `scenarioChange`; `usage` (:2654) read and, on apply, written | through a new fragment `lib/Settings/register.d/architecture-future-state-scenarios.json` |
+| Derivation | new `lib/Service/LandscapeAtDateDerivation.php` | pure, uses `PortfolioReportDerivation::deriveLifecyclePhase` (`lib/Service/PortfolioReportDerivation.php:58`) |
+| Service | new `lib/Service/LandscapeComparisonService.php` | reads usages through `ReferenceComponentCoverageService` and scores both landscapes with `ReferenceComponentCoverageDerivation` |
+| Controller and route | new `lib/Controller/LandscapeComparisonController.php`, route `landscapeComparison#index` at `GET /api/landscape-comparison`, next to `portfolioReport#index` (`appinfo/routes.php:303`) | |
+| Pages | new `src/manifest.d/architecture-future-state-scenarios.json` with `Scenarios` (index), `ScenarioDetail` (detail) and `LandscapeComparison` (custom) | |
+| Views | new `src/views/architecture/LandscapeComparisonView.vue`; `src/views/LifecycleRoadmapView.vue` gains a Compare with the plan button in its header (:4 to :24) | registered in `src/customComponents.js` |
+| Store | new `src/store/modules/scenarioApply.js` | writes through OpenRegister's objects API |
+| Menu | `src/menu-layout.json` relocates `Scenarios` under the `Architecture` group | |
+
+The fragment merges through `SettingsService::loadSettings` (`lib/Service/SettingsService.php:1653-1680`, `deepMergeConfig` at :7338) with `components.schemas`, `components.registers.stackiq.schemas` and `components.registers.stackiq.configuration.schemas` entries for both new schemas.
+
+## Decisions
+
+### D1. The plan is read from the dates, at any date
+
+The landscape on date D holds every usage whose phase on D, by `deriveLifecyclePhase($usage, D)` (`PortfolioReportDerivation.php:58`), is In production or To be phased out. A usage whose `plannedReplacementDate` is on or before D leaves the landscape on that date and its `plannedReplacement` module enters it as a planned successor, carrying the usage's `usedForReferenceComponents`. A usage with no phase date but a `status` of In production or To be phased out (the schema default is In production, register.json usage `status`) is in today's landscape with that phase and stays in every later landscape until a date or a scenario change says otherwise, because most usages carry a status and no dates. A usage with neither a phase date nor one of those status values reads Onbekend and is listed apart as not dated.
+
+Today's landscape is the same function with D set to today. So "today" and "the plan on D" come from one rule. The Portfolio roadmap uses the same date rule in the browser (`src/utils/lifecyclePhase.js:101`); the one difference is the status fallback, and a usage it adds is one the roadmap shows in its Onbekend lane.
+
+Rejected: a stored snapshot of the landscape per date. It would be a second copy of the usages that drifts when a date is edited, which the archived lifecycle change ruled out for the phase (its design Decision 1).
+
+### D2. A scenario is a change set on top of the plan
+
+`scenario`:
+
+| Field | Type | Notes |
+|---|---|---|
+| name | string, required | |
+| description | string | |
+| organisation | related `organization`, required | the landscape it changes; the comparison checks access on it |
+| targetDate | date, required | |
+| status | enum draft, proposed, adopted, rejected, default draft, facetable | lifecycle in the Declarative section |
+| appliedAt | date-time | set when the scenario is applied |
+
+`scenarioChange`:
+
+| Field | Type | Notes |
+|---|---|---|
+| scenario | related `scenario`, required | |
+| action | enum add, phase out, replace, required | |
+| usage | related `usage` | required for phase out and replace |
+| module | related `module` | required for add and replace |
+| referenceComponents | list of related `element`, query `gemmaType=referentiecomponent` | for add and replace; the form fills it from `module.referenceComponents` |
+| effectiveDate | date | defaults to the scenario's target date |
+| note | string | |
+| appliedTo | related `usage` | set on apply, so a second apply changes nothing |
+
+The scenario landscape on its target date is the plan on that date with the changes applied in order of `effectiveDate`. Each difference in the comparison names its source: plan or scenario.
+
+Rejected: future-state flags on usages, as BlueDolphin does on objects. A flag holds one future; two options for the same decision (replace A by B, or by C) need two change sets side by side.
+
+Rejected: a copy of every usage per scenario. Copies go stale the moment today's landscape changes, while a change set stays small and is always read against the current data.
+
+### D3. One comparison endpoint
+
+`GET /api/landscape-comparison?organisation=&date=&scenario=` (scenario optional; with a scenario, its organisation and target date are used). The controller runs `OrganisationReportAccess::isAuthorised` before any read and fails closed, as the two report controllers do. `LandscapeComparisonService` reads the organisation's usages once with the bounded query of `ReferenceComponentCoverageService`, and reads the scenario's changes with RBAC on. `LandscapeAtDateDerivation` builds both landscapes, and `ReferenceComponentCoverageDerivation` scores each for coverage. The response:
+
+```json
+{
+ "organisation": "00000000-0000-0000-0000-000000000000",
+ "today": "2026-09-27",
+ "date": "2027-06-30",
+ "scenario": null,
+ "applications": [
+ { "moduleName": "Zaaksysteem A", "change": "removed", "source": "plan", "date": "2027-03-01" }
+ ],
+ "coverage": [
+ { "component": "Zaakregistratiecomponent", "today": "overlap", "future": "covered" }
+ ],
+ "notDated": 2,
+ "truncated": false
+}
+```
+
+`change` is one of added, removed, replaced (with `replacedBy`) and unchanged; `coverage` lists only components whose state differs.
+
+Rejected: computing the comparison in the browser with `lifecyclePhase.js`. The coverage half needs the reference components and the organisation-scoped usage read that `architecture-reference-component-coverage` put behind one bounded endpoint; a second path in the browser would read them differently.
+
+### D4. The pages
+
+`Scenarios` (`/scenarios`) is a `CnIndexPage` over `scenario` with columns name, organisation, targetDate and status, and quick filters All, Draft, Proposed and Adopted. `ScenarioDetail` (`/scenarios/:id`) is a `type: detail` page with a `data` widget, an `object-list` widget over `scenarioChange` with filter `{"scenario": "@objectId"}` and columns action, usage, module and effectiveDate, the body widget `LandscapeComparisonView` bound to the scenario, `lifecycleActions` on, and the History tab.
+
+`LandscapeComparison` (`/landscape-comparison`) is a custom page holding `LandscapeComparisonView` with an organisation picker and a date picker, for the plan alone. The Portfolio roadmap header gets a button Compare with the plan that opens it with the roadmap's organisation.
+
+`LandscapeComparisonView.vue` shows two columns, Today and the chosen date, with a `CnDataTable` of application differences (a text tag Added, Removed or Replaced by, and the source), a table of coverage differences (gap closed, gap opened, overlap resolved, overlap created) and the not dated count. Colours are Nextcloud CSS variables and every state is also a word.
+
+### D5. Applying an adopted scenario
+
+On an adopted scenario that has no `appliedAt`, the scenario page offers Apply to landscape. `src/store/modules/scenarioApply.js` writes each change through OpenRegister's objects API as the signed-in user:
+
+| Action | Write |
+|---|---|
+| add | a new `usage` with `consumer` the scenario's organisation, `module`, `usedForReferenceComponents`, `status` Planned and `startDateInProduction` the effective date |
+| phase out | `startDateOutPhased` on the usage set to the effective date |
+| replace | `plannedReplacement` and `plannedReplacementDate` on the usage |
+
+It stores the written usage in `appliedTo` after each write and sets `appliedAt` last. A retry skips changes that have `appliedTo`. After the apply, the plan comparison and the Portfolio roadmap show the changes, because they read the same fields.
+
+Rejected: a PHP service for the apply. It is three plain object writes per change with no rule the platform does not already enforce (ADR-022, config rule "Uses OpenRegister API directly from frontend").
+
+## Declarative versus imperative
+
+- The scenario status lifecycle is declared as `configuration.x-openregister-lifecycle` on `scenario`: initial draft, final adopted, transitions propose (draft to proposed), adopt (proposed to adopted), reject (proposed to rejected) and rework (proposed or rejected to draft). The `from` and `to` values are the enum values exactly (register changelog 2.4.4, register.json:7).
+- The scenario to change and change to usage links are `related-object` properties; the change list is a manifest `object-list`. No PHP.
+- The comparison is imperative, because it joins usages, planned dates, a change set and reference components across two registers, which no `x-openregister-aggregation` expresses. It is a pure derivation behind one bounded endpoint.
+- The apply is imperative and runs in the browser store.
+
+## Seed data
+
+All objects live in the `stackiq` register. They use the three usages the register already seeds (register.json `components.objects`).
+
+### Schema: `scenario`
+
+| Field | Object 1 |
+|---|---|
+| slug | `seed-scenario-delft-2027` |
+| name | Servicedesk en schuldhulp in 2027 |
+| organisation | `gemeente-delft` |
+| targetDate | 2027-06-30 |
+| status | proposed |
+
+### Schema: `scenarioChange`
+
+| Field | Object 1 | Object 2 |
+|---|---|---|
+| slug | `seed-scenario-change-uitfaseren` | `seed-scenario-change-toevoegen` |
+| scenario | `seed-scenario-delft-2027` | `seed-scenario-delft-2027` |
+| action | phase out | add |
+| usage | `gebruik-suite4-gem-delft-eigenaar` | |
+| module | | `topdesk-itsm` |
+| effectiveDate | 2027-06-30 | 2027-03-01 |
+| note | Schuldhulp gaat naar de regio. | Eigen servicedesk in plaats van de gedeelde. |
+
+The module slug `topdesk-itsm` is the module the seeded TOPdesk usage of Servicecenter Rijnland points at, so the demo needs no new module. The seeded usages hold `status` `in-gebruik`, which is not an enum value, and no phase dates, so the Suite4 usage reads not dated until its status is set; the demo scenario shows that case on purpose. The Playwright spec builds its own usages with dates through OpenRegister's objects API instead of relying on the seed.
+
+## Risks
+
+- **Undated usages.** A usage with no phase date and no current status value is in neither landscape. The count of not dated usages sits next to the comparison so a reader sees why an application is missing.
+- **Two sources for one date.** A plan replacement and a scenario change can touch the same usage. The scenario change wins, and the difference says both sources.
+- **Partial apply.** A failed write stops the apply with a notice naming the change; `appliedTo` makes the retry safe, and `appliedAt` is set only when every change is written.
+- **Schema versions.** Both schemas are new, so no version bump is needed on existing schemas.
diff --git a/openspec/changes/architecture-future-state-scenarios/proposal.md b/openspec/changes/architecture-future-state-scenarios/proposal.md
new file mode 100644
index 000000000..f05924552
--- /dev/null
+++ b/openspec/changes/architecture-future-state-scenarios/proposal.md
@@ -0,0 +1,49 @@
+---
+kind: code
+depends_on:
+ - architecture-views-editor
+ - architecture-reference-component-coverage
+ - landscape-usage-registration
+---
+
+# Compare a future landscape with today's
+
+## Summary
+
+A municipal information manager picks a date and sees the organisation's landscape on that date next to today's: which applications come in, go out or are replaced, and which reference component gaps and overlaps that closes or opens. The future comes from what the data already plans (planned usages, phase-out dates, planned replacements). On top of that plan they can write a named scenario, a what-if with its own additions, phase-outs and replacements, compare it the same way, take it through a proposal and adoption, and apply an adopted scenario to the landscape as planned changes.
+
+## Why
+
+This change builds one row of the stackiq parity matrix: `stackiq:arch-scenarios`, "Model a future-state landscape and compare it with today's." No tender or feature request names it.
+
+- SAP LeanIX rates yes: "plan your target architecture and monitor initiative progress" (https://help.sap.com/docs/leanix/ea/sap-leanix-architecture-and-road-map-planning), and "Understanding your architecture across the past, present, and future ... introducing the committed future" (https://updates.leanix.net/announcements/plan-with-consistent-future-architecture-data-introducing-the-committed-future).
+- BlueDolphin rates yes: "Objects can be either Current (default) or Future state" (https://help.bluedolphin.io/en/articles/11967531-object-lifecycle-state) and "Map current and future state capabilities" (https://bluedolphin.io/capability-based-planning/).
+- GEMMA Softwarecatalogus rates partial: "geplande harmonisaties ... met een status gepland met bijbehorende datum. Zo kan ook het uiteindelijke doel-landschap in 1 overzicht inzichtelijk worden gemaakt" (https://www.softwarecatalogus.nl/node/19703), with no side-by-side comparison.
+
+The lane decided build because two competitors rate yes and architecture is a core area. The matrix note holds: planned usage and planned replacements exist per record, but there is no future-state model and no comparison with today.
+
+## What stackiq has today
+
+- A usage carries five phase start dates, from `startDateAcquisition` to `startDateOutPhased`, a `status` with the value Planned, and `plannedReplacement` with `plannedReplacementDate` (`lib/Settings/softwarecatalogus_register.json:3070` and the usage schema at :2654). The archived change `2026-06-14-application-lifecycle-tracking` added the replacement fields as "an organisation's portfolio decision about its usage" (its design Decision 3).
+- The phase of a usage at any moment is a pure function of those dates, in the browser (`src/utils/lifecyclePhase.js:101`, `derivePhase(gebruik, now)`) and in PHP (`lib/Service/PortfolioReportDerivation.php:58`, `deriveLifecyclePhase`). Both take the moment as an argument.
+- The Portfolio roadmap page (`src/manifest.json:1013`, `src/views/LifecycleRoadmapView.vue`) groups today's usages by phase and orders them by the nearest EOL, phase-out or replacement date (`buildEntry`, :394). It shows one moment, today, and no comparison.
+- `architecture-reference-component-coverage` adds a pure coverage derivation and the shared organisation check `OrganisationReportAccess`.
+
+## What this change builds
+
+- A landscape comparison: `lib/Service/LandscapeComparisonService.php` and `GET /api/landscape-comparison`, which builds today's landscape and the landscape on a date (the plan, plus a scenario when one is named) and returns the application differences and the coverage differences.
+- Two schemas in the `stackiq` register: `scenario` (name, organisation, target date, status) and `scenarioChange` (add, phase out or replace).
+- A Scenarios index and a scenario page with the comparison, under the Architecture menu group, and a Compare with the plan page reached from the Portfolio roadmap.
+- An Apply to landscape action on an adopted scenario that writes its changes into the usages as planned dates and replacements.
+
+## Out of scope
+
+- Cost of a future landscape. Cost stays with the contract administration, as the archived lifecycle change decided.
+- Future states of GEMMA elements or views. BlueDolphin marks objects as future; this change works on the organisation's applications in use.
+- Drawing a target architecture view. The view editor from `architecture-views-editor` can draw one; linking a view to a scenario can follow.
+- Approval of a scenario by a board. The adopt transition records the decision; routing it to decidiq is `architecture-decision-register`'s question.
+
+## Risks
+
+- A plan built from dates is only as good as the dates. Usages without dates have phase Onbekend at every moment; the comparison lists them apart as "not dated" instead of guessing.
+- Applying a scenario writes to usages other people own. It runs only on an adopted scenario, as the signed-in user with their rights, and every write shows in the usage's History tab.
diff --git a/openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md b/openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md
new file mode 100644
index 000000000..c6b1e1206
--- /dev/null
+++ b/openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md
@@ -0,0 +1,99 @@
+# future-state-scenarios specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-future-state-scenarios
+
+## Purpose
+
+A municipality compares its landscape of today with its landscape on a future date: first as the data already plans it, then with a named scenario of its own on top. The comparison shows which applications come, go or are replaced, and which reference component gaps and overlaps that changes. An adopted scenario can be applied to the usages as planned dates and replacements. Scenarios are objects in the `stackiq` register (ADR-001) with a declared status lifecycle (ADR-031), shown with `CnIndexPage` and `CnDetailPage` (ADR-012).
+
+## ADDED Requirements
+
+### Requirement: REQ-FSS-001 Stackiq SHALL derive an organisation's landscape on any date from its usage dates
+
+The landscape on a date SHALL hold every usage of the organisation whose phase on that date, derived from its phase start dates, is In production or To be phased out. A usage whose planned replacement date is on or before that date SHALL leave the landscape, and its planned replacement module SHALL enter it as a planned successor with the same reference components. A usage with no phase date but a status of In production or To be phased out SHALL be in today's landscape and in every later one until a date or a scenario change removes it. A usage with neither SHALL be counted as not dated and SHALL be in neither landscape. Today's landscape SHALL be the same rule with today's date.
+
+#### Scenario: A planned replacement shows on its date
+@e2e exclude A pure derivation; tests/Unit/Service/LandscapeAtDateDerivationTest.php asserts that a usage with plannedReplacementDate 2027-03-01 is in the landscape on 2027-02-28 and replaced by its successor on 2027-03-01.
+
+- **GIVEN** a usage in production with a planned replacement by another module on 2027-03-01
+- **WHEN** the landscape is derived for 2027-02-28 and for 2027-03-01
+- **THEN** the first SHALL hold the usage
+- **AND** the second SHALL hold the successor module instead, with the usage's reference components
+
+#### Scenario: A usage with only a status counts, one with nothing is counted apart
+@e2e exclude A pure derivation; tests/Unit/Service/LandscapeAtDateDerivationTest.php asserts that a usage with status In production and no dates is in both landscapes, and that a usage with neither a date nor a current status is in neither and raises the not dated count by one.
+
+- **GIVEN** a usage with status In production and no dates, and a usage with no phase date and the status in-gebruik
+- **WHEN** today's landscape and a future landscape are derived
+- **THEN** the first SHALL be in both landscapes
+- **AND** the second SHALL be in neither, and the not dated count SHALL be one
+
+### Requirement: REQ-FSS-002 An information manager SHALL compare today's landscape with the plan on a date
+
+`GET /api/landscape-comparison?organisation=&date=` SHALL return the application differences between today and the date (added, removed, replaced by, unchanged, each with its date and the source plan), the reference components whose coverage state differs, and the not dated count. It SHALL refuse a user not authorised for the organisation before it reads anything. The page `LandscapeComparison` at `/landscape-comparison`, opened from a Compare with the plan button on the Portfolio roadmap, SHALL show both landscapes side by side with these differences in text.
+
+#### Scenario: An information manager sees what the plan changes by next summer
+@e2e tests/e2e/workflows/future-state-scenarios.spec.ts
+
+- **GIVEN** a usage of the test organisation with a planned replacement on 2027-03-01, created by the test fixture
+- **WHEN** a municipal information manager opens Portfolio roadmap, chooses Compare with the plan and picks 2027-06-30
+- **THEN** the comparison SHALL list the usage as replaced by its successor with source plan
+- **AND** today's column SHALL still hold the usage
+
+#### Scenario: Another organisation's comparison is refused
+@e2e exclude Needs a second organisation; tests/Unit/Controller/LandscapeComparisonControllerTest.php asserts a 403 before any service call through OrganisationReportAccess.
+
+- **GIVEN** a user of municipality A
+- **WHEN** they call `GET /api/landscape-comparison` for municipality B
+- **THEN** the response SHALL be 403
+
+### Requirement: REQ-FSS-003 An information manager SHALL write a scenario of additions, phase-outs and replacements
+
+Stackiq SHALL offer a Scenarios page at `/scenarios` (page `Scenarios`) and a scenario page at `/scenarios/:id` (page `ScenarioDetail`) under the Architecture menu group. A scenario SHALL have a name, a description, an organisation, a target date and a status. A scenario change SHALL be one of add (a module with the reference components it will be used for), phase out (a usage) or replace (a usage by a module), with an optional effective date that defaults to the target date. The scenario page SHALL list its changes and SHALL show the comparison between today and the scenario landscape, where the scenario landscape is the plan on the target date with the changes applied, and every difference SHALL name its source, plan or scenario.
+
+#### Scenario: An information manager tries a replacement
+@e2e tests/e2e/workflows/future-state-scenarios.spec.ts
+
+- **GIVEN** a usage in production of the test organisation and a second module, created by the test fixture
+- **WHEN** a municipal information manager opens Architecture, then Scenarios, creates a scenario for the test organisation with a target date next year, and adds a change that replaces the usage by the second module
+- **THEN** the scenario page SHALL list the change
+- **AND** the comparison SHALL show the usage as replaced by the second module with source scenario
+
+#### Scenario: A scenario change wins over the plan
+@e2e exclude A pure derivation; tests/Unit/Service/LandscapeAtDateDerivationTest.php asserts that a scenario phase out of a usage that the plan replaces reads as removed with both sources named.
+
+- **GIVEN** a usage the plan replaces on the target date and a scenario that phases it out
+- **WHEN** the scenario landscape is derived
+- **THEN** the usage SHALL be removed with the source scenario
+- **AND** the difference SHALL also name the plan
+
+### Requirement: REQ-FSS-004 A scenario SHALL move through a declared lifecycle and an adopted scenario SHALL be applied to the landscape
+
+The `scenario` status SHALL move through transitions declared as `x-openregister-lifecycle`: propose (draft to proposed), adopt (proposed to adopted), reject (proposed to rejected) and rework (proposed or rejected to draft), with values that are members of the status enum. An adopted scenario without an applied date SHALL offer Apply to landscape, which SHALL write each change as the signed-in user: add creates a usage with status Planned and the effective date as its production start, phase out sets the usage's phased out date, and replace sets its planned replacement and date. Each applied change SHALL record the usage it wrote, and a retry SHALL skip it. The scenario SHALL record when it was applied.
+
+#### Scenario: An information manager applies an adopted scenario
+@e2e tests/e2e/workflows/future-state-scenarios.spec.ts
+
+- **GIVEN** a proposed scenario of the test organisation, created by the test fixture, that adds a module on 2027-03-01 and phases out a usage on 2027-06-30
+- **WHEN** a municipal information manager applies Adopt and then Apply to landscape
+- **THEN** a new usage of that module SHALL exist with status Planned and production start 2027-03-01
+- **AND** the phased out usage SHALL carry the phased out date 2027-06-30
+- **AND** Apply to landscape SHALL no longer be offered
+
+#### Scenario: A retried apply writes nothing twice
+@e2e exclude A store rule; tests/vitest/scenarioApply.spec.js asserts that a change with appliedTo is skipped and that appliedAt is set only after the last write.
+
+- **GIVEN** an apply that failed after its first change was written
+- **WHEN** the information manager applies again
+- **THEN** the first change SHALL NOT be written again
+- **AND** the scenario SHALL get its applied date once every change is written
+
+#### Scenario: The lifecycle matches the enum
+@e2e exclude The transition engine is OpenRegister's; tests/Unit/Settings/ScenarioRegisterShapeTest.php asserts every lifecycle from and to value is a member of the status enum.
+
+- **GIVEN** the merged register
+- **WHEN** the shape test reads the scenario lifecycle
+- **THEN** every `from` and `to` value SHALL be a status enum value
diff --git a/openspec/changes/architecture-future-state-scenarios/tasks.md b/openspec/changes/architecture-future-state-scenarios/tasks.md
new file mode 100644
index 000000000..d3e82920f
--- /dev/null
+++ b/openspec/changes/architecture-future-state-scenarios/tasks.md
@@ -0,0 +1,72 @@
+# Tasks: architecture-future-state-scenarios
+
+## Implementation tasks
+
+### Task 1: Landscape on a date
+- **spec_ref**: openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md#requirement-req-fss-001-stackiq-shall-derive-an-organisations-landscape-on-any-date-from-its-usage-dates
+- **files**: `lib/Service/LandscapeAtDateDerivation.php`, `tests/Unit/Service/LandscapeAtDateDerivationTest.php`
+- **acceptance_criteria**:
+ - GIVEN usages with phase dates WHEN the landscape is derived for a date THEN it holds the usages in production or to be phased out on that date
+ - GIVEN a planned replacement on or before the date WHEN the landscape is derived THEN the successor module replaces the usage with its reference components
+ - GIVEN a usage with only a current status, and one with nothing WHEN both landscapes are derived THEN the first is in both and the second is counted as not dated
+ - GIVEN a scenario change and a plan replacement on one usage WHEN the scenario landscape is derived THEN the scenario wins and both sources are named
+- [ ] Implement
+- [ ] Test (PHPUnit `LandscapeAtDateDerivationTest`)
+
+### Task 2: Comparison service, controller and route
+- **spec_ref**: openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md#requirement-req-fss-002-an-information-manager-shall-compare-todays-landscape-with-the-plan-on-a-date
+- **files**: `lib/Service/LandscapeComparisonService.php`, `lib/Controller/LandscapeComparisonController.php`, `appinfo/routes.php`, `tests/Unit/Service/LandscapeComparisonServiceTest.php`, `tests/Unit/Controller/LandscapeComparisonControllerTest.php`
+- **acceptance_criteria**:
+ - GIVEN a user of another organisation WHEN the endpoint is called THEN it answers 403 before the service runs
+ - GIVEN an organisation and a date WHEN the endpoint is called THEN it returns application and coverage differences in the shape of design D3
+ - GIVEN a scenario id WHEN the endpoint is called THEN the scenario's organisation and target date are used and its changes are read with RBAC on
+- [ ] Implement
+- [ ] Test (PHPUnit `LandscapeComparisonServiceTest`, `LandscapeComparisonControllerTest`)
+
+### Task 3: Register fragment for scenarios
+- **spec_ref**: openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md#requirement-req-fss-004-a-scenario-shall-move-through-a-declared-lifecycle-and-an-adopted-scenario-shall-be-applied-to-the-landscape
+- **files**: `lib/Settings/register.d/architecture-future-state-scenarios.json`, `tests/Unit/Settings/ScenarioRegisterShapeTest.php`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it loads THEN the `stackiq` register lists `scenario` and `scenarioChange` with magic mapping on
+ - GIVEN the scenario lifecycle WHEN the shape test reads it THEN every `from` and `to` value is a status enum value
+ - GIVEN a fresh install WHEN the seed runs THEN the demo scenario and its two changes exist
+- [ ] Implement
+- [ ] Test (PHPUnit `ScenarioRegisterShapeTest`, `RegisterFragmentMergeTest`)
+
+### Task 4: Comparison view, scenario pages and the roadmap button
+- **spec_ref**: openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md#requirement-req-fss-003-an-information-manager-shall-write-a-scenario-of-additions-phase-outs-and-replacements
+- **files**: `src/manifest.d/architecture-future-state-scenarios.json`, `src/menu-layout.json`, `src/views/architecture/LandscapeComparisonView.vue`, `src/views/LifecycleRoadmapView.vue`, `src/customComponents.js`, `tests/e2e/workflows/future-state-scenarios.spec.ts`
+- **acceptance_criteria**:
+ - GIVEN the effective manifest WHEN it is built THEN `Scenarios`, `ScenarioDetail` and `LandscapeComparison` exist and Scenarios sits under the Architecture group
+ - GIVEN the Portfolio roadmap WHEN Compare with the plan is chosen THEN the comparison page opens for the roadmap's organisation
+ - GIVEN a comparison WHEN it renders THEN every difference carries its change and source as text
+- [ ] Implement
+- [ ] Test (`tests/validate-manifest.js`, Playwright `future-state-scenarios.spec.ts` plan and scenario scenarios)
+
+### Task 5: Apply an adopted scenario
+- **spec_ref**: openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md#requirement-req-fss-004-a-scenario-shall-move-through-a-declared-lifecycle-and-an-adopted-scenario-shall-be-applied-to-the-landscape
+- **files**: `src/store/modules/scenarioApply.js`, `src/views/architecture/LandscapeComparisonView.vue`, `tests/vitest/scenarioApply.spec.js`
+- **acceptance_criteria**:
+ - GIVEN an adopted scenario without appliedAt WHEN Apply to landscape runs THEN add, phase out and replace write the fields of design D5
+ - GIVEN a change with appliedTo WHEN the apply runs again THEN it is skipped
+ - GIVEN a failed write WHEN the apply stops THEN appliedAt stays empty and the notice names the change
+- [ ] Implement
+- [ ] Test (vitest `scenarioApply.spec.js`, Playwright apply scenario)
+
+### Task 6: Documentation and translations
+- **spec_ref**: openspec/changes/architecture-future-state-scenarios/specs/future-state-scenarios/spec.md#requirement-req-fss-003-an-information-manager-shall-write-a-scenario-of-additions-phase-outs-and-replacements
+- **files**: `docs/features/future-state-scenarios.md`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the feature page WHEN it is read THEN it shows the plan comparison, a scenario page and the apply result, each in a screenshot
+ - GIVEN a Dutch instance WHEN the scenario pages render THEN every new label and enum value reads in Dutch
+- [ ] Implement
+- [ ] Test (`tests/l10n` key parity, screenshots captured with Playwright)
+
+## Verification
+
+- `openspec validate architecture-future-state-scenarios --type change --strict`
+- PHPUnit: `LandscapeAtDateDerivationTest`, `LandscapeComparisonServiceTest`, `LandscapeComparisonControllerTest`, `ScenarioRegisterShapeTest`, `RegisterFragmentMergeTest`
+- vitest: `scenarioApply.spec.js`
+- Playwright: `tests/e2e/workflows/future-state-scenarios.spec.ts`
+- Documentation in `docs/features/future-state-scenarios.md` with screenshots (ADR-010)
+- English and Dutch strings for every new label and enum value (ADR-005)
diff --git a/openspec/changes/architecture-process-mapping/.openspec.yaml b/openspec/changes/architecture-process-mapping/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-process-mapping/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-process-mapping/design.md b/openspec/changes/architecture-process-mapping/design.md
new file mode 100644
index 000000000..fcbc424d9
--- /dev/null
+++ b/openspec/changes/architecture-process-mapping/design.md
@@ -0,0 +1,135 @@
+# Design: architecture-process-mapping
+
+Read at development 49e65cb4. Line numbers below are from that sha. `GebruikDetail` comes from the open change `landscape-usage-registration` (its `design.md`, `src/manifest.d/usages.json`), and the Architecture menu group from `architecture-views-editor` (its design D8).
+
+## Where it fits
+
+| Layer | Touched | Read at |
+|---|---|---|
+| Register | `stackiq` register (`lib/Settings/softwarecatalogus_register.json:817`), new schemas `process` and `processStep` | through a new fragment `lib/Settings/register.d/architecture-process-mapping.json` |
+| Register, read only | `vng-gemma` `element` (:4130) for the reference process, `usage` (:2654) for the supporting applications | no change to either schema |
+| Pages | new `src/manifest.d/architecture-process-mapping.json` with `Processen` (index), `ProcesDetail` (detail) and `ProcesStapDetail` (detail) | |
+| Pages | `GebruikDetail` in `src/manifest.d/usages.json` (from `landscape-usage-registration`) gains an `object-list` widget | |
+| Menu | `src/menu-layout.json` relocates `Processen` under the `Architecture` group | |
+| Views | new `src/views/architecture/ProcessStepFlow.vue` and `src/views/architecture/ProcessStepUsages.vue`, registered in `src/customComponents.js` | |
+| Service, controller, routes | none | the frontend writes through OpenRegister's objects API (config rule "Uses OpenRegister API directly from frontend") |
+
+The fragment merges through `SettingsService::loadSettings` (`lib/Service/SettingsService.php:1653-1680`, `deepMergeConfig` at :7338). It carries `components.schemas.process`, `components.schemas.processStep`, `components.registers.stackiq.schemas: ["process", "processStep"]` and `components.registers.stackiq.configuration.schemas.: {"magicMapping": true, "autoCreateTable": true}` for both.
+
+## Decisions
+
+### D1. A process is organisation data in the `stackiq` register
+
+`process` and `processStep` live in the `stackiq` register next to `usage`, with the same authorization shape `usage` has (register.json, `usage.authorization`): create and update for the catalogue groups, read for `gebruik-beheerder` and `aanbod-beheerder` matched on `_organisation`. Processes are the municipality's own, like its usages, so OpenRegister multitenancy scopes them to the organisation that made them.
+
+`process` carries `configuration.jsonld.type` `https://schema.org/HowTo` and `processStep` carries `https://schema.org/HowToStep`, in the way `module` carries `SoftwareApplication`.
+
+Rejected: a process as an AMEF `element` of type `BusinessProcess` in the `vng-gemma` register, with steps as child elements and Composition relations. The AMEF register holds VNG's model, `element` has 86 properties built for GEMMA content, and a municipality's process would need the `origin` guards of `architecture-views-editor` D9 on every reader. The supporting applications are `usage` objects in the `stackiq` register, and a relation across the two registers is what the organisation data already does through `usedForReferenceComponents`.
+
+### D2. The schemas
+
+`process`:
+
+| Field | Type | Notes |
+|---|---|---|
+| name | string, required | |
+| description | string | |
+| processOwner | related `contactPerson` | picked from the organisation's contact roles, as `landscape-usage-registration` does for owners |
+| status | enum draft, active, retired, default draft, facetable | lifecycle in the Declarative section |
+| referenceProcess | related `element` in `vng-gemma`, `objectConfiguration.queryParams` `type=BusinessProcess` | the GEMMA reference process this one follows |
+| tags | list of strings, facetable | |
+
+`processStep`:
+
+| Field | Type | Notes |
+|---|---|---|
+| process | related `process`, required | |
+| name | string, required | |
+| description | string | |
+| stepType | enum task, event, decision, default task | |
+| position | integer, required | the order within the process |
+| follows | list of `processStep` uuids | empty means "the step before it by position" |
+| usages | list of related `usage` | the applications in use that support the step |
+| riskLevel | enum not assessed, low, medium, high, default not assessed, facetable | |
+| riskNote | string | |
+| complianceCheck | enum not checked, compliant, not compliant, not applicable, default not checked, facetable | |
+| complianceNote | string | |
+| checkedOn | date | when the compliance check was last done |
+
+The `referenceProcess` uuid is stable across GEMMA imports, because the import sets an element's uuid to its GEMMA object id (`lib/Service/ArchiMateImportService.php:4794-4798`).
+
+### D3. Pages under the Architecture group
+
+`Processen` (`/processen`) is a `CnIndexPage` (manifest `type: index`) over `process` with columns name, status, processOwner and tags, the schema facets in the sidebar, and quick filters All, Active and Draft.
+
+`ProcesDetail` (`/processen/:id`) is a `type: detail` page on the ADR-062 grid with:
+- a `data` widget for name, description, status, owner, reference process and tags,
+- an `object-list` widget `process-steps` over `processStep` with filter `{"process": "@objectId"}`, columns position, name, stepType, riskLevel and complianceCheck, sorted on position, `rowRoute: ProcesStapDetail`,
+- a body widget `ProcessStepFlow` (see D4),
+- `lifecycleActions` on, and the History tab in the sidebar.
+
+`ProcesStapDetail` (`/processtappen/:id`) is a `type: detail` page with a `data` widget over every step field and a body widget `ProcessStepUsages` that lists the step's usages. It is a small custom component rather than an `object-list`, because it compares the stored uuids with the returned objects to count the hidden ones (see Risks).
+
+The menu entry `Processen` is relocated under the `Architecture` group that `architecture-views-editor` adds (its D8), so the top-level count does not grow (ADR-097).
+
+### D4. The step flow is read-only on `CnGraphCanvas`
+
+`ProcessStepFlow.vue` loads the steps of one process, turns each into a node (name, step type, risk level, and the names of the supporting applications) and draws an edge from each uuid in `follows` to the step, or from the step with the next lower position when `follows` is empty. It passes them to `CnGraphCanvas` (`@conduction/nextcloud-vue` 2.57.1, `src/components/CnGraphCanvas/CnGraphCanvas.vue`, props `nodes`, `edges` and `readOnly` at :178, :184 and :196) with `readOnly` true, and places them with `layoutFlowNodes` (`src/composables/flowGraphLayout.js:329`), imported through the package's `./src/*` export as `architecture-assistant-drafted-views` D4 does. A step with a high risk or a failed compliance check gets `--color-error` on its border, and the text on the node says the same, so colour is never the only signal (WCAG 1.4.1).
+
+Rejected: an editable BPMN canvas. The rows ask to model processes and link applications, and a list with an order and a `follows` list does that. An editor is a second drawing tool next to the view editor, and it can come later on the same data.
+
+Rejected: OpenRegister flows. A flow (`openregister-ro/appinfo/routes.php:825`, BPMN export) is an automation that runs; a business process here is a description of how the municipality works, with owners, risks and applications. Storing descriptions as flows would put non-runnable flows in the flow engine's list.
+
+### D5. Fixed step fields, not customer-defined questionnaires
+
+The step fields are properties of `processStep`: risk level, risk note, compliance check, compliance note and checked on. `CnDetailPage` and `CnFormDialog` render them from the schema, and the facets filter on them.
+
+Rejected: questions a functional administrator defines per step type, answered per step, as BlueDolphin offers. That needs a question-definition schema and a form renderer for answers of any type, which is a second form system beside the schema-driven one (ADR-012). Letting an administrator add properties to `processStep` in OpenRegister's schema editor was also rejected: the repair step re-imports the register JSON and a version bump replaces the properties, so an added question would vanish on an update. The matrix row names risk level and a compliance check, which the fixed fields cover.
+
+### D6. The application in use lists the steps it supports
+
+`GebruikDetail` gets an `object-list` widget `usage-process-steps` over `processStep` with filter `{"usages": "@objectId"}`, columns process, name, riskLevel and complianceCheck, `rowRoute: ProcesStapDetail`, titled "Process steps this application supports". OpenRegister filters an array property on one value with a JSON containment test (`openregister-ro/lib/Db/MagicMapper/MagicSearchHandler.php:1601`), so no index or service is needed.
+
+## Declarative versus imperative
+
+- The process status lifecycle is declared as `configuration.x-openregister-lifecycle` on `process`: field `status`, initial draft, transitions activate (draft to active), retire (active to retired) and reopen (retired to draft). The `from` and `to` values are the enum values exactly (register changelog 2.4.4, register.json:7). `lifecycleActions` on `ProcesDetail` renders them.
+- The step to process and step to usage links are `related-object` properties, so OpenRegister keeps them in its relation index. No PHP.
+- The two lists are manifest `object-list` widgets with filters. No aggregation or notification is added.
+- `ProcessStepFlow.vue` is the only imperative piece, and it only reads.
+
+## Seed data
+
+All objects live in the `stackiq` register. The reference process is the GEMMA element "Bedrijfsproces Behandelen vergunningaanvraag" (`lib/Settings/GEMMA_release.xml:950`), uuid `01f2e505-8245-44e5-860c-336a831eaae9`. On an instance without a GEMMA import the reference stays empty.
+
+### Schema: `process`
+
+| Field | Object 1 |
+|---|---|
+| slug | `seed-proces-vergunningaanvraag` |
+| name | Behandelen vergunningaanvraag |
+| description | Van intake tot besluit op een aanvraag voor een vergunning. |
+| status | active |
+| referenceProcess | `01f2e505-8245-44e5-860c-336a831eaae9` |
+| tags | vergunningen |
+
+### Schema: `processStep`
+
+| Field | Object 1 | Object 2 | Object 3 |
+|---|---|---|---|
+| slug | `seed-stap-intake` | `seed-stap-toetsen` | `seed-stap-besluiten` |
+| process | `seed-proces-vergunningaanvraag` | `seed-proces-vergunningaanvraag` | `seed-proces-vergunningaanvraag` |
+| name | Intake vergunningaanvraag | Toetsen indieningsvereisten | Besluiten vergunningaanvraag |
+| stepType | event | task | decision |
+| position | 1 | 2 | 3 |
+| usages | `gebruik-topdesk-gem-leiden-deelnemers` | none | none |
+| riskLevel | low | medium | high |
+| complianceCheck | compliant | not checked | not compliant |
+| complianceNote | | | Besluit wordt nog niet gearchiveerd volgens de selectielijst. |
+
+The usage slug is one of the three usages the register already seeds (register.json `components.objects`).
+
+## Risks
+
+- **An array filter on MariaDB.** The containment test at `MagicSearchHandler.php:1601` is PostgreSQL SQL. The Playwright scenario for D6 runs on the CI database, and a MariaDB instance needs a check before this ships there.
+- **Hidden usages.** RBAC can hide a linked usage from a reader. `ProcesStapDetail` compares the stored uuids with the returned objects and shows "1 linked application is not visible to you" instead of a silent gap.
+- **Steps out of order.** Two steps with the same position draw side by side. The index sorts on position and then name, and the form warns on a duplicate position without refusing it.
diff --git a/openspec/changes/architecture-process-mapping/proposal.md b/openspec/changes/architecture-process-mapping/proposal.md
new file mode 100644
index 000000000..d9e56582c
--- /dev/null
+++ b/openspec/changes/architecture-process-mapping/proposal.md
@@ -0,0 +1,48 @@
+---
+kind: code
+depends_on:
+ - architecture-views-editor
+ - landscape-usage-registration
+---
+
+# Model business processes and link their steps to the applications that support them
+
+## Summary
+
+A municipal information manager records the organisation's business processes in stackiq, step by step, and names for each step the applications in use that support it. Each step carries a risk level and a compliance check. The process page shows the steps as a flow, and the page of an application in use lists the process steps it supports. A process can point at the GEMMA reference process it follows.
+
+## Why
+
+This change builds two rows of the stackiq parity matrix.
+
+- `stackiq:arch-process-mapping`, "Model business processes and link them to the applications that support them." No tender or feature request names it. SAP LeanIX rates yes: "business context subtype 'Process : Processes show the different steps and interactions', related to applications" (https://help.sap.com/docs/leanix/ea/business-context-modeling-guidelines). BlueDolphin rates yes: "The Create BPMN diagram button allows you to create a diagram directly from a business process" (https://help.bluedolphin.io/en/articles/11967673-process-linked-to-ea-perspectives) and "For each application, you will find different processes in which the selected application is involved" (https://help.bluedolphin.io/en/articles/11967500-getting-started-with-process-publication-portal). The lane decided build because two competitors rate yes and architecture is a core area.
+- `stackiq:arch-process-step-fields`, "Record structured fields on individual process steps, such as risk level or a compliance check." The demand is a changelog entry, https://bluedolphin.io/blog/july-2026-bluedolphin-updates/. BlueDolphin rates yes: customers can "define questionnaires directly on BPMN elements such as tasks and events" to "centralize documentation like risk levels, compliance checks, and technical specifications" (https://help.bluedolphin.io/en/articles/15874771-questionnaires-for-bpmn-elements). Decided build: core area.
+
+The matrix notes for both rows hold: stackiq models no processes.
+
+## What stackiq has today
+
+- The register holds 20 schemas (`lib/Settings/softwarecatalogus_register.json`, `components.schemas`) and none is a process. The `stackiq` register (:817) lists 15 of them, the `vng-gemma` register (:916) the five AMEF schemas.
+- The ArchiMate import keeps every element type. It copies `xsi:type` into `type` without a filter (`lib/Service/ArchiMateImportService.php:973-980` and :5244-5249), and it sets an element's uuid to its GEMMA object id (:4794-4798), so the uuid survives a re-import. The GEMMA release in `lib/Settings/GEMMA_release.xml` holds 157 `BusinessProcess` elements, such as "Bedrijfsproces Behandelen vergunningaanvraag" (:950). These are VNG's reference processes. No page shows them: the only AMEF page, Standaarden (`src/manifest.json:701`), filters on `gemmaType` standaard.
+- The organisation's applications are `usage` objects (register.json:2654). A usage links to reference components (`usedForReferenceComponents`) and, through `GebruikSyncService`, to AMEF element ids in `amefElements` (`lib/Service/GebruikSyncService.php:170-272`), never to a process.
+- OpenRegister's flows (`src/manifest.json:1057`, page Flows) are automation flows with a BPMN export (`openregister-ro/appinfo/routes.php:825`). They run work; they do not describe how the municipality works.
+
+## What this change builds
+
+- Two schemas in the `stackiq` register through a fragment `lib/Settings/register.d/architecture-process-mapping.json`: `process` and `processStep`, with the step fields risk level, risk note, compliance check, compliance note and checked on.
+- A Processes index page and a process detail page with a steps list and a read-only step flow on `CnGraphCanvas`, and a step detail page, under the Architecture menu group.
+- A list "Process steps this application supports" on the usage detail page `GebruikDetail`.
+- A link from a process to the GEMMA reference process it follows.
+
+## Out of scope
+
+- Drawing processes freehand in BPMN. The step flow is read-only and follows the step order. A BPMN editor can follow once the process data is in use.
+- Customer-defined questionnaires on steps. This change ships a fixed set of step fields. See design D5 for why.
+- Putting processes into the ArchiMate export. The organisation export (`lib/Service/ArchiMateExportService.php:2734`) draws applications into GEMMA views, and adding processes there is a later change.
+- Drafting a process with an assistant. `architecture-assistant-drafted-views` drafts views only.
+- Automation. Running a process is OpenRegister's flow engine (ADR-065), not this change.
+
+## Risks
+
+- A step lists usages across the whole organisation. A usage the reader may not see is left out of the list by OpenRegister RBAC, which can make a step look unsupported. The step detail says how many linked applications are hidden.
+- GEMMA reference processes exist only after a GEMMA import. On an instance without one, the reference field offers nothing to pick, which is correct but can look broken. The field's help text says so.
diff --git a/openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md b/openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md
new file mode 100644
index 000000000..4c4bc588e
--- /dev/null
+++ b/openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md
@@ -0,0 +1,116 @@
+# business-process-mapping specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-process-mapping
+
+## Purpose
+
+A municipality describes its business processes in stackiq, step by step, and links each step to the applications in use that support it. Steps carry a risk level and a compliance check. A process (schema.org `HowTo`) and its steps (schema.org `HowToStep`) are objects in the `stackiq` register (ADR-001), shown with `CnIndexPage`, `CnDetailPage` and a read-only `CnGraphCanvas` (ADR-012), with the status lifecycle declared on the schema (ADR-031).
+
+## ADDED Requirements
+
+### Requirement: REQ-BPM-001 A municipal information manager SHALL record a business process with ordered steps
+
+Stackiq SHALL offer a Processes page at `/processen` (page `Processen`) over the `process` schema and a process page at `/processen/:id` (page `ProcesDetail`). A process SHALL have a name, a description, an owner picked from the organisation's contact roles, a status, tags and an optional GEMMA reference process. A step SHALL be a `processStep` object with the process, a name, a description, a step type (task, event or decision), a position and an optional list of steps it follows. The process page SHALL list its steps in position order. Processes and steps SHALL be scoped to the organisation that created them.
+
+#### Scenario: An information manager adds a process with three steps
+@e2e tests/e2e/workflows/process-mapping.spec.ts
+
+- **GIVEN** a municipal information manager signed in to stackiq
+- **WHEN** they open Architecture, then Processes, create the process Behandelen melding and add the steps Registreren, Beoordelen and Afhandelen at positions 1, 2 and 3
+- **THEN** the process page SHALL list the three steps in that order
+- **AND** the Processes page SHALL list the process with status draft
+
+#### Scenario: Another municipality does not see the process
+@e2e exclude The CI instance has one organisation; tests/Unit/Settings/ProcessMappingRegisterShapeTest.php asserts that the read rules of process and processStep match on _organisation, as usage does.
+
+- **GIVEN** a process of municipality A
+- **WHEN** a user of municipality B opens the Processes page
+- **THEN** the process SHALL NOT be listed
+
+### Requirement: REQ-BPM-002 A step SHALL name the applications in use that support it
+
+A step SHALL hold a list of `usage` objects: the organisation's applications in use that support the step. The usage page `GebruikDetail` SHALL show a list "Process steps this application supports" with every step that names the usage, its process, its risk level and its compliance check, each row opening the step page at `/processtappen/:id` (page `ProcesStapDetail`). When a linked usage is not visible to the reader, the step page SHALL say how many linked applications are hidden.
+
+#### Scenario: An application owner sees which process steps their application supports
+@e2e tests/e2e/workflows/process-mapping.spec.ts
+
+- **GIVEN** the seeded step Intake vergunningaanvraag linked to the seeded TOPdesk usage
+- **WHEN** an application owner opens that usage at `/gebruik/:id`
+- **THEN** the list "Process steps this application supports" SHALL show Intake vergunningaanvraag with the process Behandelen vergunningaanvraag
+- **AND** choosing the row SHALL open the step page
+
+#### Scenario: A hidden usage is counted, not dropped
+@e2e exclude Needs two organisations with different rights; tests/vitest/processStepUsages.spec.js asserts that two stored usage uuids with one returned object give the notice "1 linked application is not visible to you".
+
+- **GIVEN** a step linked to two usages, one of which the reader may not read
+- **WHEN** the reader opens the step page
+- **THEN** the page SHALL list the visible usage
+- **AND** it SHALL show that one linked application is not visible to them
+
+### Requirement: REQ-BPM-003 A step SHALL carry a risk level and a compliance check
+
+Every `processStep` SHALL have a risk level (not assessed, low, medium or high, default not assessed), a risk note, a compliance check (not checked, compliant, not compliant or not applicable, default not checked), a compliance note and the date of the last check. The risk level and the compliance check SHALL be facetable, and the step list on the process page SHALL show both.
+
+#### Scenario: An information manager marks a step as not compliant
+@e2e tests/e2e/workflows/process-mapping.spec.ts
+
+- **GIVEN** the step Besluiten vergunningaanvraag with compliance check not checked
+- **WHEN** a municipal information manager edits the step, sets the risk level to high, the compliance check to not compliant and a compliance note, and saves
+- **THEN** the step list on the process page SHALL show high and not compliant for that step
+- **AND** the step page SHALL show the compliance note
+
+#### Scenario: The step fields have defaults
+@e2e exclude A schema default; tests/Unit/Settings/ProcessMappingRegisterShapeTest.php asserts the enums and defaults of riskLevel and complianceCheck.
+
+- **GIVEN** the merged register
+- **WHEN** a step is created without a risk level or a compliance check
+- **THEN** it SHALL read not assessed and not checked
+
+### Requirement: REQ-BPM-004 The process page SHALL show the steps as a read-only flow
+
+The process page SHALL render the steps on a read-only `CnGraphCanvas`: one node per step with its name, type, risk level and supporting applications, and an edge from each step it follows, or from the step before it by position when it follows none. A step with a high risk or a not compliant check SHALL be marked in the error colour and in text.
+
+#### Scenario: A reader sees the flow of a process
+@e2e tests/e2e/workflows/process-mapping.spec.ts
+
+- **GIVEN** the seeded process Behandelen vergunningaanvraag with three steps
+- **WHEN** a municipal information manager opens its process page
+- **THEN** the flow SHALL show three nodes connected in position order
+- **AND** the node Besluiten vergunningaanvraag SHALL read high risk and not compliant
+
+#### Scenario: A branch follows the follows list
+@e2e exclude A pure mapping; tests/vitest/processStepFlow.spec.js asserts that a step whose follows list names two steps gets two incoming edges and no edge from the step before it by position.
+
+- **GIVEN** a step that follows two earlier steps
+- **WHEN** the flow is built
+- **THEN** the step SHALL have one incoming edge from each of the two
+- **AND** no edge from the step before it by position
+
+### Requirement: REQ-BPM-005 A process SHALL move through a declared lifecycle and MAY follow a GEMMA reference process
+
+The `process` status SHALL move through transitions declared as `x-openregister-lifecycle` on the schema: activate (draft to active), retire (active to retired) and reopen (retired to draft), with `from` and `to` values that are members of the status enum. A process MAY reference one AMEF `element` of type `BusinessProcess` as its GEMMA reference process, and the process page SHALL show that reference with a link to it.
+
+#### Scenario: An owner activates a process
+@e2e tests/e2e/workflows/process-mapping.spec.ts
+
+- **GIVEN** a process in status draft
+- **WHEN** its owner applies Activate on the process page
+- **THEN** the process SHALL read active
+- **AND** the transition SHALL appear in its History tab
+
+#### Scenario: The lifecycle matches the enum
+@e2e exclude The transition engine is OpenRegister's; tests/Unit/Settings/ProcessMappingRegisterShapeTest.php asserts every lifecycle from and to value is a member of the status enum.
+
+- **GIVEN** the merged register
+- **WHEN** the shape test reads the process lifecycle
+- **THEN** every `from` and `to` value SHALL be a status enum value
+
+#### Scenario: A process points at its GEMMA reference process
+@e2e exclude The CI instance runs without a GEMMA import; tests/Unit/Settings/ProcessMappingRegisterShapeTest.php asserts that referenceProcess is a related element filtered on type BusinessProcess.
+
+- **GIVEN** an imported GEMMA model with the process Bedrijfsproces Behandelen vergunningaanvraag
+- **WHEN** an information manager picks it as the reference process of their process
+- **THEN** the process page SHALL show the reference by name with a link to its element page
diff --git a/openspec/changes/architecture-process-mapping/tasks.md b/openspec/changes/architecture-process-mapping/tasks.md
new file mode 100644
index 000000000..0e8984fa4
--- /dev/null
+++ b/openspec/changes/architecture-process-mapping/tasks.md
@@ -0,0 +1,62 @@
+# Tasks: architecture-process-mapping
+
+## Implementation tasks
+
+### Task 1: Register fragment for process and processStep
+- **spec_ref**: openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md#requirement-req-bpm-003-a-step-shall-carry-a-risk-level-and-a-compliance-check
+- **files**: `lib/Settings/register.d/architecture-process-mapping.json`, `tests/Unit/Settings/ProcessMappingRegisterShapeTest.php`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it loads THEN the `stackiq` register lists `process` and `processStep` with magic mapping on
+ - GIVEN `processStep` WHEN the shape test reads it THEN `riskLevel` and `complianceCheck` have the enums and defaults of the design and are facetable
+ - GIVEN the process lifecycle WHEN the shape test reads it THEN every `from` and `to` value is a status enum value
+ - GIVEN both schemas WHEN the shape test reads their read rules THEN they match on `_organisation` as `usage` does
+ - GIVEN a fresh install WHEN the seed runs THEN the process and its three steps exist
+- [ ] Implement
+- [ ] Test (PHPUnit `ProcessMappingRegisterShapeTest`, `RegisterFragmentMergeTest`)
+
+### Task 2: Processes index, process page and step page
+- **spec_ref**: openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md#requirement-req-bpm-001-a-municipal-information-manager-shall-record-a-business-process-with-ordered-steps
+- **files**: `src/manifest.d/architecture-process-mapping.json`, `src/menu-layout.json`
+- **acceptance_criteria**:
+ - GIVEN the effective manifest WHEN it is built THEN `Processen`, `ProcesDetail` and `ProcesStapDetail` exist with the routes of the design
+ - GIVEN the effective menu WHEN it renders THEN Processes sits under the Architecture group and the top-level count is unchanged
+ - GIVEN a process page WHEN it renders THEN its steps list is sorted on position and its lifecycle actions show
+- [ ] Implement
+- [ ] Test (`tests/validate-manifest.js`, Playwright `tests/e2e/workflows/process-mapping.spec.ts` create and lifecycle scenarios)
+
+### Task 3: Step flow on CnGraphCanvas
+- **spec_ref**: openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md#requirement-req-bpm-004-the-process-page-shall-show-the-steps-as-a-read-only-flow
+- **files**: `src/views/architecture/ProcessStepFlow.vue`, `src/utils/processStepFlow.js`, `src/customComponents.js`, `tests/vitest/processStepFlow.spec.js`
+- **acceptance_criteria**:
+ - GIVEN steps without a follows list WHEN the flow is built THEN edges run in position order
+ - GIVEN a step that follows two steps WHEN the flow is built THEN it has two incoming edges
+ - GIVEN a step with high risk or not compliant WHEN it renders THEN its node uses `--color-error` and says so in text
+- [ ] Implement
+- [ ] Test (vitest `processStepFlow.spec.js`, Playwright flow scenario)
+
+### Task 4: Supporting applications on the usage and step pages
+- **spec_ref**: openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md#requirement-req-bpm-002-a-step-shall-name-the-applications-in-use-that-support-it
+- **files**: `src/manifest.d/usages.json`, `src/manifest.d/architecture-process-mapping.json`, `src/views/architecture/ProcessStepUsages.vue`, `tests/vitest/processStepUsages.spec.js`
+- **acceptance_criteria**:
+ - GIVEN a step that names a usage WHEN that usage's page opens THEN the list "Process steps this application supports" shows the step and its process
+ - GIVEN two stored usage uuids of which one is returned WHEN the step page renders THEN it shows the visible usage and says one is hidden
+- [ ] Implement
+- [ ] Test (vitest `processStepUsages.spec.js`, Playwright usage page scenario)
+
+### Task 5: Documentation and translations
+- **spec_ref**: openspec/changes/architecture-process-mapping/specs/business-process-mapping/spec.md#requirement-req-bpm-001-a-municipal-information-manager-shall-record-a-business-process-with-ordered-steps
+- **files**: `docs/features/business-processes.md`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the feature page WHEN it is read THEN it shows the process page with its flow and the usage page with its step list, each in a screenshot
+ - GIVEN a Dutch instance WHEN the Processes page renders THEN every new label and enum value reads in Dutch
+- [ ] Implement
+- [ ] Test (`tests/l10n` key parity, screenshots captured with Playwright)
+
+## Verification
+
+- `openspec validate architecture-process-mapping --type change --strict`
+- PHPUnit: `ProcessMappingRegisterShapeTest`, `RegisterFragmentMergeTest`
+- vitest: `processStepFlow.spec.js`, `processStepUsages.spec.js`
+- Playwright: `tests/e2e/workflows/process-mapping.spec.ts`
+- Documentation in `docs/features/business-processes.md` with screenshots (ADR-010)
+- English and Dutch strings for every new label and enum value (ADR-005)
diff --git a/openspec/changes/architecture-reference-component-coverage/.openspec.yaml b/openspec/changes/architecture-reference-component-coverage/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-reference-component-coverage/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-reference-component-coverage/design.md b/openspec/changes/architecture-reference-component-coverage/design.md
new file mode 100644
index 000000000..057a7e4cf
--- /dev/null
+++ b/openspec/changes/architecture-reference-component-coverage/design.md
@@ -0,0 +1,74 @@
+# Design: architecture-reference-component-coverage
+
+Read at development 49e65cb4. Line numbers below are from that sha. The read-only rendering of a GEMMA view (`src/utils/viewGraph.js` on `CnGraphCanvas`) comes from `architecture-views-editor` (its D3 and D4).
+
+## Where it fits
+
+| Layer | Touched | Read at |
+|---|---|---|
+| Derivation | new `lib/Service/ReferenceComponentCoverageDerivation.php` | pure, like `lib/Service/PortfolioReportDerivation.php` |
+| Service | new `lib/Service/ReferenceComponentCoverageService.php` | reads usages the way `PortfolioReportService::buildRows` does (:229) |
+| Service | `lib/Service/PortfolioReportService.php` `buildRow` (:284), `buildReport` (:138), `buildCsv` (:166) | overlap per row, in the summary and the CSV |
+| Access check | new `lib/Service/OrganisationReportAccess.php`, taken from `PortfolioReportController::isAuthorisedForOrganisation` (`lib/Controller/PortfolioReportController.php:139`) | both report controllers call it |
+| Controller and route | new `lib/Controller/ReferenceComponentCoverageController.php`, route `referenceComponentCoverage#index` at `GET /api/reference-component-coverage` next to `portfolioReport#index` (`appinfo/routes.php:303`) | |
+| Pages | new `src/manifest.d/reference-component-coverage.json` with the custom page `ReferenceComponentCoverage` (`/reference-component-coverage`) and a second card on `Reports` (`src/manifest.json:1027`) | |
+| Views | new `src/views/organisaties/ReferenceComponentCoverage.vue` and `src/views/organisaties/CoverageViewMap.vue`; `src/views/organisaties/PortfolioReport.vue` gains an overlap section | registered in `src/customComponents.js` next to `PortfolioReportView` (:32, :137) |
+| Register | none | |
+
+## Decisions
+
+### D1. Coverage is counted on the organisation's usages
+
+A reference component is covered by a usage of the organisation when the usage names it in `usedForReferenceComponents` (`lib/Settings/softwarecatalogus_register.json:2982`) and its `status` is not Acquisition, Planned or Phased out. The derivation gives each reference component one state:
+
+| State | Rule |
+|---|---|
+| gap | no counting usage |
+| covered | one counting usage |
+| overlap | two or more counting usages with different modules |
+
+Two usages of the same module (two versions side by side during a migration) are one application for this count. A gap is also marked fillable when a module the organisation already uses declares the component in `module.referenceComponents` (:6992). That is the GEMMA Softwarecatalogus tile "Pakketten met meer mogelijkheden".
+
+Rejected: counting on `module.referenceComponents`. That says what a product can do, not what the municipality uses it for, and it would mark a component covered by a product the municipality bought for something else.
+
+### D2. A bounded, organisation-scoped backend endpoint
+
+`ReferenceComponentCoverageService::build(organisationUuid)` reads the organisation's usages with the same query `PortfolioReportService::buildRows` uses (`consumer` equal to the organisation, bounded by the page size ceiling, :544) and the reference components with `gemmaType=referentiecomponent`, the query the schemas use for their pickers (register.json:2993), bounded at 1,000 as `FacetService::ELEMENT_LOOKUP_LIMIT` is (`lib/Service/FacetService.php:95`). It resolves module names once per module, like `PortfolioReportService::fetchRelation` (:482), and hands everything to the derivation.
+
+`GET /api/reference-component-coverage?organisation=&format=json|csv` returns `{ organisation, generatedAt, truncated, usagesWithoutComponent, summary: { gap, fillable, covered, overlap }, components: [{ uuid, name, state, fillable, usages: [{ uuid, moduleName, status }] }] }`, or the same rows as CSV.
+
+The controller runs the organisation check before any query and fails closed, as `PortfolioReportController::index` does (:86). The check moves into `OrganisationReportAccess::isAuthorised(user, organisationUuid)` and both controllers call it, so the two reports keep one rule.
+
+Rejected: computing coverage in the browser from OpenRegister facets on `usage.usedForReferenceComponents`. A facet has no bucket for a value no row holds, so gaps need the full component list anyway, and overlap needs the usages behind each count. The portfolio report moved the same kind of cross-register join to the backend for the same reason (its manifest note, `src/manifest.json:1040`).
+
+### D3. The page: summary, table and map
+
+`ReferenceComponentCoverage.vue` follows `PortfolioReport.vue`: the same organisation picker (:61), Refresh and Export CSV buttons, and a truncation notice. Under that:
+
+- a summary with the four counts and "N applications in use name no reference component",
+- a `CnDataTable` of components with columns name, state, applications and fillable, and quick filters All, Gaps, Fillable gaps and Overlap,
+- `CoverageViewMap.vue`: a picker of imported GEMMA views from `GET /api/views` (`appinfo/routes.php:185`), and the chosen view drawn read-only through `viewGraph.js` on `CnGraphCanvas` (`@conduction/nextcloud-vue` 2.57.1, `src/components/CnGraphCanvas/CnGraphCanvas.vue`, `readOnly` at :196). Every node whose element is a reference component gets its state: a border in `--color-error` (gap), `--color-success` (covered) or `--color-warning` (overlap), and a text badge with the count and the application names, so colour is never the only signal.
+
+The page is reached from a second card on the Reports page, "Reference component coverage", next to Portfolio rationalization. No menu entry is added (ADR-097).
+
+Rejected: drawing the map with `ViewService` enrichment (`include_gebruik`). It groups usages by the single field `elementRef` (`lib/Service/ViewService.php:914`), so a usage for three components lands on at most one node.
+
+### D4. Overlap in the portfolio report
+
+`PortfolioReportService::buildRow` adds `referenceComponents` (the names the usage names) and `overlapsWith`: for each shared component, the other modules that cover it. The derivation computes this from the rows `buildRows` already fetched, so the report makes one extra bounded read, the component names. `buildReport` adds `overlap` (the number of rows with at least one overlap) to its payload, and `buildCsv` adds the column `overlapsWith` as `component: module | module`. `PortfolioReport.vue` shows an Overlap section under the quadrant summary that lists each overlapping component with its applications, and marks overlapping rows in the row list. The card text "Overlapping and ageing software across the portfolio." (`src/manifest.json:1031`) then describes what the report does.
+
+## Declarative versus imperative
+
+This change adds aggregation, so ADR-031's declarative route was checked first.
+
+- OpenRegister facets on `usage.usedForReferenceComponents` count usages per component that has one, but return no bucket for a component nobody uses, and gaps are exactly those.
+- OpenRegister's aggregation primitive omits empty buckets by contract ("buckets with zero rows SHALL be omitted from the response", `openregister-ro/openspec/specs/aggregation-api/spec.md:32`) and groups one collection, while coverage joins usages in `stackiq` with reference components in `vng-gemma`.
+
+So the join is imperative, in a pure derivation class with its own unit tests, behind one bounded endpoint. No lifecycle, notification or relation is added, and no schema changes.
+
+## Risks
+
+- **Seeded status values.** The three seeded usages hold `status` `in-gebruik` (register.json `components.objects`), which is not an enum value. The derivation counts any status other than Acquisition, Planned and Phased out, so an unknown value counts as in use rather than hiding an application.
+- **No GEMMA import.** Without an imported model there are no reference components. The page then shows "Import the GEMMA model to see coverage" instead of an empty table, and the portfolio report shows no Overlap section.
+- **`elementRef` enrichment.** `ViewService` keeps grouping on `elementRef`. A later change can move it to `usedForReferenceComponents`; this change does not depend on it.
+- **Large organisations.** A usage ceiling that truncates also truncates coverage. The page shows the truncation notice the portfolio report shows.
diff --git a/openspec/changes/architecture-reference-component-coverage/proposal.md b/openspec/changes/architecture-reference-component-coverage/proposal.md
new file mode 100644
index 000000000..18e2a1fd6
--- /dev/null
+++ b/openspec/changes/architecture-reference-component-coverage/proposal.md
@@ -0,0 +1,47 @@
+---
+kind: code
+depends_on:
+ - architecture-views-editor
+---
+
+# Show which reference components your landscape covers, misses and doubles
+
+## Summary
+
+A municipal information manager opens a coverage report for their organisation. It lists every GEMMA reference component with the applications in use that fulfil it, and marks each one as a gap (no application), covered (one) or overlap (two or more). The same result is drawn on a GEMMA view of their choice, as a map. The portfolio rationalization report gains the overlap it promises on its card, so a reader sees overlapping and ageing software in one place.
+
+## Why
+
+This change builds four rows of the stackiq parity matrix. No tender or feature request names them.
+
+- `stackiq:arch-capability-map`, "Map applications to business capabilities or functions and see the map." Rated partial, built. SAP LeanIX rates yes: "A business capability is supported by an application" and a "Business capability map" (https://help.sap.com/docs/leanix/ea/meta-model, https://help.sap.com/docs/leanix/ea/application-portfolio-assessment). BlueDolphin rates yes: "Drag and drop multi-layer current and future state capability mapping" (https://bluedolphin.io/capability-based-planning/). GEMMA Softwarecatalogus rates partial: packages are plotted "op een GEMMA architectuurkaart" (https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F). The lane decided build: the missing half is a map view of applications on reference components inside stackiq.
+- `stackiq:arch-gap-analysis`, "Find reference components that no application in your landscape covers." Rated no. GEMMA Softwarecatalogus rates partial with the tile "Pakketten met meer mogelijkheden" (https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1), SAP LeanIX partial with a Matrix Report for "Coverage gap analysis" (https://help.sap.com/docs/leanix/ea/report-types), BlueDolphin partial: "Identify capability gaps" (https://bluedolphin.io/capability-based-planning/). Decided build: core area.
+- `stackiq:life-overlap`, "Find applications that overlap because they fulfil the same reference component." Rated no. GEMMA Softwarecatalogus rates yes: "Deze tegel signaleert dat er meer dan 1 pakket(versie) bij eenzelfde referentiecomponent in productie is" (https://www.softwarecatalogus.nl/Releasebrief%20GEMMA%20Softwarecatalogus%20versie%204.1). BlueDolphin rates yes: "overlapping application functions are quickly made visible" (https://help.bluedolphin.io/en/articles/11967472-welcome-to-bluedolphin). Decided build: two competitors rate yes.
+- `stackiq:life-rationalisation-report`, "Open a report of overlapping and ageing software for rationalisation." Rated partial, built. SAP LeanIX rates yes: "automated TIME classification, application portfolio and landscape reports ... to streamline application rationalization" (https://help.sap.com/docs/leanix/ea/application-rationalization-evaluate-data). This row rides with `stackiq:life-overlap`: its missing half is overlap in the portfolio report, which is the overlap this change computes.
+
+## What stackiq has today
+
+- The mapping exists in the data. `module.referenceComponents` (`lib/Settings/softwarecatalogus_register.json:6992`, module schema at :6777) says which reference components a product implements, and `usage.usedForReferenceComponents` (:2982) which ones the organisation uses it for. Both relate to `element` objects with `gemmaType=referentiecomponent`. The GEMMA release holds 168 reference components (`lib/Settings/GEMMA_release.xml`, elements of type `ApplicationComponent` with GEMMA type Referentiecomponent).
+- `lib/Service/FacetService.php` counts modules per reference component across the catalogue (`DIMENSIONS`, :109, built in `buildDimensionValueMap`, :648). It never lists a component with no module, and it works on `module`, not on one organisation's usages.
+- The view API enriches a view's nodes with the organisation's usages (`lib/Service/ViewService.php:813`, `getGebruikData`), but it groups usages by the single field `elementRef` (:914), not by `usedForReferenceComponents`, so a usage for three components lands on one node or none. No page renders a view (`architecture-views-editor`, What stackiq has today).
+- The organisation export draws applications into copies of GEMMA views (`lib/Service/ArchiMateExportService.php:2734`, `copyAndEnrichViews`), so the map exists only in Archi after an admin export.
+- The portfolio report (`GET /api/portfolio-report`, `appinfo/routes.php:303`) is built by `lib/Service/PortfolioReportService.php` from the organisation's usages (`buildRows`, :229) with TIME quadrants, EOL exposure, cloud share and cost, and a CSV (`buildCsv`, :166). No row carries a reference component. The Reports card still reads "Overlapping and ageing software across the portfolio." (`src/manifest.json:1031`).
+
+## What this change builds
+
+- `lib/Service/ReferenceComponentCoverageDerivation.php`, pure functions that turn usages and reference components into a coverage list with gap, covered and overlap states.
+- `lib/Service/ReferenceComponentCoverageService.php` and `GET /api/reference-component-coverage`, organisation-scoped and bounded like the portfolio report, with a CSV.
+- A Reference component coverage page with a table, filters for gaps and overlaps, and a map on a GEMMA view, reached from a new card on the Reports page.
+- Overlap in the portfolio report: per row, the reference components it shares with another application in use, a count in the summary and a column in the CSV.
+
+## Out of scope
+
+- The organisation's own capability model. The map uses GEMMA reference components and GEMMA views, which is what municipalities share. A self-defined capability tree is a later change.
+- Fixing `ViewService` enrichment on `elementRef`. The coverage map reads its own endpoint and leaves the view API as it is. The `elementRef` grouping is named in Risks.
+- Planned future coverage. Usages in status Acquisition or Planned are shown but do not count as coverage. `architecture-future-state-scenarios` compares current and planned landscapes.
+- The catalogue-wide facet counts on the Modules page, which stay as they are.
+
+## Risks
+
+- A usage that names no reference component covers nothing, so a municipality that never filled `usedForReferenceComponents` sees every component as a gap. The page says how many usages name no component, next to the gap count.
+- The report reads usages with RBAC off after an organisation check, as the portfolio report does. The check is shared, not copied, so the two reports cannot drift.
diff --git a/openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md b/openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md
new file mode 100644
index 000000000..16516faba
--- /dev/null
+++ b/openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md
@@ -0,0 +1,97 @@
+# reference-component-coverage specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-reference-component-coverage
+
+## Purpose
+
+A municipality sees, per GEMMA reference component, which of its applications in use fulfil it: none (a gap), one, or several (an overlap). It reads the result as a table, on a GEMMA view as a map, and as overlap in the portfolio rationalization report. The data stays in OpenRegister (ADR-001); the join between the organisation's usages and the GEMMA reference components runs in one bounded, organisation-scoped endpoint, because no declarative aggregation returns empty buckets (ADR-031).
+
+## ADDED Requirements
+
+### Requirement: REQ-RCC-001 Stackiq SHALL give each reference component a coverage state for one organisation
+
+`GET /api/reference-component-coverage?organisation=` SHALL return every reference component with the organisation's usages that name it in `usedForReferenceComponents` and a state: gap when no counting usage names it, covered when one module does, overlap when two or more different modules do. A usage SHALL count unless its status is Acquisition, Planned or Phased out. A gap SHALL be marked fillable when a module the organisation uses declares the component in `module.referenceComponents`. The response SHALL say how many usages name no component. The endpoint SHALL refuse a user who is not authorised for the organisation before it reads anything, with the same check the portfolio report uses, and SHALL offer the same rows as CSV with `format=csv`.
+
+#### Scenario: Two applications for one component read as overlap
+@e2e exclude The rule is a pure derivation; tests/Unit/Service/ReferenceComponentCoverageDerivationTest.php asserts gap, covered and overlap, that two usages of one module count once, and that Planned and Phased out usages do not count.
+
+- **GIVEN** an organisation with two usages in production of different modules that both name the reference component Zaakregistratiecomponent
+- **WHEN** the coverage is derived
+- **THEN** Zaakregistratiecomponent SHALL read overlap with both applications
+- **AND** a component no usage names SHALL read gap
+
+#### Scenario: A gap the organisation could fill is marked
+@e2e exclude A pure derivation; tests/Unit/Service/ReferenceComponentCoverageDerivationTest.php asserts that a gap is fillable when a used module lists the component in referenceComponents.
+
+- **GIVEN** a usage of a module whose `referenceComponents` include Documentbeheercomponent, while no usage names Documentbeheercomponent
+- **WHEN** the coverage is derived
+- **THEN** Documentbeheercomponent SHALL read gap and fillable
+
+#### Scenario: Another organisation's coverage is refused
+@e2e exclude Needs a second organisation; tests/Unit/Controller/ReferenceComponentCoverageControllerTest.php asserts a 403 before any service call for a user of another organisation, and tests/Unit/Service/OrganisationReportAccessTest.php covers the shared rule.
+
+- **GIVEN** a signed-in user whose organisation is municipality A
+- **WHEN** they call `GET /api/reference-component-coverage?organisation=`
+- **THEN** the response SHALL be 403
+- **AND** no usage SHALL be read
+
+### Requirement: REQ-RCC-002 A coverage page SHALL list the components with filters for gaps and overlaps
+
+Stackiq SHALL offer a Reference component coverage page at `/reference-component-coverage` (page `ReferenceComponentCoverage`), reached from a card on the Reports page. After an organisation is picked it SHALL show the counts of gaps, fillable gaps, covered components and overlaps, the number of usages that name no component, and a table of components with their state and applications, with the quick filters All, Gaps, Fillable gaps and Overlap, and an Export CSV button. Without any reference component it SHALL say that the GEMMA model must be imported.
+
+#### Scenario: An information manager filters on overlap
+@e2e tests/e2e/workflows/reference-component-coverage.spec.ts
+
+- **GIVEN** two reference component elements and two usages of different modules that both name the first, created by the test fixture through OpenRegister's objects API
+- **WHEN** a municipal information manager opens Reports, chooses Reference component coverage, picks the organisation and chooses the quick filter Overlap
+- **THEN** the table SHALL show the first component with both applications
+- **AND** the summary SHALL read one overlap and one gap
+
+#### Scenario: The page explains an instance without GEMMA
+@e2e tests/e2e/workflows/reference-component-coverage.spec.ts
+
+- **GIVEN** an instance with no reference component elements
+- **WHEN** a municipal information manager opens the coverage page and picks an organisation
+- **THEN** the page SHALL say that the GEMMA model must be imported to see coverage
+
+### Requirement: REQ-RCC-003 The coverage SHALL be drawn on a GEMMA view as a map
+
+The coverage page SHALL let the user pick an imported GEMMA view and SHALL draw it read-only on `CnGraphCanvas`. Every node of a reference component SHALL carry its state as a border colour (the error colour for a gap, the success colour for covered, the warning colour for an overlap) and as a text badge with the number and names of its applications.
+
+#### Scenario: An information manager sees their applications on a GEMMA view
+@e2e tests/e2e/workflows/reference-component-coverage.spec.ts
+
+- **GIVEN** the fixture from REQ-RCC-002 and a view created by the fixture that holds both reference components
+- **WHEN** the information manager picks that view on the coverage page
+- **THEN** the node of the first component SHALL read overlap with two application names
+- **AND** the node of the second SHALL read gap
+
+#### Scenario: Colour is never the only signal
+@e2e exclude A rendering rule; tests/vitest/coverageViewMap.spec.js asserts that every reference component node carries a text badge with its state and that colours are CSS variables.
+
+- **GIVEN** a view with a gap, a covered and an overlap node
+- **WHEN** the map renders
+- **THEN** each of the three nodes SHALL carry its state in text
+
+### Requirement: REQ-RCC-004 The portfolio rationalization report SHALL show overlapping applications
+
+Each row of `GET /api/portfolio-report` SHALL carry the reference components its usage names and, per shared component, the other modules that cover it. The report SHALL count the rows with an overlap, the CSV SHALL have an `overlapsWith` column, and the Portfolio rationalization page SHALL list each overlapping component with its applications and mark overlapping rows.
+
+#### Scenario: The portfolio report shows overlap next to ageing
+@e2e tests/e2e/workflows/reference-component-coverage.spec.ts
+
+- **GIVEN** the fixture from REQ-RCC-002
+- **WHEN** a municipal information manager opens Portfolio rationalization and picks the organisation
+- **THEN** an Overlap section SHALL list the first component with both applications
+- **AND** both rows SHALL be marked as overlapping in the row list
+
+#### Scenario: The CSV carries the overlap
+@e2e exclude A file body; tests/Unit/Service/PortfolioReportServiceOverlapTest.php asserts the overlapsWith column holds "component: module" for an overlapping row and is empty for a row without overlap.
+
+- **GIVEN** two overlapping rows and one row without overlap
+- **WHEN** the CSV is built
+- **THEN** the overlapping rows SHALL name the component and the other module in `overlapsWith`
+- **AND** the third row SHALL leave it empty
diff --git a/openspec/changes/architecture-reference-component-coverage/tasks.md b/openspec/changes/architecture-reference-component-coverage/tasks.md
new file mode 100644
index 000000000..b184fe133
--- /dev/null
+++ b/openspec/changes/architecture-reference-component-coverage/tasks.md
@@ -0,0 +1,80 @@
+# Tasks: architecture-reference-component-coverage
+
+## Implementation tasks
+
+### Task 1: Coverage derivation
+- **spec_ref**: openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md#requirement-req-rcc-001-stackiq-shall-give-each-reference-component-a-coverage-state-for-one-organisation
+- **files**: `lib/Service/ReferenceComponentCoverageDerivation.php`, `tests/Unit/Service/ReferenceComponentCoverageDerivationTest.php`
+- **acceptance_criteria**:
+ - GIVEN usages and components WHEN the coverage is derived THEN each component reads gap, covered or overlap by the rules of design D1
+ - GIVEN two usages of one module WHEN the coverage is derived THEN they count as one application
+ - GIVEN a gap and a used module that declares it WHEN the coverage is derived THEN the gap is fillable
+ - GIVEN a usage with an unknown status WHEN the coverage is derived THEN it counts
+- [ ] Implement
+- [ ] Test (PHPUnit `ReferenceComponentCoverageDerivationTest`)
+
+### Task 2: Shared organisation check
+- **spec_ref**: openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md#requirement-req-rcc-001-stackiq-shall-give-each-reference-component-a-coverage-state-for-one-organisation
+- **files**: `lib/Service/OrganisationReportAccess.php`, `lib/Controller/PortfolioReportController.php`, `tests/Unit/Service/OrganisationReportAccessTest.php`
+- **acceptance_criteria**:
+ - GIVEN an admin, an ambtenaar, a member and a non-member WHEN the check runs THEN only the non-member is refused, as today
+ - GIVEN the portfolio report controller WHEN it runs THEN it calls the shared check and its existing tests stay green
+- [ ] Implement
+- [ ] Test (PHPUnit `OrganisationReportAccessTest`, existing `PortfolioReportControllerTest`)
+
+### Task 3: Coverage service, controller and route
+- **spec_ref**: openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md#requirement-req-rcc-001-stackiq-shall-give-each-reference-component-a-coverage-state-for-one-organisation
+- **files**: `lib/Service/ReferenceComponentCoverageService.php`, `lib/Controller/ReferenceComponentCoverageController.php`, `appinfo/routes.php`, `tests/Unit/Controller/ReferenceComponentCoverageControllerTest.php`, `tests/Unit/Service/ReferenceComponentCoverageServiceTest.php`
+- **acceptance_criteria**:
+ - GIVEN a user of another organisation WHEN the endpoint is called THEN it answers 403 before the service runs
+ - GIVEN an organisation WHEN the endpoint is called THEN usages and components are read with bounded limits and the payload has the shape of design D2
+ - GIVEN `format=csv` WHEN the endpoint is called THEN the same rows come back as CSV
+- [ ] Implement
+- [ ] Test (PHPUnit `ReferenceComponentCoverageControllerTest`, `ReferenceComponentCoverageServiceTest`)
+
+### Task 4: Coverage page and Reports card
+- **spec_ref**: openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md#requirement-req-rcc-002-a-coverage-page-shall-list-the-components-with-filters-for-gaps-and-overlaps
+- **files**: `src/manifest.d/reference-component-coverage.json`, `src/views/organisaties/ReferenceComponentCoverage.vue`, `src/customComponents.js`, `tests/e2e/workflows/reference-component-coverage.spec.ts`
+- **acceptance_criteria**:
+ - GIVEN the Reports page WHEN it renders THEN it shows the card Reference component coverage next to Portfolio rationalization
+ - GIVEN a picked organisation WHEN the page loads THEN it shows the counts, the table and the four quick filters
+ - GIVEN no reference components WHEN the page loads THEN it says the GEMMA model must be imported
+- [ ] Implement
+- [ ] Test (Playwright `reference-component-coverage.spec.ts` overlap filter and empty model scenarios)
+
+### Task 5: Coverage map on a GEMMA view
+- **spec_ref**: openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md#requirement-req-rcc-003-the-coverage-shall-be-drawn-on-a-gemma-view-as-a-map
+- **files**: `src/views/organisaties/CoverageViewMap.vue`, `tests/vitest/coverageViewMap.spec.js`
+- **acceptance_criteria**:
+ - GIVEN a picked view WHEN it renders THEN it is read-only and every reference component node carries its state as a CSS variable colour and as text
+ - GIVEN a node whose element is not a reference component WHEN it renders THEN it carries no state
+- [ ] Implement
+- [ ] Test (vitest `coverageViewMap.spec.js`, Playwright map scenario)
+
+### Task 6: Overlap in the portfolio report
+- **spec_ref**: openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md#requirement-req-rcc-004-the-portfolio-rationalization-report-shall-show-overlapping-applications
+- **files**: `lib/Service/PortfolioReportService.php`, `src/views/organisaties/PortfolioReport.vue`, `tests/Unit/Service/PortfolioReportServiceOverlapTest.php`
+- **acceptance_criteria**:
+ - GIVEN two rows that share a component WHEN the report is built THEN both carry `overlapsWith` and the payload counts two overlapping rows
+ - GIVEN the CSV WHEN it is built THEN it has the `overlapsWith` column
+ - GIVEN the page WHEN the report has overlap THEN an Overlap section lists each component with its applications
+- [ ] Implement
+- [ ] Test (PHPUnit `PortfolioReportServiceOverlapTest`, Playwright portfolio overlap scenario)
+
+### Task 7: Documentation and translations
+- **spec_ref**: openspec/changes/architecture-reference-component-coverage/specs/reference-component-coverage/spec.md#requirement-req-rcc-002-a-coverage-page-shall-list-the-components-with-filters-for-gaps-and-overlaps
+- **files**: `docs/features/reference-component-coverage.md`, `docs/features/portfolio-rationalization.md`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the feature pages WHEN they are read THEN they show the coverage table, the map and the Overlap section, each in a screenshot
+ - GIVEN a Dutch instance WHEN the coverage page renders THEN every new label reads in Dutch
+- [ ] Implement
+- [ ] Test (`tests/l10n` key parity, screenshots captured with Playwright)
+
+## Verification
+
+- `openspec validate architecture-reference-component-coverage --type change --strict`
+- PHPUnit: `ReferenceComponentCoverageDerivationTest`, `OrganisationReportAccessTest`, `ReferenceComponentCoverageControllerTest`, `ReferenceComponentCoverageServiceTest`, `PortfolioReportServiceOverlapTest`, and the existing portfolio report tests
+- vitest: `coverageViewMap.spec.js`
+- Playwright: `tests/e2e/workflows/reference-component-coverage.spec.ts`
+- Documentation in `docs/features/` with screenshots (ADR-010)
+- English and Dutch strings for every new label (ADR-005)
diff --git a/openspec/changes/architecture-round-trip-check/.openspec.yaml b/openspec/changes/architecture-round-trip-check/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-round-trip-check/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-round-trip-check/design.md b/openspec/changes/architecture-round-trip-check/design.md
new file mode 100644
index 000000000..6977cf2b6
--- /dev/null
+++ b/openspec/changes/architecture-round-trip-check/design.md
@@ -0,0 +1,69 @@
+# Design: architecture-round-trip-check
+
+Read at development 49e65cb4. Line numbers below are from that sha.
+
+## Where it fits
+
+| Layer | Touched | Read at |
+|---|---|---|
+| Comparator | new `lib/Service/ArchiMateModelComparator.php` | pure |
+| Service | new `lib/Service/ArchiMateRoundTripService.php` | uses the import's conversion and the export's generation |
+| Import service | `lib/Service/ArchiMateImportService.php`: the steps before the save in `importArchiMateFileFromPathOptimized` (:347), that is `validateArchiMateFile` (:204), `parseArchiMateXml` (:629), `extractModelIdentifier` (:663) and `transformArchiMateXmlToObjectsBatch` (:4175), move into one public method `convertFileToObjects(string $filePath): array`, which the import then calls | |
+| Export service | `lib/Service/ArchiMateExportService.php`: a public `generateXmlFromObjects(array $objects): string` that runs `generateXmlDirectly` (:1009) and `runQualityAssuranceChecks` (:2143), which `exportArchiMateXml` (:951) then calls | |
+| Controller and route | `SettingsController::checkArchiMateRoundTrip`, route `settings#checkArchiMateRoundTrip` at `POST /api/archimate/round-trip-check`; the old route (`appinfo/routes.php:107`) and `testArchiMateRoundTrip` (`lib/Controller/SettingsController.php:2886`) go | the upload handling of `importArchiMate` (:1490) is the pattern |
+| Removed | `ArchiMateService::testRoundTrip` (`lib/Service/ArchiMateService.php:1496`), `createTestArchiMateXml` (:1559), `createTempFile` (:1585); the store action `testRoundTrip` (`src/store/modules/settings.js:1953`) | |
+| View | new `src/views/settings/sections/ArchiMateRoundTripCheck.vue`, placed in `src/views/settings/sections/ArchiMateImportExport.vue` after its Export part (:555) | |
+| Store | `src/store/modules/settings.js` gains `checkRoundTrip(file, mode)` | |
+
+## Decisions
+
+### D1. The check compares two exchange files by identifier
+
+`ArchiMateModelComparator::compare(string $sourceXml, string $resultXml): array` reads both files into maps keyed by identifier:
+
+| Category | Compared on |
+|---|---|
+| elements | type, name, documentation, property values by property definition name |
+| relationships | type, source, target, name, property values |
+| views | name, viewpoint, the set of node element references, the set of connection relationship references |
+| view nodes | per view: element reference, parent, position and size |
+| property definitions | name, type |
+| organizations | the folder tree and the items under each folder |
+
+For each category it returns the count in the source, the count in the result, and the identifiers that are missing, extra or changed, each changed one with the fields that differ. It returns the first 50 examples per category with their names and the full counts, so a report on a GEMMA release stays readable. Order of elements in a file is never a difference.
+
+Rejected: counting objects, which is what the current code tries. Equal counts can hide one element lost and another added, and a count says nothing about a relationship whose target changed.
+
+### D2. Two modes, neither writes
+
+`ArchiMateRoundTripService::check(string $filePath, string $mode): array`:
+
+- `before-import`: `ArchiMateImportService::convertFileToObjects` turns the file into the objects the import would save, `ArchiMateExportService::generateXmlFromObjects` turns those objects into an exchange file, and the comparator compares it with the source. Nothing is saved. This covers loss in the import's conversion and the export's generation.
+- `against-imported`: reads the model identifier from the file, reads the stored AMEF objects whose `model_identifier` equals it (the import stamps it on every object, `ArchiMateImportService.php:592`) through the export's reader (`getObjectsFromDatabase`, `ArchiMateExportService.php:808`), generates the exchange file from them and compares. This also covers what OpenRegister dropped when it stored the objects. When no object carries that identifier, it answers that the model is not imported.
+
+Both modes run the code paths the real import and export run, because the import and the full export call the two new public methods themselves. A check that ran a copy of the conversion would pass while the real import lost data.
+
+Rejected: importing a test model and exporting it again, which the current code does (`lib/Service/ArchiMateService.php:1504`). It writes a test model into the register every user reads and leaves it there.
+
+Rejected: a built-in test model. A small hand-written file shows only that the small file survives; the admin's question is whether their GEMMA release does.
+
+### D3. Admin only, upload only
+
+`POST /api/archimate/round-trip-check` takes a multipart upload `archiMateFile` and a `mode`, with the same upload handling as the import (:1490): no `file_path` parameter, the presence check of `validateArchiMateFile` (`ArchiMateImportService.php:204`), and the admin check the import makes (`SettingsController.php:1496`). The uploaded temporary file is PHP's own and is not copied. The response is the comparator's result with the mode, the model identifier and the time taken.
+
+The current endpoint is `@NoAdminRequired` (:2880) and writes to the register, so a signed-in user without admin rights can put objects into the AMEF register today. Removing it closes that.
+
+### D4. The report on the settings page
+
+`ArchiMateRoundTripCheck.vue` sits under the ArchiMate import and export on the admin settings page. It holds a file picker, a choice between "Before import (nothing is written)" and "Against the imported model", and a Check button. The result is a table with one row per category (in the file, after the round trip, missing, extra, changed) and, per category, an expandable list of examples with identifier, name and the fields that differ. A summary line says "No losses found" or names the categories with losses. Colours are Nextcloud CSS variables and every state is also written as text.
+
+## Declarative versus imperative
+
+The change adds no lifecycle, aggregation, notification, relation or widget behaviour. It is a read-only comparison of two files, imperative by nature, and it removes code.
+
+## Risks
+
+- **Moving import steps.** `convertFileToObjects` wraps code the import already runs, in the same order. The existing decomposition tests (`tests/Unit/Service/ArchiMateImportServiceDecompositionTest.php`, `ArchiMateExportServiceDecompositionTest.php`) must stay green, and a new test imports `lib/Settings/GEMMA_testdata_below_1_5mb.xml` through both the old and the new entry and compares the object lists.
+- **Findings on day one.** The check will likely report losses on a real GEMMA file, for example property names the import lowercases (`convertToCamelCase`, `ArchiMateImportService.php:2256`). That is the point; the report names them and the fixes are separate changes.
+- **Memory.** A before-import check on a GEMMA release holds the converted objects and two XML documents at once. The route runs under the import's limits, and the page warns that a large file takes as long as an import.
+- **Tests that mock the old endpoint.** `tests/Unit/Controller/SettingsControllerEmailArchiMateContractTest.php:458` and :482 mock `testRoundTrip`; they move to the new route.
diff --git a/openspec/changes/architecture-round-trip-check/proposal.md b/openspec/changes/architecture-round-trip-check/proposal.md
new file mode 100644
index 000000000..23a1b7243
--- /dev/null
+++ b/openspec/changes/architecture-round-trip-check/proposal.md
@@ -0,0 +1,41 @@
+---
+kind: code
+depends_on: []
+---
+
+# Check that an ArchiMate model survives import and export
+
+## Summary
+
+A Nextcloud admin uploads an ArchiMate exchange file on the settings page and gets a report of what would be lost if stackiq imported and exported it: elements, relationships, views, view nodes, connections and property values that go missing, appear or change on the way. The check can run before an import, writing nothing, or against a model already imported. It replaces a round-trip endpoint that can never succeed, is open to any signed-in user, and imports a test model into the live register.
+
+## Why
+
+This change builds one row of the stackiq parity matrix: `stackiq:arch-round-trip`, "Check that a model survives import and export without losing elements or relations." The row comes from stackiq's own code (feature archimate-import-and-export); no tender, feature request or competitor names it, and no competitor rates yes. The lane decided build: "Built state but rated no: the code exists and does not work, so the change repairs it." The matrix note: "There is an endpoint, but its comparison is broken (a missing key against a placeholder string) and no page calls it."
+
+## What stackiq has today
+
+- `POST /api/archimate/test-round-trip` (`appinfo/routes.php:107`) runs `SettingsController::testArchiMateRoundTrip` (`lib/Controller/SettingsController.php:2886`), marked `@NoAdminRequired`: any signed-in user may call it, while the ArchiMate import itself requires an admin (:1496).
+- It calls `ArchiMateService::testRoundTrip` (`lib/Service/ArchiMateService.php:1496`), which imports a built-in test model into the live AMEF register through `importArchiMateFileFromPath` (:1504) and leaves it there. The test model (:1559) uses Archi's native namespace instead of the exchange format, uses the `xsi` prefix without declaring it, and relates `test-element-1` to a `test-element-2` that does not exist. Its temporary file (:1585) is never removed.
+- The comparison reads `$importResult['imported_count']` (:1528), a key no import path sets; the import returns per-section `statistics` (`lib/Service/ArchiMateImportService.php:444` and :572). It compares that with `exported_count`, which the export returns as the literal string `calculated_in_export_service` (`lib/Service/ArchiMateService.php:271`), and the export covers the whole register, not the test model. So the check can never report success. The service returns an `error` key while the controller reads `message`.
+- The store action `testRoundTrip` (`src/store/modules/settings.js:1953`) has no caller. Only `tests/Unit/Controller/SettingsControllerEmailArchiMateContractTest.php:458` and :482 exercise the endpoint, with the service mocked.
+- The import the settings page runs is the optimised one by default (`SettingsController.php:1594`, `useOptimized` defaults to true). It runs as separate steps: parse (`ArchiMateImportService.php:629`), read the model identifier (:663), convert to objects (`transformArchiMateXmlToObjectsBatch`, :4175) and save (:1291). The export reads objects (`ArchiMateExportService.php:808`), generates XML from them (`generateXmlDirectly`, :1009) and runs quality checks (:2143). Every imported object carries its `model_identifier` (`ArchiMateImportService.php:592`).
+
+## What this change builds
+
+- `lib/Service/ArchiMateModelComparator.php`, a pure comparison of two exchange files by identifier: elements, relationships, views with their nodes and connections, property definitions and property values.
+- `lib/Service/ArchiMateRoundTripService.php` with two modes: before import (the import's conversion steps and the export's generation in memory, no write) and against the imported model (an export of the stored objects of that model, read-only).
+- `POST /api/archimate/round-trip-check`, admin only, taking an uploaded file and a mode.
+- A Check a model file part in the ArchiMate section of the admin settings, with a report per category and examples.
+- Removal of the old endpoint, the service method, its test model and temporary file, and the unused store action.
+
+## Out of scope
+
+- Fixing what the check finds. The report names the losses; repairs to the import or export are their own changes.
+- Comparing with Archi's native `.archimate` format. The check works on the Open Group exchange format that the import and export use.
+- A schedule that runs the check on every import.
+
+## Risks
+
+- A check before import converts the whole file in memory, as an import does. On a GEMMA release that takes the same time and memory as an import, so the page says so and the route keeps the import's limits.
+- The before-import mode cannot see what OpenRegister drops when it stores an object. The against-imported mode can, which is why both exist.
diff --git a/openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md b/openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md
new file mode 100644
index 000000000..60276b878
--- /dev/null
+++ b/openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md
@@ -0,0 +1,88 @@
+# archimate-round-trip-check specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-round-trip-check
+
+## Purpose
+
+A Nextcloud admin checks, before or after an import, that an ArchiMate exchange file survives stackiq's import and export without losing or changing elements, relationships, views or property values. The check writes nothing and runs the same conversion and generation code as the real import and export. It replaces a round-trip endpoint that could never succeed, was open to every signed-in user and wrote a test model into the live register.
+
+## ADDED Requirements
+
+### Requirement: REQ-ART-001 Stackiq SHALL compare two exchange files by identifier per category
+
+The comparison SHALL key elements, relationships, views, view nodes, property definitions and organization folders by identifier, and SHALL report per category the count in the source, the count after the round trip, and the missing, extra and changed identifiers, each changed one with the fields that differ. Elements SHALL be compared on type, name, documentation and property values; relationships on type, source, target, name and property values; views on name, viewpoint and their node and connection references; view nodes on element reference, parent, position and size. The order of items in a file SHALL NOT count as a difference. The report SHALL hold at most 50 examples per category and always the full counts.
+
+#### Scenario: A relationship with a changed target is reported
+@e2e exclude A pure comparison; tests/Unit/Service/ArchiMateModelComparatorTest.php compares two files that differ in one relationship target and asserts one changed relationship naming the field target, and no other difference.
+
+- **GIVEN** two exchange files that are equal except for the target of one relationship
+- **WHEN** they are compared
+- **THEN** the relationships category SHALL report one changed identifier with the field target
+- **AND** every other category SHALL report no difference
+
+#### Scenario: Reordered elements are not a difference
+@e2e exclude A pure comparison; tests/Unit/Service/ArchiMateModelComparatorTest.php compares a file with itself in reversed element order and asserts no difference.
+
+- **GIVEN** a file and the same file with its elements in reverse order
+- **WHEN** they are compared
+- **THEN** no category SHALL report a difference
+
+### Requirement: REQ-ART-002 The check SHALL run before an import or against an imported model without writing
+
+`POST /api/archimate/round-trip-check` SHALL take an uploaded exchange file and a mode. In the mode before-import it SHALL convert the file with the import's own conversion, generate an exchange file from the result with the export's own generation, and compare it with the upload, saving nothing. In the mode against-imported it SHALL read the stored objects whose model identifier equals the file's, generate an exchange file from them and compare, saving nothing; when no stored object has that identifier it SHALL say the model is not imported. The import and the full export SHALL call the same conversion and generation methods the check calls.
+
+#### Scenario: A check before import leaves the register untouched
+@e2e exclude Needs a GEMMA-sized file and minutes of runtime; tests/Unit/Service/ArchiMateRoundTripServiceTest.php runs the before-import mode on lib/Settings/GEMMA_testdata_below_1_5mb.xml with ObjectService mocked and asserts that no save method is called and a report comes back for every category.
+
+- **GIVEN** a Nextcloud admin and a GEMMA exchange file
+- **WHEN** they run the check before import
+- **THEN** the report SHALL list every category with its counts
+- **AND** the AMEF register SHALL hold the same objects as before
+
+#### Scenario: The import and the check convert the same way
+@e2e exclude A refactor guard; tests/Unit/Service/ArchiMateImportServiceConvertTest.php converts the fixture through importArchiMateFileFromPathOptimized with the save mocked and through convertFileToObjects, and asserts equal object lists.
+
+- **GIVEN** the fixture file
+- **WHEN** it is converted by the import and by the check
+- **THEN** both SHALL produce the same objects
+
+#### Scenario: A model that was never imported is named as such
+@e2e exclude The CI instance has no imported model; tests/Unit/Service/ArchiMateRoundTripServiceTest.php asserts the against-imported mode answers "model not imported" when no stored object carries the file's model identifier.
+
+- **GIVEN** an exchange file whose model identifier no stored object carries
+- **WHEN** a Nextcloud admin runs the check against the imported model
+- **THEN** the answer SHALL say the model is not imported
+
+### Requirement: REQ-ART-003 Only an admin SHALL run the check, and the old round-trip endpoint SHALL be removed
+
+The check route SHALL refuse a signed-in user who is not a Nextcloud admin with 403 and SHALL accept only a multipart upload, never a file path. `POST /api/archimate/test-round-trip`, `SettingsController::testArchiMateRoundTrip`, `ArchiMateService::testRoundTrip` with its built-in test model and temporary file, and the store action `testRoundTrip` SHALL be removed.
+
+#### Scenario: A user without admin rights is refused
+@e2e exclude The route test covers it without a second user; tests/Unit/Controller/SettingsControllerRoundTripCheckTest.php asserts a 403 for a non-admin and a 400 for a body with file_path, before the service is called.
+
+- **GIVEN** a signed-in user who is not an admin
+- **WHEN** they post a file to `/api/archimate/round-trip-check`
+- **THEN** the response SHALL be 403
+- **AND** the service SHALL NOT run
+
+#### Scenario: The old endpoint is gone
+@e2e exclude A route table rule; tests/Unit/SettingsRouteTableTest.php asserts no route named settings#testArchiMateRoundTrip and one route settings#checkArchiMateRoundTrip.
+
+- **GIVEN** the route table
+- **WHEN** it is read
+- **THEN** `/api/archimate/test-round-trip` SHALL NOT exist
+
+### Requirement: REQ-ART-004 The admin settings page SHALL show the round-trip report
+
+The ArchiMate section of the admin settings SHALL offer Check a model file with a file picker, the choice "Before import (nothing is written)" or "Against the imported model", and a Check button. The result SHALL show a table with one row per category (in the file, after the round trip, missing, extra, changed), an expandable list of examples per category, and a summary that reads "No losses found" or names the categories with losses.
+
+#### Scenario: An admin checks a small model before importing it
+@e2e tests/e2e/workflows/archimate-round-trip-check.spec.ts
+
+- **GIVEN** a Nextcloud admin on the stackiq admin settings page and a small exchange file from the test fixtures
+- **WHEN** they choose Check a model file, pick the file, keep Before import and choose Check
+- **THEN** the page SHALL show the table with a row for elements, relationships and views
+- **AND** the summary SHALL read "No losses found" or name the categories with losses
diff --git a/openspec/changes/architecture-round-trip-check/tasks.md b/openspec/changes/architecture-round-trip-check/tasks.md
new file mode 100644
index 000000000..cb4804653
--- /dev/null
+++ b/openspec/changes/architecture-round-trip-check/tasks.md
@@ -0,0 +1,69 @@
+# Tasks: architecture-round-trip-check
+
+## Implementation tasks
+
+### Task 1: Model comparator
+- **spec_ref**: openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md#requirement-req-art-001-stackiq-shall-compare-two-exchange-files-by-identifier-per-category
+- **files**: `lib/Service/ArchiMateModelComparator.php`, `tests/Unit/Service/ArchiMateModelComparatorTest.php`
+- **acceptance_criteria**:
+ - GIVEN two files that differ in one relationship target WHEN they are compared THEN exactly one changed relationship is reported with the field target
+ - GIVEN a file and itself in another order WHEN they are compared THEN no difference is reported
+ - GIVEN more than 50 differences in a category WHEN they are compared THEN 50 examples and the full counts come back
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchiMateModelComparatorTest`)
+
+### Task 2: One conversion and one generation entry
+- **spec_ref**: openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md#requirement-req-art-002-the-check-shall-run-before-an-import-or-against-an-imported-model-without-writing
+- **files**: `lib/Service/ArchiMateImportService.php`, `lib/Service/ArchiMateExportService.php`, `tests/Unit/Service/ArchiMateImportServiceConvertTest.php`
+- **acceptance_criteria**:
+ - GIVEN the fixture `lib/Settings/GEMMA_testdata_below_1_5mb.xml` WHEN it is converted by the optimised import with the save mocked and by `convertFileToObjects` THEN the object lists are equal
+ - GIVEN `exportArchiMateXml` WHEN it runs THEN it calls `generateXmlFromObjects`, and the existing decomposition tests stay green
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchiMateImportServiceConvertTest`, `ArchiMateImportServiceDecompositionTest`, `ArchiMateExportServiceDecompositionTest`)
+
+### Task 3: Round-trip service with two modes
+- **spec_ref**: openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md#requirement-req-art-002-the-check-shall-run-before-an-import-or-against-an-imported-model-without-writing
+- **files**: `lib/Service/ArchiMateRoundTripService.php`, `tests/Unit/Service/ArchiMateRoundTripServiceTest.php`
+- **acceptance_criteria**:
+ - GIVEN the before-import mode WHEN it runs on the fixture THEN no save method is called and every category is reported
+ - GIVEN the against-imported mode and stored objects of the model WHEN it runs THEN it compares only objects with that model identifier
+ - GIVEN no stored object with the model identifier WHEN the against-imported mode runs THEN it answers that the model is not imported
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchiMateRoundTripServiceTest`)
+
+### Task 4: Admin route and removal of the old round trip
+- **spec_ref**: openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md#requirement-req-art-003-only-an-admin-shall-run-the-check-and-the-old-round-trip-endpoint-shall-be-removed
+- **files**: `lib/Controller/SettingsController.php`, `appinfo/routes.php`, `lib/Service/ArchiMateService.php`, `src/store/modules/settings.js`, `tests/Unit/Controller/SettingsControllerRoundTripCheckTest.php`, `tests/Unit/Controller/SettingsControllerEmailArchiMateContractTest.php`, `tests/Unit/SettingsRouteTableTest.php`
+- **acceptance_criteria**:
+ - GIVEN a non-admin WHEN they post to the check route THEN the answer is 403 before the service runs
+ - GIVEN a body with `file_path` WHEN it is posted THEN the answer is 400
+ - GIVEN the route table WHEN it is read THEN `settings#testArchiMateRoundTrip` is gone and `settings#checkArchiMateRoundTrip` exists
+ - GIVEN the source WHEN it is searched THEN `testRoundTrip`, `createTestArchiMateXml` and `createTempFile` are gone
+- [ ] Implement
+- [ ] Test (PHPUnit `SettingsControllerRoundTripCheckTest`, `SettingsRouteTableTest`, updated `SettingsControllerEmailArchiMateContractTest`)
+
+### Task 5: Report on the admin settings page
+- **spec_ref**: openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md#requirement-req-art-004-the-admin-settings-page-shall-show-the-round-trip-report
+- **files**: `src/views/settings/sections/ArchiMateRoundTripCheck.vue`, `src/views/settings/sections/ArchiMateImportExport.vue`, `src/store/modules/settings.js`, `tests/e2e/workflows/archimate-round-trip-check.spec.ts`
+- **acceptance_criteria**:
+ - GIVEN the admin settings page WHEN the ArchiMate section renders THEN Check a model file offers a file picker, the two modes and a Check button
+ - GIVEN a result WHEN it renders THEN a row per category shows the counts, examples expand per category, and the summary names the categories with losses or reads "No losses found"
+- [ ] Implement
+- [ ] Test (Playwright `archimate-round-trip-check.spec.ts`)
+
+### Task 6: Documentation and translations
+- **spec_ref**: openspec/changes/architecture-round-trip-check/specs/archimate-round-trip-check/spec.md#requirement-req-art-004-the-admin-settings-page-shall-show-the-round-trip-report
+- **files**: `docs/features/archimate-import-export.md`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the feature page WHEN it is read THEN it explains both modes and shows a report in a screenshot
+ - GIVEN a Dutch instance WHEN the check renders THEN every label and summary reads in Dutch
+- [ ] Implement
+- [ ] Test (`tests/l10n` key parity, screenshot captured with Playwright)
+
+## Verification
+
+- `openspec validate architecture-round-trip-check --type change --strict`
+- PHPUnit: `ArchiMateModelComparatorTest`, `ArchiMateImportServiceConvertTest`, `ArchiMateRoundTripServiceTest`, `SettingsControllerRoundTripCheckTest`, `SettingsRouteTableTest`, and the existing ArchiMate decomposition tests
+- Playwright: `tests/e2e/workflows/archimate-round-trip-check.spec.ts`
+- Documentation in `docs/features/archimate-import-export.md` with a screenshot (ADR-010)
+- English and Dutch strings for every new label (ADR-005)
diff --git a/openspec/changes/architecture-views-editor/.openspec.yaml b/openspec/changes/architecture-views-editor/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-views-editor/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-views-editor/design.md b/openspec/changes/architecture-views-editor/design.md
new file mode 100644
index 000000000..da31d622f
--- /dev/null
+++ b/openspec/changes/architecture-views-editor/design.md
@@ -0,0 +1,137 @@
+# Design: architecture-views-editor
+
+Read at development 49e65cb4. Line numbers below are from that sha.
+
+## Where it fits
+
+| Layer | Touched | Read at |
+|---|---|---|
+| Register | `vng-gemma` register (`lib/Settings/softwarecatalogus_register.json:916`), schemas `view` (:5299), `element` (:4130), `relation` (:6300) | through a new fragment `lib/Settings/register.d/architecture-views.json` |
+| Service | `lib/Service/ViewService.php` `getViewsFromRegister` (:232) and `getViewFromRegister` (:307) | the drawn views filter |
+| Service | `lib/Service/ArchiMateExportService.php` `getObjectsFromDatabase` (:808, the read at :844) | the drawn objects filter |
+| Routes | none added. `appinfo/routes.php:185-187` stays as it is | |
+| Pages | new `src/manifest.d/architecture-views.json` with `Views` (index) and `ViewEditor` (custom); `src/menu-layout.json` relocations | |
+| Views | new `src/views/architecture/ArchitectureViewEditor.vue`, `src/views/architecture/ViewVersionCompare.vue` | registered in `src/customComponents.js` |
+| Store and utils | new `src/store/modules/architectureView.js`, `src/utils/viewGraph.js`, `src/utils/viewDiff.js` | `src/store/modules/view.js` is left alone |
+
+The fragment is merged by `SettingsService::loadSettings` (`lib/Service/SettingsService.php:1653-1680`). `deepMergeConfig` (:7338) appends lists and replaces lists under `authorization`. So the fragment carries `components.schemas.view-version`, `components.registers.vng-gemma.schemas: ["view-version"]` and `components.registers.vng-gemma.configuration.schemas.view-version: {"magicMapping": true, "autoCreateTable": true}`, plus the new properties on `view`, `element` and `relation`. It bumps `view` to 0.0.8, `element` to 0.0.12 and `relation` to 0.0.9.
+
+## Decisions
+
+### D1. A drawn view is a `view` object with `origin: drawn`
+
+A user's view is stored in the same `view` schema as the imported GEMMA views, with `origin` set to `drawn`. The import writes `origin: imported`. A view imported before this change has no `origin` and counts as imported. Every reader that must see only GEMMA content keeps views whose `origin` is empty or `imported`, so a later origin value is left out by default.
+
+Rejected: a new schema in the `stackiq` register. `ViewService` and both ArchiMate exports read only the AMEF `view` schema, so a second store would split the views list and leave drawn views out of any later export.
+
+### D2. Imported views open read-only, and Copy to edit makes a drawn copy
+
+The import saves views with `@self.id` equal to the ArchiMate identifier (`lib/Service/ArchiMateImportService.php:5394`) through `saveObjects` (:1587), which updates the object with that id. An edit to an imported view would be overwritten without a word on the next GEMMA import. The editor therefore opens `origin: imported` views read-only and offers Copy to edit. The copy gets a fresh identifier `id-`, `origin: drawn`, `status: draft` and `basedOn` set to the source view's uuid.
+
+Rejected: editing in place with a "protected" flag the import respects. The import is 5,961 lines with three save paths (:1369, :1587, :1695), and a flag that one of them forgets fails silently.
+
+### D3. The editor saves the shape the import writes
+
+The editor writes `xml.viewNodes` and `xml.viewRelationships` in the import's shape: a flat node list with `viewNodeId`, `parent`, `elementRef`, `x`, `y`, `width`, `height`, `name` and `type` (:2886 to :3058), and connections with `viewRelationshipId`, `modelRelationshipId`, `sourceId`, `targetId`, `type` and `bendpoints` (:3364). It fills the required `nodes` and `connections` fields with the same lists. `ViewService::transformView` (`lib/Service/ViewService.php:1451`) and the exporter then read a drawn view the way they read an imported one.
+
+`src/utils/viewGraph.js` maps that shape to and from `CnGraphCanvas` nodes and edges. A node with a `parent` becomes a Vue Flow child node of that parent, so a grouping keeps its children.
+
+Rejected: storing the canvas's own JSON. Two shapes need two readers, and the export would miss drawn views.
+
+### D4. The canvas is `CnGraphCanvas`
+
+`CnGraphCanvas` (`@conduction/nextcloud-vue` 2.57.1, `src/components/CnGraphCanvas/CnGraphCanvas.vue`) takes `nodes`, `edges` and `readOnly`, emits a connection for pointer and keyboard input alike, and carries labelled zoom controls. The editor renders an ArchiMate element in the `node` slot: the element name, its ArchiMate type and the layer colour from Nextcloud CSS variables (ADR-003).
+
+Rejected: a separate diagram library. ADR-012 asks for the shared components, and `CnGraphCanvas` already carries the keyboard contract (ADR-059).
+
+### D5. A drawn connection references a `relation` object
+
+The ArchiMate exchange format needs every relationship connection to name a relationship. When the user connects two elements with a relation type, the store looks for a `relation` object of that type between the two elements (`source`, `target` and `type`, register.json:6346 and :6376) and reuses it, or creates one with `origin: drawn`. The connection stores its id as `modelRelationshipId`.
+
+A new element placed from the palette ("New application component", and the other ArchiMate element types) is created as an `element` object with `origin: drawn` and the ArchiMate `type`. An existing GEMMA element is placed by reference and is not changed.
+
+### D6. Versions are explicit snapshots in `view-version`
+
+Save version writes a `view-version` object with the view's uuid, a version number, a label, the saving user, the time and a copy of `xml.viewNodes` and `xml.viewRelationships`. Compare versions loads two snapshots, or one snapshot and the current view, and `src/utils/viewDiff.js` sorts every node and connection by id into added, removed, changed and unchanged. A node counts as changed when its name, element, parent, position, size or style differs. `ViewVersionCompare.vue` renders both sides on a read-only `CnGraphCanvas`, marks added in `--color-success`, removed in `--color-error` and changed in `--color-warning`, and lists the same result as text for screen readers.
+
+Rejected: OpenRegister's audit trail with `CnVersionHistory`. OpenRegister replaces any changed value over 65,536 bytes with a descriptor (`openregister-ro/lib/Db/AuditTrailPayloadHelper.php:51` and :150), so the node list of a large view cannot be rebuilt from its history. And `computeObjectDiff` (`@conduction/nextcloud-vue` `src/utils/computeObjectDiff.js:141`) compares arrays by index, so one node removed from the middle reads as every later node changed. The audit trail still records who saved what, in the sidebar History tab.
+
+### D7. Tags, status and owner filter the views list
+
+`view.tags` is a facetable string list. `view.status` is a facetable enum `draft`, `in review`, `published`, `retired` with default `draft`. `view.origin` is facetable. The `Views` index page is a `CnIndexPage` (manifest `type: index`) over `@resolve:amef_register` and `view`, with columns name, viewpoint, status, tags and origin, the schema facets in its sidebar, and quick filters All, Mine (`{"_owner": "@me"}`), Drawn and Imported. `@me` is resolved by `@conduction/nextcloud-vue` (`src/utils/resolveFilterTokens.js:119`).
+
+### D8. The menu gains a group, not an entry
+
+ADR-097 caps the main menu at six entries, and stackiq has 13 after relocation. The fragment adds a group `Architecture` (order 50, no route) and `src/menu-layout.json` relocates `Standaarden` and the new `Views` entry under it. The count of top-level entries stays 13.
+
+### D9. Drawn objects stay inside the organisation
+
+Drawn views, elements and relations are scoped to the organisation that created them through OpenRegister multitenancy. Three readers bypass that today and each gets a filter:
+
+- `ViewService::getViewsFromRegister` caches one list for all callers (`views_list`, :234, 30 minutes, :74). It keeps only views whose `origin` is empty or `imported`, so the cache only ever holds GEMMA views.
+- `ViewService::getView` (:166) reads one view through `getViewFromRegister` (:307) with `_rbac: false` and `_multitenancy: false` (:328), so `GET /api/views/{viewId}` returns any view to any signed-in user. It answers a view whose `origin` is not empty or `imported` with a 404, the same answer as a missing view, so a uuid does not reveal that a drawn view exists.
+- `ArchiMateExportService::getObjectsFromDatabase` reads with `_rbac: false` and `_multitenancy: false` (:844). The full model export keeps only objects whose `origin` is empty or `imported`.
+
+The editor and the index read drawn views through OpenRegister's objects API, which applies RBAC and multitenancy.
+
+### D10. One editor at a time
+
+The editor takes OpenRegister's object lock through `useObjectLock` (`@conduction/nextcloud-vue` `src/composables/useObjectLock.js:66`) before it enters edit mode, and shows who holds the lock otherwise (ADR-033).
+
+## Declarative versus imperative
+
+- The view status lifecycle is declared in the fragment as `configuration.x-openregister-lifecycle` on `view`, in the shape `usage` already uses (field `status`, `initial` draft, named transitions): submit (draft to in review), publish (in review to published), rework (in review to draft), retire (published to retired), reopen (retired to draft). The `from` and `to` values are the enum values exactly, because a lifecycle whose values match no row offers no transition and raises no error (register changelog 2.4.4, register.json:7). No PHP.
+- Copy to edit, Save version and relation reuse write through OpenRegister's objects API from `src/store/modules/architectureView.js`. They add no controller and no service (ADR-022, config rule "Uses OpenRegister API directly from frontend").
+- The three backend filters in D9 are changes to existing readers, not new behaviour.
+
+## Seed data
+
+The fragment seeds a small drawn example so the Views page is not empty on a fresh install. All objects live in the `vng-gemma` register.
+
+### Schema: `element`
+
+| Field | Object 1 | Object 2 | Object 3 |
+|---|---|---|---|
+| slug | `seed-el-zaaksysteem` | `seed-el-dms` | `seed-el-zaakregistratie` |
+| identifier | `id-seed-el-zaaksysteem` | `id-seed-el-dms` | `id-seed-el-zaakregistratie` |
+| type | `ApplicationComponent` | `ApplicationComponent` | `ApplicationService` |
+| name | Zaaksysteem | Documentbeheer | Zaakregistratie |
+| origin | drawn | drawn | drawn |
+
+### Schema: `relation`
+
+| Field | Object 1 | Object 2 |
+|---|---|---|
+| slug | `seed-rel-zaak-dms` | `seed-rel-zaak-registratie` |
+| type | `Flow` | `Realization` |
+| source | `id-seed-el-zaaksysteem` | `id-seed-el-zaaksysteem` |
+| target | `id-seed-el-dms` | `id-seed-el-zaakregistratie` |
+| origin | drawn | drawn |
+
+### Schema: `view`
+
+| Field | Object 1 | Object 2 |
+|---|---|---|
+| slug | `seed-view-zaakgericht-nu` | `seed-view-zaakgericht-concept` |
+| name | Zaakgericht werken, huidige situatie | Zaakgericht werken, concept |
+| status | published | draft |
+| tags | zaakgericht, applicatielandschap | zaakgericht |
+| origin | drawn | drawn |
+| nodes | the three elements | the first two elements |
+
+### Schema: `view-version`
+
+| Field | Object 1 |
+|---|---|
+| slug | `seed-view-zaakgericht-nu-v1` |
+| view | uuid of `seed-view-zaakgericht-nu` |
+| versionNumber | 1 |
+| label | Eerste opzet |
+| nodes | the first two elements, so a compare with the current view shows one addition |
+
+## Risks
+
+- **Nested ArchiMate nodes on Vue Flow.** Vue Flow draws a child node relative to its parent, while the import stores absolute coordinates. `viewGraph.js` converts both ways and its vitest spec round-trips an imported GEMMA view without moving a node.
+- **Partial saves.** A save that creates relations and then the view can fail between the two. The store writes relations first, reuses them on a retry, and reports a failed view write without leaving the canvas.
+- **Large views.** A GEMMA view with a few hundred nodes is a large object. The editor loads one view, never the whole list with nodes, and the index columns do not include `xml`.
+- **Schema versions.** The fragment bumps three AMEF schema versions. The register changelog entry 2.4.4 (register.json:7) records why: a deployed version equal to or above the declared one makes the import skip, and OpenRegister compares only properties, required and authorization, never `configuration`, where the lifecycle lives.
diff --git a/openspec/changes/architecture-views-editor/proposal.md b/openspec/changes/architecture-views-editor/proposal.md
new file mode 100644
index 000000000..bfcc11dca
--- /dev/null
+++ b/openspec/changes/architecture-views-editor/proposal.md
@@ -0,0 +1,53 @@
+---
+kind: code
+depends_on: []
+---
+
+# Draw, tag and compare architecture views in stackiq
+
+## Summary
+
+An application owner can draw an ArchiMate view in stackiq: place elements, connect them, save the view and open it again. Views get tags, a status and an owner, and the views list filters on all three. An owner can save a named version of a view and compare two versions, with additions, removals and changes marked on the canvas and listed as text. Imported GEMMA views open read-only, and Copy to edit makes a drawn copy.
+
+## Why
+
+Three rows of the stackiq parity matrix are built by this change.
+
+- `stackiq:arch-modelling`, "Draw and edit architecture models yourself inside the tool." SAP LeanIX rates yes: "free draw and data flow diagrams edited in the diagram editor, with an ArchiMate 3.2 shape template" (https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams). BlueDolphin rates yes: "users create and edit ArchiMate architecture views in the view editor" (https://help.bluedolphin.io/en/articles/11967507-create-an-architecture-view). No tender or feature request names it. The lane decided build because two competitors rate yes and architecture is a core area.
+- `stackiq:arch-diagram-version-compare`, "Compare two saved versions of an architecture diagram and see what was added, removed or changed." The demand is a changelog entry, https://updates.leanix.net/announcements/compare-the-content-of-different-diagram-versions. SAP LeanIX rates yes: "Selecting Compare Changes ... on a prior diagram version shows color-coded highlighting (green for additions, red for removals, yellow for modifications), a side-by-side view of differences, and an additional text-based summary". The matrix holds no evidence URL beyond the changelog entry. Decided build: core area.
+- `stackiq:arch-view-tags`, "Tag saved diagrams and views and filter the view list by tag, owner or status to find them again." The demand is a changelog entry, https://help.bluedolphin.io/en/articles/16096602-discover-and-manage-views-in-the-views-list. BlueDolphin rates yes: "Bring structure to your Views list with tags", with view filters "Owner Contributors Tags Favorited Private Project Status Type" (https://bluedolphin.io/product-news/). Decided build: core area.
+
+The rated rows say stackiq renders no architecture view. The pending row `stackiq:arch-gemma-views` rates stackiq partial with state built. Both hold, because they describe different things. The API that serves enriched views exists (`appinfo/routes.php:185-187`), and so does the organisation export that draws applications into copies of GEMMA views (`lib/Service/ArchiMateExportService.php:2734`). No page draws a view: `src/store/modules/view.js:15` defines `useViewStore`, nothing under `src/` imports it, and nothing under `src/` reads `viewNodes` or `viewRelationships`. The pending row's own note says the same.
+
+## What stackiq has today
+
+- The AMEF register `vng-gemma` (`lib/Settings/softwarecatalogus_register.json:916`) holds the schemas `element` (:4130), `view` (:5299), `model` (:5689), `property-definition` (:6140) and `relation` (:6300). The `view` schema is at version 0.0.7 (:5304) and its authorization only grants public read (:5678). It has no tag, status or owner field of its own.
+- The ArchiMate import writes each view with `@self.id` set to the ArchiMate identifier (`lib/Service/ArchiMateImportService.php:5394`) and stores the diagram under `xml.viewNodes` and `xml.viewRelationships`: a flat node list with `parent` references, `elementRef`, `x`, `y`, `width` and `height` (:2886 to :3058), and connections with `modelRelationshipId`, `sourceId` and `targetId` (:3364). It saves through `saveObjects` (:1587), which updates an object with the same id. A re-import overwrites every imported view.
+- `lib/Controller/ViewController.php:82` and `lib/Service/ViewService.php:108` serve `GET /api/views`, and `ViewService::transformView` (:1451) turns `xml.viewNodes` into `viewNodes` with a `position` and a `style`. The list is cached for all callers under one key, `views_list` (:234), for 30 minutes (:74).
+- The full ArchiMate export reads every AMEF object with `_rbac: false` and `_multitenancy: false` (`lib/Service/ArchiMateExportService.php:844`).
+- `src/manifest.json` has one page over the AMEF register, Standaarden (:701), filtered to `gemmaType` standaard. The main menu has 15 entries next to Dashboard, 13 after `src/menu-layout.json` relocates two of them.
+- OpenRegister keeps an audit trail per object and can revert to a version (`openregister-ro/appinfo/routes.php:1344` and :1453). It replaces any changed value over 65,536 bytes with a descriptor (`openregister-ro/lib/Db/AuditTrailPayloadHelper.php:51` and :150).
+- `@conduction/nextcloud-vue` 2.57.1 ships `CnGraphCanvas` (`src/components/CnGraphCanvas/CnGraphCanvas.vue`, a Vue Flow canvas with `nodes`, `edges` and `readOnly` props), `CnVersionHistory` and the `useObjectLock` composable (`src/composables/useObjectLock.js:66`).
+
+## What this change builds
+
+- A register fragment `lib/Settings/register.d/architecture-views.json` that adds `tags`, `status`, `origin` and `basedOn` to `view`, adds `origin` to `element` and `relation`, declares the view status lifecycle, and adds a `view-version` schema to the `vng-gemma` register.
+- A Views index page and a view editor page in `src/manifest.d/architecture-views.json`, reached from an Architecture menu group that takes the place of the top-level Standards entry.
+- A canvas editor on `CnGraphCanvas` that places elements, draws connections backed by `relation` objects, and saves in the shape the import already writes.
+- Copy to edit for imported views, which open read-only.
+- Save version and Compare versions, with a diff keyed by node and connection id.
+- Backend guards: drawn views stay out of the shared `/api/views` list, the single view read `/api/views/{viewId}` and the full ArchiMate export.
+
+## Out of scope
+
+- Drawing the organisation's own applications (stackiq `module` objects) into a view. The organisation export does that into copies of GEMMA views today, and the pending row `stackiq:arch-gemma-views` covers it.
+- Drafting a view with an assistant. That is `architecture-assistant-drafted-views`, which depends on this change.
+- Putting a view into Word or PowerPoint. That is `architecture-views-to-office-documents`.
+- Business processes on a view. That is `architecture-process-mapping`.
+- Editing an imported GEMMA view in place, and writing a drawn view back into the GEMMA model.
+- Live co-editing. One editor holds the lock (ADR-033), others read.
+
+## Risks
+
+- A drawn view in the AMEF register sits next to VNG's GEMMA content. The `origin` field and the three backend guards keep them apart. A future import path that forgets the guard would mix them, so the guards get their own tests.
+- Snapshots are copies of the node list. A view with many versions grows the register. Versions are only saved on an explicit action, not on every save.
diff --git a/openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md b/openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md
new file mode 100644
index 000000000..68c2f3fc9
--- /dev/null
+++ b/openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md
@@ -0,0 +1,127 @@
+# architecture-views-editor specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-views-editor
+
+## Purpose
+
+An application owner draws ArchiMate views in stackiq instead of only importing them from Archi. Views carry tags, a status and an owner, so a municipality finds its views again, and saved versions can be compared to see what changed. Imported GEMMA views stay as VNG publishes them. Data lives in OpenRegister's AMEF register (ADR-001), the canvas is `CnGraphCanvas` (ADR-012), and the status lifecycle is declared on the schema (ADR-031).
+
+## ADDED Requirements
+
+### Requirement: REQ-AVE-001 An application owner SHALL draw and save an architecture view
+
+Stackiq SHALL offer a view editor at `/views/:id` (page `ViewEditor`) on `CnGraphCanvas`. An application owner SHALL be able to create a view, place existing AMEF elements and new elements of an ArchiMate element type, connect two elements with an ArchiMate relation type, move and resize nodes, and save. The saved view SHALL be a `view` object in the `vng-gemma` register with `origin` set to `drawn`, and its diagram SHALL be stored in `xml.viewNodes` and `xml.viewRelationships` in the shape the ArchiMate import writes, so `ViewService` reads it unchanged. A new element SHALL be saved as an `element` object with `origin` set to `drawn`.
+
+#### Scenario: An application owner draws a view and opens it again
+@e2e tests/e2e/workflows/architecture-views.spec.ts
+
+- **GIVEN** an application owner signed in to stackiq
+- **WHEN** they open the Views page, choose New view, place two application components, connect them with a flow relation and save
+- **THEN** the Views page SHALL list the view with status draft and origin drawn
+- **AND** opening it again SHALL show both nodes at the saved positions and the connection between them
+
+#### Scenario: A saved drawn view reads like an imported one
+@e2e exclude The shape is not visible in the browser; tests/vitest/viewGraph.spec.js round-trips a drawn canvas and an imported GEMMA view through the store's save shape, and tests/Unit/Service/ViewServiceDrawnViewTest.php reads a drawn view through ViewService::transformView.
+
+- **GIVEN** a drawn view saved by the editor
+- **WHEN** `ViewService::transformView` reads it
+- **THEN** every node SHALL carry `identifier`, `position` and `elementRef` as it does for an imported view
+- **AND** every child node SHALL keep its `parent`
+
+### Requirement: REQ-AVE-002 Imported GEMMA views SHALL open read-only and SHALL be copied before editing
+
+A view with `origin` set to `imported` SHALL open in the editor without edit controls. Its Copy to edit action SHALL create a new `view` with a fresh identifier, `origin` set to `drawn`, `status` set to `draft` and `basedOn` set to the source view's uuid, and SHALL open the copy in edit mode. A later ArchiMate import SHALL NOT change a drawn view.
+
+#### Scenario: A municipal information manager copies a GEMMA view to adapt it
+@e2e tests/e2e/workflows/architecture-views.spec.ts
+
+- **GIVEN** an imported GEMMA view on the Views page
+- **WHEN** a municipal information manager opens it
+- **THEN** the canvas SHALL show no edit controls and SHALL offer Copy to edit
+- **AND** choosing Copy to edit SHALL open a new drawn view whose Based on field names the GEMMA view
+
+#### Scenario: A re-import leaves a drawn copy alone
+@e2e exclude An import needs a GEMMA model file and minutes of runtime; tests/Unit/Service/ArchitectureViewsImportIsolationTest.php imports a view whose identifier differs from the copy's and asserts the copy's nodes are unchanged.
+
+- **GIVEN** a drawn copy of a GEMMA view
+- **WHEN** a Nextcloud admin imports the GEMMA model again
+- **THEN** the imported view SHALL be updated
+- **AND** the drawn copy SHALL keep its nodes, connections and status
+
+### Requirement: REQ-AVE-003 A drawn connection SHALL reference a relation object
+
+When the user connects two elements, the editor SHALL reuse a `relation` object of the chosen type between the same source and target, or SHALL create one with `origin` set to `drawn`. The connection SHALL store that relation's id as `modelRelationshipId`, so the ArchiMate export writes a valid relationship reference.
+
+#### Scenario: Connecting the same two elements twice reuses one relation
+@e2e exclude The relation lookup is a store concern; tests/vitest/architectureViewStore.spec.js asserts one relation is created for the first connection and reused for the second.
+
+- **GIVEN** a drawn view with a flow connection from Zaaksysteem to Documentbeheer
+- **WHEN** the application owner draws a second flow connection between the same two elements on another view
+- **THEN** no second `relation` object SHALL be created
+- **AND** both connections SHALL carry the same `modelRelationshipId`
+
+### Requirement: REQ-AVE-004 The views list SHALL filter on tag, status and owner
+
+The `Views` page at `/views` SHALL be a `CnIndexPage` over the `view` schema with columns name, viewpoint, status, tags and origin. `tags` SHALL be a facetable list of strings, `status` a facetable enum of draft, in review, published and retired, and `origin` a facetable enum of imported and drawn. The page SHALL offer the quick filters All, Mine, Drawn and Imported, where Mine filters on the signed-in user as owner. The status transitions SHALL be declared as `x-openregister-lifecycle` on the `view` schema.
+
+#### Scenario: A municipal information manager finds views by tag
+@e2e tests/e2e/workflows/architecture-views.spec.ts
+
+- **GIVEN** two drawn views, one tagged zaakgericht and one tagged financien
+- **WHEN** a municipal information manager selects the tag zaakgericht in the Views sidebar
+- **THEN** the list SHALL show only the view tagged zaakgericht
+
+#### Scenario: Mine shows only the signed-in user's views
+@e2e tests/e2e/workflows/architecture-views.spec.ts
+
+- **GIVEN** a drawn view owned by the signed-in application owner and one owned by a colleague
+- **WHEN** the application owner chooses the quick filter Mine
+- **THEN** the list SHALL show only their own view
+
+#### Scenario: A published view moves through the declared lifecycle
+@e2e exclude The transition engine is OpenRegister's; tests/Unit/Service/ArchitectureViewsRegisterShapeTest.php asserts every lifecycle from and to value is a member of the status enum and the view schema version is bumped.
+
+- **GIVEN** a drawn view in status in review
+- **WHEN** the owner applies the publish transition
+- **THEN** the view SHALL read published
+- **AND** the transition SHALL appear in the view's History tab
+
+### Requirement: REQ-AVE-005 An owner SHALL save named versions and compare two of them
+
+The editor SHALL offer Save version, which SHALL write a `view-version` object with the view's uuid, the next version number, a label, the saving user, the time and a copy of the view's nodes and connections. Compare versions SHALL let the user pick two versions, or one version and the current view, and SHALL show both on read-only canvases with added items marked in the success colour, removed items in the error colour and changed items in the warning colour, next to a text list of the same changes. A node SHALL count as changed when its name, element, parent, position, size or style differs.
+
+#### Scenario: An application owner sees what changed since the last version
+@e2e tests/e2e/workflows/architecture-views.spec.ts
+
+- **GIVEN** a drawn view with a saved version 1 holding two nodes
+- **WHEN** the application owner adds a third node, saves, and compares version 1 with the current view
+- **THEN** the third node SHALL be marked as added on the current side
+- **AND** the text list SHALL read one added node, no removed nodes and no changed nodes
+
+#### Scenario: A reordered node list is not a change
+@e2e exclude A pure function; tests/vitest/viewDiff.spec.js asserts that two snapshots with the same nodes in a different order give no added, removed or changed entries.
+
+- **GIVEN** two snapshots with the same nodes in a different order
+- **WHEN** `viewDiff` compares them
+- **THEN** it SHALL report no added, removed or changed nodes
+
+### Requirement: REQ-AVE-006 Drawn views SHALL stay inside the organisation that drew them
+
+Drawn views, elements and relations SHALL be scoped to the organisation that created them. `GET /api/views` SHALL return only views whose `origin` is empty or `imported`, because its list is cached for all callers. `GET /api/views/{viewId}` SHALL answer 404 for a view whose `origin` is neither, because it reads without RBAC. The full ArchiMate export (`POST /api/archimate/export`) SHALL keep only objects whose `origin` is empty or `imported`. The editor SHALL take OpenRegister's object lock before edit mode and SHALL show who holds the lock when another user has it.
+
+#### Scenario: Another municipality does not see a drawn view
+@e2e exclude The CI instance has one organisation; tests/Unit/Service/ViewServiceDrawnViewTest.php asserts the views query keeps only an empty or imported origin and the single view read answers 404 for a drawn view, and tests/Unit/Service/ArchiMateExportServiceDrawnFilterTest.php asserts the full export skips drawn objects.
+
+- **GIVEN** a drawn view of municipality A
+- **WHEN** a user of municipality B calls `GET /api/views` or `GET /api/views/{viewId}` with its uuid, or a Nextcloud admin runs the full ArchiMate export
+- **THEN** the drawn view SHALL NOT be in the response or in the exported file
+
+#### Scenario: A second editor sees the lock
+@e2e tests/e2e/workflows/architecture-views.spec.ts
+
+- **GIVEN** an application owner editing a drawn view
+- **WHEN** a colleague opens the same view
+- **THEN** the colleague SHALL see the view read-only with a notice naming who is editing it
diff --git a/openspec/changes/architecture-views-editor/tasks.md b/openspec/changes/architecture-views-editor/tasks.md
new file mode 100644
index 000000000..b26534cdf
--- /dev/null
+++ b/openspec/changes/architecture-views-editor/tasks.md
@@ -0,0 +1,101 @@
+# Tasks: architecture-views-editor
+
+## Implementation tasks
+
+### Task 1: Register fragment for drawn views and versions
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-004-the-views-list-shall-filter-on-tag-status-and-owner
+- **files**: `lib/Settings/register.d/architecture-views.json`, `tests/Unit/Service/ArchitectureViewsRegisterShapeTest.php`
+- **acceptance_criteria**:
+ - GIVEN the merged register WHEN it loads THEN `view` has `tags`, `status`, `origin` and `basedOn`, and `element` and `relation` have `origin`
+ - GIVEN the merged register WHEN it loads THEN `vng-gemma` lists `view-version` with magic mapping on
+ - GIVEN the view lifecycle WHEN the shape test reads it THEN every `from` and `to` value is a member of the status enum
+ - GIVEN the fragment WHEN it is compared with development THEN `view`, `element` and `relation` carry bumped versions
+- [ ] Implement
+- [ ] Test (PHPUnit `ArchitectureViewsRegisterShapeTest`, `RegisterFragmentMergeTest`)
+
+### Task 2: Views index page and Architecture menu group
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-004-the-views-list-shall-filter-on-tag-status-and-owner
+- **files**: `src/manifest.d/architecture-views.json`, `src/menu-layout.json`
+- **acceptance_criteria**:
+ - GIVEN the effective manifest WHEN it is built THEN `Views` is an index page at `/views` over `@resolve:amef_register` and `view` with the quick filters All, Mine, Drawn and Imported
+ - GIVEN the effective menu WHEN it renders THEN Standards and Views sit under an Architecture group and the top-level count is unchanged
+- [ ] Implement
+- [ ] Test (`tests/validate-manifest.js`, Playwright `tests/e2e/workflows/architecture-views.spec.ts` tag and Mine filters)
+
+### Task 3: Canvas shape mapping
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-001-an-application-owner-shall-draw-and-save-an-architecture-view
+- **files**: `src/utils/viewGraph.js`, `tests/vitest/viewGraph.spec.js`
+- **acceptance_criteria**:
+ - GIVEN an imported GEMMA view WHEN it is mapped to canvas nodes and back THEN every node keeps its absolute position, size and parent
+ - GIVEN a canvas with a child node WHEN it is mapped to the save shape THEN the child carries its parent's `viewNodeId`
+- [ ] Implement
+- [ ] Test (vitest `viewGraph.spec.js`)
+
+### Task 4: View editor page on CnGraphCanvas
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-001-an-application-owner-shall-draw-and-save-an-architecture-view
+- **files**: `src/views/architecture/ArchitectureViewEditor.vue`, `src/store/modules/architectureView.js`, `src/customComponents.js`, `src/manifest.d/architecture-views.json`
+- **acceptance_criteria**:
+ - GIVEN the editor WHEN the user places two elements, connects them and saves THEN a `view` with `origin` drawn holds both nodes and the connection
+ - GIVEN a new element from the palette WHEN the view is saved THEN an `element` with `origin` drawn and the chosen ArchiMate type exists
+ - GIVEN a colleague holds the lock WHEN the user opens the view THEN it is read-only with a notice naming the colleague
+- [ ] Implement
+- [ ] Test (Playwright `architecture-views.spec.ts` draw and reopen, lock notice)
+
+### Task 5: Relations behind connections
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-003-a-drawn-connection-shall-reference-a-relation-object
+- **files**: `src/store/modules/architectureView.js`, `tests/vitest/architectureViewStore.spec.js`
+- **acceptance_criteria**:
+ - GIVEN no relation of the chosen type between two elements WHEN they are connected THEN one `relation` with `origin` drawn is created
+ - GIVEN such a relation exists WHEN they are connected again THEN it is reused
+ - GIVEN the view write fails after the relation write WHEN the user saves again THEN no second relation is created
+- [ ] Implement
+- [ ] Test (vitest `architectureViewStore.spec.js`)
+
+### Task 6: Read-only imported views and Copy to edit
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-002-imported-gemma-views-shall-open-read-only-and-shall-be-copied-before-editing
+- **files**: `src/views/architecture/ArchitectureViewEditor.vue`, `src/store/modules/architectureView.js`, `tests/Unit/Service/ArchitectureViewsImportIsolationTest.php`
+- **acceptance_criteria**:
+ - GIVEN an imported view WHEN it opens THEN no edit control renders and Copy to edit is offered
+ - GIVEN Copy to edit WHEN it completes THEN a drawn view with a fresh identifier and `basedOn` opens in edit mode
+ - GIVEN a re-import WHEN it runs THEN the drawn copy is unchanged
+- [ ] Implement
+- [ ] Test (Playwright copy flow, PHPUnit `ArchitectureViewsImportIsolationTest`)
+
+### Task 7: Save version and compare versions
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-005-an-owner-shall-save-named-versions-and-compare-two-of-them
+- **files**: `src/utils/viewDiff.js`, `src/views/architecture/ViewVersionCompare.vue`, `src/store/modules/architectureView.js`, `tests/vitest/viewDiff.spec.js`
+- **acceptance_criteria**:
+ - GIVEN Save version WHEN it completes THEN a `view-version` holds the next number, the label and a copy of the nodes and connections
+ - GIVEN two snapshots WHEN they are compared THEN added, removed and changed are keyed by node and connection id, and order alone is no change
+ - GIVEN the compare page WHEN it renders THEN colours use `--color-success`, `--color-error` and `--color-warning` and the text list names every change
+- [ ] Implement
+- [ ] Test (vitest `viewDiff.spec.js`, Playwright compare scenario)
+
+### Task 8: Keep drawn objects out of the shared list, the single view read and the full export
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-006-drawn-views-shall-stay-inside-the-organisation-that-drew-them
+- **files**: `lib/Service/ViewService.php`, `lib/Service/ArchiMateExportService.php`, `tests/Unit/Service/ViewServiceDrawnViewTest.php`, `tests/Unit/Service/ArchiMateExportServiceDrawnFilterTest.php`
+- **acceptance_criteria**:
+ - GIVEN a drawn and an imported view WHEN `GET /api/views` runs THEN only the imported view is returned and cached
+ - GIVEN a drawn view WHEN `GET /api/views/{viewId}` is called with its uuid THEN the answer is 404
+ - GIVEN drawn objects WHEN the full ArchiMate export runs THEN none of them is in the file
+ - GIVEN a view imported before this change with no origin WHEN either reader runs THEN it is kept as imported
+- [ ] Implement
+- [ ] Test (PHPUnit `ViewServiceDrawnViewTest`, `ArchiMateExportServiceDrawnFilterTest`)
+
+### Task 9: Documentation and translations
+- **spec_ref**: openspec/changes/architecture-views-editor/specs/architecture-views-editor/spec.md#requirement-req-ave-001-an-application-owner-shall-draw-and-save-an-architecture-view
+- **files**: `docs/features/architecture-views.md`, `l10n/en.json`, `l10n/nl.json`
+- **acceptance_criteria**:
+ - GIVEN the feature page WHEN it is read THEN it shows the editor, the tag filter and a compare, each with a screenshot
+ - GIVEN a Dutch instance WHEN the Views page renders THEN every new string reads in Dutch
+- [ ] Implement
+- [ ] Test (`tests/l10n` key parity, screenshots captured with Playwright)
+
+## Verification
+
+- `openspec validate architecture-views-editor --type change --strict`
+- PHPUnit: `ArchitectureViewsRegisterShapeTest`, `ArchitectureViewsImportIsolationTest`, `ViewServiceDrawnViewTest`, `ArchiMateExportServiceDrawnFilterTest`
+- vitest: `viewGraph.spec.js`, `viewDiff.spec.js`, `architectureViewStore.spec.js`
+- Playwright: `tests/e2e/workflows/architecture-views.spec.ts`
+- Documentation in `docs/features/architecture-views.md` with screenshots (ADR-010)
+- English and Dutch strings for every new label (ADR-005)
diff --git a/openspec/changes/architecture-views-to-office-documents/.openspec.yaml b/openspec/changes/architecture-views-to-office-documents/.openspec.yaml
new file mode 100644
index 000000000..7f2ad572a
--- /dev/null
+++ b/openspec/changes/architecture-views-to-office-documents/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-09-27
diff --git a/openspec/changes/architecture-views-to-office-documents/design.md b/openspec/changes/architecture-views-to-office-documents/design.md
new file mode 100644
index 000000000..2c8c42c2b
--- /dev/null
+++ b/openspec/changes/architecture-views-to-office-documents/design.md
@@ -0,0 +1,56 @@
+# Design: architecture-views-to-office-documents
+
+Read at development 49e65cb4. Line numbers below are from that sha. The view page (`ViewEditor`, `src/views/architecture/ArchitectureViewEditor.vue`) and the guard on `ViewService::getView` come from `architecture-views-editor` (its D3 and D9).
+
+## Where it fits
+
+| Layer | Touched | Read at |
+|---|---|---|
+| Service | new `lib/Service/ViewImageService.php` | reads `xml.viewNodes` and `xml.viewRelationships` in the import's shape (`lib/Service/ArchiMateImportService.php:2886` to :3058, :3364) |
+| Service | new `lib/Service/ViewDocumentGateway.php` | the one place stackiq talks to filinq |
+| Controller and routes | `lib/Controller/ViewController.php` gains `getViewImage` and `createViewDocument`; routes `view#getViewImage` at `GET /api/views/{viewId}/image.svg` and `view#createViewDocument` at `POST /api/views/{viewId}/document`, next to `view#getView` (`appinfo/routes.php:187`) | `ViewController::getView` (:218) is the pattern |
+| Initial state | `lib/AppInfo/Application.php` provides `view_document_export` next to `amef_register` (:908) | the frontend reads it with `loadState` |
+| View | `src/views/architecture/ArchitectureViewEditor.vue` gains an Export menu | |
+| Register, pages | none | |
+
+## Decisions
+
+### D1. Stackiq draws the picture on the server, as SVG
+
+`ViewImageService::renderSvg(array $view): string` walks the stored nodes and connections and writes one SVG: a rectangle per node at its absolute `x`, `y`, `width` and `height`, children inside their parents, the element name and ArchiMate type as text, and a path per connection through its bendpoints with the arrowhead of its relation type. A caption holds the view name and the date. The palette is the ArchiMate layer convention (business, application, technology, motivation, grouping) in one constant, because an exported file is read outside Nextcloud where the theme's CSS variables do not resolve (ADR-003 governs the UI, not a file).
+
+Rejected: capturing the canvas in the browser. `CnGraphCanvas` draws nodes as HTML and edges as SVG, the library ships no image export, and adding one would mean a DOM snapshot library whose output depends on the browser, the zoom and the theme. The stored geometry gives the same picture on every call, and filinq can take it without a browser.
+
+Rejected: an SVG made from the canvas's own node list. It would picture what the canvas shows after pan and zoom; the stored view is what the user saved.
+
+### D2. The image route reads with RBAC on
+
+`GET /api/views/{viewId}/image.svg` (`#[NoAdminRequired]`) reads the view through OpenRegister's `ObjectService::find` with RBAC and multitenancy on, not through `ViewService::getView`, which reads with both off (`lib/Service/ViewService.php:328`). A reader gets imported GEMMA views and the drawn views of their own organisation; any other uuid gets a 404. The response is `image/svg+xml` with a download file name built from the view name.
+
+Text from the view (names, the caption) is escaped before it goes into the SVG, and the SVG holds no script, no external reference and no `foreignObject`, so a view name cannot inject markup into a file that Word or a browser opens.
+
+### D3. Word and PowerPoint through one gateway to filinq
+
+`ViewDocumentGateway::isAvailable(): bool` and `requestDocument(string $format, array $content, string $userId): array` are the only code that knows filinq. `$format` is `docx` or `pptx`. `$content` holds the view name, description, viewpoint, a legend of the element types on the view, the generation date, a link back to the view page, and the SVG from D1. The result is the Files path and file id of the new document, which the frontend opens.
+
+The gateway consumes filinq's published document contract, resolved the way ADR-075 Decision 2 prescribes: never a container lookup of filinq internals, never a loopback HTTP call to filinq routes, never a guessed endpoint. `isAvailable` is true only when that contract resolves; "filinq is installed" is not the probe (ADR-087 Decision 5 makes the same point for office suites). When it is false, `POST /api/views/{viewId}/document` answers 503 with a message, and nothing is written.
+
+The contract does not exist at the shas read (proposal, Risks). The gateway is written against the contract's declared operations, render-template-with-data (ADR-075 Decision 1), and its unit tests run against a stub of that contract, so the stackiq half is done and tested when filinq publishes.
+
+Rejected: generating the `.docx` or `.pptx` in stackiq with a PHP office library. ADR-075 gives document generation one owner and bans a second engine in a leaf app.
+
+Rejected: a typed `IEventDispatcher` event that stackiq defines and filinq would have to listen for (the ADR-041 route the contract approvals use). The event class belongs to the app that owns the command; stackiq inventing one would be a phantom contract that nothing dispatches to.
+
+### D4. The Export menu
+
+The view page gets an Export menu with Download SVG, Create Word document and Create PowerPoint slide. Download SVG fetches the image route. The two document actions read the initial state `view_document_export` (provided through `IInitialState`, as `amef_register` is at `lib/AppInfo/Application.php:908`); when it is false they are disabled with the text "Word and PowerPoint need the document app filinq", so the absence is visible (ADR-075 Decision 4). After a document is made, a toast names the file and offers Open in Files.
+
+## Declarative versus imperative
+
+The change adds no lifecycle, aggregation, notification, relation or widget behaviour. It is two read-only renderers and one outbound call, all imperative by nature.
+
+## Risks
+
+- **Missing contract.** Until filinq publishes its document contract, only the SVG download works. The spec keeps the document scenarios behind the gateway's availability, and the Playwright spec covers the disabled state.
+- **Large views.** A GEMMA view with a few hundred nodes makes an SVG of a few hundred kilobytes. The route streams it and sets no cache header for drawn views, which can change.
+- **Fidelity.** The SVG shows boxes, names, types and arrows, not Archi's icons. The caption says the picture is drawn by stackiq, and the ArchiMate export stays the exact exchange format.
diff --git a/openspec/changes/architecture-views-to-office-documents/proposal.md b/openspec/changes/architecture-views-to-office-documents/proposal.md
new file mode 100644
index 000000000..4dd9b6201
--- /dev/null
+++ b/openspec/changes/architecture-views-to-office-documents/proposal.md
@@ -0,0 +1,48 @@
+---
+kind: code
+depends_on:
+ - architecture-views-editor
+---
+
+# Put an architecture view into a Word or PowerPoint document
+
+## Summary
+
+An application owner who looks at a view in stackiq can download it as an SVG image, or ask for a Word document or a PowerPoint slide that holds the view with its name, description, legend and date. Stackiq draws the image. The document is made by filinq, the fleet's document app, and lands in the user's Files, where the office suite opens it. When filinq is not there, the two document actions say so and the image download still works.
+
+## Why
+
+This change builds one row of the stackiq parity matrix: `stackiq:arch-views-office`, "Put architecture views into Word or PowerPoint documents straight from the tool." It comes from the Helmond architecture repository tender, https://www.tenderned.nl/aankondigingen/overzicht/398728; the matrix note reads "Helmond REQ19 asks for architecture views embedded in office documents."
+
+No competitor rates yes. Three rate partial:
+- GEMMA Softwarecatalogus: "Download de kaart met de knop [download SVG] ... De kaart volledig schaalbaar" (https://www.softwarecatalogus.nl/Hoe%20print%20ik%20een%20kaart%3F).
+- SAP LeanIX: "Using the HTML Embed Code, you can embed and have live data from the SAP LeanIX inside a tool such as Confluence and PowerPoint" (https://help.sap.com/docs/leanix/ea/using-reports), with diagrams exported as PDF, SVG and PNG (https://help.sap.com/docs/leanix/ea/importing-and-exporting-diagrams).
+- BlueDolphin: "To use the image of a view, for example, in a document, you can download the view as a file in PNG, SVG, PDF" (https://help.bluedolphin.io/en/articles/11967514-download-a-view).
+
+The lane decided build on tender demand and a core area.
+
+## What stackiq has today
+
+- The only view exports are ArchiMate exchange files: `POST /api/archimate/export` and `GET /api/archimate/export/organization/{organizationUuid}` (`appinfo/routes.php:97-98`). No image, Word or PowerPoint output exists in `lib/` or `src/`.
+- No page draws a view today; `architecture-views-editor` adds the view page on `CnGraphCanvas`. `CnGraphCanvas` in `@conduction/nextcloud-vue` 2.57.1 has no image export, and the library has no image export dependency.
+- The stored view holds everything a picture needs: `xml.viewNodes` with `x`, `y`, `width`, `height`, `parent`, `name` and `type`, and `xml.viewRelationships` with source, target, type and bendpoints (`lib/Service/ArchiMateImportService.php:2886` to :3058 and :3364).
+- `ViewService::getView` reads one view without RBAC (`lib/Service/ViewService.php:307`, the read at :328); `architecture-views-editor` limits that path to imported views.
+- Stackiq holds no filinq integration: `grep -rn -i "docudesk\|filinq" lib src` finds only a comment in `lib/Repair/MigrateSchemaApplicationId.php:26`.
+
+## What this change builds
+
+- `lib/Service/ViewImageService.php`, which draws a view's stored geometry as a standalone SVG, and `GET /api/views/{viewId}/image.svg`, which reads the view with RBAC on.
+- `lib/Service/ViewDocumentGateway.php` and `POST /api/views/{viewId}/document`, which hand the SVG and the view's text to filinq for a Word or PowerPoint file in the user's Files.
+- An Export menu on the view page with Download SVG, Create Word document and Create PowerPoint slide, with the last two disabled and explained when filinq cannot take the request.
+
+## Out of scope
+
+- Making the Word or PowerPoint file. That is filinq's (ADR-075, ADR-087): its template rendering, its office format codec and its conversions. This change needs filinq's published document contract (ADR-075 Decision 1) and does not define it.
+- Inserting a view into a document that is already open in the office suite. ADR-087 Decision 4 allows that only as a suite-specific extra behind a probe.
+- PNG and PDF downloads. Word and PowerPoint read SVG, and filinq can convert when a template needs a bitmap.
+- Live embedding that updates when the view changes, as LeanIX offers.
+
+## Risks
+
+- filinq's document contract does not exist yet at the shas read: ADR-075 is Proposed, OpenRegister 4fee776 has no capability registry (`grep -rn "pdf-export" openregister-ro/lib` finds nothing), and `@conduction/nextcloud-vue` 2.57.1 has no `CnIntegrationGate`. The SVG download ships on its own; the two document actions stay disabled with a notice until the contract lands. This is the sibling half the change assumes.
+- filinq's documented backends are Mpdf and PhpWord (ADR-075 Context). A PowerPoint file needs a presentation writer or a conversion through `IConversionManager` (ADR-087 Decision 1), which filinq has to confirm.
diff --git a/openspec/changes/architecture-views-to-office-documents/specs/architecture-view-office-export/spec.md b/openspec/changes/architecture-views-to-office-documents/specs/architecture-view-office-export/spec.md
new file mode 100644
index 000000000..fdec9be8b
--- /dev/null
+++ b/openspec/changes/architecture-views-to-office-documents/specs/architecture-view-office-export/spec.md
@@ -0,0 +1,77 @@
+# architecture-view-office-export specification
+
+**Status**: proposed
+**Scope**: stackiq
+**OpenSpec changes**:
+- architecture-views-to-office-documents
+
+## Purpose
+
+An application owner takes an architecture view out of stackiq into a document: as an SVG image they can place anywhere, or as a Word document or PowerPoint slide made for them. Stackiq draws the image from the stored view. The document is made by filinq, the fleet's document app (app id docudesk), through its published contract (ADR-075, ADR-087); stackiq never generates office files itself.
+
+## ADDED Requirements
+
+### Requirement: REQ-AVO-001 Stackiq SHALL draw a view as a standalone SVG from its stored geometry
+
+`GET /api/views/{viewId}/image.svg` SHALL return an SVG image of the view: every node at its stored position and size with its name and ArchiMate type, children inside their parents, every connection along its bendpoints with the arrowhead of its relation type, and a caption with the view name and date. It SHALL read the view with OpenRegister RBAC and multitenancy on and SHALL answer 404 for a view the caller may not read. Every text taken from the view SHALL be escaped, and the SVG SHALL contain no script, no external reference and no `foreignObject`.
+
+#### Scenario: An application owner downloads a view as SVG
+@e2e tests/e2e/workflows/architecture-view-export.spec.ts
+
+- **GIVEN** the seeded drawn view Zaakgericht werken, huidige situatie
+- **WHEN** an application owner opens it and chooses Export, then Download SVG
+- **THEN** the browser SHALL receive an SVG file named after the view
+- **AND** the file SHALL hold the text Zaaksysteem, Documentbeheer and Zaakregistratie
+
+#### Scenario: A view name cannot inject markup
+@e2e exclude A rendering rule; tests/Unit/Service/ViewImageServiceTest.php renders a view named with a script tag and asserts the output escapes it and contains no script, external href or foreignObject.
+
+- **GIVEN** a drawn view whose name holds `