Skip to main content
Version: Latest

9. First-Login Onboarding

This chapter summarizes what was verified for this task. For full details on every onboarding endpoint, the recommendation engine, the settings-patch schema, and the internal apply bridge, see Business Onboarding & Smart Configuration — particularly Chapter 5 — User Journey, which this signup flow feeds directly into. If POST apply returns a 501 "bridge is not configured" response, that is expected/documented behavior, not a bug — see Chapter 21 — Onboarding Apply Bridge: Local Setup & Live Verification for exactly how to configure and verify it, and a troubleshooting quick-reference. If the recommendation's WarehouseId/CashAccountId/SalesInvoiceTemplateId warnings persist even with the bridge configured, see Tenant Operational Defaults — a separate phase that provisions the missing default records and wires their Ids directly, since the bridge's own patch engine never sets a Guid property regardless of bridge configuration.

9.1 Endpoints (all under api/v1/onboarding, all require an authenticated tenant JWT)

EndpointMethodPermissionPurpose
statusGETTenantPermissions.Onboarding.ViewReturns { isRequired, status, currentStep, canSkip }
survey?lang=arGETTenantPermissions.Onboarding.ViewReturns the active survey's steps/questions/options
answersPOSTTenantPermissions.Onboarding.AnswerSaves a flat Dictionary<string, object> of answers (merged into the session, not replaced)
recommendationPOSTTenantPermissions.Onboarding.AnswerGenerates a settings-patch preview from saved answers
applyPOSTTenantPermissions.Onboarding.ApplyWrites the generated patch to the tenant's real AppSettings
skipPOSTTenantPermissions.Onboarding.SkipBypasses onboarding entirely

9.2 Verified live in this task, for the new dev tenant registered per this guide

  1. GET status immediately after first login → isRequired: true, status: "NotStarted".
  2. GET survey?lang=ar → returned the current survey's full step/question tree (activity type, POS usage, payment methods, inventory/VAT/cost-center questions, etc. — see the survey reference chapter for the authoritative list).
  3. POST answers with a Retail Store scenario (POS enabled, cash+card payments, VAT enabled, prices include VAT, simple cost centers) → 200, session ID returned.
  4. POST recommendation200, confidence 95, profile RetailStore — a full settingsPatch covering CashierAppsSettings, ProductSettings, DiscountSettings, TaxSettings, LoyaltySettings, CostCenterSettings, FinancialSettings, NotificationSettings, plus warnings (no default warehouse/cash account/invoice template exist yet — expected, since the Starter Kit has not been applied — see Chapter 11) and nextActions.
  5. POST apply with { "sessionId": "...", "acceptAll": true }first attempt returned 501 ("the onboarding apply bridge is not configured on this host") because the dev process was started with the bridge disabled by default (OnboardingApplyBridgeSettings.Enabled = false, matching the production-safe default). After restarting the local process with the bridge enabled and a matching dev-only internal API key on both sides (OnboardingApplyBridgeSettings__InternalApiKey / InternalServiceAuthSettings__OnboardingApplyApiKey), the same call returned 200 — "Onboarding settings applied."
  6. GET status again → isRequired: false, status: "Applied", appliedProfileCode: "RetailStore", completedOn/appliedOn timestamps populated.

9.3 acceptAll is mandatory in the current phase

POST apply requires "acceptAll": true in the body — omitting it (or sending only sessionId) returns a clear failure message ("AcceptAll must be true in Phase 1."), not a crash. Partial/override application is reserved for a future phase (overrides is accepted but ignored today).

9.4 Dashboard access readiness

After step 6 above, every condition needed for normal dashboard access was satisfied for this tenant: authenticated login succeeds, the tenant is active and verified, onboarding status is Applied with isRequired: false, and no blocking first-login step remains. Onboarding never gates login itself — it is a first-run wizard the client shows based on status.isRequired, not a server-side login block.