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>
This commit is contained in:
2026-02-28 23:39:42 +01:00
parent f8a2394da5
commit ef9ea29643
26 changed files with 2055 additions and 699 deletions

View File

@@ -49,6 +49,7 @@ if TYPE_CHECKING:
from app.modules.contracts.cms import MediaUsageProviderProtocol
from app.modules.contracts.features import FeatureProviderProtocol
from app.modules.contracts.metrics import MetricsProviderProtocol
from app.modules.contracts.onboarding import OnboardingProviderProtocol
from app.modules.contracts.widgets import DashboardWidgetProviderProtocol
from app.modules.enums import FrontendType
@@ -486,6 +487,29 @@ class ModuleDefinition:
# to report where media is being used.
media_usage_provider: "Callable[[], MediaUsageProviderProtocol] | None" = None
# =========================================================================
# Onboarding Provider (Module-Driven Post-Signup Onboarding)
# =========================================================================
# Callable that returns an OnboardingProviderProtocol implementation.
# Modules declare onboarding steps (what needs to be configured after signup)
# and provide completion checks. The core module's OnboardingAggregator
# discovers and aggregates all providers into a dashboard checklist banner.
#
# Example:
# 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,
# )
#
# The provider will be discovered by core's OnboardingAggregator service.
onboarding_provider: "Callable[[], OnboardingProviderProtocol] | None" = None
# =========================================================================
# Menu Item Methods (Legacy - uses menu_items dict of IDs)
# =========================================================================
@@ -955,6 +979,24 @@ class ModuleDefinition:
return None
return self.media_usage_provider()
# =========================================================================
# Onboarding Provider Methods
# =========================================================================
def has_onboarding_provider(self) -> bool:
"""Check if this module has an onboarding provider."""
return self.onboarding_provider is not None
def get_onboarding_provider_instance(self) -> "OnboardingProviderProtocol | None":
"""Get the onboarding provider instance for this module.
Returns:
OnboardingProviderProtocol instance, or None
"""
if self.onboarding_provider is None:
return None
return self.onboarding_provider()
# =========================================================================
# Magic Methods
# =========================================================================