Skip to main content
Version: Latest

24. Starter Kit Apply E2E Verification — Package Behavior Matrix (2026-07-20)

24.1 Purpose

A verification-only pass (no code changed in either repo) confirming the Tenant Starter Kit Preview/Apply flow end-to-end against the current four Shumoul subscription packages (see Subscription Packages & Entitlements), extending Chapter 22's single-tenant live pass (which used one legacy test tenant entitled for everything, and so never exercised cross-package Blocked/Skipped differentiation).

24.2 Current flow — confirmed correct, no changes needed

TenantStarterKitService (Shumoul.Framework.MultiTenancy.Api/StarterKits/) orchestrates seven steps — AccountingChartAccounts → AccountingChartMappings → TenantOperationalDefaults → CashBankAccountingLink → InventoryAccountCategory → CostCenters (accounting chain) and ProductCatalogPrerequisites → ProductCatalogCategories → ProductCatalogItems (product chain) — by delegating to each step's own, independently-tested ITenant*ApplyService. The orchestrator itself never writes a tenant database directly.

  • Entitlement chain confirmed correct end-to-end: IsFeatureAllowedAsyncGetTenantAllowedFeatureKeysAsyncITenantFeatureService.TenantFeaturesIDsITenantSubscriptionService.GetTenantPackageId resolves via TenantSubscription.PlanPackageFK.PackageId (i.e. TenantSubscription.PackageId → SubscriptionPlanPackage.Id → SubscriptionPlanPackage.PackageId → SubscriptionPackage.Id), filtered to Status == Active — the correct chain, not the incorrect direct join a much earlier phase mistakenly used elsewhere. No fix was needed here.
  • Onboarding never auto-triggers Starter Kit: confirmed by exhaustive source search — zero references to "StarterKit" exist anywhere in Shumoul.Saas.Api's Shumoul.Infrastructure/Shumoul.Application/ Shumoul.Api projects. Onboarding's settings-patch apply and Starter Kit remain two entirely separate administrative surfaces, as required.
  • needsCostCenters is read from the tenant's latest onboarding answer via OnboardingAnswerReader, with an explicit IncludeCostCenters request value always overriding the onboarding-derived default — confirmed both by source and live call (§24.4).
  • Idempotency mechanism: every one of the seven underlying BackEnd apply services (AccountingChartTemplateAccountApplyService, AccountingChartTemplateMappingApplyService, InventoryAccountCategoryTemplateApplyService, CostCenterTemplateApplyService, ProductCatalogPrerequisiteTemplateApplyService, ProductCatalogTemplateApplyService, ProductCatalogItemTemplateApplyService) already has its own dedicated ReApplyingTheSameSnapshotIsIdempotent-style unit test, and TenantOperationalDefaultsProvisioningService has SkipExisting_AndCreateNoDuplicates_OnSecondApply — this was already thoroughly proven at the per-service level before this pass; this pass adds the missing end-to-end confirmation (§24.4).
  • Error model already correctly distinguishes Blocked (package doesn't allow it) / Skipped (excluded by request, or a dependency didn't succeed) / Failed (attempted, didn't succeed) / Applied/Succeeded/Planned (worked) — every message observed live was specific and actionable (e.g. "Tenant does not have the products feature entitlement (Features.ProductsManagement).", never a raw stack trace or generic 500).

Conclusion: no gaps requiring a code change were found. This pass is documentation + live verification only.

24.3 Package behavior matrix (live-confirmed, 2026-07-20)

PackageAccounting chain (6 steps)Product chain (3 steps)
Shumoul StarterBlocked — no Features.AccountManagementPlanned/Succeeded — has Features.ProductsManagement
Shumoul POSBlocked — no Features.AccountManagementPlanned/Succeeded — has Features.ProductsManagement
Shumoul Finance StarterPlanned/Succeeded — has Features.AccountManagementBlocked — no Features.ProductsManagement
Shumoul Finance AdvancedPlanned/Succeeded — has Features.AccountManagementBlocked — no Features.ProductsManagement

TenantOperationalDefaults is never gated by Features.AccountManagement alone (it resolves Warehouse/CashAccount/SalesInvoiceTemplate via POS-or-accounting keys internally) — confirmed Planned for all four packages live. CostCenters follows the onboarding needsCostCenters answer (or an explicit override) independently of the rest of the accounting chain's entitlement gate, but still requires Features.AccountManagement — so it is only ever reachable for the two Finance packages.

24.4 Live verification (this pass)

Dev host started clean, root-tenant admin login, real HTTP round trip through api/Saas/TenantStarterKits/{Preview,Apply} (bridges enabled locally only, same loopback pattern as Chapter 22 — never a production hostname). Tenants: the four safe dev tenants from Subscription Packages & Entitlements, Chapter 16183581 (Starter), 510611 (POS), 171994 (Finance Starter), 793084 (Finance Advanced).

Preview — confirmed to write nothing (verified via before/after DB counts) and to match §24.3 exactly for all four tenants in one pass, including the exact Blocked/Skipped/Planned status split per step.

Apply — idempotency proof, tenant 171994 (Finance Starter), CostCenters had never been applied to this tenant before this pass:

Step1st Apply2nd Apply (immediately after)
AccountingChartAccountsInserted=0, SkippedExisting=81Inserted=0, SkippedExisting=81
AccountingChartMappingsApplied=0, Skipped=6, Unsupported=6identical
TenantOperationalDefaultsCreated=0, SkippedExisting=2identical
CashBankAccountingLinkApplied=0, Skipped=2identical
InventoryAccountCategoryApplied=0, Skipped=13identical
CostCentersInserted=10, SkippedExisting=0Inserted=0, SkippedExisting=10

dbo.CostCenters for tenant 171994: 0 → 10 → 10 (confirmed via direct SQL — no duplication on the second Apply). Two new Saas.TenantStarterKitApplyLogs rows were written (one per Apply call, per the table's own "every commit call" design — never merged/deduplicated), both Status=Succeeded.

Apply — idempotency proof, tenant 183581 (Starter), product chain already applied in an earlier phase:

Step1st Apply (this pass)2nd Apply
TenantOperationalDefaultsCreated=0, SkippedExisting=3, EntitlementSkipped=1identical
ProductCatalogPrerequisitesSkippedExisting=6, 0 createdidentical
ProductCatalogCategoriesInserted=0, SkippedExisting=6identical
ProductCatalogItemsItems=0, SkippedExisting=2identical

BusinessTypes/ProductDepartments/ProductCategories/Products/Warehouses/CashAccounts row counts for tenant 183581: unchanged across both applies (1/1/6/2/1/1 before, during, and after).

Side effects: zero GeneralLedgerJournalEntries/PaymentVouchers/ReceiptVouchers/ StockItemTransactions/AccountOpeningBalances rows for either tenant across the entire pass — confirmed via direct SQL, matching Operational Boundaries.

Tenant 171994 has no onboarding answer on file for cost centers. Requesting IncludeCostCenters: true explicitly still applied the step, with an automatic warning surfaced in the response: "No onboarding answer was found for cost centers for this tenant; applying anyway based on this explicit admin request." — confirming an explicit request always wins over a missing/negative onboarding default, exactly as designed.

24.6 Cross-reference: the shared-DB caching bug is confirmed fixed here too

Subscription Packages & Entitlements, Chapters 16–17 document a shared-DB cross-tenant AppSettings cache leak that first surfaced as a false CashBankAccountingLink MissingDependency on this exact tenant pair. This pass's live Preview/Apply calls against 171994/793084 (both on the same shared physical database) showed zero MissingDependency false positives — CashBankAccountingLink correctly resolved SkippedAlreadySet for both tenants, confirming the caching fix holds for Starter Kit's own call path too.

24.7 Test suites

No source changed in either repo, so the existing baselines apply unchanged — see Chapter 22 for the last full run. This pass's live verification is a supplement to, not a replacement for, that automated baseline.

24.8 Outcome

Tenant Starter Kit Preview/Apply is confirmed working correctly, idempotent, and entitlement-safe across all four current subscription packages, with no code change required. Shumoul.Framework.MultiTenancy.Api package version is unchanged.