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

@@ -10,6 +10,47 @@ const storeDashLog = window.LogConfig.loggers.dashboard ||
storeDashLog.info('Loading...');
storeDashLog.info('[STORE DASHBOARD] data function exists?', typeof data);
/**
* Onboarding banner component.
* Fetches onboarding steps from API, supports session-scoped dismiss.
*/
function onboardingBanner() {
return {
visible: false,
steps: [],
totalSteps: 0,
completedSteps: 0,
progressPercentage: 0,
async init() {
// Check session-scoped dismiss
if (sessionStorage.getItem('onboarding_dismissed')) {
return;
}
try {
const response = await apiClient.get('/store/dashboard/onboarding');
this.steps = response.steps || [];
this.totalSteps = response.total_steps || 0;
this.completedSteps = response.completed_steps || 0;
this.progressPercentage = response.progress_percentage || 0;
// Show banner only if there are incomplete steps
if (this.totalSteps > 0 && !response.all_completed) {
this.visible = true;
}
} catch (error) {
storeDashLog.error('Failed to load onboarding status', error);
}
},
dismiss() {
sessionStorage.setItem('onboarding_dismissed', 'true');
this.visible = false;
}
};
}
function storeDashboard() {
storeDashLog.info('[STORE DASHBOARD] storeDashboard() called');
storeDashLog.info('[STORE DASHBOARD] data function exists inside?', typeof data);