Signup Customization

Intelligence Engine for self-service signup — configurable onboarding questions with branching logic, option-level visibility conditions, and declarative recommendation rules that map user answers to the right edition.

The Signup Customization system is SCRIPE's Intelligence Engine for the self-service signup flow. Platform administrators define a question tree, each answer option carries a signal weight, and declarative RecommendationRules map answer patterns to specific editions — automatically guiding users to the plan best suited to their needs.

What Is the Intelligence Engine?

The Intelligence Engine is the recommendation system behind SCRIPE's self-service signup. Instead of presenting a static pricing table, users answer a short onboarding questionnaire. The engine matches their answers against RecommendationRules and presents a personalized edition recommendation with a localized reason. Administrators configure questions, options, and rules without code changes.

Signup Flow Overview

The full signup flow from category selection through recommendation.

User starts signup
Category Selection (EditionCategory)
Global Onboarding Questions (Key, QuestionType)
Category-scoped Questions (EditionCategoryId)
Answers stored as SignupSessionAnswer
RecommendationEngine evaluates RecommendationRules
Recommended Edition displayed with reason text
User proceeds to billing / free signup

OnboardingQuestion Entity

Each OnboardingQuestion represents a single step in the onboarding flow. Questions can be global (shown to all users) or scoped to an EditionCategory. Question-level branching is supported via DependsOnQuestionKey + DependsOnAnswerValue.

FieldTypeDescription
Keystring (max 100)Stable slug used in code and seeding, e.g. "team_size", "erp_priorities". Must be unique.
EditionCategoryIdGuid?Optional FK to EditionCategory. Null = global (shown to all users). Non-null = only shown for that category.
QuestionTypeQuestionType enumSingleSelect (0) or MultiSelect (1).
MinSelectionsintMinimum number of options the user must select. Default 1.
MaxSelectionsintMaximum number of options the user may select. Default 1 (typically 1 for SingleSelect).
IsRequiredboolWhether the question must be answered before proceeding. Default true.
SortOrderintDisplay order within the flow. Lower values appear first.
DependsOnQuestionKeystring? (max 100)Key of a preceding question this question depends on for conditional branching. Null = always shown.
DependsOnAnswerValuestring? (max 200)The answer value from the preceding question that must be selected for this question to appear.
LabelEnstring (max 500)Question text displayed to the user in English.
LabelArstring (max 500)Question text displayed to the user in Arabic.
HintEnstring? (max 1000)Optional helper/hint text shown beneath the question in English.
HintArstring? (max 1000)Optional helper/hint text shown beneath the question in Arabic.
IconKeystring? (max 100)Lucide icon name displayed alongside the question (e.g. "users", "target"). See lucide.dev/icons.
IsSystemboolIf true, this question is system-seeded and cannot be deleted by users.

OnboardingAnswerOption Entity

Each OnboardingAnswerOption is a selectable answer choice for a question. Options carry scoring signals (SignalWeight) for the recommendation engine and optional visibility relevance boosts (RelevanceBoost) that re-rank options based on earlier answers.

FieldTypeDescription
OnboardingQuestionIdGuidFK to the parent OnboardingQuestion.
Valuestring (max 200)Stable slug used in scoring and branching logic, e.g. "solo", "2-10", "compliance". Unique within the same question.
LabelEnstring (max 500)Primary display label in English (e.g. "Just me", "2–10 people").
LabelArstring (max 500)Primary display label in Arabic.
SublabelEnstring? (max 500)Optional secondary/descriptive label in English shown beneath the main label.
SublabelArstring? (max 500)Optional secondary/descriptive label in Arabic.
IconKeystring? (max 100)Lucide icon name displayed alongside the option (e.g. "user", "users", "building-2").
SortOrderintDisplay order within the option list. Lower values appear first.
SignalWeightintInteger weight contributed to the edition recommendation score when selected. Default 0 (neutral). Positive = push toward edition; negative = de-prioritize.
RelevanceBoostintInteger boost applied to this option's ranking when its visibility conditions are satisfied. Default 0.

Option-Level Visibility Conditions

OnboardingAnswerOptionCondition enables fine-grained client-side visibility control at the individual option level. Unlike question-level branching (which shows/hides entire questions), option conditions show/hide specific answer choices based on earlier answers.

FieldTypeDescription
AnswerOptionIdGuidFK to the owning OnboardingAnswerOption.
DependsOnQuestionKeystring (max 100)Stable Key of the preceding question whose answer this condition reacts to, e.g. "scale_healthcare".
MatchValuesRawstring (max 1000)Backing storage: comma-delimited answer values that satisfy this condition. Accessed via MatchValues computed property.
MatchValuesIReadOnlyList<string> (computed)The set of answer values that trigger visibility. Condition is satisfied if the user's selected values intersect this set (AnyOf / OR semantics).
MatchModeConditionMatchMode enumCurrently only AnyOf (0) — option visible if user's selection intersects MatchValues.

SignupSessionAnswer Entity

SignupSessionAnswer persists each user's answer during an in-progress signup. It deliberately uses SignupSessionRef (a plain string) instead of a FK to the SignupSession entity to avoid cross-module coupling — the Entitlements module never imports Identity session types.

FieldTypeDescription
SignupSessionRefstring (max 256)Ties the answer to the in-flight SignupSession by its stable Ref string. Avoids a cross-module FK while allowing grouping and resume queries.
QuestionKeystring (max 100)The question this answer belongs to. Matches OnboardingQuestion.Key.
ValueJsonstring (max 4000)The submitted answer serialized as JSON. Single-select: "\"solo\"". Multi-select: "[\"compliance\",\"scale\"]".
AnsweredAtDateTimeUTC timestamp of when the user submitted this answer.

RecommendationRule Entity

RecommendationRules are the declarative matching engine. Each rule defines a ConditionJson predicate, a target edition (by tier level or specific ID), and a ScoreBonus. Rules evaluated in Priority order accumulate scores per candidate edition — the highest-scoring edition wins.

FieldTypeDescription
Namestring (max 200)Stable slug used for seeding and upsert operations, e.g. "base-solo-free", "team-compliance-ultra".
EditionCategoryIdGuid?Optional scope to a specific edition category. Null = rule applies across all categories.
ConditionJsonstring (max 4000)JSON predicate bag matched against signup answers. Single value: {"team_size":"solo"}. Multi-value (any match): {"priorities":["compliance","security"]}.
RecommendedTierLevelint?Target tier when no specific edition is pinned. 0 = Free, 1 = Pro, 2 = Ultra, 3 = Enterprise. Null = use RecommendedEditionId instead.
RecommendedEditionIdGuid?Pin recommendation to a specific edition. Takes precedence over RecommendedTierLevel when both are set.
ScoreBonusintScore added when this rule matches. Higher totals surface the edition higher in the recommendation list.
ReasonEnstring (max 1000)English explanation shown to the user explaining why this edition was recommended.
ReasonArstring (max 1000)Arabic explanation shown to the user.
PriorityintTie-break evaluation order. Lower values are evaluated first.
IsSystemboolIf true, this rule is system-seeded and protected from deletion in the admin UI.

Scoring Algorithm

The recommendation engine evaluates all active rules, accumulates scores, and returns the top-scoring edition with the reason from the highest-priority matching rule.

RecommendationEngine (conceptual)C#
// 1. Load all active RecommendationRules ordered by Priority ASC
// 2. For each rule, parse ConditionJson and match against SignupSessionAnswers
// 3. Matched rules add ScoreBonus to the candidate edition's total score
// 4. Sort editions by total score DESC
// 5. Return top edition with the highest-priority matching rule's ReasonEn/ReasonAr

API Endpoints

Admin endpoints for question/rule management require entitlements.manage permission. Flow and answer endpoints are public — no authentication required during signup.

MethodEndpointDescriptionAuth
GET/api/v1/onboarding/questionsList all onboarding questions with their options and conditions🔒 Required
POST/api/v1/onboarding/questionsCreate a new onboarding question with answer options🔒 Required
PUT/api/v1/onboarding/questions/{id}Update an existing question (label, hint, sort order, branching)🔒 Required
DELETE/api/v1/onboarding/questions/{id}Delete a non-system onboarding question🔒 Required
GET/api/v1/onboarding/flowGet the full onboarding flow for a given category (public - used during signup)🔒 Required
POST/api/v1/onboarding/answersSubmit answers for a signup session step (public)🔒 Required
GET/api/v1/onboarding/recommendGet edition recommendation based on submitted answers (public)🔒 Required
GET/api/v1/onboarding/rulesList all recommendation rules🔒 Required
POST/api/v1/onboarding/rulesCreate or upsert a recommendation rule by stable Name slug🔒 Required