32 KiB
Comprehensive Architecture Analysis: UnifiedOnboardingWizard
Executive Summary
The UnifiedOnboardingWizard is a 14-step onboarding flow that has evolved to integrate multiple concerns (file upload, inventory management, product categorization, stock entry, ML training) into a single, monolithic UploadSalesDataStep component. While the overall wizard architecture is sound, there is significant technical debt in the step implementations, particularly in UploadSalesDataStep which mixes file upload, inventory management, and state management responsibilities.
1. CURRENT ARCHITECTURE OVERVIEW
1.1 Wizard Structure
Location: /frontend/src/components/domain/onboarding/
The wizard consists of:
- UnifiedOnboardingWizard.tsx - Main wizard orchestrator (533 lines)
- WizardContext.tsx - State management (277 lines)
- OnboardingWizard.tsx - Deprecated (567 lines - SHOULD BE DELETED)
- 14 individual step components (ranging from 736 to 74,627 lines)
1.2 Visible Steps Flow
The wizard displays 14 steps in this order:
Phase 1: Discovery
├─ 1. bakery-type-selection (BakeryTypeSelectionStep)
└─ 2. setup (RegisterTenantStep)
Phase 2a: AI-Assisted Inventory Path
├─ 3. smart-inventory-setup (UploadSalesDataStep) ⚠️ MEGA-COMPONENT
├─ 4. product-categorization (ProductCategorizationStep)
├─ 5. initial-stock-entry (InitialStockEntryStep)
└─ (Auto-completes: suppliers-setup)
Phase 2b: Setup Operations
├─ 6. suppliers-setup (SuppliersSetupStep)
├─ 7. recipes-setup (RecipesSetupStep - conditional)
├─ 8. production-processes (ProductionProcessesStep - conditional)
Phase 3: Advanced Features
├─ 9. quality-setup (QualitySetupStep)
└─ 10. team-setup (TeamSetupStep)
Phase 4: ML & Finalization
├─ 11. ml-training (MLTrainingStep)
├─ 12. setup-review (ReviewSetupStep)
└─ 13. completion (CompletionStep)
Note: Step numbering is complex because:
- Steps 1-13 are in UnifiedOnboardingWizard
- SetupWizard (deprecated) has separate steps (setup-welcome, suppliers-setup, etc.)
- Conditional visibility based on bakeryType
- Auto-completion logic for suppliers-setup
2. DETAILED ARCHITECTURAL ISSUES
2.1 ISSUE #1: UploadSalesDataStep is a Mega-Component (74,627 lines)
Severity: CRITICAL
Current Responsibilities:
- File upload & validation (lines 1-169)
- Automatic file analysis with AI (lines 141-169)
- AI-based product classification (lines 171-247)
- Inventory item form management (lines 249-433)
- Stock lot management (lines 335-435)
- Batch operations (lines 437-589)
- Sales data import (lines 548-569)
- UI rendering for two distinct phases:
- File upload phase (lines 1408-1575)
- Inventory list/editing phase (lines 612-1405)
- Modal integration (BatchAddIngredientsModal)
Problems:
- Violates Single Responsibility Principle
- Hard to test (>1500 lines in single component)
- Multiple state variables (23 useState calls)
- Tightly couples file upload with inventory management
- Complex conditional rendering logic
- Difficult to reuse any sub-functionality
Code Indicators:
// Line 22-114: THREE separate form interfaces and states
interface ProgressState { ... }
interface InventoryItemForm { ... }
// Plus: [selectedFile, isValidating, validationResult, inventoryItems, ...]
// TOTAL: 23+ state variables
const [selectedFile, setSelectedFile] = useState<File | null>(null);
const [isValidating, setIsValidating] = useState(false);
const [validationResult, setValidationResult] = useState<ImportValidationResponse | null>(null);
// ... 20 more state declarations
2.2 ISSUE #2: Separated File Upload & Inventory Concerns
Severity: HIGH
The UploadSalesDataStep handles TWO distinct user journeys:
Journey 1: File Upload & Auto-Classification
User uploads CSV
↓
Validate file (validateFileMutation)
↓
Classify products (classifyBatchMutation)
↓
Generate AI suggestions
↓
Show inventory list for review
Journey 2: Manual Inventory Entry
After AI suggestions generated
↓
Edit/add inventory items manually
↓
Add stock lots per item
↓
Create all ingredients via API (createIngredient)
↓
Create all stock lots (addStockMutation)
↓
Import sales data
Problem: Both journeys are in ONE component with complex conditional rendering:
// Line 613: Conditional branch for entire second phase
if (showInventoryStep) {
// 800+ lines of inventory management UI
return (<div className="space-y-6"> ... </div>);
}
// Line 1408: Final 167 lines for file upload UI
return (<div className="space-y-6"> ... </div>);
2.3 ISSUE #3: State Management Fragmentation
Severity: MEDIUM
Local Component State (UploadSalesDataStep):
- File selection:
selectedFile,isValidating,validationResult - Inventory:
inventoryItems,showInventoryStep,error,progressState - Form data:
formData,editingId,isAdding,formErrors - Stock lots:
addingStockForId,stockFormData,stockErrors,ingredientStocks
Wizard Context State (WizardContext.tsx):
bakeryType,dataSource,uploadedFileName,uploadedFileSizeaiSuggestions,aiAnalysisComplete,categorizedProducts,productsWithStock- Various completion flags:
categorizationCompleted,stockEntryCompleted, etc.
Backend Progress State (API):
useUserProgress()fetches current step, completed steps, completion percentageuseMarkStepCompleted()updates backend after step completion
Problem: No clear separation of concerns
- Wizard context is "source of truth" but individual steps also have local state
- UI state (isAdding, editingId) mixed with data state (inventoryItems)
- No clear data flow: Step data → Wizard context → Backend
- Difficult to understand which data persists across sessions
2.4 ISSUE #4: Circular State Dependencies
Severity: MEDIUM
UploadSalesDataStep → Wizard Context:
// Line 320: Updates wizard context on completion
wizardContext.updateAISuggestions(data.aiSuggestions);
wizardContext.setAIAnalysisComplete(true);
// Line 325:
wizardContext.updateCategorizedProducts(data.categorizedProducts);
ProductCategorizationStep → Wizard Context:
// Receives products from wizard context
// Updates categorizedProducts in wizard context
onUpdate?.({ categorizedProducts: updatedProducts });
InitialStockEntryStep → Wizard Context:
// Receives products from categorization
// Updates productsWithStock in wizard context
onUpdate?.({ productsWithStock: updatedProducts });
Problem: Steps update wizard context via onUpdate() AND onComplete()
- Data flows both ways (child → parent AND parent → child)
- Difficult to trace data transformations
- No clear contract between parent and child
2.5 ISSUE #5: Tight Coupling Between Wizard & Setup Components
Severity: HIGH
UnifiedOnboardingWizard mixes:
- 8 onboarding-specific steps from
/onboarding/steps/ - 5 setup-specific steps from
/setup-wizard/steps/
Import at line 22-28:
import {
SuppliersSetupStep,
RecipesSetupStep,
QualitySetupStep,
TeamSetupStep,
ReviewSetupStep,
} from '../setup-wizard/steps';
Problem:
- UnifiedOnboardingWizard shouldn't need setup-wizard imports
- Creates dependency between onboarding and setup domains
- Changes in setup steps affect onboarding flow
- Makes it harder to modify setup flow independently
- Violates layering/module boundaries
2.6 ISSUE #6: Auto-Completion Logic Scattered
Severity: MEDIUM
Auto-completion of suppliers-setup (line 349-365):
// In UnifiedOnboardingWizard.handleStepComplete()
if (currentStep.id === 'smart-inventory-setup' && data?.shouldAutoCompleteSuppliers) {
try {
await markStepCompleted.mutateAsync({
userId: user.id,
stepName: 'suppliers-setup',
data: { auto_completed: true, ... }
});
} catch (supplierError) {
console.warn('Could not auto-complete suppliers-setup step');
}
}
Auto-completion of user_registered (line 204-232):
// In OnboardingWizardContent.useEffect()
useEffect(() => {
if (userProgress && user?.id && !autoCompletionAttempted && !markStepCompleted.isPending) {
const userRegisteredStep = userProgress.steps.find(s => s.step_name === 'user_registered');
if (!userRegisteredStep?.completed) {
// Auto-complete...
}
}
}, [...]);
Problem:
- Auto-completion logic is buried in step completion handler
- No clear policy for which steps can be auto-completed
- Difficult to add new auto-completion rules
- Inconsistent with manual step completion flow
2.7 ISSUE #7: Condition Functions Are Scattered & Duplicated
Severity: LOW-MEDIUM
Step visibility conditions (line 59-165):
const ALL_STEPS: StepConfig[] = [
{
id: 'smart-inventory-setup',
condition: (ctx) => ctx.tenantId !== null,
},
{
id: 'product-categorization',
condition: (ctx) => ctx.state.aiAnalysisComplete,
},
{
id: 'initial-stock-entry',
condition: (ctx) => ctx.state.categorizationCompleted,
},
{
id: 'suppliers-setup',
// Always show - no conditional
},
{
id: 'recipes-setup',
condition: (ctx) =>
ctx.state.bakeryType === 'production' || ctx.state.bakeryType === 'mixed',
},
// ... more conditions
];
Identical conditions in WizardContext (line 183-189):
getVisibleSteps = (): string[] => {
// ... same conditions repeated
if (state.bakeryType === 'production' || state.bakeryType === 'mixed') {
steps.push('recipes-setup');
}
if (state.bakeryType === 'retail' || state.bakeryType === 'mixed') {
steps.push('production-processes');
}
};
Problem:
- Same logic defined in TWO places
- Changes require updates in multiple files
- No single source of truth for visibility rules
- Conditions are business logic, should be defined separately
2.8 ISSUE #8: Complex Data Transformations Without Clear Contracts
Severity: MEDIUM**
UploadSalesDataStep → ProductCategorizationStep:
// Line 203-235: UploadSalesDataStep generates InventoryItemForm[]
const items: InventoryItemForm[] = classificationResponse.suggestions.map((suggestion) => ({
id: `ai-${index}-${Date.now()}`,
name: suggestion.suggested_name,
// ... 15 more properties
}));
// Then completes with:
onComplete({
createdIngredients,
totalItems: createdIngredients.length,
validationResult,
// ... more data
});
// But ProductCategorizationStep expects Product[] (different interface!)
interface Product {
id: string;
name: string;
category?: string;
confidence?: number;
type?: 'ingredient' | 'finished_product' | null;
suggestedType?: 'ingredient' | 'finished_product';
}
Problem:
- No clear transformation between step outputs and next step inputs
- Multiple data formats for similar data
- Type mismatches not caught until runtime
- No schema/contract for inter-step communication
3. STEP DEPENDENCIES & DATA FLOW
3.1 Dependency Diagram
BakeryTypeSelectionStep
└─> wizardContext.updateBakeryType()
└─> affects visibility of: recipes-setup, production-processes
RegisterTenantStep
└─> wizardContext.tenantId (implicit - via tenant store)
└─> enables: smart-inventory-setup
UploadSalesDataStep [MEGA-COMPONENT]
├─> Validates file (validateFileMutation)
├─> Classifies products (classifyBatchMutation)
├─> Creates inventory (createIngredient) ← INVENTORY CONCERN
├─> Creates stock lots (addStockMutation) ← INVENTORY CONCERN
├─> Imports sales data (importMutation)
├─> wizardContext.updateAISuggestions()
├─> wizardContext.setAIAnalysisComplete()
├─> markStepCompleted() [auto-completes suppliers-setup] ← ORCHESTRATION
└─> onComplete() with shouldAutoCompleteSuppliers flag
ProductCategorizationStep
├─> Input: wizard context aiSuggestions or initialData.categorizedProducts
├─> onUpdate() → wizardContext.updateCategorizedProducts()
└─> onComplete()
└─> wizardContext.markStepComplete('categorizationCompleted')
InitialStockEntryStep
├─> Input: categorizedProducts (which type: ingredient or finished_product?)
├─> onUpdate() → wizardContext.updateProductsWithStock()
└─> onComplete()
└─> wizardContext.markStepComplete('stockEntryCompleted')
SuppliersSetupStep (from setup-wizard)
├─> May be auto-completed by UploadSalesDataStep
└─> Creates suppliers
RecipesSetupStep (conditional: production or mixed)
└─> Depends on suppliers existing
ProductionProcessesStep (conditional: retail or mixed)
└─> May depend on recipes?
MLTrainingStep
└─> Input: inventory data from previous steps
└─> No explicit dependency check
ReviewSetupStep
└─> Shows summary of configuration
CompletionStep
└─> Final step, navigates away
3.2 Data Flow Diagram
┌─────────────────────────────────────────────────────────────────┐
│ UnifiedOnboardingWizard │
│ (Step Orchestrator) │
└─────────────────────────────────────────────────────────────────┘
↑ ↑
│ state (VISIBLE_STEPS, currentStepIndex) │ markStepCompleted()
│ │
┌────┴───────────────────────────────────────────────────┴──┐
│ WizardContext │
│ (State: bakeryType, aiSuggestions, categorizedProducts) │
│ (State: productsWithStock, various completion flags) │
└────┬───────────────────────────────────────────────────┬───┘
│ onUpdate() / onComplete() │
│ (data flows FROM steps TO context) │
│ │
┌────┴────────────────────────────────────────────────┬──┘
│ Individual Steps │
│ │
│ BakeryTypeSelectionStep │
│ RegisterTenantStep │
│ UploadSalesDataStep ⚠️ [73KB, 23 state vars] │
│ ├─ File validation │
│ ├─ AI classification │
│ ├─ Inventory creation │
│ └─ Stock lot management │
│ ProductCategorizationStep │
│ InitialStockEntryStep │
│ SuppliersSetupStep (from setup-wizard) │
│ ... │
└──────────────────────────────────────────────────────┘
│ │
│ │
API mutations Backend progress
(validateFile, classifyBatch, (useUserProgress,
createIngredient, addStock, useMarkStepCompleted)
importSalesData)
3.3 Data Transformation Pipeline
CSV/JSON File
↓
[UploadSalesDataStep] validateFileMutation
↓ (ImportValidationResponse)
├─ total_records, valid_records, invalid_records
├─ product_list: string[]
└─ ...
↓
[UploadSalesDataStep] classifyBatchMutation
↓ (ProductSuggestionResponse[])
├─ id, suggested_name, product_type
├─ category, unit_of_measure
├─ confidence_score
├─ estimated_shelf_life_days
├─ requires_refrigeration, requires_freezing, is_seasonal
├─ low_stock_threshold, reorder_point
└─ sales_data: { total_quantity, average_daily_sales }
↓
[UploadSalesDataStep] Transform to InventoryItemForm[]
├─ id: string (temporary UI ID)
├─ name, product_type, category
├─ unit_of_measure
├─ stock_quantity (calculated from sales data)
├─ cost_per_unit (estimated)
├─ estimated_shelf_life_days
├─ requires_refrigeration, requires_freezing, is_seasonal
├─ low_stock_threshold, reorder_point
├─ isSuggested: boolean
├─ confidence_score
└─ sales_data: { total_quantity, average_daily_sales }
↓
[UploadSalesDataStep] User review & manual edits
├─ Add/edit/delete inventory items
├─ Add stock lots (optional)
└─ ...
↓
[UploadSalesDataStep] createIngredient mutations (parallel)
↓ (Ingredient[])
├─ id (from backend)
├─ name, product_type, category
├─ unit_of_measure, shelf_life_days
├─ requires_refrigeration, requires_freezing, is_seasonal
├─ low_stock_threshold, max_stock_level, reorder_point
└─ average_cost
↓
[UploadSalesDataStep] addStockMutation (parallel)
↓ (StockResponse[])
├─ id (from backend)
├─ ingredient_id
├─ current_quantity
├─ expiration_date
├─ supplier_id
├─ batch_number
├─ production_stage
└─ quality_status
↓
[UploadSalesDataStep] importMutation (sales data)
↓
[ProductCategorizationStep] ← BUT RECEIVES: wizard context aiSuggestions
↓ (Product[] with type: 'ingredient' | 'finished_product')
↓
[InitialStockEntryStep] ← Receives: categorizedProducts
↓ (ProductWithStock[] with initialStock)
↓
[Backend] Final inventory saved
Problem: Data transformations are implicit and scattered across files. No clear schema/types for inter-step data passing.
4. LEGACY & DEPRECATED COMPONENTS
4.1 OnboardingWizard.tsx - DEPRECATED
Location: /frontend/src/components/domain/onboarding/OnboardingWizard.tsx
Status: DEPRECATED but still exported in index.ts
Usage:
// frontend/src/components/domain/onboarding/index.ts
export { OnboardingWizard } from './OnboardingWizard'; ← EXPORTED BUT NOT USED
export { UnifiedOnboardingWizard } from './UnifiedOnboardingWizard'; ← THIS IS USED
Confirmation of non-usage:
- OnboardingPage.tsx uses only UnifiedOnboardingWizard
- No other imports of OnboardingWizard found in codebase
- Old wizard has simplified step flow (4 steps vs 14)
Recommendation: DELETE OnboardingWizard.tsx and remove from index.ts exports
4.2 SetupWizard.tsx - STILL IN USE
Location: /frontend/src/components/domain/setup-wizard/SetupWizard.tsx
Status: ACTIVE but DEPRECATED by design
Usage:
// frontend/src/pages/setup/SetupPage.tsx
const SetupPage: React.FC = () => {
return <SetupWizard />;
};
Problem:
- UnifiedOnboardingWizard imports setup-wizard steps directly
- Creates tight coupling between onboarding and setup domains
- SetupWizard is now redundant - setup steps are integrated into UnifiedOnboardingWizard
- Separate SetupPage route still exists (/app/setup)
Recommendation:
- Remove setup-wizard imports from UnifiedOnboardingWizard
- Keep SetupWizard.tsx for backwards compatibility OR
- Transition to new onboarding flow only and deprecate SetupPage
4.3 Route Duplication
Current Routes:
/app/onboarding→ OnboardingPage → UnifiedOnboardingWizard ✓ CORRECT/app/setup→ SetupPage → SetupWizard ✓ LEGACY (now integrated into onboarding)
Recommendation:
- Remove /app/setup route OR
- Make it redirect to /app/onboarding for backwards compatibility
5. FILES TO DELETE
| File | Status | Reason |
|---|---|---|
/frontend/src/components/domain/onboarding/OnboardingWizard.tsx |
DELETE | Fully deprecated, non-functional |
/frontend/src/pages/setup/SetupPage.tsx |
DELETE or REDIRECT | Setup flow now integrated into onboarding |
| Setup wizard route entry in routes.config.ts | REMOVE | Duplicate with onboarding |
6. ARCHITECTURAL PROBLEMS SUMMARY
Problem #1: MEGA-COMPONENT (UploadSalesDataStep)
- Type: Single Responsibility Principle Violation
- Severity: CRITICAL
- Impact: Hard to test, maintain, and extend
- Solution: Split into:
- FileUploadPhase (controlled by parent)
- InventoryManagementPhase (separate component or reusable)
- AI classification logic (service)
Problem #2: State Management Fragmentation
- Type: State Distribution Anti-Pattern
- Severity: HIGH
- Impact: Difficult to trace data flow, understand state transitions
- Solution:
- Clear separation: UI state (local) vs Data state (context)
- Define explicit data contracts between steps
- Consider step output → context mapping layer
Problem #3: Mixed Concerns in One Component
- Type: Separation of Concerns Violation
- Severity: HIGH
- Impact: Tight coupling, difficult to test individual features
- Solution:
- File upload logic → FileUploadService
- Inventory form logic → InventoryFormComponent
- Stock lot logic → StockLotComponent
- Composition pattern to combine them
Problem #4: Duplicate Visibility Logic
- Type: DRY Principle Violation
- Severity: MEDIUM
- Impact: Maintenance burden, potential inconsistencies
- Solution:
- Extract visibility rules into dedicated config/service
- Single source of truth for step conditions
Problem #5: Circular Data Dependencies
- Type: Bidirectional Data Flow Anti-Pattern
- Severity: MEDIUM
- Impact: Hard to understand data flow direction
- Solution:
- Strict unidirectional data flow (parent → child via props, child → parent via callbacks)
- Clear input/output contracts for each step
Problem #6: Tight Coupling: Onboarding ↔ Setup Wizard
- Type: Module Boundary Violation
- Severity: HIGH
- Impact: Difficult to modify either wizard independently
- Solution:
- Remove setup-wizard imports from UnifiedOnboardingWizard
- Define step interface contract
- Load steps dynamically by configuration
Problem #7: Complex Auto-Completion Logic
- Type: Business Logic Distribution
- Severity: MEDIUM
- Impact: Difficult to understand which steps auto-complete
- Solution:
- Centralized auto-completion policy
- Explicit configuration for which steps can auto-complete
- Clear rules for completion dependencies
Problem #8: No Clear Inter-Step Communication Contract
- Type: Interface Definition Anti-Pattern
- Severity: MEDIUM
- Impact: Type mismatches between steps (InventoryItemForm vs Product vs ProductWithStock)
- Solution:
- Define Step Interface Contract
- Create transformation layer between step outputs
- Use consistent naming/typing across all steps
7. STEP RESPONSIBILITIES MATRIX
| Step | Primary Responsibility | State Type | Dependencies | Outputs |
|---|---|---|---|---|
| BakeryTypeSelectionStep | Select bakery model | UI | None | bakeryType |
| RegisterTenantStep | Register bakery details | API call | bakeryType | tenantId, tenant object |
| UploadSalesDataStep | File upload + Inventory mgmt + Stock lots | API calls + Local forms | tenantId | Ingredients[] + Stock[] + Sales import result |
| ProductCategorizationStep | Classify products | Drag-drop state | aiSuggestions | categorizedProducts |
| InitialStockEntryStep | Set initial stock levels | Form state | categorizedProducts | productsWithStock |
| SuppliersSetupStep | Add suppliers | API + Form | tenantId | suppliers (or auto-completed) |
| RecipesSetupStep | Create recipes | API + Complex forms | ingredients + suppliers | recipes |
| ProductionProcessesStep | Define processes | API + Complex forms | bakeryType | processes |
| QualitySetupStep | Set quality standards | API + Forms | tenantId | quality templates |
| TeamSetupStep | Add team members | API + Forms | tenantId | team members |
| MLTrainingStep | Train ML models | API poll + long-running | inventory data | trained models |
| ReviewSetupStep | Show configuration summary | Read-only | All previous data | (none, informational) |
| CompletionStep | Celebrate + redirect | Navigation | None | Navigate to dashboard |
8. RECOMMENDATIONS FOR REFACTORING
Immediate Actions (Quick Wins)
-
Delete OnboardingWizard.tsx
- Remove from exports in index.ts
- Impact: LOW (not used)
- Time: 5 minutes
-
Remove setup-wizard imports from UnifiedOnboardingWizard
- Load setup steps dynamically
- Create step registry/configuration
- Impact: MEDIUM (refactoring pattern needed)
- Time: 2-3 hours
-
Extract visibility rules to dedicated config
- Move bakeryType conditions to one place
- Impact: LOW (pure refactoring)
- Time: 1 hour
Medium-term Refactoring (1-2 Sprint)
-
Split UploadSalesDataStep
- Extract FileUploadPhase (lines 1408-1575)
- Extract InventoryManagementPhase (lines 612-1405)
- Create composition layer
- Move AI classification to service
- Impact: HIGH (major refactoring)
- Time: 6-8 hours
-
Define Inter-Step Data Contracts
- Create interfaces for step input/output
- Add transformation layer between steps
- Impact: HIGH (enforces consistency)
- Time: 4-6 hours
-
Separate UI State from Data State in WizardContext
- Move isAdding, editingId to component state
- Keep only data state in context
- Impact: MEDIUM (refactoring)
- Time: 3-4 hours
Long-term Architecture (2-3 Months)
-
Implement Step Interface Contract
- Define standard step props/callback signatures
- Enforce typing at wizard level
- Impact: HIGH (system-wide improvement)
- Time: 1-2 sprints
-
Extract Auto-Completion Policy Engine
- Centralized configuration for auto-completion
- Clear rules for step dependencies
- Impact: MEDIUM (optional feature)
- Time: 1 sprint
-
Consolidate Setup & Onboarding Routes
- Make /app/setup redirect to /app/onboarding
- OR keep SetupPage for post-onboarding scenarios
- Impact: LOW-MEDIUM (routing refactoring)
- Time: 2-3 hours
9. CURRENT STEP-BY-STEP FLOW DIAGRAM
┌───────────────────────────────────────────────────────────┐
│ USER FLOW: UnifiedOnboardingWizard (14 Steps) │
└───────────────────────────────────────────────────────────┘
START: User completes registration
↓ Auto-completes user_registered step
STEP 1: Bakery Type Selection
└─> SELECT: production | retail | mixed
└─> STORES: bakeryType in context
STEP 2: Register Tenant
└─> ENTER: Bakery name, address, phone, city
└─> API: registerBakery()
└─> STORES: tenantId, tenant object
STEP 3: Upload Sales Data (⚠️ MEGA-COMPONENT)
├─> UPLOAD: CSV/JSON file with sales history
│ └─> API: validateFile()
│ └─> API: classifyBatch() [AI classification]
│ └─> DISPLAY: Suggested inventory items
│
└─> REVIEW & EDIT: Inventory items
├─ ALLOW: Add, edit, delete items
├─ ALLOW: Add stock lots per item
│ └─> FIELDS: Quantity, expiration date, supplier, batch number
│
└─> API: createIngredient() [parallel for all items]
└─> API: addStock() [parallel for all stock lots]
└─> API: importSalesData() [background import]
└─> Auto-complete: suppliers-setup step
STEP 4: Product Categorization
├─> DISPLAY: Suggested AI classifications
├─> ALLOW: Drag-drop to categorize as ingredient or finished_product
└─> STORES: categorizedProducts in context
STEP 5: Initial Stock Entry
├─> DISPLAY: All products from categorization
├─> ALLOW: Enter initial stock quantities
└─> STORES: productsWithStock in context
STEP 6: Suppliers Setup ⭐ (May be auto-completed)
├─> IF auto-completed: Display "✓ Auto-setup"
└─> ELSE: ALLOW: Add suppliers (company, contact, details)
└─> API: createSupplier()
STEP 7: Recipes Setup (CONDITIONAL: production or mixed bakeries)
├─> ALLOW: Create recipes with ingredients
├─> INPUT: Select ingredients from inventory
├─> INPUT: Set quantities, proportions
└─> API: createRecipe()
STEP 8: Production Processes (CONDITIONAL: retail or mixed bakeries)
├─> ALLOW: Define production workflows
└─> API: createProcess()
STEP 9: Quality Setup
├─> ALLOW: Define quality templates/standards
└─> API: createQualityTemplate()
STEP 10: Team Setup
├─> ALLOW: Add team members, assign roles
└─> API: inviteUser()
STEP 11: ML Training
├─> INFO: "Training personalized AI model..."
├─> DISPLAY: Progress indicator
├─> WAIT: For training job completion (API poll)
└─> DISPLAY: Model accuracy metrics
STEP 12: Setup Review
├─> DISPLAY: Summary of all configuration
└─> ALLOW: Review before finalizing
STEP 13: Completion
└─> DISPLAY: "✓ Setup complete!"
└─> REDIRECT: /app/dashboard
END: User is now in the main application
10. SUMMARY TABLE
| Aspect | Status | Priority | Notes |
|---|---|---|---|
| Overall Architecture | FUNCTIONAL | - | Works but has technical debt |
| UnifiedOnboardingWizard Main | GOOD | LOW | Well-structured orchestrator |
| WizardContext | ACCEPTABLE | MEDIUM | State management needs clarification |
| UploadSalesDataStep | POOR | CRITICAL | 74KB mega-component needs refactoring |
| OnboardingWizard (old) | DEPRECATED | HIGH | Should be deleted |
| SetupWizard Integration | PROBLEMATIC | HIGH | Tight coupling needs fixing |
| Visibility Rules | DUPLICATE | MEDIUM | DRY principle violation |
| Inter-Step Contracts | UNDEFINED | MEDIUM | No formal interface definition |
| Auto-Completion | AD-HOC | MEDIUM | Needs centralized policy |
| State Management | FRAGMENTED | MEDIUM | Mixing UI and data state |
APPENDIX: FILE STATISTICS
| File | Size | LOC | Complexity | Status |
|---|---|---|---|---|
| UnifiedOnboardingWizard.tsx | 20.5 KB | 533 | MEDIUM | GOOD |
| WizardContext.tsx | 9.5 KB | 277 | MEDIUM | ACCEPTABLE |
| OnboardingWizard.tsx | 19.5 KB | 567 | MEDIUM | DEPRECATED |
| UploadSalesDataStep.tsx | 74.6 KB | 1577 | HIGH | POOR |
| ProductCategorizationStep.tsx | 14.3 KB | 365 | MEDIUM | ACCEPTABLE |
| InitialStockEntryStep.tsx | 11.2 KB | 286 | LOW | GOOD |
| BakeryTypeSelectionStep.tsx | 11 KB | 277 | MEDIUM | GOOD |
| RegisterTenantStep.tsx | 7.8 KB | ~200 | LOW | GOOD |
| SetupWizard.tsx | ~30 KB | ~800 | MEDIUM | ACTIVE |
| TOTAL ONBOARDING | ~169 KB | ~3665 | - | - |