17. Known Limitations
17.1 No partial/override apply
apply requires acceptAll: true; the overrides field exists in the request contract but is accepted and
ignored, not processed. An admin cannot currently accept most of a recommendation while rejecting or editing
individual values before applying — it's all-or-nothing.
17.2 Recommendation regeneration overwrites history
Calling POST recommendation again — even after a session is already Applied — regenerates and overwrites
RecommendedProfileCode/GeneratedSettingsPatchJson/etc. on the same session row. There is no history of
multiple recommendations generated over time, only the most recent one.
17.3 Registration/verification flow is now exercised for real; OTP/notification delivery is not
Earlier phases of this feature's testing used a tenant seeded directly into the database rather than a real
Register → Verify → Login flow. The New Subscriber E2E run (docs/testing/ NEW_SUBSCRIBER_E2E_TEST_REPORT.md, Shumoul.BackEnd/Shumoul repo) has since exercised the real
POST api/Tenant/Registration/Register and tenant-verification endpoints end-to-end, confirming the exact
transition from "tenant just registered" through "tenant verified/activated" to "first login shows
onboarding" against the real registration pipeline — not simulated.
What remains genuinely non-functional: no real email/SMS/WhatsApp provider call succeeds or was relied upon in that test run. Registration/verification used to fail outright (500 errors, transaction rollback) whenever a notification-dispatch handler threw, because those handlers ran before the transaction committed — this was fixed by wrapping the dispatch calls in try/catch so a failed notification is logged and swallowed instead of blocking tenant creation (see the E2E report's Bug #1/#2). The underlying delivery mechanism itself (actually sending the OTP email/SMS/WhatsApp message) is still not implemented in this environment — registration and verification succeed despite delivery failing, not because delivery works.
17.4 Platform-admin permissions are deny-by-default only for a standalone host
OnboardingCurrentUserPermissionsService is a narrow, claims-based ICurrentUserPermissionsService that
only knows how to evaluate Permissions.Onboarding.*; every other permission it sees is denied. This is
no longer the whole story when the package is consumed by Shumoul.Api (the normal deployment): a fix
registers it with services.TryAddScoped<ICurrentUserPermissionsService, OnboardingCurrentUserPermissionsService>()
instead of AddScoped, so when Shumoul.Api's own AddIdentity() has already registered the real,
DB-backed CurrentUserPermissionsService (which queries ApplicationDbContext's Roles/RoleClaims) before
AddMultiTenancy() runs, that real implementation wins and correctly evaluates every
TenancyPermissions/TenantPermissions check — SubscriptionPlans, Tenants, Currencies,
SharedDbConnectionStrings, PaymentMethods, etc. — against the actual database, not a stub.
The deny-by-default OnboardingCurrentUserPermissionsService stub only takes effect as a genuine fallback:
a standalone host (e.g. Shumoul.Framework.MultiTenancy.Host) that never calls AddIdentity() itself has no
other registration to compete with, so it still gets this narrow, Onboarding-only, safe-by-default
implementation. In that configuration, every non-Onboarding permission is still denied to everyone, exactly
as this section previously described — that part of the analysis remains correct for a standalone host, just
not for the Shumoul.Api-hosted configuration this platform actually runs.
17.5 Only the Admin role name is real today
The tenant-admin detection accepts Owner, TenantOwner, Admin, TenantAdmin, Administrator, and
SuperAdmin role-claim values, but only Admin is ever actually assigned by the current tenant-provisioning
seeder. The others are forward-compatible placeholders, not currently reachable through any real flow.
17.6 Cross-tenant safety proof is partly source-level
The deepest cross-tenant guard (OnboardingService's session.TenantId != CurrentTenantId check) has been
verified by direct source review and by live tests where an earlier gate (tenant subscription status)
intercepted the cross-tenant attempt first. A live test that reaches that exact code path — two real,
fully-provisioned tenants, one admin token from each — has not been executed, since only one dev tenant
fixture existed at the time of testing.
17.7 Some TaxController/TaxGroupController actions remain anonymous by design
A handful of read-only dropdown/lookup actions in those two controllers (unrelated to onboarding) are intentionally left public — see Chapter 15 — because they carry no permission attribute of their own and appear to serve pre-registration lookup use cases. This wasn't re-examined as part of this feature's own scope beyond documenting the decision.
17.8 No Angular implementation yet
This entire feature is backend-complete and documented, but the Angular client does not yet exist. See Chapter 13 for the integration guide and a ready-to-use prompt to start that work.
17.9 Settings-engine gaps carried from Phase 8
See Chapter 20, §20.8 — Known Remaining Gaps / Not Blockers
for the AppSettingService per-property round-trip performance note, the still-unwired
SalesInvoiceTemplateSettings/PrinterSettings groups, and the pre-existing SetLoyaltyAsync parameter-type
bug found while adding Phase 8's three new groups. None of these block first-login onboarding.
17.10 Dev/staging subscription data drift — see the remediation tool
A dev/staging tenant's TenantSubscription can point at a SubscriptionPlanPackage row that has since
been removed or reorganized, which blocks meaningful entitlement testing for that tenant. A root-admin-only
Preview/Apply tool now exists to diagnose and safely repair this — see
Subscription Packages & Entitlements, Chapter 16.
It is disabled (Apply) by default in every environment and never guesses a target package.
17.11 AppSettings caching is now tenant-isolated
Every AppSettings cache key used by onboarding's settings-patch apply (GetAppSetting<T>/SetAppSetting<T>
via IAppSettingService) now embeds the resolved tenant identity — see
Subscription Packages & Entitlements, Chapter 17.
Previously, two tenants served by the same host process (isolated-DB or shared-DB) could read or invalidate
each other's cached settings; InternalOnboardingSettingsPatchService.ApplyGroupAsync<T>'s
GetAppSetting<T>(refreshCache: true) call is now also actually honored (it was previously silently
ignored).
