Skip to main content
Version: Latest

Business Activities

Phase 4 (2026-07-15). Saas.BusinessActivities is the stable master-data key that every starter template family in this guide (accounting, inventory account category, cost center, product catalog) scopes itself by. Purely additive — zero tenant-side effects, no migration on any tenant database.

Purpose

Before this phase, "what type of business is this tenant" only existed as the onboarding survey's activityType answer value (a free-form string inside OptionsJson). That's fine for driving the survey UI, but starter templates need a real, FK-able, queryable table to key off — not a JSON blob. BusinessActivity.Code is designed to be exactly the same value space as the onboarding activityType answer options, so the two concepts stay in lockstep without onboarding's own API contract changing at all.

BusinessActivity is master data, not an entitlement. No entitlement service references it; a tenant's set of allowed features/settings groups is governed entirely by subscription feature entitlements, completely independent of which BusinessActivity the tenant picked.

Current codes

Exactly 5 exist, seeded and active:

RestaurantCafe
Supermarket
RetailStore
Services
WholesaleDistribution

(A sixth, "Manufacturing," appears only in old illustrative planning notes — it was never actually seeded and is not a real code.)

Schema

Saas.BusinessActivities:

ColumnTypeNotes
IdGuid PK
Codenvarchar(128), uniqueStable identity — must exactly match an onboarding activityType answer-option value. Never display text.
Namenvarchar(256), nullableArabic display name
FNamenvarchar(256), nullableEnglish display name
Descriptionnvarchar(1000), nullableArabic
FDescriptionnvarchar(1000), nullableEnglish
IsActive, DisplayOrdervia BaseEntity

Indexes: unique IX_BusinessActivities_Code, plus IsActive/DisplayOrder.

Deliberately no soft deleteBusinessActivity has no ISoftDelete, matching the precedent set by OnboardingProfile/SubscriptionFeature/SubscriptionFeatureSettingsGroup. Deletion (rare, admin CRUD only) is a hard RemoveAsync.

Naming convention correction

BusinessActivity originally shipped with NameAr/NameEn/DescriptionAr/DescriptionEn columns. A dedicated cleanup phase (SCHEMA_CONVENTION_CLEANUP, 2026-07-16, migration 20260716195141_Update_SaasTemplates_AlignNameFNameConvention) renamed these — and the equivalent columns on AccountingChartTemplate/AccountingChartTemplateAccount — to the platform-wide Name (Arabic) / FName (English) / Description (Arabic) / FDescription (English) convention. Every table introduced in this initiative after that cleanup (InventoryAccountCategoryTemplate, CostCenterTemplate, ProductCatalogTemplate and children) already used Name/FName from inception — the cleanup was a one-time correction of the two earliest tables, not a recurring pattern.

Platform-wide rule going forward: do not use NameAr/NameEn/DescriptionAr/DescriptionEn/ NotesAr/NotesEn in any new database table without explicit approval.

The migration was a pure RenameColumn operation (20 calls, no data movement, no dropped indexes) — but its own history is a documented cautionary tale: dotnet ef migrations add's auto-scaffolded rename-pairing heuristic got the pairing backwards for 2 of the 3 renamed tables (it would have silently swapped every row's Arabic/English text). This was caught by independent review before ever applying to any database, and the migration was hand-corrected. Lesson carried forward: never trust dotnet ef migrations add's auto-generated rename pairing when 2+ properties change on the same entity at once — always hand-verify each RenameColumn pair.

The Excel/JSON import parsers for AccountingChartTemplate (not a table, a wire/DTO shape) kept the old NameAr/NameEn field names as accepted legacy aliases — official Name/FName always wins if both are supplied; a legacy-only input is folded into the official field automatically.

API

BusinessActivitiesController, route api/Saas/BusinessActivities:

EndpointVerbPermission
GetGETPermissions.BusinessActivities.ViewAll
GetActiveGET[AllowAnonymous] — the one public endpoint, needed so the onboarding survey UI (unauthenticated, pre-tenant-login) can list activities
GetDetails/{id}GET.View
GetByCode/{code}GET.View
CreatePOST.Create
Update/{id}PUT.Edit
Delete/{id}DELETE.Delete
Active/{id}POST.Activate
Inactive/{id}POST.Deactivate

Seed behavior

Insert-missing, fill-blank-only, matched by Code alone. An admin-edited, non-blank Name/FName/ Description/FDescription is never overwritten on reseed; IsActive/DisplayOrder are only set on first insert.

Where BusinessActivity is used downstream

Every one of these template families carries a required BusinessActivityId FK and enforces "at most one active default template per BusinessActivity" via a unique filtered index:

The Tenant Starter Kit resolves one BusinessActivity per orchestration call and uses it to pick every family's default template unless an explicit template Id is supplied.