Skip to content

feat(config): store ExApp config & preferences in the server's app/user config#889

Open
oleksandr-nc wants to merge 2 commits into
mainfrom
feat/migrate-exapp-config-to-server-tables
Open

feat(config): store ExApp config & preferences in the server's app/user config#889
oleksandr-nc wants to merge 2 commits into
mainfrom
feat/migrate-exapp-config-to-server-tables

Conversation

@oleksandr-nc
Copy link
Copy Markdown
Contributor

@oleksandr-nc oleksandr-nc commented May 29, 2026

Moves ExApp config and per-user preferences from AppAPI's custom appconfig_ex / preferences_ex tables to the server's IAppConfig (oc_appconfig) and IUserConfig (oc_preferences). The server gained typed/lazy/sensitive value support in NC 29 and 32, and AppAPI now targets 35, so the custom tables are no longer needed.

The OCS endpoints used by ExApps are unchanged, so nc_py_api and existing ExApps keep working as-is. One migration backfills existing rows into the server tables (decrypting and re-encrypting sensitive values through the server); a second drops the old tables once the backfill reports no failures.

@oleksandr-nc oleksandr-nc requested a review from kyteinsky as a code owner May 29, 2026 13:37
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR completes the migration of AppAPI's configuration and preference storage from custom appconfig_ex/preferences_ex tables with Entity-based mappers to Nextcloud's standard IAppConfig and IUserConfig interfaces. Changes include refactoring ExAppConfig and ExAppPreference into plain typed DTOs, rewriting services to use server-backed config with transparent encryption and lazy writes, adding backfill and gated-drop migrations, updating controller messages and route comments, and adding integration tests for lazy/eager cache and sensitive-flag behaviors.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: moving ExApp config and preferences storage from custom tables to the server's built-in config storage interfaces.
Description check ✅ Passed The description is directly related to the changeset, explaining the rationale (server now has typed/lazy/sensitive support), the migration strategy, and backward compatibility with ExApps.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1a16ec45-d77e-4401-bbc7-f43eef67dab4

📥 Commits

Reviewing files that changed from the base of the PR and between 8f011da and b11d908.

📒 Files selected for processing (16)
  • appinfo/info.xml
  • appinfo/routes.php
  • lib/Controller/AppConfigController.php
  • lib/Controller/PreferencesController.php
  • lib/Db/ExAppConfig.php
  • lib/Db/ExAppConfigMapper.php
  • lib/Db/ExAppPreference.php
  • lib/Db/ExAppPreferenceMapper.php
  • lib/Migration/Version035000Date20260529120000.php
  • lib/Migration/Version035000Date20260529130000.php
  • lib/Service/ExAppConfigService.php
  • lib/Service/ExAppPreferenceService.php
  • tests/php/Controller/AppConfigControllerTest.php
  • tests/php/Controller/PreferencesControllerTest.php
  • tests/php/Migration/Version034000Date20260428144801Test.php
  • tests/php/Service/StorageLazyLoadingTest.php
💤 Files with no reviewable changes (3)
  • lib/Db/ExAppConfigMapper.php
  • lib/Db/ExAppPreferenceMapper.php
  • tests/php/Migration/Version034000Date20260428144801Test.php

Comment thread tests/php/Service/StorageLazyLoadingTest.php
…g/IUserConfig storage

Signed-off-by: Oleksander Piskun <oleksandr2088@icloud.com>
@oleksandr-nc oleksandr-nc force-pushed the feat/migrate-exapp-config-to-server-tables branch from b11d908 to 3067622 Compare May 29, 2026 14:06
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/php/Service/StorageLazyLoadingTest.php (1)

94-105: ⚡ Quick win

Add cold-cache lazy-read coverage for preferences too.

The config side has parity tests for “not in eager cache”, “readable after lazy load”, and “sensitive round-trip from cold cache”, but the preference side currently only asserts isLazy() plus eager external visibility. That leaves the rewritten IUserConfig lazy-read path largely untested, so a regression there would still pass this suite. Please add at least one cold-cache lazy preference read and one sensitive lazy preference round-trip test here.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7170d5be-bfd1-411d-8229-7bd84f508687

📥 Commits

Reviewing files that changed from the base of the PR and between b11d908 and 3067622.

📒 Files selected for processing (16)
  • appinfo/info.xml
  • appinfo/routes.php
  • lib/Controller/AppConfigController.php
  • lib/Controller/PreferencesController.php
  • lib/Db/ExAppConfig.php
  • lib/Db/ExAppConfigMapper.php
  • lib/Db/ExAppPreference.php
  • lib/Db/ExAppPreferenceMapper.php
  • lib/Migration/Version035000Date20260529120000.php
  • lib/Migration/Version035000Date20260529130000.php
  • lib/Service/ExAppConfigService.php
  • lib/Service/ExAppPreferenceService.php
  • tests/php/Controller/AppConfigControllerTest.php
  • tests/php/Controller/PreferencesControllerTest.php
  • tests/php/Migration/Version034000Date20260428144801Test.php
  • tests/php/Service/StorageLazyLoadingTest.php
💤 Files with no reviewable changes (3)
  • tests/php/Migration/Version034000Date20260428144801Test.php
  • lib/Db/ExAppConfigMapper.php
  • lib/Db/ExAppPreferenceMapper.php
✅ Files skipped from review due to trivial changes (2)
  • appinfo/info.xml
  • appinfo/routes.php
🚧 Files skipped from review as they are similar to previous changes (6)
  • lib/Controller/PreferencesController.php
  • lib/Controller/AppConfigController.php
  • lib/Db/ExAppPreference.php
  • lib/Service/ExAppPreferenceService.php
  • lib/Service/ExAppConfigService.php
  • lib/Db/ExAppConfig.php

Comment thread lib/Migration/Version035000Date20260529120000.php Outdated
Comment thread lib/Migration/Version035000Date20260529130000.php
…on gate flag once no legacy table remains

Signed-off-by: Oleksander Piskun <oleksandr2088@icloud.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/Migration/Version035000Date20260529120000.php (1)

121-159: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Bound IUserConfig per-user cache growth during preferences backfill to prevent occ upgrade OOM
migratePreferences() now writes via IUserConfig::setValueString(... lazy: true, ...) while IUserConfig maintains an internal in-memory per-user cache for the lifetime of the PHP process/command; with large backfills this can accumulate cache entries for every touched user (no automatic size/LRU eviction is provided), reintroducing the OOM risk even though legacy reads are batched. Using the provided invalidation hook IUserConfig::clearCache(string $userId, bool $reload=false): void after each batch bounds memory.

🔧 Proposed fix
 		$lastId = 0;
 		while (($rows = $this->fetchBatch('preferences_ex', ['userid', 'appid', 'configkey', 'configvalue', 'sensitive'], $lastId)) !== []) {
+			$touchedUsers = [];
 			foreach ($rows as $row) {
 				$lastId = (int)$row['id'];
 				$userId = (string)$row['userid'];
+				$touchedUsers[$userId] = true;
 				$appId = (string)$row['appid'];
 				$configKey = (string)$row['configkey'];
 				$sensitive = (int)($row['sensitive'] ?? 0) === 1;
@@
 				} catch (Throwable $e) {
 					$output->warning(sprintf('Preferences migration: failed to migrate user %s app %s key %s (row id=%d): %s — skipping', $userId, $appId, $configKey, $lastId, $e->getMessage()));
 					$failed++;
 				}
 			}
+			// Drop per-user caches so the backfill cannot OOM on instances with many users.
+			foreach (array_keys($touchedUsers) as $uid) {
+				$this->userConfig->clearCache($uid, false);
+			}
 		}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 169ffa10-7007-4619-9088-17f02605bffd

📥 Commits

Reviewing files that changed from the base of the PR and between 3067622 and 74d7ad2.

📒 Files selected for processing (2)
  • lib/Migration/Version035000Date20260529120000.php
  • lib/Migration/Version035000Date20260529130000.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/Migration/Version035000Date20260529130000.php

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant