Files
orion/app/modules/contracts/onboarding.py
Samir Boulahtit ef9ea29643 feat: module-driven onboarding system + simplified 3-step signup
Add OnboardingProviderProtocol so modules declare their own post-signup
onboarding steps. The core OnboardingAggregator discovers enabled
providers and exposes a dashboard API (GET /dashboard/onboarding).
A session-scoped banner on the store dashboard shows a checklist that
guides merchants through setup without blocking signup.

Signup is simplified from 4 steps to 3 (Plan → Account → Payment):
store creation is merged into account creation, store language is
captured from the user's browsing language, and platform-specific
template branching is removed.

Includes 47 unit and integration tests covering all new providers,
the aggregator, the API endpoint, and the signup service changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:39:42 +01:00

155 lines
4.6 KiB
Python

# app/modules/contracts/onboarding.py
"""
Onboarding provider protocol for module-driven post-signup onboarding.
Each module defines its own onboarding steps (what needs to be configured)
and provides completion checks. The core module's OnboardingAggregator
discovers and aggregates all providers into a dashboard checklist.
Benefits:
- Modules own their onboarding steps (billing module doesn't need to know)
- Steps appear/disappear based on which modules are enabled
- Easy to add new steps (just implement protocol in your module)
- Dashboard banner guides merchants without blocking signup
Usage:
# 1. Implement the protocol in your module
class MarketplaceOnboardingProvider:
@property
def onboarding_category(self) -> str:
return "marketplace"
def get_onboarding_steps(self) -> list[OnboardingStepDefinition]:
return [
OnboardingStepDefinition(
key="marketplace.connect_api",
title_key="onboarding.marketplace.connect_api.title",
description_key="onboarding.marketplace.connect_api.description",
icon="plug",
route_template="/store/{store_code}/letzshop",
order=200,
)
]
def is_step_completed(self, db, store_id, step_key) -> bool:
...
# 2. Register in module definition
def _get_onboarding_provider():
from app.modules.marketplace.services.marketplace_onboarding import (
marketplace_onboarding_provider,
)
return marketplace_onboarding_provider
marketplace_module = ModuleDefinition(
code="marketplace",
onboarding_provider=_get_onboarding_provider,
# ...
)
# 3. Steps appear automatically in dashboard when module is enabled
"""
from dataclasses import dataclass
from typing import TYPE_CHECKING, Protocol, runtime_checkable
if TYPE_CHECKING:
from sqlalchemy.orm import Session
@dataclass
class OnboardingStepDefinition:
"""
Definition of a single onboarding step.
Attributes:
key: Unique identifier (e.g., "marketplace.connect_api")
Format: "{module}.{step_name}" for consistency
title_key: i18n key for display title
description_key: i18n key for description text
icon: Lucide icon name for UI display (e.g., "plug", "package")
route_template: URL template with {store_code} placeholder
order: Display sort order (lower = first). Default 100.
category: Grouping category (typically matches module code)
"""
key: str
title_key: str
description_key: str
icon: str
route_template: str
order: int = 100
category: str = ""
@dataclass
class OnboardingStepStatus:
"""
An onboarding step paired with its completion status.
Attributes:
step: The step definition
completed: Whether the step has been completed
"""
step: OnboardingStepDefinition
completed: bool
@runtime_checkable
class OnboardingProviderProtocol(Protocol):
"""
Protocol for modules that provide onboarding steps.
Each module implements this to declare what setup steps are needed
after signup. The core module's OnboardingAggregator discovers and
aggregates all providers into a dashboard checklist banner.
Implementation Notes:
- Providers should be stateless (all data via db session)
- Return empty list from get_onboarding_steps() if no steps needed
- is_step_completed() should be efficient (called per step per page load)
- Use consistent key format: "{category}.{step_name}"
"""
@property
def onboarding_category(self) -> str:
"""
Category name for this provider's onboarding steps.
Should match the module code (e.g., "marketplace", "tenancy").
"""
...
def get_onboarding_steps(self) -> list[OnboardingStepDefinition]:
"""
Get onboarding step definitions provided by this module.
Returns:
List of OnboardingStepDefinition objects
"""
...
def is_step_completed(
self, db: "Session", store_id: int, step_key: str
) -> bool:
"""
Check if a specific onboarding step is completed for a store.
Args:
db: Database session for queries
store_id: ID of the store to check
step_key: The step key to check (from OnboardingStepDefinition.key)
Returns:
True if the step is completed
"""
...
__all__ = [
"OnboardingStepDefinition",
"OnboardingStepStatus",
"OnboardingProviderProtocol",
]