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)
| Endpoint | Method | Permission | Purpose |
|---|---|---|---|
status | GET | TenantPermissions.Onboarding.View | Returns { isRequired, status, currentStep, canSkip } |
survey?lang=ar | GET | TenantPermissions.Onboarding.View | Returns the active survey's steps/questions/options |
answers | POST | TenantPermissions.Onboarding.Answer | Saves a flat Dictionary<string, object> of answers (merged into the session, not replaced) |
recommendation | POST | TenantPermissions.Onboarding.Answer | Generates a settings-patch preview from saved answers |
apply | POST | TenantPermissions.Onboarding.Apply | Writes the generated patch to the tenant's real AppSettings |
skip | POST | TenantPermissions.Onboarding.Skip | Bypasses onboarding entirely |
9.2 Verified live in this task, for the new dev tenant registered per this guide
GET statusimmediately after first login →isRequired: true,status: "NotStarted".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).POST answerswith a Retail Store scenario (POS enabled, cash+card payments, VAT enabled, prices include VAT, simple cost centers) →200, session ID returned.POST recommendation→200, confidence95, profileRetailStore— a fullsettingsPatchcoveringCashierAppsSettings,ProductSettings,DiscountSettings,TaxSettings,LoyaltySettings,CostCenterSettings,FinancialSettings,NotificationSettings, pluswarnings(no default warehouse/cash account/invoice template exist yet — expected, since the Starter Kit has not been applied — see Chapter 11) andnextActions.POST applywith{ "sessionId": "...", "acceptAll": true }→ first attempt returned501("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 returned200— "Onboarding settings applied."GET statusagain →isRequired: false,status: "Applied",appliedProfileCode: "RetailStore",completedOn/appliedOntimestamps 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.
