Skip to main content

Expanded Onboarding Patterns

Expanded Onboarding Patterns

When to Use This Skill

Use this skill when implementing expanded onboarding patterns patterns in your codebase.

How to Use This Skill

  1. Review the patterns and examples below
  2. Apply the relevant patterns to your implementation
  3. Follow the best practices outlined in this skill

Level 1: Quick Reference (Under 500 tokens)

Onboarding State Structure

interface OnboardingState {
userId: string;
currentStep: number;
totalSteps: number;
completedModules: string[];
skippedModules: string[];
pace: 'quick' | 'standard' | 'thorough';
startedAt: Date;
lastActiveAt: Date;
}

const defaultState: OnboardingState = {
userId: '',
currentStep: 0,
totalSteps: 7,
completedModules: [],
skippedModules: [],
pace: 'standard',
startedAt: new Date(),
lastActiveAt: new Date(),
};

Module Structure

interface OnboardingModule {
id: string;
title: string;
description: string;
estimatedMinutes: number;
prerequisites: string[];
exercises: Exercise[];
checkpoints: Checkpoint[];
}

Level 2: Implementation Details (Under 2000 tokens)

Adaptive Pacing Logic

function adjustPace(state: OnboardingState, feedback: UserFeedback): OnboardingState {
let newPace = state.pace;

// Speed up if user is breezing through
if (feedback.completionTime < feedback.estimatedTime * 0.5 &&
feedback.exerciseScore > 90) {
newPace = state.pace === 'thorough' ? 'standard' : 'quick';
}

// Slow down if user is struggling
if (feedback.exerciseScore < 60 || feedback.requestedHelp) {
newPace = state.pace === 'quick' ? 'standard' : 'thorough';
}

return { ...state, pace: newPace };
}

Session Persistence

const STORAGE_KEY = 'onboarding_state';

function saveState(state: OnboardingState): void {
localStorage.setItem(STORAGE_KEY, JSON.stringify({
...state,
lastActiveAt: new Date(),
}));
}

function loadState(): OnboardingState | null {
const saved = localStorage.getItem(STORAGE_KEY);
if (!saved) return null;

const state = JSON.parse(saved);
state.startedAt = new Date(state.startedAt);
state.lastActiveAt = new Date(state.lastActiveAt);
return state;
}

function canResume(state: OnboardingState): boolean {
const hoursSinceActive =
(Date.now() - state.lastActiveAt.getTime()) / (1000 * 60 * 60);
return hoursSinceActive < 72; // 3 days
}

Level 3: Complete Reference (Full tokens)

Complete Onboarding Flow

class OnboardingManager {
private state: OnboardingState;
private modules: OnboardingModule[];

constructor() {
this.state = loadState() || defaultState;
this.modules = loadModules();
}

async startOrResume(): Promise<void> {
if (this.state.currentStep > 0 && canResume(this.state)) {
console.log(`Resuming from step ${this.state.currentStep}`);
} else {
this.state = { ...defaultState, userId: generateUserId() };
}

await this.runCurrentModule();
}

async runCurrentModule(): Promise<void> {
const module = this.modules[this.state.currentStep];

// Check prerequisites
const missingPrereqs = module.prerequisites.filter(
p => !this.state.completedModules.includes(p)
);

if (missingPrereqs.length > 0) {
throw new Error(`Missing prerequisites: ${missingPrereqs.join(', ')}`);
}

// Run module content
for (const exercise of module.exercises) {
const result = await this.runExercise(exercise);
if (!result.passed && this.state.pace === 'thorough') {
await this.provideAdditionalHelp(exercise);
}
}

// Mark complete
this.state.completedModules.push(module.id);
this.state.currentStep++;
saveState(this.state);
}

getProgress(): number {
return (this.state.currentStep / this.state.totalSteps) * 100;
}
}

Best Practices:

  • Persist state frequently
  • Offer skip options for advanced users
  • Provide progress indicators
  • Celebrate milestones
  • Allow pace adjustment anytime

Success Output

When successfully implementing expanded onboarding patterns:

✅ SKILL COMPLETE: expanded-onboarding-patterns

Completed:
- [x] OnboardingState structure defined with all required fields
- [x] OnboardingModule structure created with exercises and checkpoints
- [x] Adaptive pacing logic implemented (adjustPace function)
- [x] Session persistence enabled (saveState/loadState)
- [x] OnboardingManager class implemented with startOrResume flow
- [x] Progress tracking functional (getProgress method)

Outputs:
- OnboardingState TypeScript interface
- OnboardingModule TypeScript interface
- Adaptive pacing functions
- Session persistence utilities
- Complete OnboardingManager class

Completion Checklist

Before marking this skill as complete, verify:

  • OnboardingState includes all required fields (userId, currentStep, totalSteps, completedModules, skippedModules, pace, timestamps)
  • OnboardingModule defines prerequisites, exercises, and checkpoints
  • Adaptive pacing logic adjusts based on completion time and exercise scores
  • Session persistence saves to localStorage with lastActiveAt timestamp
  • Resume capability checks if session can be resumed (<72 hours)
  • OnboardingManager initializes from saved state or creates new
  • Prerequisites validated before running module
  • Additional help provided when pace is "thorough" and exercises fail
  • Progress calculation returns percentage (0-100%)

Failure Indicators

This skill has FAILED if:

  • ❌ OnboardingState missing required fields (userId, pace, timestamps)
  • ❌ Pacing logic does not adapt to user feedback (always same pace)
  • ❌ Session state not persisted to localStorage after updates
  • ❌ Resume logic fails to check 72-hour expiration window
  • ❌ Prerequisites not validated before module execution
  • ❌ No fallback for missing or invalid saved state
  • ❌ Progress percentage calculation incorrect or missing

When NOT to Use

Do NOT use this skill when:

  • Building simple linear onboarding (no adaptive pacing needed)
  • No session persistence required (single-session only)
  • Fixed pace without user feedback adaptation
  • No prerequisite dependencies between modules
  • Onboarding is single-page form (not multi-step flow)

Use alternatives instead:

  • For simple linear flow → Use basic step-by-step component
  • For no persistence → Remove localStorage, use React state only
  • For fixed pace → Skip adjustPace logic, use constant pace
  • For single-page → Use form wizard pattern instead

Anti-Patterns (Avoid)

Anti-PatternProblemSolution
Not persisting stateUser loses progress on refreshCall saveState() after every step
Ignoring user feedbackPace never adjusts, poor UXImplement adjustPace with score/time analysis
Skipping prerequisite checksUser sees module before readyValidate prerequisites in runCurrentModule
No resume capabilityUser must restart every timeImplement canResume and loadState
Fixed totalSteps hardcodedCan't add/remove modules flexiblyCalculate from modules.length dynamically
Missing lastActiveAt updatesCan't determine session freshnessUpdate lastActiveAt on every saveState

Principles

This skill embodies CODITECT automation principles:

  • #1 Recycle → Extend → Re-Use → Create - Reuses OnboardingState and OnboardingModule interfaces across all onboarding implementations
  • #2 First Principles - Understands WHY adaptive pacing matters (user retention and comprehension)
  • #4 Keep It Simple - Provides clear state structure and simple pacing heuristics
  • #5 Eliminate Ambiguity - Explicit pace values ('quick'|'standard'|'thorough') eliminate interpretation
  • #6 Clear, Understandable, Explainable - Three-level progressive disclosure makes patterns accessible
  • #8 No Assumptions - Validates prerequisites and checks session freshness before proceeding

Full Standard: CODITECT-STANDARD-AUTOMATION.md