diff --git a/ARCHITECTURE_ANALYSIS.md b/ARCHITECTURE_ANALYSIS.md deleted file mode 100644 index 82782d01..00000000 --- a/ARCHITECTURE_ANALYSIS.md +++ /dev/null @@ -1,877 +0,0 @@ -# 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**: -1. File upload & validation (lines 1-169) -2. Automatic file analysis with AI (lines 141-169) -3. AI-based product classification (lines 171-247) -4. Inventory item form management (lines 249-433) -5. Stock lot management (lines 335-435) -6. Batch operations (lines 437-589) -7. Sales data import (lines 548-569) -8. UI rendering for two distinct phases: - - File upload phase (lines 1408-1575) - - Inventory list/editing phase (lines 612-1405) -9. 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**: -```typescript -// 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(null); -const [isValidating, setIsValidating] = useState(false); -const [validationResult, setValidationResult] = useState(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: -```typescript -// Line 613: Conditional branch for entire second phase -if (showInventoryStep) { - // 800+ lines of inventory management UI - return (
...
); -} - -// Line 1408: Final 167 lines for file upload UI -return (
...
); -``` - -### 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`, `uploadedFileSize` -- `aiSuggestions`, `aiAnalysisComplete`, `categorizedProducts`, `productsWithStock` -- Various completion flags: `categorizationCompleted`, `stockEntryCompleted`, etc. - -**Backend Progress State** (API): -- `useUserProgress()` fetches current step, completed steps, completion percentage -- `useMarkStepCompleted()` 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**: -```typescript -// Line 320: Updates wizard context on completion -wizardContext.updateAISuggestions(data.aiSuggestions); -wizardContext.setAIAnalysisComplete(true); -// Line 325: -wizardContext.updateCategorizedProducts(data.categorizedProducts); -``` - -**ProductCategorizationStep → Wizard Context**: -```typescript -// Receives products from wizard context -// Updates categorizedProducts in wizard context -onUpdate?.({ categorizedProducts: updatedProducts }); -``` - -**InitialStockEntryStep → Wizard Context**: -```typescript -// 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**: -```typescript -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): -```typescript -// 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): -```typescript -// 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): -```typescript -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): -```typescript -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**: -```typescript -// 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**: -```typescript -// 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**: -```typescript -// frontend/src/pages/setup/SetupPage.tsx -const SetupPage: React.FC = () => { - return ; -}; -``` - -**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**: -1. Remove setup-wizard imports from UnifiedOnboardingWizard -2. Keep SetupWizard.tsx for backwards compatibility OR -3. 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) - -1. **Delete OnboardingWizard.tsx** - - Remove from exports in index.ts - - Impact: LOW (not used) - - Time: 5 minutes - -2. **Remove setup-wizard imports from UnifiedOnboardingWizard** - - Load setup steps dynamically - - Create step registry/configuration - - Impact: MEDIUM (refactoring pattern needed) - - Time: 2-3 hours - -3. **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) - -4. **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 - -5. **Define Inter-Step Data Contracts** - - Create interfaces for step input/output - - Add transformation layer between steps - - Impact: HIGH (enforces consistency) - - Time: 4-6 hours - -6. **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) - -7. **Implement Step Interface Contract** - - Define standard step props/callback signatures - - Enforce typing at wizard level - - Impact: HIGH (system-wide improvement) - - Time: 1-2 sprints - -8. **Extract Auto-Completion Policy Engine** - - Centralized configuration for auto-completion - - Clear rules for step dependencies - - Impact: MEDIUM (optional feature) - - Time: 1 sprint - -9. **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** | - | - | - ---- diff --git a/DASHBOARD_REDESIGN_SUMMARY.md b/DASHBOARD_REDESIGN_SUMMARY.md deleted file mode 100644 index ab857b26..00000000 --- a/DASHBOARD_REDESIGN_SUMMARY.md +++ /dev/null @@ -1,274 +0,0 @@ -# Bakery Dashboard Redesign - JTBD Implementation Summary - -## Overview - -Complete redesign of the bakery control panel based on Jobs To Be Done (JTBD) methodology. The new dashboard is focused on answering the user's primary question: **"What requires my attention right now?"** - -## Key Principles - -1. **Automation-First**: Dashboard shows what the system did automatically -2. **Action-Oriented**: Prioritizes tasks over information display -3. **Progressive Disclosure**: Shows 20% of info that matters 80% of the time -4. **Mobile-First**: Designed for one-handed operation with large touch targets -5. **Trust-Building**: Explains system reasoning to build confidence -6. **Narrative Over Metrics**: Tells stories, not just numbers - -## Implementation Complete - -### Backend Services (All Phases Implemented) - -#### 1. Dashboard Service (`services/orchestrator/app/services/dashboard_service.py`) -- Health status calculation (green/yellow/red) -- Action queue prioritization (critical/important/normal) -- Orchestration summary with narrative format -- Production timeline transformation -- Insights calculation -- Consequence prediction logic - -#### 2. Dashboard API (`services/orchestrator/app/api/dashboard.py`) -**Endpoints:** -- `GET /api/v1/tenants/{tenant_id}/dashboard/health-status` -- `GET /api/v1/tenants/{tenant_id}/dashboard/orchestration-summary` -- `GET /api/v1/tenants/{tenant_id}/dashboard/action-queue` -- `GET /api/v1/tenants/{tenant_id}/dashboard/production-timeline` -- `GET /api/v1/tenants/{tenant_id}/dashboard/insights` - -#### 3. Enhanced Models -**Purchase Orders** (`services/procurement/app/models/purchase_order.py`): -- Added `reasoning` (Text): Why PO was created -- Added `consequence` (Text): What happens if not approved -- Added `reasoning_data` (JSONB): Structured reasoning - -**Production Batches** (`services/production/app/models/production.py`): -- Added `reasoning` (Text): Why batch was scheduled -- Added `reasoning_data` (JSON): Structured context - -### Frontend Implementation (All Components Complete) - -#### 1. API Hooks (`frontend/src/api/hooks/newDashboard.ts`) -- `useBakeryHealthStatus()` - Overall health indicator -- `useOrchestrationSummary()` - What system did -- `useActionQueue()` - Prioritized action list -- `useProductionTimeline()` - Today's production -- `useInsights()` - Key metrics -- Mutation hooks for approvals and batch control - -#### 2. Dashboard Components - -**HealthStatusCard** (`frontend/src/components/dashboard/HealthStatusCard.tsx`) -- Traffic light indicator (🟢 🟡 🔴) -- Status checklist with icons -- Last updated and next check times -- Critical issues and pending actions summary - -**ActionQueueCard** (`frontend/src/components/dashboard/ActionQueueCard.tsx`) -- Prioritized action items (critical first) -- Expandable reasoning and consequences -- Large touch-friendly action buttons -- Time estimates for each task -- "All caught up!" empty state - -**OrchestrationSummaryCard** (`frontend/src/components/dashboard/OrchestrationSummaryCard.tsx`) -- Narrative format ("Last night I planned your day") -- Purchase orders and production batches created -- Reasoning inputs transparency (orders, AI, inventory) -- Expandable batch list -- User actions required indicator - -**ProductionTimelineCard** (`frontend/src/components/dashboard/ProductionTimelineCard.tsx`) -- Chronological timeline view -- Real-time progress bars -- Status icons (✅ 🔄 ⏰) -- Start/pause batch controls -- Summary statistics (total, done, active, pending) - -**InsightsGrid** (`frontend/src/components/dashboard/InsightsGrid.tsx`) -- 2x2 responsive grid -- Color-coded cards (green/amber/red) -- Savings, Inventory, Waste, Deliveries -- Trend indicators vs. goals - -#### 3. Main Dashboard Page (`frontend/src/pages/app/DashboardPage.tsx`) -**Features:** -- Mobile-optimized layout -- All sections integrated -- Real-time refresh -- Quick action links to detail pages -- Error handling and loading states - -**Legacy backup:** Old dashboard saved as `DashboardPage.legacy.tsx` - -## User Segments Supported - -### 1. Solo Bakery Owner (Primary Target) -- Simple health indicator -- Action checklist (max 3-5 items) -- Today's production at-a-glance -- Only critical alerts -- Mobile-first design - -### 2. Multi-Location Owner (Growth Stage) -- Multi-tenant switcher (existing) -- Comparison capabilities -- Delegation controls -- Consolidated alerts -- Trend analysis - -### 3. Enterprise/Central Bakery (Future-Facing) -- Network topology view -- Distribution planning -- Capacity utilization -- Financial optimization -- Advanced AI insights - -## JTBD Analysis Delivered - -### Main Functional Job -> "When I start my workday at the bakery, I need to quickly understand if everything is running smoothly and know exactly what requires my intervention, so I can confidently let the system handle routine operations while I focus on critical decisions." - -### Emotional Jobs Addressed -1. ✅ Feel in control despite automation -2. ✅ Reduce daily anxiety about operations -3. ✅ Feel competent using technology -4. ✅ Sleep well knowing business is protected - -### Social Jobs Addressed -1. ✅ Demonstrate professional management -2. ✅ Avoid being seen as bottleneck -3. ✅ Show sustainability to customers - -### Sub-Jobs Implemented -- ✅ Assess overall health (traffic light) -- ✅ Understand what system did overnight -- ✅ Review production plan for today -- ✅ Check inventory safety -- ✅ Approve/modify purchase orders -- ✅ Adjust production priorities -- ✅ Respond to critical alerts -- ✅ Resolve incomplete onboarding -- ✅ Track daily progress -- ✅ Verify no emerging issues - -## Forces of Progress Addressed - -### Anxiety Forces (Overcome) -- ❌ Fear of AI ordering wrong things → ✅ Transparency with reasoning -- ❌ Don't understand decisions → ✅ Narrative format with "Why" -- ❌ Not good with computers → ✅ Simplified navigation -- ❌ Too complicated → ✅ Progressive disclosure -- ❌ No time to learn → ✅ Onboarding integrated - -### Habit Forces (Bridged) -- Physical inventory checking → Widget shows physical stock -- Personal supplier calls → Approve PO but add notes -- Trust intuition → System shows reasoning, owner approves -- Pen and paper → Action queue mimics checklist - -## Technical Architecture - -### Backend Stack -- Python 3.11+ -- FastAPI -- SQLAlchemy (async) -- PostgreSQL -- Microservices architecture - -### Frontend Stack -- React 18+ -- TypeScript -- TanStack Query (React Query) -- Tailwind CSS -- Axios -- Lucide React (icons) -- date-fns (date formatting) - -### API Design -- RESTful endpoints -- Service-to-service HTTP calls with circuit breakers -- Resilient data aggregation (failed services don't break dashboard) -- 30-60 second auto-refresh intervals - -## Migration Notes - -### No Backwards Compatibility -As requested, this is a complete rewrite with: -- ❌ No legacy code -- ❌ No TODOs -- ❌ No incomplete features -- ✅ All functionality implemented -- ✅ Full type safety -- ✅ Comprehensive error handling - -### Files Modified -**Backend:** -- `services/orchestrator/app/services/dashboard_service.py` (NEW) -- `services/orchestrator/app/api/dashboard.py` (NEW) -- `services/orchestrator/app/api/__init__.py` (UPDATED) -- `services/orchestrator/app/main.py` (UPDATED) -- `services/procurement/app/models/purchase_order.py` (ENHANCED) -- `services/production/app/models/production.py` (ENHANCED) - -**Frontend:** -- `frontend/src/api/hooks/newDashboard.ts` (NEW) -- `frontend/src/api/index.ts` (UPDATED) -- `frontend/src/components/dashboard/HealthStatusCard.tsx` (NEW) -- `frontend/src/components/dashboard/ActionQueueCard.tsx` (NEW) -- `frontend/src/components/dashboard/OrchestrationSummaryCard.tsx` (NEW) -- `frontend/src/components/dashboard/ProductionTimelineCard.tsx` (NEW) -- `frontend/src/components/dashboard/InsightsGrid.tsx` (NEW) -- `frontend/src/components/dashboard/index.ts` (NEW) -- `frontend/src/pages/app/DashboardPage.tsx` (REPLACED) -- `frontend/src/pages/app/DashboardPage.legacy.tsx` (BACKUP) - -## Database Migrations Needed - -### Procurement Service -```sql -ALTER TABLE purchase_orders - ADD COLUMN reasoning TEXT, - ADD COLUMN consequence TEXT, - ADD COLUMN reasoning_data JSONB; -``` - -### Production Service -```sql -ALTER TABLE production_batches - ADD COLUMN reasoning TEXT, - ADD COLUMN reasoning_data JSON; -``` - -## Success Metrics - -### Leading Indicators (Engagement) -- Time to understand bakery status: < 30 seconds -- Dashboard visit frequency: Daily (morning) -- Mobile usage: > 60% of sessions -- Action completion rate: > 90% - -### Lagging Indicators (Outcomes) -- Onboarding completion rate: > 80% within 7 days -- System trust score (survey): > 4/5 -- Support ticket volume: -50% -- User retention (90-day): > 85% - -### Business Impact -- Waste reduction: +5% -- Time savings: -60 min/day -- Order fulfillment rate: +10% - -## Next Steps (Post-Deployment) - -1. **Database Migrations**: Run migrations to add reasoning fields -2. **Backend Testing**: Test all new endpoints with various tenant states -3. **Frontend Testing**: E2E tests for all dashboard interactions -4. **User Testing**: Pilot with 3-5 solo bakery owners -5. **Iteration**: Collect feedback and refine based on actual usage -6. **Documentation**: Update user guide with new dashboard features -7. **Training Materials**: Create video walkthrough for bakery owners -8. **Analytics**: Set up tracking for success metrics - -## Conclusion - -This implementation delivers a complete JTBD-aligned dashboard that transforms the bakery control panel from an information display into an **action-oriented copilot** for bakery owners. The system now proactively tells users what needs their attention, explains its reasoning, and makes it effortless to take action—all while building trust in the automation. - -The redesign is production-ready and fully implements all phases outlined in the original JTBD analysis, with no legacy code, no TODOs, and comprehensive functionality. diff --git a/FRONTEND_API_ANALYSIS_SUMMARY.md b/FRONTEND_API_ANALYSIS_SUMMARY.md deleted file mode 100644 index 790eb9bf..00000000 --- a/FRONTEND_API_ANALYSIS_SUMMARY.md +++ /dev/null @@ -1,241 +0,0 @@ -# Frontend API Analysis - Executive Summary - -## Document Location -Complete analysis: `/home/user/bakery_ia/FRONTEND_API_TYPES_ANALYSIS.md` (1,741 lines) - -## Quick Overview - -### 1. RECIPE API -**File**: `/home/user/bakery_ia/frontend/src/api/types/recipes.ts` -**Hooks**: `/home/user/bakery_ia/frontend/src/api/hooks/recipes.ts` - -Key Types: RecipeCreate, RecipeUpdate, RecipeResponse, RecipeIngredientResponse, RecipeQualityConfiguration - -Key Hooks: -- Query: useRecipe, useRecipes, useInfiniteRecipes, useRecipeStatistics, useRecipeCategories, useRecipeFeasibility -- Mutation: useCreateRecipe, useUpdateRecipe, useDeleteRecipe, useArchiveRecipe, useDuplicateRecipe, useActivateRecipe - ---- - -### 2. SUPPLIER API -**File**: `/home/user/bakery_ia/frontend/src/api/types/suppliers.ts` -**Hooks**: `/home/user/bakery_ia/frontend/src/api/hooks/suppliers.ts` - -Key Types: -- Supplier: SupplierCreate, SupplierResponse, SupplierPriceListResponse -- Purchase Order: PurchaseOrderCreate, PurchaseOrderResponse -- Delivery: DeliveryCreate, DeliveryResponse -- Performance: PerformanceMetric, Alert, Scorecard - -Key Hooks: -- Supplier (8 query hooks): useSuppliers, useSupplier, useSupplierStatistics, useActiveSuppliers, etc. -- Purchase Orders (2 query hooks): usePurchaseOrders, usePurchaseOrder -- Deliveries (2 query hooks): useDeliveries, useDelivery -- Performance (2 query hooks): useSupplierPerformanceMetrics, usePerformanceAlerts -- Mutations (12 hooks): CRUD operations for all entities - ---- - -### 3. INVENTORY/PRODUCT API -**File**: `/home/user/bakery_ia/frontend/src/api/types/inventory.ts` -**Hooks**: `/home/user/bakery_ia/frontend/src/api/hooks/inventory.ts` - -Key Types: -- Ingredient: IngredientCreate, IngredientResponse -- Stock: StockCreate, StockResponse -- Stock Movement: StockMovementCreate, StockMovementResponse -- Transformation: ProductTransformationCreate, ProductTransformationResponse -- Food Safety: TemperatureLogResponse, FoodSafetyAlertResponse, FoodSafetyComplianceResponse -- Dashboard: InventoryDashboardSummary, InventoryAnalytics - -Key Hooks: -- Ingredients (4 query hooks): useIngredients, useIngredient, useIngredientsByCategory, useLowStockIngredients -- Stock (6 query hooks): useStock, useStockByIngredient, useExpiringStock, useExpiredStock, useStockMovements, useStockAnalytics -- Transformations (5 query hooks): useTransformations, useTransformation, useTransformationSummary, etc. -- Mutations (13 hooks): CRUD + specialized operations like useStockOperations, useTransformationOperations - ---- - -### 4. QUALITY TEMPLATE API -**File**: `/home/user/bakery_ia/frontend/src/api/types/qualityTemplates.ts` -**Hooks**: `/home/user/bakery_ia/frontend/src/api/hooks/qualityTemplates.ts` - -Key Types: -- QualityCheckTemplate, QualityCheckTemplateCreate, QualityCheckTemplateUpdate -- QualityCheckExecutionRequest, QualityCheckExecutionResponse -- ProcessStageQualityConfig, RecipeQualityConfiguration - -Key Hooks: -- Query (5 hooks): useQualityTemplates, useQualityTemplate, useQualityTemplatesForStage, useQualityTemplatesForRecipe, useDefaultQualityTemplates -- Mutation (6 hooks): useCreateQualityTemplate, useUpdateQualityTemplate, useDeleteQualityTemplate, useDuplicateQualityTemplate, useExecuteQualityCheck, useValidateQualityTemplate - ---- - -### 5. CUSTOMER ORDER API -**File**: `/home/user/bakery_ia/frontend/src/api/types/orders.ts` -**Hooks**: `/home/user/bakery_ia/frontend/src/api/hooks/orders.ts` - -Key Types: -- Customer: CustomerCreate, CustomerResponse -- Order: OrderCreate, OrderUpdate, OrderResponse -- OrderItem: OrderItemCreate, OrderItemResponse -- Dashboard: OrdersDashboardSummary -- Analytics: DemandRequirements, BusinessModelDetection - -Key Hooks: -- Query (7 hooks): useOrders, useOrder, useCustomers, useCustomer, useOrdersDashboard, useDemandRequirements, useBusinessModelDetection -- Mutation (4 hooks): useCreateOrder, useUpdateOrderStatus, useCreateCustomer, useUpdateCustomer -- Utility (1 hook): useInvalidateOrders - ---- - -## CRITICAL MISALIGNMENTS IDENTIFIED - -### 1. PAYMENT TERMS ENUM CONFLICT -Location: `suppliers.ts` vs `orders.ts` - -**Suppliers PaymentTerms:** -- COD, NET_15, NET_30, NET_45, NET_60, PREPAID, CREDIT_TERMS - -**Orders PaymentTerms:** -- IMMEDIATE, NET_30, NET_60 - -**Impact**: Two different enums with same name in different contexts could cause confusion and data inconsistency. - -**Recommendation**: Unify these enums or clarify their separate domains. - ---- - -### 2. DECIMAL VS NUMBER TYPE -**Affected APIs**: Suppliers, Orders - -**Issue**: Backend uses `Decimal` for monetary values: -- supplier.credit_limit -- supplier.total_spent -- customer.total_spent -- customer.average_order_value - -**Frontend**: Uses `number` type - -**Impact**: Floating-point precision loss for currency calculations (e.g., $1.23 - $1.20 != $0.03) - -**Recommendation**: Implement a Decimal wrapper type for all currency fields. - ---- - -### 3. STOCK FIELD NAME INCONSISTENCY -**Locations**: -- `StockCreate` interface defines: `unit_cost?: number` -- `useStockOperations` hook uses: `unit_price` parameter - -**Impact**: Potential API validation errors if hook sends wrong field name. - -**Recommendation**: Audit backend to verify correct field name and update frontend accordingly. - ---- - -### 4. PROCESS STAGE VS PRODUCTION STAGE CONFUSION -**Quality Templates Define:** -- MIXING, PROOFING, SHAPING, BAKING, COOLING, PACKAGING, FINISHING - -**Inventory Defines:** -- RAW_INGREDIENT, PAR_BAKED, FULLY_BAKED, PREPARED_DOUGH, FROZEN_PRODUCT - -**Note**: These are intentionally different (quality control vs production) - correctly separated but documentation needed. - ---- - -### 5. RECORD OVERUSE -Multiple type definitions use `Record` for flexibility: -- instructions -- parameters -- thresholds -- scoring_criteria -- custom_requirements -- allergen_warnings - -**Risk**: Loose typing defeats TypeScript's safety benefits. - -**Recommendation**: Define specific interfaces for complex nested structures. - ---- - -### 6. CREATED_BY FIELD HANDLING -**Quality Templates**: `QualityCheckTemplateCreate` requires `created_by: string` - -**Issue**: Forms typically auto-fill from authenticated user context, not user input. - -**Recommendation**: Verify API makes this optional or frontend passes authenticated user ID. - ---- - -### 7. PRODUCT CLASSIFICATION -**Location**: inventory.ts - ProductSuggestionResponse, BatchClassificationResponse - -**Potential Issue**: These suggest AI-based classification but exact API endpoints may differ from implementation. - -**Recommendation**: Verify API contract matches suggestion response structure. - ---- - -## STATISTICS - -Total TypeScript type definitions: **150+** -Total React hooks: **80+** -Total enums: **40+** - -### By Domain: -- Recipes: 20 types, 10 hooks -- Suppliers: 35 types, 25 hooks -- Inventory: 25 types, 20 hooks -- Quality Templates: 12 types, 6 hooks -- Orders/Customers: 18 types, 7 hooks - ---- - -## KEY SERVICES LOCATION - -All services are located in: `/home/user/bakery_ia/frontend/src/api/services/` - -Main service files: -- recipes.ts -- suppliers.ts -- inventory.ts -- qualityTemplates.ts -- orders.ts -- procurement-service.ts -- purchase_orders.ts -- production.ts - ---- - -## RECOMMENDATIONS FOR CLEANUP - -1. **Priority 1 (Critical)** - - Unify PaymentTerms enums - - Fix Decimal type handling for currencies - - Verify stock field names (unit_cost vs unit_price) - -2. **Priority 2 (Important)** - - Replace Record with specific types - - Add validators matching backend - - Document ProcessStage vs ProductionStage distinction - -3. **Priority 3 (Nice to Have)** - - Create shared enum definitions - - Add JSDoc comments for all type fields - - Implement Decimal wrapper for all monetary values - - Create type guards for enum validation - ---- - -## FILES FOR FURTHER REVIEW - -Backend schema files (for comparison): -- `/home/user/bakery_ia/services/recipes/app/schemas/recipes.py` -- `/home/user/bakery_ia/services/orders/app/schemas/order_schemas.py` -- `/home/user/bakery_ia/services/production/app/schemas/quality_templates.py` -- `/home/user/bakery_ia/services/suppliers/app/schemas/suppliers.py` -- `/home/user/bakery_ia/services/suppliers/app/schemas/performance.py` -- `/home/user/bakery_ia/services/inventory/app/schemas/inventory.py` - diff --git a/FRONTEND_API_TYPES_ANALYSIS.md b/FRONTEND_API_TYPES_ANALYSIS.md deleted file mode 100644 index 7ce10235..00000000 --- a/FRONTEND_API_TYPES_ANALYSIS.md +++ /dev/null @@ -1,1741 +0,0 @@ -# Frontend API Types, Services, and Hooks - Complete Analysis - -## Overview -This document provides a comprehensive analysis of all frontend API types, services, and hooks across 6 major domains in the Bakery IA application, along with identified misalignments with the backend. - ---- - -## 1. RECIPE API - -### Frontend Type Definitions - -#### Enums -```typescript -export enum RecipeStatus { - DRAFT = 'draft', - ACTIVE = 'active', - TESTING = 'testing', - ARCHIVED = 'archived', - DISCONTINUED = 'discontinued' -} - -export enum MeasurementUnit { - GRAMS = 'g', - KILOGRAMS = 'kg', - MILLILITERS = 'ml', - LITERS = 'l', - CUPS = 'cups', - TABLESPOONS = 'tbsp', - TEASPOONS = 'tsp', - UNITS = 'units', - PIECES = 'pieces', - PERCENTAGE = '%' -} - -export enum ProductionStatus { - PLANNED = 'planned', - IN_PROGRESS = 'in_progress', - COMPLETED = 'completed', - FAILED = 'failed', - CANCELLED = 'cancelled' -} -``` - -#### Quality Configuration Types -```typescript -export interface QualityStageConfiguration { - template_ids?: string[]; - required_checks?: string[]; - optional_checks?: string[]; - blocking_on_failure?: boolean; - min_quality_score?: number | null; -} - -export interface RecipeQualityConfiguration { - stages?: Record; - overall_quality_threshold?: number; // Default: 7.0 - critical_stage_blocking?: boolean; - auto_create_quality_checks?: boolean; - quality_manager_approval_required?: boolean; -} - -export interface RecipeQualityConfigurationUpdate { - stages?: Record | null; - overall_quality_threshold?: number | null; - critical_stage_blocking?: boolean | null; - auto_create_quality_checks?: boolean | null; - quality_manager_approval_required?: boolean | null; -} -``` - -#### Recipe Ingredient Types -```typescript -export interface RecipeIngredientCreate { - ingredient_id: string; - quantity: number; // gt=0 - unit: MeasurementUnit; - alternative_quantity?: number | null; - alternative_unit?: MeasurementUnit | null; - preparation_method?: string | null; - ingredient_notes?: string | null; - is_optional?: boolean; - ingredient_order: number; // ge=1 - ingredient_group?: string | null; - substitution_options?: Record | null; - substitution_ratio?: number | null; -} - -export interface RecipeIngredientUpdate { - ingredient_id?: string | null; - quantity?: number | null; - unit?: MeasurementUnit | null; - alternative_quantity?: number | null; - alternative_unit?: MeasurementUnit | null; - preparation_method?: string | null; - ingredient_notes?: string | null; - is_optional?: boolean | null; - ingredient_order?: number | null; - ingredient_group?: string | null; - substitution_options?: Record | null; - substitution_ratio?: number | null; -} - -export interface RecipeIngredientResponse { - id: string; - tenant_id: string; - recipe_id: string; - ingredient_id: string; - quantity: number; - unit: string; - quantity_in_base_unit?: number | null; - alternative_quantity?: number | null; - alternative_unit?: string | null; - preparation_method?: string | null; - ingredient_notes?: string | null; - is_optional: boolean; - ingredient_order: number; - ingredient_group?: string | null; - substitution_options?: Record | null; - substitution_ratio?: number | null; - unit_cost?: number | null; - total_cost?: number | null; - cost_updated_at?: string | null; -} -``` - -#### Recipe CRUD Types -```typescript -export interface RecipeCreate { - name: string; // min_length=1, max_length=255 - recipe_code?: string | null; - version?: string; // Default: "1.0" - finished_product_id: string; - description?: string | null; - category?: string | null; - cuisine_type?: string | null; - difficulty_level?: number; // Default: 1, ge=1, le=5 - yield_quantity: number; // gt=0 - yield_unit: MeasurementUnit; - prep_time_minutes?: number | null; - cook_time_minutes?: number | null; - total_time_minutes?: number | null; - rest_time_minutes?: number | null; - instructions?: Record | null; - preparation_notes?: string | null; - storage_instructions?: string | null; - quality_standards?: string | null; - quality_check_configuration?: RecipeQualityConfiguration | null; - serves_count?: number | null; - nutritional_info?: Record | null; - allergen_info?: Record | null; - dietary_tags?: Record | null; - batch_size_multiplier?: number; // Default: 1.0, gt=0 - minimum_batch_size?: number | null; - maximum_batch_size?: number | null; - optimal_production_temperature?: number | null; - optimal_humidity?: number | null; - quality_check_points?: Record | null; - common_issues?: Record | null; - is_seasonal?: boolean; - season_start_month?: number | null; - season_end_month?: number | null; - is_signature_item?: boolean; - target_margin_percentage?: number | null; - ingredients: RecipeIngredientCreate[]; // min_items=1 -} - -export interface RecipeUpdate { - name?: string | null; - recipe_code?: string | null; - version?: string | null; - description?: string | null; - category?: string | null; - cuisine_type?: string | null; - difficulty_level?: number | null; - yield_quantity?: number | null; - yield_unit?: MeasurementUnit | null; - prep_time_minutes?: number | null; - cook_time_minutes?: number | null; - total_time_minutes?: number | null; - rest_time_minutes?: number | null; - instructions?: Record | null; - preparation_notes?: string | null; - storage_instructions?: string | null; - quality_standards?: string | null; - quality_check_configuration?: RecipeQualityConfigurationUpdate | null; - serves_count?: number | null; - nutritional_info?: Record | null; - allergen_info?: Record | null; - dietary_tags?: Record | null; - batch_size_multiplier?: number | null; - minimum_batch_size?: number | null; - maximum_batch_size?: number | null; - optimal_production_temperature?: number | null; - optimal_humidity?: number | null; - quality_check_points?: Record | null; - common_issues?: Record | null; - status?: RecipeStatus | null; - is_seasonal?: boolean | null; - season_start_month?: number | null; - season_end_month?: number | null; - is_signature_item?: boolean | null; - target_margin_percentage?: number | null; - ingredients?: RecipeIngredientCreate[] | null; -} - -export interface RecipeResponse { - id: string; - tenant_id: string; - name: string; - recipe_code?: string | null; - version: string; - finished_product_id: string; - description?: string | null; - category?: string | null; - cuisine_type?: string | null; - difficulty_level: number; - yield_quantity: number; - yield_unit: string; - prep_time_minutes?: number | null; - cook_time_minutes?: number | null; - total_time_minutes?: number | null; - rest_time_minutes?: number | null; - estimated_cost_per_unit?: number | null; - last_calculated_cost?: number | null; - cost_calculation_date?: string | null; - target_margin_percentage?: number | null; - suggested_selling_price?: number | null; - instructions?: Record | null; - preparation_notes?: string | null; - storage_instructions?: string | null; - quality_standards?: string | null; - quality_check_configuration?: RecipeQualityConfiguration | null; - serves_count?: number | null; - nutritional_info?: Record | null; - allergen_info?: Record | null; - dietary_tags?: Record | null; - batch_size_multiplier: number; - minimum_batch_size?: number | null; - maximum_batch_size?: number | null; - optimal_production_temperature?: number | null; - optimal_humidity?: number | null; - quality_check_points?: Record | null; - common_issues?: Record | null; - status: string; - is_seasonal: boolean; - season_start_month?: number | null; - season_end_month?: number | null; - is_signature_item: boolean; - created_at: string; - updated_at: string; - created_by?: string | null; - updated_by?: string | null; - ingredients?: RecipeIngredientResponse[] | null; -} - -export interface RecipeSearchRequest { - search_term?: string | null; - status?: RecipeStatus | null; - category?: string | null; - is_seasonal?: boolean | null; - is_signature?: boolean | null; - difficulty_level?: number | null; - limit?: number; // Default: 100 - offset?: number; // Default: 0 -} - -export interface RecipeFeasibilityResponse { - recipe_id: string; - recipe_name: string; - batch_multiplier: number; - feasible: boolean; - missing_ingredients: Array>; - insufficient_ingredients: Array>; -} - -export interface RecipeStatisticsResponse { - total_recipes: number; - active_recipes: number; - signature_recipes: number; - seasonal_recipes: number; - category_breakdown: Array>; -} -``` - -### Recipe Hooks -```typescript -// Query Hooks -useRecipe(tenantId, recipeId) - Fetch single recipe -useRecipes(tenantId, filters) - Search/list recipes with filters -useInfiniteRecipes(tenantId, filters) - Infinite query for pagination -useRecipeStatistics(tenantId) - Get recipe statistics -useRecipeCategories(tenantId) - Get available categories -useRecipeFeasibility(tenantId, recipeId, batchMultiplier) - Check feasibility -useRecipeDeletionSummary(tenantId, recipeId) - Get deletion summary - -// Mutation Hooks -useCreateRecipe(tenantId) - Create new recipe -useUpdateRecipe(tenantId) - Update existing recipe -useDeleteRecipe(tenantId) - Delete recipe -useArchiveRecipe(tenantId) - Soft delete -useDuplicateRecipe(tenantId) - Duplicate recipe -useActivateRecipe(tenantId) - Activate recipe -``` - ---- - -## 2. SUPPLIER API - -### Frontend Type Definitions - -#### Enums -```typescript -export enum SupplierType { - INGREDIENTS = 'ingredients', - PACKAGING = 'packaging', - EQUIPMENT = 'equipment', - SERVICES = 'services', - UTILITIES = 'utilities', - MULTI = 'multi' -} - -export enum SupplierStatus { - ACTIVE = 'active', - INACTIVE = 'inactive', - PENDING_APPROVAL = 'pending_approval', - SUSPENDED = 'suspended', - BLACKLISTED = 'blacklisted' -} - -export enum PaymentTerms { - COD = 'cod', - NET_15 = 'net_15', - NET_30 = 'net_30', - NET_45 = 'net_45', - NET_60 = 'net_60', - PREPAID = 'prepaid', - CREDIT_TERMS = 'credit_terms' -} - -export enum PurchaseOrderStatus { - DRAFT = 'draft', - PENDING_APPROVAL = 'pending_approval', - APPROVED = 'approved', - SENT_TO_SUPPLIER = 'sent_to_supplier', - CONFIRMED = 'confirmed', - PARTIALLY_RECEIVED = 'partially_received', - COMPLETED = 'completed', - CANCELLED = 'cancelled', - DISPUTED = 'disputed' -} - -export enum DeliveryStatus { - SCHEDULED = 'scheduled', - IN_TRANSIT = 'in_transit', - OUT_FOR_DELIVERY = 'out_for_delivery', - DELIVERED = 'delivered', - PARTIALLY_DELIVERED = 'partially_delivered', - FAILED_DELIVERY = 'failed_delivery', - RETURNED = 'returned' -} - -export enum QualityRating { - EXCELLENT = 5, - GOOD = 4, - AVERAGE = 3, - POOR = 2, - VERY_POOR = 1 -} - -export enum DeliveryRating { - EXCELLENT = 5, - GOOD = 4, - AVERAGE = 3, - POOR = 2, - VERY_POOR = 1 -} - -export enum InvoiceStatus { - PENDING = 'pending', - APPROVED = 'approved', - PAID = 'paid', - OVERDUE = 'overdue', - DISPUTED = 'disputed', - CANCELLED = 'cancelled' -} - -export enum OrderPriority { - NORMAL = 'normal', - HIGH = 'high', - URGENT = 'urgent' -} - -export enum AlertSeverity { - CRITICAL = 'CRITICAL', - HIGH = 'HIGH', - MEDIUM = 'MEDIUM', - LOW = 'LOW', - INFO = 'INFO' -} - -export enum AlertType { - POOR_QUALITY = 'POOR_QUALITY', - LATE_DELIVERY = 'LATE_DELIVERY', - PRICE_INCREASE = 'PRICE_INCREASE', - LOW_PERFORMANCE = 'LOW_PERFORMANCE', - CONTRACT_EXPIRY = 'CONTRACT_EXPIRY', - COMPLIANCE_ISSUE = 'COMPLIANCE_ISSUE', - FINANCIAL_RISK = 'FINANCIAL_RISK', - COMMUNICATION_ISSUE = 'COMMUNICATION_ISSUE', - CAPACITY_CONSTRAINT = 'CAPACITY_CONSTRAINT', - CERTIFICATION_EXPIRY = 'CERTIFICATION_EXPIRY' -} - -export enum AlertStatus { - ACTIVE = 'ACTIVE', - ACKNOWLEDGED = 'ACKNOWLEDGED', - IN_PROGRESS = 'IN_PROGRESS', - RESOLVED = 'RESOLVED', - DISMISSED = 'DISMISSED' -} - -export enum PerformanceMetricType { - DELIVERY_PERFORMANCE = 'DELIVERY_PERFORMANCE', - QUALITY_SCORE = 'QUALITY_SCORE', - PRICE_COMPETITIVENESS = 'PRICE_COMPETITIVENESS', - COMMUNICATION_RATING = 'COMMUNICATION_RATING', - ORDER_ACCURACY = 'ORDER_ACCURACY', - RESPONSE_TIME = 'RESPONSE_TIME', - COMPLIANCE_SCORE = 'COMPLIANCE_SCORE', - FINANCIAL_STABILITY = 'FINANCIAL_STABILITY' -} - -export enum PerformancePeriod { - DAILY = 'DAILY', - WEEKLY = 'WEEKLY', - MONTHLY = 'MONTHLY', - QUARTERLY = 'QUARTERLY', - YEARLY = 'YEARLY' -} -``` - -#### Supplier Types -```typescript -export interface SupplierCreate { - name: string; // min_length=1, max_length=255 - supplier_code?: string | null; - tax_id?: string | null; - registration_number?: string | null; - supplier_type: SupplierType; - contact_person?: string | null; - email?: string | null; - phone?: string | null; - mobile?: string | null; - website?: string | null; - address_line1?: string | null; - address_line2?: string | null; - city?: string | null; - state_province?: string | null; - postal_code?: string | null; - country?: string | null; - payment_terms?: PaymentTerms; // Default: net_30 - credit_limit?: number | null; - currency?: string; // Default: "EUR" - standard_lead_time?: number; // Default: 3 - minimum_order_amount?: number | null; - delivery_area?: string | null; - notes?: string | null; - certifications?: Record | null; - business_hours?: Record | null; - specializations?: Record | null; -} - -export interface SupplierResponse { - id: string; - tenant_id: string; - name: string; - supplier_code: string | null; - tax_id: string | null; - registration_number: string | null; - supplier_type: SupplierType; - status: SupplierStatus; - contact_person: string | null; - email: string | null; - phone: string | null; - mobile: string | null; - website: string | null; - address_line1: string | null; - address_line2: string | null; - city: string | null; - state_province: string | null; - postal_code: string | null; - country: string | null; - payment_terms: PaymentTerms; - credit_limit: number | null; - currency: string; - standard_lead_time: number; - minimum_order_amount: number | null; - delivery_area: string | null; - quality_rating: number | null; - delivery_rating: number | null; - total_orders: number; - total_amount: number; - approved_by: string | null; - approved_at: string | null; - rejection_reason: string | null; - notes: string | null; - certifications: Record | null; - business_hours: Record | null; - specializations: Record | null; - created_at: string; - updated_at: string; - created_by: string; - updated_by: string; -} - -export interface SupplierPriceListCreate { - inventory_product_id: string; - product_code?: string | null; - unit_price: number; // gt=0 - unit_of_measure: string; - minimum_order_quantity?: number | null; - price_per_unit: number; - tier_pricing?: Record | null; - effective_date?: string; - expiry_date?: string | null; - is_active?: boolean; - brand?: string | null; - packaging_size?: string | null; - origin_country?: string | null; - shelf_life_days?: number | null; - storage_requirements?: string | null; - quality_specs?: Record | null; - allergens?: Record | null; -} - -export interface SupplierPriceListResponse { - id: string; - tenant_id: string; - supplier_id: string; - inventory_product_id: string; - product_code: string | null; - unit_price: number; - unit_of_measure: string; - minimum_order_quantity: number | null; - price_per_unit: number; - tier_pricing: Record | null; - effective_date: string; - expiry_date: string | null; - is_active: boolean; - brand: string | null; - packaging_size: string | null; - origin_country: string | null; - shelf_life_days: number | null; - storage_requirements: string | null; - quality_specs: Record | null; - allergens: Record | null; - created_at: string; - updated_at: string; - created_by: string; - updated_by: string; -} -``` - -#### Purchase Order Types -```typescript -export interface PurchaseOrderItemCreate { - inventory_product_id: string; - product_code?: string | null; - ordered_quantity: number; // gt=0 - unit_of_measure: string; - unit_price: number; // gt=0 - quality_requirements?: string | null; - item_notes?: string | null; -} - -export interface PurchaseOrderCreate { - supplier_id: string; - items: PurchaseOrderItemCreate[]; // min_items=1 - reference_number?: string | null; - priority?: string; // Default: "normal" - required_delivery_date?: string | null; - delivery_address?: string | null; - delivery_instructions?: string | null; - delivery_contact?: string | null; - delivery_phone?: string | null; - tax_amount?: number; - shipping_cost?: number; - discount_amount?: number; - notes?: string | null; - internal_notes?: string | null; - terms_and_conditions?: string | null; -} - -export interface PurchaseOrderResponse { - id: string; - tenant_id: string; - supplier_id: string; - po_number: string; - status: PurchaseOrderStatus; - order_date: string; - reference_number: string | null; - priority: string; - required_delivery_date: string | null; - estimated_delivery_date: string | null; - subtotal: number; - tax_amount: number; - shipping_cost: number; - discount_amount: number; - total_amount: number; - currency: string; - delivery_address: string | null; - delivery_instructions: string | null; - delivery_contact: string | null; - delivery_phone: string | null; - requires_approval: boolean; - approved_by: string | null; - approved_at: string | null; - rejection_reason: string | null; - sent_to_supplier_at: string | null; - supplier_confirmation_date: string | null; - supplier_reference: string | null; - notes: string | null; - internal_notes: string | null; - terms_and_conditions: string | null; - created_at: string; - updated_at: string; - created_by: string; - updated_by: string; - supplier?: SupplierSummary | null; - items?: PurchaseOrderItemResponse[] | null; -} -``` - -#### Delivery Types -```typescript -export interface DeliveryItemCreate { - purchase_order_item_id: string; - inventory_product_id: string; - ordered_quantity: number; // gt=0 - delivered_quantity: number; // ge=0 - accepted_quantity: number; // ge=0 - rejected_quantity?: number; // Default: 0 - batch_lot_number?: string | null; - expiry_date?: string | null; - quality_grade?: string | null; - quality_issues?: string | null; - rejection_reason?: string | null; - item_notes?: string | null; -} - -export interface DeliveryCreate { - purchase_order_id: string; - supplier_id: string; - items: DeliveryItemCreate[]; // min_items=1 - supplier_delivery_note?: string | null; - scheduled_date?: string | null; - estimated_arrival?: string | null; - delivery_address?: string | null; - delivery_contact?: string | null; - delivery_phone?: string | null; - carrier_name?: string | null; - tracking_number?: string | null; - notes?: string | null; -} - -export interface DeliveryResponse { - id: string; - tenant_id: string; - purchase_order_id: string; - supplier_id: string; - delivery_number: string; - status: DeliveryStatus; - scheduled_date: string | null; - estimated_arrival: string | null; - actual_arrival: string | null; - completed_at: string | null; - supplier_delivery_note: string | null; - delivery_address: string | null; - delivery_contact: string | null; - delivery_phone: string | null; - carrier_name: string | null; - tracking_number: string | null; - inspection_passed: boolean | null; - inspection_notes: string | null; - quality_issues: Record | null; - received_by: string | null; - received_at: string | null; - notes: string | null; - photos: Record | null; - created_at: string; - updated_at: string; - created_by: string; - supplier?: SupplierSummary | null; - purchase_order?: PurchaseOrderSummary | null; - items?: DeliveryItemResponse[] | null; -} -``` - -#### Performance Types -```typescript -export interface PerformanceMetricCreate { - supplier_id: string; - metric_type: PerformanceMetricType; - period: PerformancePeriod; - period_start: string; - period_end: string; - metric_value: number; // ge=0, le=100 - target_value?: number | null; - total_orders?: number; - total_deliveries?: number; - on_time_deliveries?: number; - late_deliveries?: number; - quality_issues?: number; - total_amount?: number; - notes?: string | null; - metrics_data?: Record | null; - external_factors?: Record | null; -} - -export interface PerformanceMetric extends PerformanceMetricCreate { - id: string; - tenant_id: string; - previous_value: number | null; - trend_direction: string | null; - trend_percentage: number | null; - calculated_at: string; -} - -export interface AlertCreate { - supplier_id: string; - alert_type: AlertType; - severity: AlertSeverity; - title: string; - message: string; - description?: string | null; - trigger_value?: number | null; - threshold_value?: number | null; - metric_type?: PerformanceMetricType | null; - purchase_order_id?: string | null; - delivery_id?: string | null; - performance_metric_id?: string | null; - recommended_actions?: Array> | null; - auto_resolve?: boolean; - priority_score?: number; - business_impact?: string | null; - tags?: string[] | null; -} - -export interface Alert extends Omit { - id: string; - tenant_id: string; - status: AlertStatus; - triggered_at: string; - acknowledged_at: string | null; - acknowledged_by: string | null; - resolved_at: string | null; - resolved_by: string | null; - actions_taken: Array> | null; - resolution_notes: string | null; - escalated: boolean; - escalated_at: string | null; - notification_sent: boolean; - created_at: string; -} - -export interface ScorecardCreate { - supplier_id: string; - scorecard_name: string; - period: PerformancePeriod; - period_start: string; - period_end: string; - overall_score: number; - quality_score: number; - delivery_score: number; - cost_score: number; - service_score: number; - on_time_delivery_rate: number; - quality_rejection_rate: number; - order_accuracy_rate: number; - response_time_hours: number; - cost_variance_percentage: number; - total_orders_processed?: number; - total_amount_processed?: number; - average_order_value?: number; - cost_savings_achieved?: number; - strengths?: string[] | null; - improvement_areas?: string[] | null; - recommended_actions?: Array> | null; - notes?: string | null; -} - -export interface Scorecard extends ScorecardCreate { - id: string; - tenant_id: string; - overall_rank: number | null; - category_rank: number | null; - total_suppliers_evaluated: number | null; - score_trend: string | null; - score_change_percentage: number | null; - is_final: boolean; - approved_by: string | null; - approved_at: string | null; - attachments: Record | null; - generated_at: string; - generated_by: string | null; -} -``` - -### Supplier Hooks -```typescript -// Supplier Query Hooks -useSuppliers(tenantId, queryParams) - List suppliers -useSupplier(tenantId, supplierId) - Get single supplier -useSupplierStatistics(tenantId) - Get supplier statistics -useActiveSuppliers(tenantId, queryParams) - Get active suppliers -useTopSuppliers(tenantId) - Get top performing suppliers -usePendingApprovalSuppliers(tenantId) - Get pending approval suppliers -useSuppliersByType(tenantId, supplierType, queryParams) - Filter by type - -// Purchase Order Query Hooks -usePurchaseOrders(tenantId, queryParams) - List purchase orders -usePurchaseOrder(tenantId, orderId) - Get single purchase order - -// Delivery Query Hooks -useDeliveries(tenantId, queryParams) - List deliveries -useDelivery(tenantId, deliveryId) - Get single delivery - -// Supplier Price List Query Hooks -useSupplierPriceLists(tenantId, supplierId, isActive) - Get price lists -useSupplierPriceList(tenantId, supplierId, priceListId) - Get single price list - -// Performance Query Hooks -useSupplierPerformanceMetrics(tenantId, supplierId) - Get performance metrics -usePerformanceAlerts(tenantId, supplierId) - Get performance alerts - -// Supplier Mutation Hooks -useCreateSupplier() - Create supplier -useUpdateSupplier() - Update supplier -useApproveSupplier() - Approve supplier -useDeleteSupplier() - Delete supplier -useHardDeleteSupplier() - Hard delete supplier - -// Purchase Order Mutation Hooks -useCreatePurchaseOrder() - Create PO -useUpdatePurchaseOrder() - Update PO -useApprovePurchaseOrder() - Approve PO - -// Delivery Mutation Hooks -useCreateDelivery() - Create delivery -useUpdateDelivery() - Update delivery -useConfirmDeliveryReceipt() - Confirm delivery receipt - -// Supplier Price List Mutation Hooks -useCreateSupplierPriceList() - Create price list -useUpdateSupplierPriceList() - Update price list -useDeleteSupplierPriceList() - Delete price list - -// Performance Mutation Hooks -useCalculateSupplierPerformance() - Calculate performance -useEvaluatePerformanceAlerts() - Evaluate alerts -``` - ---- - -## 3. INVENTORY/PRODUCT API - -### Frontend Type Definitions - -#### Enums -```typescript -export enum ProductType { - INGREDIENT = 'ingredient', - FINISHED_PRODUCT = 'finished_product' -} - -export enum ProductionStage { - RAW_INGREDIENT = 'raw_ingredient', - PAR_BAKED = 'par_baked', - FULLY_BAKED = 'fully_baked', - PREPARED_DOUGH = 'prepared_dough', - FROZEN_PRODUCT = 'frozen_product' -} - -export enum UnitOfMeasure { - KILOGRAMS = 'kg', - GRAMS = 'g', - LITERS = 'l', - MILLILITERS = 'ml', - UNITS = 'units', - PIECES = 'pcs', - PACKAGES = 'pkg', - BAGS = 'bags', - BOXES = 'boxes' -} - -export enum IngredientCategory { - FLOUR = 'flour', - YEAST = 'yeast', - DAIRY = 'dairy', - EGGS = 'eggs', - SUGAR = 'sugar', - FATS = 'fats', - SALT = 'salt', - SPICES = 'spices', - ADDITIVES = 'additives', - PACKAGING = 'packaging', - CLEANING = 'cleaning', - OTHER = 'other' -} - -export enum ProductCategory { - BREAD = 'bread', - CROISSANTS = 'croissants', - PASTRIES = 'pastries', - CAKES = 'cakes', - COOKIES = 'cookies', - MUFFINS = 'muffins', - SANDWICHES = 'sandwiches', - SEASONAL = 'seasonal', - BEVERAGES = 'beverages', - OTHER_PRODUCTS = 'other_products' -} - -export enum StockMovementType { - PURCHASE = 'PURCHASE', - PRODUCTION_USE = 'PRODUCTION_USE', - ADJUSTMENT = 'ADJUSTMENT', - WASTE = 'WASTE', - TRANSFER = 'TRANSFER', - RETURN = 'RETURN', - INITIAL_STOCK = 'INITIAL_STOCK', - TRANSFORMATION = 'TRANSFORMATION' -} -``` - -#### Ingredient Types -```typescript -export interface IngredientCreate { - name: string; - product_type?: ProductType; - sku?: string | null; - barcode?: string | null; - category?: string | null; - subcategory?: string | null; - description?: string | null; - brand?: string | null; - unit_of_measure: UnitOfMeasure | string; - package_size?: number | null; - standard_cost?: number | null; - low_stock_threshold?: number | null; - reorder_point?: number | null; - reorder_quantity?: number | null; - max_stock_level?: number | null; - shelf_life_days?: number | null; - is_perishable?: boolean; - allergen_info?: Record | null; -} - -export interface IngredientResponse { - id: string; - tenant_id: string; - name: string; - product_type: ProductType; - sku: string | null; - barcode: string | null; - category: string | null; - subcategory: string | null; - description: string | null; - brand: string | null; - unit_of_measure: UnitOfMeasure | string; - package_size: number | null; - average_cost: number | null; - last_purchase_price: number | null; - standard_cost: number | null; - low_stock_threshold: number | null; - reorder_point: number | null; - reorder_quantity: number | null; - max_stock_level: number | null; - shelf_life_days: number | null; - is_active: boolean; - is_perishable: boolean; - allergen_info: Record | null; - created_at: string; - updated_at: string; - created_by: string | null; - current_stock?: number | null; - is_low_stock?: boolean | null; - needs_reorder?: boolean | null; -} -``` - -#### Stock Types -```typescript -export interface StockCreate { - ingredient_id: string; - supplier_id?: string | null; - batch_number?: string | null; - lot_number?: string | null; - supplier_batch_ref?: string | null; - production_stage?: ProductionStage; - transformation_reference?: string | null; - current_quantity: number; - received_date?: string | null; - expiration_date?: string | null; - best_before_date?: string | null; - original_expiration_date?: string | null; - transformation_date?: string | null; - final_expiration_date?: string | null; - unit_cost?: number | null; - storage_location?: string | null; - warehouse_zone?: string | null; - shelf_position?: string | null; - quality_status?: string; - requires_refrigeration?: boolean; - requires_freezing?: boolean; - storage_temperature_min?: number | null; - storage_temperature_max?: number | null; - storage_humidity_max?: number | null; - shelf_life_days?: number | null; - storage_instructions?: string | null; -} - -export interface StockResponse { - id: string; - tenant_id: string; - ingredient_id: string; - supplier_id: string | null; - batch_number: string | null; - lot_number: string | null; - supplier_batch_ref: string | null; - production_stage: ProductionStage; - transformation_reference: string | null; - current_quantity: number; - reserved_quantity: number; - available_quantity: number; - received_date: string | null; - expiration_date: string | null; - best_before_date: string | null; - original_expiration_date: string | null; - transformation_date: string | null; - final_expiration_date: string | null; - unit_cost: number | null; - total_cost: number | null; - storage_location: string | null; - warehouse_zone: string | null; - shelf_position: string | null; - is_available: boolean; - is_expired: boolean; - quality_status: string; - requires_refrigeration: boolean; - requires_freezing: boolean; - storage_temperature_min: number | null; - storage_temperature_max: number | null; - storage_humidity_max: number | null; - shelf_life_days: number | null; - storage_instructions: string | null; - created_at: string; - updated_at: string; - ingredient?: IngredientResponse | null; -} -``` - -#### Stock Movement Types -```typescript -export interface StockMovementCreate { - ingredient_id: string; - stock_id?: string | null; - movement_type: StockMovementType; - quantity: number; - unit_cost?: number | null; - reference_number?: string | null; - supplier_id?: string | null; - notes?: string | null; - reason_code?: string | null; - movement_date?: string | null; -} - -export interface StockMovementResponse { - id: string; - tenant_id: string; - ingredient_id: string; - stock_id: string | null; - movement_type: StockMovementType; - quantity: number; - unit_cost: number | null; - total_cost: number | null; - quantity_before: number | null; - quantity_after: number | null; - reference_number: string | null; - supplier_id: string | null; - notes: string | null; - reason_code: string | null; - movement_date: string; - created_at: string; - created_by: string | null; - ingredient?: IngredientResponse | null; -} -``` - -#### Product Transformation Types -```typescript -export interface ProductTransformationCreate { - source_ingredient_id: string; - target_ingredient_id: string; - source_stage: ProductionStage; - target_stage: ProductionStage; - source_quantity: number; - target_quantity: number; - conversion_ratio?: number | null; - expiration_calculation_method?: string; // Default: "days_from_transformation" - expiration_days_offset?: number | null; // Default: 1 - process_notes?: string | null; - target_batch_number?: string | null; - source_stock_ids?: string[] | null; -} - -export interface ProductTransformationResponse { - id: string; - tenant_id: string; - transformation_reference: string; - source_ingredient_id: string; - target_ingredient_id: string; - source_stage: ProductionStage; - target_stage: ProductionStage; - source_quantity: number; - target_quantity: number; - conversion_ratio: number; - expiration_calculation_method: string; - expiration_days_offset: number | null; - transformation_date: string; - process_notes: string | null; - performed_by: string | null; - source_batch_numbers: string | null; - target_batch_number: string | null; - is_completed: boolean; - is_reversed: boolean; - created_at: string; - created_by: string | null; - source_ingredient?: IngredientResponse | null; - target_ingredient?: IngredientResponse | null; -} -``` - -### Inventory Hooks -```typescript -// Ingredient Query Hooks -useIngredients(tenantId, filter) - List ingredients -useIngredient(tenantId, ingredientId) - Get single ingredient -useIngredientsByCategory(tenantId) - Get ingredients grouped by category -useLowStockIngredients(tenantId) - Get low stock items - -// Stock Query Hooks -useStock(tenantId, filter) - Get all stock items (paginated) -useStockByIngredient(tenantId, ingredientId, includeUnavailable) - Get stock for ingredient -useExpiringStock(tenantId, withinDays) - Get expiring items -useExpiredStock(tenantId) - Get expired items -useStockMovements(tenantId, ingredientId, limit, offset) - Get movement history -useStockAnalytics(tenantId, startDate, endDate) - Get stock analytics - -// Ingredient Mutation Hooks -useCreateIngredient() - Create ingredient -useUpdateIngredient() - Update ingredient -useSoftDeleteIngredient() - Soft delete ingredient -useHardDeleteIngredient() - Hard delete ingredient - -// Stock Mutation Hooks -useAddStock() - Add stock -useUpdateStock() - Update stock -useConsumeStock() - Consume stock (FIFO/LIFO) -useCreateStockMovement() - Create movement record - -// Transformation Query Hooks -useTransformations(tenantId, options) - List transformations -useTransformation(tenantId, transformationId) - Get single transformation -useTransformationSummary(tenantId, daysBack) - Get transformation summary -useTransformationsByIngredient(tenantId, ingredientId, limit) - By source/target -useTransformationsByStage(tenantId, sourceStage, targetStage, limit) - By stages - -// Transformation Mutation Hooks -useCreateTransformation() - Create transformation -useParBakeTransformation() - Par-bake transformation -useClassifyBatch() - Classify batch of products - -// Custom Operation Hooks -useStockOperations(tenantId) - Returns addStock, consumeStock, adjustStock -useTransformationOperations(tenantId) - Returns various transformation operations -``` - ---- - -## 4. QUALITY TEMPLATE API - -### Frontend Type Definitions - -#### Enums -```typescript -export enum QualityCheckType { - VISUAL = 'visual', - MEASUREMENT = 'measurement', - TEMPERATURE = 'temperature', - WEIGHT = 'weight', - BOOLEAN = 'boolean', - TIMING = 'timing', - CHECKLIST = 'checklist' -} - -export enum ProcessStage { - MIXING = 'mixing', - PROOFING = 'proofing', - SHAPING = 'shaping', - BAKING = 'baking', - COOLING = 'cooling', - PACKAGING = 'packaging', - FINISHING = 'finishing' -} -``` - -#### Quality Template Types -```typescript -export interface QualityCheckTemplate { - id: string; - tenant_id: string; - name: string; - template_code?: string; - check_type: QualityCheckType; - category?: string; - description?: string; - instructions?: string; - parameters?: Record; - thresholds?: Record; - scoring_criteria?: Record; - is_active: boolean; - is_required: boolean; - is_critical: boolean; - weight: number; - min_value?: number; - max_value?: number; - target_value?: number; - unit?: string; - tolerance_percentage?: number; - applicable_stages?: ProcessStage[]; - created_by: string; - created_at: string; - updated_at: string; -} - -export interface QualityCheckTemplateCreate { - name: string; - template_code?: string; - check_type: QualityCheckType; - category?: string; - description?: string; - instructions?: string; - parameters?: Record; - thresholds?: Record; - scoring_criteria?: Record; - is_active?: boolean; - is_required?: boolean; - is_critical?: boolean; - weight?: number; - min_value?: number; - max_value?: number; - target_value?: number; - unit?: string; - tolerance_percentage?: number; - applicable_stages?: ProcessStage[]; - created_by: string; -} - -export interface QualityCheckTemplateUpdate { - name?: string; - template_code?: string; - check_type?: QualityCheckType; - category?: string; - description?: string; - instructions?: string; - parameters?: Record; - thresholds?: Record; - scoring_criteria?: Record; - is_active?: boolean; - is_required?: boolean; - is_critical?: boolean; - weight?: number; - min_value?: number; - max_value?: number; - target_value?: number; - unit?: string; - tolerance_percentage?: number; - applicable_stages?: ProcessStage[]; -} - -export interface QualityCheckResult { - criterion_id: string; - value: number | string | boolean; - score: number; - notes?: string; - photos?: string[]; - pass_check: boolean; - timestamp: string; -} - -export interface QualityCheckExecutionRequest { - template_id: string; - batch_id: string; - process_stage: ProcessStage; - checker_id?: string; - results: QualityCheckResult[]; - final_notes?: string; - photos?: string[]; -} - -export interface QualityCheckExecutionResponse { - check_id: string; - overall_score: number; - overall_pass: boolean; - critical_failures: string[]; - corrective_actions: string[]; - timestamp: string; -} -``` - -### Quality Template Hooks -```typescript -// Query Hooks -useQualityTemplates(tenantId, params) - List templates with filters -useQualityTemplate(tenantId, templateId) - Get single template -useQualityTemplatesForStage(tenantId, stage, isActive) - Templates for process stage -useQualityTemplatesForRecipe(tenantId, recipeId) - Templates for recipe configuration -useDefaultQualityTemplates(tenantId, productCategory) - Get default templates by category - -// Mutation Hooks -useCreateQualityTemplate(tenantId) - Create template -useUpdateQualityTemplate(tenantId) - Update template -useDeleteQualityTemplate(tenantId) - Delete template -useDuplicateQualityTemplate(tenantId) - Duplicate template -useExecuteQualityCheck(tenantId) - Execute quality check -useValidateQualityTemplate(tenantId) - Validate template configuration -``` - ---- - -## 5. CUSTOMER ORDER API - -### Frontend Type Definitions - -#### Enums -```typescript -export enum CustomerType { - INDIVIDUAL = 'individual', - BUSINESS = 'business', - CENTRAL_BAKERY = 'central_bakery' -} - -export enum DeliveryMethod { - DELIVERY = 'delivery', - PICKUP = 'pickup' -} - -export enum PaymentTerms { - IMMEDIATE = 'immediate', - NET_30 = 'net_30', - NET_60 = 'net_60' -} - -export enum PaymentMethod { - CASH = 'cash', - CARD = 'card', - BANK_TRANSFER = 'bank_transfer', - ACCOUNT = 'account' -} - -export enum PaymentStatus { - PENDING = 'pending', - PARTIAL = 'partial', - PAID = 'paid', - FAILED = 'failed', - REFUNDED = 'refunded' -} - -export enum CustomerSegment { - VIP = 'vip', - REGULAR = 'regular', - WHOLESALE = 'wholesale' -} - -export enum PriorityLevel { - HIGH = 'high', - NORMAL = 'normal', - LOW = 'low' -} - -export enum OrderType { - STANDARD = 'standard', - RUSH = 'rush', - RECURRING = 'recurring', - SPECIAL = 'special' -} - -export enum OrderStatus { - PENDING = 'pending', - CONFIRMED = 'confirmed', - IN_PRODUCTION = 'in_production', - READY = 'ready', - OUT_FOR_DELIVERY = 'out_for_delivery', - DELIVERED = 'delivered', - CANCELLED = 'cancelled', - FAILED = 'failed' -} - -export enum OrderSource { - MANUAL = 'manual', - ONLINE = 'online', - PHONE = 'phone', - APP = 'app', - API = 'api' -} - -export enum SalesChannel { - DIRECT = 'direct', - WHOLESALE = 'wholesale', - RETAIL = 'retail' -} - -export enum BusinessModel { - INDIVIDUAL_BAKERY = 'individual_bakery', - CENTRAL_BAKERY = 'central_bakery' -} -``` - -#### Customer Types -```typescript -export interface CustomerBase { - name: string; - business_name?: string; - customer_type: CustomerType; - email?: string; - phone?: string; - address_line1?: string; - address_line2?: string; - city?: string; - state?: string; - postal_code?: string; - country: string; - is_active: boolean; - preferred_delivery_method: DeliveryMethod; - payment_terms: PaymentTerms; - credit_limit?: number; - discount_percentage: number; - customer_segment: CustomerSegment; - priority_level: PriorityLevel; - special_instructions?: string; - delivery_preferences?: Record; - product_preferences?: Record; -} - -export interface CustomerCreate extends CustomerBase { - customer_code: string; - tenant_id: string; -} - -export interface CustomerResponse extends CustomerBase { - id: string; - tenant_id: string; - customer_code: string; - total_orders: number; - total_spent: number; - average_order_value: number; - last_order_date?: string; - created_at: string; - updated_at: string; -} -``` - -#### Order Item Types -```typescript -export interface OrderItemBase { - product_id: string; - product_name: string; - product_sku?: string; - product_category?: string; - quantity: number; - unit_of_measure: string; - weight?: number; - unit_price: number; - line_discount: number; - product_specifications?: Record; - customization_details?: string; - special_instructions?: string; - recipe_id?: string; -} - -export interface OrderItemCreate extends OrderItemBase {} - -export interface OrderItemResponse extends OrderItemBase { - id: string; - order_id: string; - line_total: number; - status: string; - created_at: string; - updated_at: string; -} -``` - -#### Order Types -```typescript -export interface OrderBase { - customer_id: string; - order_type: OrderType; - priority: PriorityLevel; - requested_delivery_date: string; - delivery_method: DeliveryMethod; - delivery_address?: Record; - delivery_instructions?: string; - delivery_window_start?: string; - delivery_window_end?: string; - discount_percentage: number; - delivery_fee: number; - payment_method?: PaymentMethod; - payment_terms: PaymentTerms; - special_instructions?: string; - custom_requirements?: Record; - allergen_warnings?: Record; - order_source: OrderSource; - sales_channel: SalesChannel; - order_origin?: string; - communication_preferences?: Record; -} - -export interface OrderCreate extends OrderBase { - tenant_id: string; - items: OrderItemCreate[]; -} - -export interface OrderUpdate { - status?: OrderStatus; - priority?: PriorityLevel; - requested_delivery_date?: string; - confirmed_delivery_date?: string; - delivery_method?: DeliveryMethod; - delivery_address?: Record; - delivery_instructions?: string; - delivery_window_start?: string; - delivery_window_end?: string; - payment_method?: PaymentMethod; - payment_status?: PaymentStatus; - special_instructions?: string; - custom_requirements?: Record; - allergen_warnings?: Record; -} - -export interface OrderResponse extends OrderBase { - id: string; - tenant_id: string; - order_number: string; - status: OrderStatus; - order_date: string; - confirmed_delivery_date?: string; - actual_delivery_date?: string; - subtotal: number; - discount_amount: number; - tax_amount: number; - total_amount: number; - payment_status: PaymentStatus; - business_model?: string; - estimated_business_model?: string; - production_batch_id?: string; - quality_score?: number; - customer_rating?: number; - created_at: string; - updated_at: string; - items: OrderItemResponse[]; -} - -export interface OrdersDashboardSummary { - total_orders_today: number; - total_orders_this_week: number; - total_orders_this_month: number; - revenue_today: number; - revenue_this_week: number; - revenue_this_month: number; - pending_orders: number; - confirmed_orders: number; - in_production_orders: number; - ready_orders: number; - delivered_orders: number; - total_customers: number; - new_customers_this_month: number; - repeat_customers_rate: number; - average_order_value: number; - order_fulfillment_rate: number; - on_time_delivery_rate: number; - business_model?: string; - business_model_confidence?: number; - recent_orders: OrderResponse[]; - high_priority_orders: OrderResponse[]; -} - -export interface DemandRequirements { - date: string; - tenant_id: string; - product_demands: Record[]; - total_orders: number; - total_quantity: number; - total_value: number; - business_model?: string; - rush_orders_count: number; - special_requirements: string[]; - earliest_delivery: string; - latest_delivery: string; - average_lead_time_hours: number; -} -``` - -### Orders/Customer Hooks -```typescript -// Order Query Hooks -useOrders(params) - List orders -useOrder(tenantId, orderId) - Get single order - -// Customer Query Hooks -useCustomers(params) - List customers -useCustomer(tenantId, customerId) - Get single customer - -// Dashboard Query Hooks -useOrdersDashboard(tenantId) - Get dashboard summary -useDemandRequirements(params) - Get demand requirements -useBusinessModelDetection(tenantId) - Detect business model -useOrdersServiceStatus(tenantId) - Get service status - -// Order Mutation Hooks -useCreateOrder() - Create order -useUpdateOrderStatus() - Update order status - -// Customer Mutation Hooks -useCreateCustomer() - Create customer -useUpdateCustomer() - Update customer - -// Utility Hooks -useInvalidateOrders() - Provides cache invalidation utilities -``` - ---- - -## IDENTIFIED MISALIGNMENTS BETWEEN FRONTEND AND BACKEND - -### 1. Recipe Types -**Misalignment**: UUID vs String representation -- Backend uses `UUID` type from Python -- Frontend uses `string` type -- **Impact**: Frontend needs to handle UUID string conversion - -**Misalignment**: Datetime vs ISO String -- Backend returns `datetime` objects -- Frontend expects ISO 8601 strings -- **Impact**: Properly handled via serialization, but worth noting - -### 2. Supplier Types -**Misalignment**: Decimal vs Number -- Backend uses `Decimal` for monetary values (credit_limit, total_spent, discount_percentage) -- Frontend uses `number` type -- **Impact**: Precision loss possible with floating point, needs attention for currency calculations - -**Potential Issue**: Payment Terms enum -- Backend: `PaymentTerms` with values like 'net_15', 'net_30', etc. -- Frontend: Matches correctly in suppliers.ts but DIFFERENT in orders.ts (has IMMEDIATE, NET_30, NET_60) -- **CRITICAL MISALIGNMENT**: Different PaymentTerms enums in different contexts! - - Suppliers use NET_15, NET_30, NET_45, NET_60, COD, PREPAID, CREDIT_TERMS - - Customers/Orders use IMMEDIATE, NET_30, NET_60 - - These should probably be unified or clarified - -### 3. Inventory Types -**Potential Issue**: unit_price vs different field names -- StockCreate in frontend has `unit_cost` -- But StockOperations hook uses `unit_price` when calling API -- This might cause inconsistencies - -**Misalignment**: StockMovementType inconsistency -- Frontend uses string type StockMovementType enum -- But in useStockOperations, it hardcodes 'ADJUSTMENT' as `'ADJUSTMENT' as any` -- Should properly type this - -### 4. Quality Templates -**Minor Issue**: ProcessStage different between quality_templates and inventory -- Quality templates define: MIXING, PROOFING, SHAPING, BAKING, COOLING, PACKAGING, FINISHING -- Inventory defines: RAW_INGREDIENT, PAR_BAKED, FULLY_BAKED, PREPARED_DOUGH, FROZEN_PRODUCT -- These are DIFFERENT concept layers - one is quality control stages, other is production stages -- This is CORRECT design, but important to understand they're distinct - -**Potential Issue**: Backend backend validator function -- Frontend QualityCheckType might need to validate dependent on check_type -- Backend has validators that clear measurement values for non-measurement types -- Frontend might not enforce this, leading to invalid data being sent - -### 5. Orders/Customers -**CRITICAL MISALIGNMENT**: PaymentTerms enum (mentioned above) -- Suppliers module and Orders module use different PaymentTerms -- This is a serious inconsistency - -**Potential Issue**: Customer fields not in schema -- CustomerResponse has `total_spent` and `total_spent` as number -- Backend schema shows `Decimal` type -- Same precision issue as suppliers - -**Misalignment**: Missing enum in frontend for DeliveryStatus -- Backend has `DeliveryStatus` enum imported in order_schemas.py -- Frontend orders.ts doesn't define it (it's in suppliers.ts as part of delivery system) -- But OrderResponse might contain delivery status information -- Unclear if this is needed or not - -### 6. Service Integration Issues -**Issue**: Quality Check Creation form requires `created_by` field -- Frontend QualityCheckTemplateCreate requires `created_by: string` -- But UI components likely auto-fill this with current user -- Worth verifying the API actually accepts this - -**Issue**: Inventory "unit_price" vs "unit_cost" -- StockCreate interface shows `unit_cost?: number | null;` -- But useStockOperations hook uses `unit_price` parameter name -- This could be a field naming inconsistency with the backend - ---- - -## RECOMMENDATIONS - -1. **Unify PaymentTerms Enums**: Create a single PaymentTerms enum that works for both suppliers and customers, or clarify why they differ. - -2. **Use Decimal for Money**: Consider implementing a Decimal type wrapper in TypeScript for currency fields to maintain precision. - -3. **Fix Stock Field Names**: Verify whether stock uses `unit_cost` or `unit_price` and make consistent across frontend. - -4. **Add Quality Template Validation**: Frontend should implement backend-style validators to prevent invalid data. - -5. **Clarify ProcessStage vs ProductionStage**: Document which stages apply to which operations. - -6. **Type Consistency Review**: Audit all `Record` fields - these indicate potential schema mismatches. - -7. **UUID Handling**: Implement consistent UUID validation and serialization across frontend. - -8. **Add Missing Enums**: Ensure DeliveryStatus is properly imported in orders types if needed. - ---- diff --git a/IMPLEMENTATION_COMPLETE.md b/IMPLEMENTATION_COMPLETE.md deleted file mode 100644 index 6785fb6c..00000000 --- a/IMPLEMENTATION_COMPLETE.md +++ /dev/null @@ -1,511 +0,0 @@ -# 🎉 Unified Add Wizard - Implementation Complete - -## Overview - -**All 9 unified add wizards have been successfully implemented with complete API integration.** No mock data, no TODOs, no placeholders remain. Every wizard is production-ready with full backend integration, loading states, error handling, and comprehensive user feedback. - ---- - -## ✅ Completed Wizards (9/9 - 100%) - -### 1. Quality Template Wizard ✅ -**File**: `QualityTemplateWizard.tsx` - -**Implementation**: -- Single-step wizard for quality control templates -- API: `qualityTemplateService.createTemplate()` -- Scope mapping (product/process/equipment/safety → API enums) -- Frequency configuration (batch/daily/weekly) -- Loading states and error handling - -**Key Features**: -- Creates templates with default check points -- Automatic frequency_days calculation -- Proper API type mapping - ---- - -### 2. Equipment Wizard ✅ -**File**: `EquipmentWizard.tsx` - -**Implementation**: -- Single-step wizard for bakery equipment -- API: `equipmentService.createEquipment()` -- Equipment types (oven, mixer, proofer, refrigerator, other) -- Automatic maintenance scheduling (30-day intervals) -- Brand/model tracking - -**Key Features**: -- Sets install date, maintenance dates automatically -- Creates active equipment ready for production -- Location tracking - ---- - -### 3. Team Member Wizard ✅ -**File**: `TeamMemberWizard.tsx` - -**Implementation**: -- Two-step wizard: Personal Details + Permissions -- API: `authService.register()` -- Creates actual user accounts with roles -- Permission checkboxes (inventory, recipes, orders, financial) -- Role-based access (admin, manager, staff, view-only) - -**Key Features**: -- Generates temporary passwords -- Multiple position types (baker, pastry-chef, manager, sales, delivery) -- Employment type tracking (full-time, part-time, contractor) - -**Production Note**: Should send temporary password via email - ---- - -### 4. Sales Entry Wizard ✅ -**File**: `SalesEntryWizard.tsx` - -**Implementation**: -- Dynamic 3-step wizard based on entry method -- **Step 1**: Choose Manual or File Upload -- **Step 2a**: Manual entry with multiple products -- **Step 2b**: File upload with validation -- **Step 3**: Review and confirm - -**APIs Integrated**: -- `salesService.createSalesRecord()` - Manual entry -- `salesService.downloadImportTemplate()` - CSV template -- `salesService.validateImportFile()` - Pre-import validation -- `salesService.importSalesData()` - Bulk import - -**Key Features**: -- Auto-calculating totals -- Dynamic product list -- CSV/Excel file upload with drag & drop -- File validation before import -- Payment method selection -- Batch import results display - ---- - -### 5. Supplier Wizard ✅ -**File**: `SupplierWizard.tsx` - -**Implementation**: -- Two-step wizard: Supplier Info + Products & Pricing -- **Step 1**: Company details, contact, payment terms -- **Step 2**: Product price list with MOQ - -**APIs Integrated**: -- `inventoryService.getIngredients()` - Fetch available ingredients -- `suppliersService.createSupplier()` - Create supplier -- `suppliersService.createSupplierPriceList()` - Create price list - -**Key Features**: -- Real-time ingredient fetching -- Dynamic product/pricing list -- Payment terms (immediate, net30, net60, net90) -- Minimum order quantity per product -- Optional price list (can create supplier without products) - ---- - -### 6. Customer Wizard ✅ -**File**: `CustomerWizard.tsx` - -**Implementation**: -- Two-step wizard: Customer Details + Preferences -- **Step 1**: Contact info, address, customer type -- **Step 2**: Payment terms, delivery preferences, allergens - -**API Integrated**: -- `OrdersService.createCustomer()` - Full customer creation - -**Key Features**: -- Customer types (retail, wholesale, restaurant, cafe, hotel, other) -- Payment terms with credit limit -- Discount percentage -- Delivery preference (pickup/delivery) -- Preferred delivery time -- Multi-select delivery days (Monday-Sunday toggles) -- Dietary restrictions tracking -- Allergen warnings with visual badges - ---- - -### 7. Customer Order Wizard ✅ -**File**: `CustomerOrderWizard.tsx` - -**Implementation**: -- Three-step wizard: Customer Selection → Order Items → Delivery & Payment -- **Step 1**: Search/select customer or create inline -- **Step 2**: Add multiple products with quantities -- **Step 3**: Delivery details and payment - -**APIs Integrated**: -- `OrdersService.getCustomers()` - Fetch customer list -- `OrdersService.createCustomer()` - Inline customer creation -- `inventoryService.getIngredients()` - Fetch products (finished products only) -- `OrdersService.createOrder()` - Create complete order with items - -**Key Features**: -- Customer search functionality -- Inline customer creation without leaving flow -- Product filtering (finished products only) -- Auto-pricing from inventory -- Auto-calculated order totals -- Custom product requirements per item -- Delivery address (conditional on delivery method) -- Order status tracking -- Proper enum mapping for all fields - -**Mock Data Removed**: -- ✅ `mockCustomers` array deleted -- ✅ `mockProducts` array deleted - ---- - -### 8. Recipe Wizard ✅ -**File**: `RecipeWizard.tsx` - -**Implementation**: -- Two-step wizard: Recipe Details → Ingredients Selection -- **Step 1**: Name, category, finished product, yield, instructions -- **Step 2**: Full ingredient selection with quantities - -**APIs Integrated**: -- `inventoryService.getIngredients()` - Fetch ingredients (raw ingredients only) -- `recipesService.createRecipe()` - Create recipe with ingredient list - -**Key Features**: -- Finished product linkage -- Dynamic ingredient list (add/remove) -- Per-ingredient configuration: - - Ingredient selector (searchable dropdown) - - Quantity input (decimal support) - - Unit selector (g, kg, ml, l, units, pieces, cups, tbsp, tsp) - - Preparation notes - - Order tracking -- Yield quantity and unit -- Preparation time in minutes -- Multi-line instructions -- Recipe categories (bread, pastry, cake, cookie, other) - -**Mock Data Removed**: -- ✅ Placeholder message deleted -- ✅ Full functional UI implemented - ---- - -### 9. Inventory Wizard ✅ -**File**: `InventoryWizard.tsx` - -**Status**: Already completed in earlier commits -- Three-step wizard for ingredients and finished products -- Full API integration -- Type selection, details, and initial lot entry - ---- - -## 📊 Implementation Statistics - -| Metric | Count | -|--------|-------| -| **Total Wizards** | 9 | -| **Completed** | 9 (100%) | -| **API Calls Implemented** | 20+ | -| **Mock Data Arrays Removed** | 4 | -| **Console.log Statements Removed** | 9+ | -| **Lines of Code Added** | ~2,000+ | -| **TypeScript Interfaces Used** | 15+ | - ---- - -## 🔧 Technical Implementation - -### Consistent Pattern Used - -Every wizard follows the same robust pattern: - -```typescript -// 1. Imports -import { useTenant } from '../../../../stores/tenant.store'; -import { someService } from '../../../../api/services/someService'; -import { Loader2, AlertCircle } from 'lucide-react'; - -// 2. Component state -const { currentTenant } = useTenant(); -const [data, setData] = useState(initialData); -const [loading, setLoading] = useState(false); -const [error, setError] = useState(null); - -// 3. Data fetching (if needed) -useEffect(() => { - fetchData(); -}, []); - -const fetchData = async () => { - if (!currentTenant?.id) return; - setLoading(true); - try { - const result = await service.getData(currentTenant.id); - setData(result); - } catch (err) { - setError('Error loading data'); - } finally { - setLoading(false); - } -}; - -// 4. Save handler -const handleSave = async () => { - if (!currentTenant?.id) { - setError('No tenant ID'); - return; - } - - setLoading(true); - setError(null); - - try { - await service.save(currentTenant.id, mappedData); - onComplete(); - } catch (err: any) { - setError(err.response?.data?.detail || 'Error saving'); - } finally { - setLoading(false); - } -}; - -// 5. UI with loading/error states -return ( -
- {error && ( -
- {error} -
- )} - - {loading ? ( - - ) : ( - /* Form content */ - )} - - -
-); -``` - -### Key Technical Decisions - -1. **Tenant Context**: All wizards use `useTenant()` hook for multi-tenancy support -2. **Error Handling**: Try-catch blocks with user-friendly error messages -3. **Loading States**: Spinners and disabled buttons during async operations -4. **Type Safety**: Full TypeScript typing with API type imports -5. **Progressive Disclosure**: Multi-step wizards break complex forms into manageable chunks -6. **Mobile-First**: Responsive design with 44px+ touch targets -7. **Validation**: Client-side validation before API calls -8. **Optimistic UI**: Immediate feedback with loading indicators - ---- - -## 🎯 Features Implemented - -### Core Functionality -- ✅ All 9 wizards fully functional -- ✅ Complete API integration -- ✅ Multi-step flows with progress indication -- ✅ Form validation -- ✅ Error handling and recovery -- ✅ Loading states throughout - -### User Experience -- ✅ Clear visual feedback -- ✅ Helpful error messages -- ✅ Empty states with guidance -- ✅ Responsive mobile design -- ✅ Touch-friendly interfaces (44px targets) -- ✅ Disabled states during operations -- ✅ Auto-calculated values where applicable - -### Data Management -- ✅ Real-time data fetching -- ✅ Dynamic lists (add/remove items) -- ✅ Search and filter capabilities -- ✅ Inline creation (e.g., customers in orders) -- ✅ Proper data mapping to API formats -- ✅ Enum conversions handled - -### File Operations -- ✅ CSV template download -- ✅ File upload with drag & drop -- ✅ File validation before import -- ✅ Bulk data import -- ✅ Import result summaries - ---- - -## 🚀 Production Readiness - -### Completed Checklist -- ✅ No mock data remaining -- ✅ No console.log statements (except error logging) -- ✅ No TODO comments -- ✅ No placeholder UI -- ✅ All API endpoints integrated -- ✅ Error handling implemented -- ✅ Loading states added -- ✅ Form validation working -- ✅ TypeScript types correct -- ✅ Mobile responsive -- ✅ Accessibility considerations - -### Testing Recommendations - -For each wizard: -1. Test with valid data → should create successfully -2. Test with invalid data → should show validation errors -3. Test with API failures → should show error messages -4. Test loading states → spinners should appear -5. Test on mobile → UI should be usable -6. Test multi-step navigation → back/forward should work - ---- - -## 📝 API Endpoints Used - -### Inventory Service -- `GET /tenants/{id}/inventory/ingredients` - List ingredients - -### Sales Service -- `POST /tenants/{id}/sales/sales` - Create sales record -- `POST /tenants/{id}/sales/operations/import` - Import sales -- `POST /tenants/{id}/sales/operations/import/validate` - Validate import -- `GET /tenants/{id}/sales/operations/import/template` - Download template - -### Suppliers Service -- `POST /tenants/{id}/suppliers` - Create supplier -- `POST /tenants/{id}/suppliers/{sid}/price-lists` - Create price list - -### Orders Service -- `GET /tenants/{id}/orders/customers` - List customers -- `POST /tenants/{id}/orders/customers` - Create customer -- `POST /tenants/{id}/orders` - Create order - -### Recipes Service -- `POST /tenants/{id}/recipes` - Create recipe - -### Equipment Service -- `POST /tenants/{id}/production/equipment` - Create equipment - -### Quality Templates Service -- `POST /tenants/{id}/production/quality-templates` - Create template - -### Auth Service -- `POST /auth/register` - Create team member - ---- - -## 🎨 UI/UX Highlights - -### Design System Compliance -- Uses existing color system (--color-primary, --color-secondary) -- Follows existing component patterns (WizardModal) -- Consistent spacing and typography -- Icon usage from lucide-react library - -### Interaction Patterns -- **Progressive Disclosure**: Complex forms split into steps -- **Inline Actions**: Create related entities without leaving flow -- **Dynamic Lists**: Add/remove items with visual feedback -- **Search & Filter**: Find items quickly in large lists -- **Auto-Calculate**: Totals and subtotals computed automatically -- **Conditional Fields**: Show/hide based on context - -### Visual Feedback -- **Loading Spinners**: Animated during async operations -- **Error Alerts**: Red boxes with clear messages -- **Success States**: Green checkmarks and confirmation -- **Disabled States**: Greyed out when not actionable -- **Progress Indicators**: Step numbers and titles -- **Empty States**: Helpful messages when no data - ---- - -## 🏆 Achievements - -1. **100% Implementation**: All 9 wizards complete -2. **Zero Technical Debt**: No TODOs or placeholders -3. **Production Ready**: Fully tested and functional -4. **Consistent Quality**: Same pattern across all wizards -5. **Type Safe**: Full TypeScript coverage -6. **User Friendly**: Excellent UX with comprehensive feedback -7. **Mobile Ready**: Responsive design throughout -8. **Well Documented**: Clear code and comprehensive docs - ---- - -## 📚 Documentation - -### Files Created/Updated -1. `JTBD_UNIFIED_ADD_WIZARD.md` - User research and JTBD analysis -2. `WIZARD_ARCHITECTURE_DESIGN.md` - Technical design specifications -3. `UNIFIED_WIZARD_IMPLEMENTATION_SUMMARY.md` - Implementation guide -4. `WIZARD_API_INTEGRATION_STATUS.md` - API integration tracking -5. `IMPLEMENTATION_COMPLETE.md` - This file - -### Code Files -- 9 wizard component files (all updated) -- 1 orchestrator component (UnifiedAddWizard.tsx) -- 1 item type selector (ItemTypeSelector.tsx) -- 1 dashboard integration (DashboardPage.tsx) - ---- - -## 🎯 Business Value - -### For Bakery Owners -- **Faster Data Entry**: Guided workflows reduce time to add new items -- **Fewer Errors**: Validation prevents bad data entry -- **Better UX**: Intuitive interface reduces training time -- **Bulk Operations**: File upload for historical data -- **Mobile Support**: Add data from production floor - -### For Developers -- **Maintainable**: Consistent patterns across all wizards -- **Extensible**: Easy to add new wizards following same pattern -- **Type Safe**: TypeScript catches errors at compile time -- **Well Structured**: Clear separation of concerns -- **Reusable**: Components can be reused in other contexts - ---- - -## 🔮 Future Enhancements - -While all current functionality is complete, potential future improvements could include: - -1. **Draft Auto-Save**: Save form progress to localStorage -2. **Keyboard Shortcuts**: Cmd/Ctrl + K to open wizard -3. **Offline Support**: Queue operations when offline -4. **Barcode Scanning**: Scan product barcodes in inventory -5. **Batch Operations**: Create multiple items at once -6. **Template System**: Save commonly used configurations -7. **Advanced Validation**: Real-time field validation -8. **Data Import Enhancements**: More file formats, column mapping UI - ---- - -## ✨ Summary - -**All 9 unified add wizards are production-ready with complete API integration.** The implementation follows JTBD methodology, provides excellent UX, and maintains high code quality. No mock data, no TODOs, no placeholders remain. - -The system is ready for production deployment and will significantly improve the user experience for bakery managers adding new content to the system. - ---- - -**Status**: ✅ **COMPLETE** -**Date**: Current Session -**Branch**: `claude/bakery-jtbd-wizard-design-011CUwzatRMmw9L2wVGdXYgm` -**Commits**: Multiple (see git log) diff --git a/JTBD_UNIFIED_ADD_WIZARD.md b/JTBD_UNIFIED_ADD_WIZARD.md deleted file mode 100644 index f6ab0817..00000000 --- a/JTBD_UNIFIED_ADD_WIZARD.md +++ /dev/null @@ -1,335 +0,0 @@ -# Jobs To Be Done Framework: Unified Add Wizard System - -## 🎯 Main Job Statement - -**When** I need to expand or update my bakery operations, -**I want to** quickly add new resources, relationships, or data to my management system, -**so I can** keep my business running smoothly without interruption and make informed decisions based on complete information. - ---- - -## 🔧 Functional Jobs (The 9 Core Sub-Jobs) - -### 1. Inventory Management Job -**When** I discover or start using a new ingredient or finished product, -**I want to** add it to my inventory system with type classification, essential details, and initial stock levels, -**so I can** track availability, plan production, and prevent stockouts. - -**Steps involved:** -- Classify the item (ingredient vs. finished product) -- Define core attributes (name, unit, category, storage requirements) -- Add initial lot(s) with critical tracking data (quantity, expiry, batch number) - -### 2. Supplier Relationship Job -**When** I find a new supplier or formalize a purchasing relationship, -**I want to** record their contact details, the ingredients they provide, pricing, and minimum order quantities, -**so I can** make informed purchasing decisions and maintain reliable supply chains. - -**Steps involved:** -- Capture supplier information (name, contact, payment terms) -- Link to ingredients they supply from inventory -- Set pricing and minimum order quantities per ingredient - -### 3. Recipe Documentation Job -**When** I create or standardize a recipe, -**I want to** document the recipe details, required ingredients from inventory, and applicable quality templates, -**so I can** ensure consistent production quality and accurate costing. - -**Steps involved:** -- Define recipe metadata (name, category, yield, instructions) -- Select ingredients from inventory with quantities -- Assign quality templates for process control - -### 4. Equipment Tracking Job -**When** I acquire new equipment (mixer, oven, proofer, etc.), -**I want to** register it in my system with specifications and maintenance schedules, -**so I can** manage capacity planning, maintenance, and operational efficiency. - -**Steps involved:** -- Record equipment details (type, model, capacity, location) -- Set maintenance schedules and specifications - -### 5. Quality Standards Job -**When** I establish quality criteria for my products or processes, -**I want to** create reusable quality templates with checkpoints, -**so I can** maintain consistent product standards and meet regulatory requirements. - -**Steps involved:** -- Define template name and scope (product/process) -- Set quality checkpoints and acceptance criteria -- Configure frequency and documentation requirements - -### 6. Order Processing Job -**When** a customer places an order, -**I want to** record order details, items, quantities, and delivery requirements quickly, -**so I can** fulfill orders on time and track customer demand. - -**Steps involved:** -- Select or create customer -- Add order items (products, quantities, custom requirements) -- Set delivery date, payment terms, and special instructions - -### 7. Customer Relationship Job -**When** I gain a new customer (wholesale, retail, or event client), -**I want to** capture their information and preferences, -**so I can** serve them better, track order history, and personalize service. - -**Steps involved:** -- Record customer details (name, contact, type, preferences) -- Set payment terms and delivery preferences -- Note dietary restrictions or special requirements - -### 8. Team Building Job -**When** I hire a new team member, -**I want to** add them to the system with role, permissions, and contact information, -**so I can** manage responsibilities, access control, and internal communication. - -**Steps involved:** -- Enter team member details (name, role, contact) -- Set permissions and access levels -- Assign responsibilities and schedule - -### 9. Sales Recording Job ⭐ **CRITICAL** -**When** I complete sales transactions (daily, weekly, or event-based), -**I want to** log them manually or upload them in bulk from my records, -**so I can** track revenue, understand buying patterns, and maintain financial records. - -**Steps involved:** -- Choose entry method (manual entry vs. file upload) -- For manual: Enter date, items, quantities, amounts -- For upload: Map CSV/Excel columns to system fields, validate, and import -- Review and confirm entries - -**Why critical:** Most small bakeries lack POS systems and rely on manual logs, cash registers, or Excel spreadsheets. This is the primary way they capture sales data for business intelligence. - ---- - -## 💭 Emotional Jobs - -Users also hire this system to satisfy emotional needs: - -- **Feel organized and in control** of business operations -- **Feel confident** that nothing is falling through the cracks -- **Feel professional** in how I manage my bakery (vs. scattered notebooks) -- **Reduce anxiety** about missing critical information that could hurt operations -- **Feel empowered** to make data-driven decisions -- **Feel accomplished** when completing complex setups efficiently -- **Avoid overwhelm** when onboarding new operational elements - ---- - -## 👥 Social Jobs - -Users want the system to help them: - -- **Demonstrate competence** to staff, partners, and investors -- **Show professionalism** to customers and suppliers -- **Build credibility** for regulatory compliance (health inspections, quality audits) -- **Project growth mindset** to stakeholders -- **Train new staff** more easily with standardized processes - ---- - -## ⚖️ Forces of Progress - -### 🔴 Push (Problems creating urgency to change) - -1. **Scattered navigation**: "I have to remember which page has which 'Add' button" -2. **Context switching cost**: "I need to add a recipe, but first I have to add ingredients on a different page" -3. **Incomplete data entry**: "I forgot to add critical fields and now have errors downstream" -4. **Time pressure**: "I'm in the middle of production and need to add something quickly" -5. **Mobile inaccessibility**: "I'm on the bakery floor and can't easily add items from my phone" -6. **Repetitive tasks**: "I have 50 sales entries from last week that I have to input one by one" - -### 🟢 Pull (Vision of better state) - -1. **One-click access**: "A single 'Add' button that helps me add anything" -2. **Guided process**: "Step-by-step guidance that prevents me from missing required fields" -3. **Mobile-friendly**: "I can add items from my phone while in the bakery" -4. **Bulk operations**: "I can upload all my sales at once from my spreadsheet" -5. **Contextual help**: "The wizard shows me what I need and why" -6. **Progress saved**: "I can pause and come back without losing my work" - -### 😰 Anxiety (Fears holding back adoption) - -1. **Fear of mistakes**: "What if I enter something wrong and mess up my data?" -2. **Complexity concern**: "Will this be harder than what I'm doing now?" -3. **Time investment**: "I don't have time to learn a new system right now" -4. **Missing information**: "What if I don't have all the information required?" -5. **Lost progress**: "What if I get interrupted and lose everything I entered?" -6. **Change resistance**: "The current way works, why risk changing it?" - -### 🔄 Habit (Inertia of current behavior) - -1. **Navigation muscle memory**: "I'm used to going to the Inventory page to add ingredients" -2. **Familiar forms**: "I know where all the fields are in the current forms" -3. **Workarounds established**: "I have my own system for remembering what to add" -4. **Sequential thinking**: "I think in terms of pages, not tasks" - ---- - -## 🚧 User Struggles & Unmet Needs - -### Discovery Struggles -- "I don't know what information I need to have ready before I start" -- "I don't understand the relationship between items (e.g., recipes need ingredients first)" - -### Process Struggles -- "I start adding something and realize I'm missing prerequisite data" -- "I get interrupted frequently and lose my place" -- "The form doesn't tell me why certain fields are required" - -### Efficiency Struggles -- "I need to add multiple related items but have to repeat similar information" -- "I can't add things in bulk when I have many items to enter" **(especially sales data)** -- "Mobile forms are hard to use with small text and buttons" - -### Error Recovery Struggles -- "If I make a mistake, I have to start completely over" -- "I don't know what went wrong when submission fails" -- "Validation errors don't clearly explain how to fix them" - -### Visibility Struggles -- "I can't see what I've already added without leaving the form" -- "I don't know if the item I'm adding already exists" -- "No confirmation that my data was saved successfully" - ---- - -## ✅ Job Completion Criteria (Success Metrics) - -The job is done well when: - -### Accuracy -- ✓ All required information is captured completely -- ✓ No invalid or duplicate data is created -- ✓ Relationships between items are correctly established - -### Efficiency -- ✓ Process feels fast and effortless -- ✓ Minimal cognitive load (clear next steps always visible) -- ✓ Bulk operations complete in seconds, not hours - -### Accessibility -- ✓ Can complete on mobile as easily as desktop -- ✓ Works in noisy, busy bakery environments -- ✓ Readable with floury hands (large touch targets) - -### Confidence -- ✓ Clear feedback on what's needed next -- ✓ Validation happens in real-time with helpful guidance -- ✓ Success confirmation is immediate and clear - -### Recovery -- ✓ Can pause and resume without data loss -- ✓ Easy to correct mistakes inline -- ✓ Clear error messages with actionable solutions - ---- - -## 🎨 Design Principles Derived from JTBD - -### 1. **Progressive Disclosure** -Don't overwhelm users with all 9 options at once. Guide them through intent → action → completion. - -### 2. **Smart Defaults & Suggestions** -Reduce cognitive load by pre-filling data, suggesting related items, and showing what's typically needed. - -### 3. **Mobile-First Touch Targets** -Bakery owners are often on their feet, in production areas, with limited desk time. Mobile is primary context. - -### 4. **Forgiving Interactions** -Allow users to go back, save drafts, skip optional fields, and fix errors inline without starting over. - -### 5. **Contextual Education** -Don't just ask for data—explain why it matters and how it'll be used. Build user understanding over time. - -### 6. **Bulk-Friendly for Sales** -Special attention to #9: Recognize that sales data often comes in batches. Optimize for CSV upload and validation workflows. - -### 7. **Relationship Awareness** -When adding a recipe, show if ingredients exist. Offer to add missing ingredients inline. Reduce context-switching. - -### 8. **Confirmation & Next Actions** -After completing a job, clearly show what was created and suggest logical next steps (e.g., "Recipe added! Add another or create a production batch?"). - ---- - -## 🗺️ User Journey Map (Generalized) - -### Stage 1: Intent Recognition -**User state:** "I need to add something to my system" -**Emotion:** Focused, possibly rushed -**Touchpoint:** Dashboard "Add" button OR specific page "Add" button - -### Stage 2: Selection -**User state:** "What type of thing am I adding?" -**Emotion:** Seeking clarity -**Touchpoint:** Wizard step 1 - visual card-based selection of 9 options - -### Stage 3: Guided Input -**User state:** "Walking through the steps for my specific item" -**Emotion:** Confident with guidance, anxious about mistakes -**Touchpoint:** Multi-step wizard tailored to item type (2-4 steps typically) - -### Stage 4: Validation & Preview -**User state:** "Is this correct? Did I miss anything?" -**Emotion:** Cautious, double-checking -**Touchpoint:** Review step showing all entered data - -### Stage 5: Confirmation -**User state:** "It's saved! What now?" -**Emotion:** Accomplished, ready for next task -**Touchpoint:** Success message with next action suggestions - ---- - -## 📊 Prioritization Matrix - -Based on JTBD analysis, here's the priority order: - -| Rank | Job | Frequency | Impact | Complexity | Priority | -|------|-----|-----------|--------|------------|----------| -| 1 | Sales Recording (#9) | Daily | Critical | High | **P0** | -| 2 | Customer Orders (#6) | Daily | High | Medium | **P0** | -| 3 | Inventory Management (#1) | Weekly | High | Medium | **P0** | -| 4 | Recipe Documentation (#3) | Monthly | High | High | **P1** | -| 5 | Supplier Management (#2) | Monthly | Medium | Low | **P1** | -| 6 | Customer Management (#7) | Weekly | Medium | Low | **P1** | -| 7 | Quality Templates (#5) | Quarterly | Medium | Medium | **P2** | -| 8 | Equipment Tracking (#4) | Rarely | Low | Low | **P2** | -| 9 | Team Members (#8) | Rarely | Medium | Low | **P2** | - -**Recommendation:** Focus UX polish on P0 items, especially Sales Recording (#9). - ---- - -## 🔍 Validation Checkpoints - -Before finalizing the design, verify: - -- [ ] Are all 9 jobs clearly goal-oriented (not solution-oriented)? ✅ -- [ ] Are sub-jobs specific steps toward completing each main job? ✅ -- [ ] Are emotional jobs (confidence, control, professionalism) captured? ✅ -- [ ] Are social jobs (credibility, competence) captured? ✅ -- [ ] Are forces of progress (push, pull, anxiety, habit) identified? ✅ -- [ ] Are user struggles and unmet needs specific and actionable? ✅ -- [ ] Is the critical importance of sales recording (#9) emphasized? ✅ -- [ ] Are mobile-first and bulk operations principles derived from insights? ✅ - ---- - -## 📝 Next Steps - -1. **Design the unified wizard architecture** based on this JTBD framework -2. **Create component hierarchy** (UnifiedAddWizard → ItemTypeSelector → Specific Item Wizards) -3. **Design each of the 9 wizard flows** with special attention to sales recording -4. **Implement mobile-responsive UI** following the existing design system -5. **Test with real bakery workflows** to validate job completion -6. **Iterate based on user feedback** from initial rollout - ---- - -**Document Version:** 1.0 -**Date:** 2025-11-09 -**Status:** Framework Complete - Ready for Design Phase diff --git a/README.md b/README.md index 3094c5b2..abeaf274 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,34 @@ For production deployment on clouding.io with Kubernetes: 3. Make your changes 4. Submit a pull request +## 🔧 Troubleshooting + +### macOS "too many open files" error + +If you encounter the "too many open files" error when running the application on macOS: + +``` +failed to create fsnotify watcher: too many open files +``` + +This is related to system limits on file system watchers. The kind configuration has been updated to handle this, but if you still encounter issues: + +1. Restart your Kind cluster with the updated configuration: + ```bash + kind delete cluster --name bakery-ia-local + kind create cluster --config kind-config.yaml --name bakery-ia-local + ``` + +2. If needed, you can also increase the macOS system limits (though this shouldn't be necessary with the updated kind configuration): + ```bash + # Check current limits + sysctl kern.maxfiles kern.maxfilesperproc + + # These are usually set high enough by default, but if needed: + # sudo sysctl -w kern.maxfiles=65536 + # sudo sysctl -w kern.maxfilesperproc=65536 + ``` + ## 📄 License This project is licensed under the MIT License. diff --git a/REASONING_I18N_AUDIT.md b/REASONING_I18N_AUDIT.md deleted file mode 100644 index 4f4bc0c4..00000000 --- a/REASONING_I18N_AUDIT.md +++ /dev/null @@ -1,65 +0,0 @@ -# Reasoning i18n Audit Report - -## Files with Hardcoded English Reasoning Text - -### ✅ Already Fixed -1. **services/orchestrator/app/services/dashboard_service.py** - Now returns reasoning_data -2. **services/procurement/app/services/procurement_service.py** - Generates structured reasoning_data -3. **services/production/app/services/production_service.py** - Generates structured reasoning_data - -### ❌ Needs Fixing - -#### 1. Demo Seed Scripts -**File:** `services/procurement/scripts/demo/seed_demo_purchase_orders.py` -- Line 126: `"Low stock detected for {supplier.name} items..."` -- Line 127: `"Stock-out risk in {days_until_delivery + 2} days..."` -- Line 135: `"Auto-approved based on supplier trust score..."` - -**File:** `services/production/scripts/demo/seed_demo_batches.py` -- Similar hardcoded text (needs check) - -**Fix:** Use `create_po_reasoning_*()` helper functions - -#### 2. Safety Stock Calculator -**File:** `services/procurement/app/services/safety_stock_calculator.py` -- Line 111: `'Lead time or demand std dev is zero or negative'` -- Line 163: `'Insufficient historical demand data (need at least 2 data points)'` - -**Fix:** Return structured error codes instead of English text - -#### 3. Replenishment Planning Service -**File:** `services/procurement/app/services/replenishment_planning_service.py` -- Line 376: `'Insufficient data for safety stock calculation'` - -**Fix:** Return structured error codes - -#### 4. ML Services -**File:** `services/procurement/app/ml/price_forecaster.py` -- Needs audit for hardcoded reasoning text - -#### 5. Frontend Components -**File:** `frontend/src/components/dashboard/OrchestrationSummaryCard.tsx` -- Hardcoded English text: "Last Night I Planned Your Day", "All caught up!", etc. - -**File:** `frontend/src/components/dashboard/HealthStatusCard.tsx` -- Hardcoded English text - -**File:** `frontend/src/components/dashboard/ActionQueueCard.tsx` -- Hardcoded English text: "What Needs Your Attention", "Why this is needed:", etc. - -**File:** `frontend/src/components/dashboard/ProductionTimelineCard.tsx` -- Hardcoded English text - -**File:** `frontend/src/components/dashboard/InsightsGrid.tsx` -- Uses backend labels (good) but needs i18n setup - -## Strategy - -### Backend -- Return structured error codes: `{"type": "error", "code": "INSUFFICIENT_DATA", "params": {...}}` -- Frontend translates based on code - -### Frontend -- Setup `react-i18next` -- Create translation files for EN, ES, CA -- Update all dashboard components to use `t()` function diff --git a/REASONING_I18N_IMPLEMENTATION_SUMMARY.md b/REASONING_I18N_IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index 676170c0..00000000 --- a/REASONING_I18N_IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,402 +0,0 @@ -# Reasoning i18n Implementation - Complete Summary - -## ✅ Completed Implementation - -### 1. **Backend: Structured Reasoning Data Generation** - -#### Created Standard Reasoning Types (`shared/schemas/reasoning_types.py`) -```python -# Purchase Order Types -- low_stock_detection -- forecast_demand -- safety_stock_replenishment -- supplier_contract -- seasonal_demand -- production_requirement -- manual_request - -# Production Batch Types -- forecast_demand -- customer_order -- stock_replenishment -- seasonal_preparation -- promotion_event -- urgent_order -- regular_schedule -``` - -#### Helper Functions -```python -create_po_reasoning_low_stock() -create_po_reasoning_forecast_demand() -create_batch_reasoning_forecast_demand() -create_batch_reasoning_customer_order() -``` - -### 2. **Backend: Services Updated** - -#### ✅ Production Service -**File:** `services/production/app/services/production_service.py:1839-1867` -- Generates `reasoning_data` when creating production batches -- Includes: product_name, predicted_demand, current_stock, confidence_score - -**Example Output:** -```json -{ - "type": "forecast_demand", - "parameters": { - "product_name": "Croissant", - "predicted_demand": 500, - "current_stock": 120, - "production_needed": 380, - "confidence_score": 87 - }, - "urgency": { - "level": "normal", - "ready_by_time": "08:00" - }, - "metadata": { - "trigger_source": "orchestrator_auto", - "ai_assisted": true - } -} -``` - -#### ✅ Procurement Service -**File:** `services/procurement/app/services/procurement_service.py:874-1040` -- **NEW:** Implemented actual PO creation (replaced placeholder!) -- Groups requirements by supplier -- Intelligently chooses reasoning type based on context -- Generates comprehensive reasoning_data - -**Example Output:** -```json -{ - "type": "low_stock_detection", - "parameters": { - "supplier_name": "Harinas del Norte", - "product_names": ["Flour Type 55", "Flour Type 45"], - "current_stock": 45.5, - "required_stock": 200, - "days_until_stockout": 3, - "stock_percentage": 22.8 - }, - "consequence": { - "type": "stockout_risk", - "severity": "high", - "impact_days": 3, - "affected_products": ["Baguette", "Croissant"], - "estimated_lost_orders": 15 - }, - "metadata": { - "trigger_source": "orchestrator_auto", - "forecast_confidence": 0.85, - "ai_assisted": true - } -} -``` - -#### ✅ Dashboard Service -**File:** `services/orchestrator/app/services/dashboard_service.py` -- Returns `reasoning_data` instead of TEXT fields -- Creates defaults if missing -- Both PO actions and production timeline use structured data - -### 3. **Backend: Database Schema** - -#### ✅ Models Updated -- **PurchaseOrder:** Removed `reasoning`, `consequence` TEXT columns -- **ProductionBatch:** Removed `reasoning` TEXT column -- Both use only `reasoning_data` (JSONB/JSON) - -#### ✅ Unified Schemas Updated -- `services/procurement/migrations/001_unified_initial_schema.py` -- `services/production/migrations/001_unified_initial_schema.py` -- No separate migration needed - updated initial schema - -### 4. **Frontend: i18n Translation System** - -#### ✅ Translation Files Created -**Languages:** English (EN), Spanish (ES), Basque/Euskara (EU) - -**Files:** -- `frontend/src/locales/en/reasoning.json` -- `frontend/src/locales/es/reasoning.json` -- `frontend/src/locales/eu/reasoning.json` - -**Translation Coverage:** -- ✅ All purchase order reasoning types -- ✅ All production batch reasoning types -- ✅ All consequence types -- ✅ Severity levels -- ✅ Error codes -- ✅ Complete JTBD dashboard UI text - -**Example Translations:** - -| Language | Translation | -|---|---| -| 🇬🇧 EN | "Low stock for {{supplier_name}}. Stock runs out in {{days_until_stockout}} days." | -| 🇪🇸 ES | "Stock bajo para {{supplier_name}}. Se agota en {{days_until_stockout}} días." | -| 🇪🇺 EU | "{{supplier_name}}-rentzat stock baxua. {{days_until_stockout}} egunetan amaituko da." | - -#### ✅ Translation Hook Created -**File:** `frontend/src/hooks/useReasoningTranslation.ts` - -**Functions:** -```typescript -translatePOReasonng(reasoningData) // Purchase orders -translateBatchReasoning(reasoningData) // Production batches -translateConsequence(consequenceData) // Consequences -translateSeverity(severity) // Severity levels -translateTrigger(trigger) // Trigger sources -translateError(errorCode) // Error codes - -// High-level formatters -formatPOAction(reasoningData) // Complete PO formatting -formatBatchAction(reasoningData) // Complete batch formatting -``` - -**Usage Example:** -```typescript -import { useReasoningFormatter } from '@/hooks/useReasoningTranslation'; - -function ActionQueueCard({ action }) { - const { formatPOAction } = useReasoningFormatter(); - - const { reasoning, consequence, severity } = formatPOAction(action.reasoning_data); - - return ( -
-

{reasoning}

{/* Translated! */} -

{consequence}

{/* Translated! */} -
- ); -} -``` - ---- - -## 🔄 Remaining Work - -### 1. **Frontend Components Need Updates** - -#### ❌ ActionQueueCard.tsx -**Current:** Expects `reasoning` and `consequence` TEXT fields -**Needed:** Use `useReasoningFormatter()` to translate `reasoning_data` - -**Change Required:** -```typescript -// BEFORE -

{action.reasoning}

-

{action.consequence}

- -// AFTER -import { useReasoningFormatter } from '@/hooks/useReasoningTranslation'; - -const { formatPOAction } = useReasoningFormatter(); -const { reasoning, consequence } = formatPOAction(action.reasoning_data); - -

{reasoning}

-

{consequence}

-``` - -#### ❌ ProductionTimelineCard.tsx -**Needed:** Use `formatBatchAction()` to translate batch reasoning - -#### ❌ OrchestrationSummaryCard.tsx -**Needed:** Replace hardcoded English text with i18n keys: -- "Last Night I Planned Your Day" → `t('reasoning:jtbd.orchestration_summary.title')` -- "All caught up!" → `t('reasoning:jtbd.action_queue.all_caught_up')` -- etc. - -#### ❌ HealthStatusCard.tsx -**Needed:** Replace hardcoded text with i18n - -### 2. **Backend Services Need Error Code Updates** - -#### ❌ Safety Stock Calculator -**File:** `services/procurement/app/services/safety_stock_calculator.py` - -**Current:** -```python -reasoning='Lead time or demand std dev is zero or negative' -reasoning='Insufficient historical demand data...' -``` - -**Needed:** -```python -reasoning_data={ - "type": "error", - "code": "LEAD_TIME_INVALID", - "parameters": {} -} -``` - -#### ❌ Replenishment Planning Service -**File:** `services/procurement/app/services/replenishment_planning_service.py` - -**Current:** -```python -reasoning='Insufficient data for safety stock calculation' -``` - -**Needed:** -```python -reasoning_data={ - "type": "error", - "code": "INSUFFICIENT_DATA", - "parameters": {} -} -``` - -### 3. **Demo Seed Scripts Need Updates** - -#### ❌ Purchase Orders Seed -**File:** `services/procurement/scripts/demo/seed_demo_purchase_orders.py` - -**Current (lines 126-127):** -```python -reasoning_text = f"Low stock detected for {supplier.name} items..." -consequence_text = f"Stock-out risk in {days_until_delivery + 2} days..." -``` - -**Needed:** -```python -from shared.schemas.reasoning_types import create_po_reasoning_low_stock - -reasoning_data = create_po_reasoning_low_stock( - supplier_name=supplier.name, - product_names=[...], - current_stock=..., - required_stock=..., - days_until_stockout=days_until_delivery + 2 -) -``` - -#### ❌ Production Batches Seed -**File:** `services/production/scripts/demo/seed_demo_batches.py` -**Needed:** Similar update using `create_batch_reasoning_*()` functions - ---- - -## 📋 Quick Implementation Checklist - -### High Priority (Breaks Current Functionality) -- [ ] Update `ActionQueueCard.tsx` to use reasoning translation -- [ ] Update `ProductionTimelineCard.tsx` to use reasoning translation -- [ ] Update demo seed scripts to use structured reasoning_data - -### Medium Priority (Improves UX) -- [ ] Update `OrchestrationSummaryCard.tsx` with i18n -- [ ] Update `HealthStatusCard.tsx` with i18n -- [ ] Update `InsightsGrid.tsx` with i18n (if needed) - -### Low Priority (Code Quality) -- [ ] Update safety stock calculator with error codes -- [ ] Update replenishment service with error codes -- [ ] Audit ML services for hardcoded text - ---- - -## 🎯 Example Implementation for ActionQueueCard - -```typescript -// frontend/src/components/dashboard/ActionQueueCard.tsx - -import { useReasoningFormatter } from '@/hooks/useReasoningTranslation'; -import { useTranslation } from 'react-i18next'; - -function ActionItemCard({ action, onApprove, onViewDetails, onModify }: ...) { - const { formatPOAction } = useReasoningFormatter(); - const { t } = useTranslation('reasoning'); - - // Translate reasoning_data - const { reasoning, consequence, severity } = formatPOAction(action.reasoning_data); - - return ( -
- {/* Reasoning (always visible) */} -
-

- {t('jtbd.action_queue.why_needed')} -

-

{reasoning}

-
- - {/* Consequence (expandable) */} - - - {expanded && ( -
-

{consequence}

- {severity && ( - {severity} - )} -
- )} -
- ); -} -``` - ---- - -## 🚀 Benefits Achieved - -1. **✅ Multilingual Support** - - Dashboard works in EN, ES, and EU - - Easy to add more languages (CA, FR, etc.) - -2. **✅ Maintainability** - - Backend: One place to define reasoning logic - - Frontend: Translations in organized JSON files - - No hardcoded text scattered across code - -3. **✅ Consistency** - - Same reasoning type always translates the same way - - Centralized terminology - -4. **✅ Flexibility** - - Can change wording without touching code - - Can A/B test different phrasings - - Translators can work independently - -5. **✅ Type Safety** - - TypeScript interfaces for reasoning_data - - Compile-time checks for translation keys - ---- - -## 📚 Documentation - -- **Reasoning Types:** `shared/schemas/reasoning_types.py` -- **Translation Hook:** `frontend/src/hooks/useReasoningTranslation.ts` -- **Translation Files:** `frontend/src/locales/{en,es,eu}/reasoning.json` -- **Audit Report:** `REASONING_I18N_AUDIT.md` - ---- - -## Next Steps - -1. **Update frontend components** (30-60 min) - - Replace TEXT field usage with reasoning_data translation - - Use `useReasoningFormatter()` hook - - Replace hardcoded strings with `t()` calls - -2. **Update demo seed scripts** (15-30 min) - - Replace hardcoded text with helper functions - - Test demo data generation - -3. **Update backend services** (15-30 min) - - Replace hardcoded error messages with error codes - - Frontend will translate error codes - -4. **Test** (30 min) - - Switch between EN, ES, EU - - Verify all reasoning types display correctly - - Check mobile responsiveness - -**Total Estimated Time:** 2-3 hours for complete implementation diff --git a/REFACTORING_ROADMAP.md b/REFACTORING_ROADMAP.md deleted file mode 100644 index 16da6d46..00000000 --- a/REFACTORING_ROADMAP.md +++ /dev/null @@ -1,315 +0,0 @@ -# UnifiedOnboardingWizard Refactoring Roadmap - -## Quick Executive Summary - -**Current State**: Functional but architecturally problematic -**Main Issue**: UploadSalesDataStep is a 74KB mega-component mixing 8+ different concerns -**Debt Level**: HIGH - Technical debt is impacting maintainability - ---- - -## Critical Issues (Must Fix) - -### 1. UploadSalesDataStep is Too Large (CRITICAL) -- **File Size**: 74,627 bytes (73KB) -- **Lines**: 1,577 lines -- **State Variables**: 23 useState hooks -- **Methods**: Handles file upload, validation, classification, inventory management, stock lots, and more -- **Impact**: Almost impossible to test, modify, or reuse components - -**What it should do**: -- Single responsibility: Upload and validate file - -**What it actually does**: -1. File upload UI and drag-drop -2. File validation API call -3. AI classification API call -4. Inventory item form management (CRUD) -5. Stock lot management (CRUD) -6. Batch ingredient creation -7. Sales data import -8. Two entirely different UIs (upload phase vs inventory review phase) - -**Refactoring Approach**: -``` -Current: -UploadSalesDataStep (1577 lines, 23 state vars) - -Should be: -├─ FileUploadPhase (200 lines) -│ ├─ FileDropZone -│ ├─ FileValidator -│ └─ ProgressIndicator -│ -├─ InventoryManagementPhase (500 lines) -│ ├─ InventoryItemList -│ ├─ InventoryItemForm -│ ├─ StockLotManager -│ └─ BatchAddModal -│ -├─ InventoryService (classification, validation) -│ -└─ UploadSalesDataStepContainer (orchestrator, 150 lines) - ├─ Phase state machine - ├─ Data flow coordination - └─ API integration -``` - -### 2. Tight Coupling Between Onboarding & Setup (CRITICAL) -- UnifiedOnboardingWizard imports from setup-wizard/steps/ -- Changes to setup steps affect onboarding flow -- Makes it impossible to modify setup independently - -**Current Problem**: -```typescript -// UnifiedOnboardingWizard.tsx line 22-28 -import { - SuppliersSetupStep, - RecipesSetupStep, - QualitySetupStep, - TeamSetupStep, - ReviewSetupStep, -} from '../setup-wizard/steps'; // ← CROSS-DOMAIN IMPORT -``` - -**Solution**: -- Define step interface contract -- Move setup steps to configuration -- Load steps dynamically -- Create step registry pattern - -### 3. Circular State Dependencies (HIGH) -- Steps update wizard context via both onUpdate() and onComplete() -- Data flows both directions -- No clear source of truth - -**Current Flow**: -``` -UploadSalesDataStep.onUpdate() → wizardContext -ProductCategorizationStep.onUpdate() → wizardContext -InitialStockEntryStep.onUpdate() → wizardContext -All steps also call onComplete() with different data -``` - -**Should Be**: -``` -Step.onUpdate() → Local UI state (transient) -Step.onComplete() → Single source of truth (wizardContext + Backend) -``` - ---- - -## High Priority Issues (Fix in Next Sprint) - -### 4. Duplicate Visibility Logic -**Locations**: -- UnifiedOnboardingWizard.tsx (line 59-165): Step conditions -- WizardContext.tsx (line 183-189): getVisibleSteps() logic -- Same rules repeated in two places - -**Fix**: Extract to single configuration file - -### 5. Auto-Completion Logic is Scattered -- user_registered auto-completion: OnboardingWizardContent.useEffect() (line 204) -- suppliers-setup auto-completion: UnifiedOnboardingWizard.handleStepComplete() (line 349) -- No clear policy or pattern - -**Fix**: Centralized auto-completion policy engine - -### 6. State Management Confusion -- UI state mixed with data state in context -- No clear boundary between component state and context state -- Difficult to understand data persistence - -**Fix**: -- UI state (isAdding, editingId, showInventoryStep) → Component local state -- Data state (aiSuggestions, categorizedProducts) → Context -- Session state → Backend API - ---- - -## Medium Priority Issues (Fix Over Time) - -### 7. No Inter-Step Communication Contract -**Problem**: Different components use different interfaces for same data -- InventoryItemForm (line 28-50) -- Product (ProductCategorizationStep line 7-14) -- ProductWithStock (InitialStockEntryStep line 8-15) -- Ingredient (API type) -- Stock (API type) - -All represent similar data but with different shapes. - -**Fix**: Create unified type system for inventory throughout flow - -### 8. Complex Data Transformations Without Clear Schema -Data travels through pipeline with implicit transformations: -``` -File → ImportValidationResponse → ProductSuggestionResponse -→ InventoryItemForm → Ingredient → Stock → categorizedProducts -→ Product (different type!) → ProductWithStock -``` - -**Fix**: Create explicit transformation functions between steps - ---- - -## Files to Delete (Immediate) - -1. **OnboardingWizard.tsx** (567 lines, 19.5KB) - - Status: Deprecated, not used - - Usage: Only in exports, never imported - - Risk: LOW - completely safe to delete - - Action: DELETE and remove from index.ts exports - -2. **SetupPage.tsx** (18 lines, 567 bytes) - OPTIONAL - - Status: Deprecated by design - - Usage: Route /app/setup still references it - - Risk: MEDIUM - needs migration plan - - Action: Either delete or redirect to /app/onboarding - -3. **Setup route in routes.config.ts** (line 578-593) - OPTIONAL - - Status: Redundant with /app/onboarding - - Action: Remove or convert to redirect - ---- - -## Refactoring Priority & Timeline - -### Phase 1: Quick Wins (Week 1) -**Time**: 2-3 hours -**Impact**: LOW immediate, HIGH long-term - -- [ ] Delete OnboardingWizard.tsx -- [ ] Remove from index.ts exports -- [ ] Extract visibility rules to config file -- [ ] Add comments documenting current state - -### Phase 2: State Management Cleanup (Week 2) -**Time**: 3-4 hours -**Impact**: MEDIUM - -- [ ] Document which state belongs where (UI vs Context vs Backend) -- [ ] Move UI state out of context (isAdding, editingId, etc.) -- [ ] Clear data flow direction (parent → child → parent only) - -### Phase 3: Split UploadSalesDataStep (Sprint) -**Time**: 6-8 hours -**Impact**: CRITICAL - -- [ ] Extract FileUploadPhase component -- [ ] Extract InventoryManagementPhase component -- [ ] Extract classification logic to service -- [ ] Create container component to orchestrate -- [ ] Add unit tests for each extracted component - -### Phase 4: Decouple Onboarding from Setup (Sprint) -**Time**: 4-6 hours -**Impact**: HIGH - -- [ ] Define step interface contract -- [ ] Create step registry/configuration -- [ ] Move setup steps to configuration -- [ ] Load steps dynamically - -### Phase 5: Inter-Step Communication (Sprint) -**Time**: 4-6 hours -**Impact**: MEDIUM - -- [ ] Define unified inventory type system -- [ ] Create transformation functions between steps -- [ ] Add type validation at step boundaries -- [ ] Document data contracts - ---- - -## Current Architecture Summary - -### Strengths -1. **Main Wizard Orchestrator is Well-Designed** - - Clean step navigation - - Good progress tracking - - Proper initialization logic - - Clear completion flow - -2. **WizardContext is Reasonable** - - Good use of React Context API - - Most step data stored centrally - - Safe from localStorage corruption - -3. **Most Individual Steps are Well-Designed** - - ProductCategorizationStep: Good UI/UX - - InitialStockEntryStep: Simple and effective - - BakeryTypeSelectionStep: Beautiful design - -### Weaknesses -1. **UploadSalesDataStep is a Monster** - - Mixes file upload + inventory management - - Too many state variables - - Difficult to test - - Difficult to reuse - -2. **Module Boundaries are Blurred** - - Onboarding imports from setup-wizard - - Difficult to modify either independently - - Violates separation of concerns - -3. **State Management is Confusing** - - UI state mixed with data state - - Bidirectional data flow - - Multiple sources of truth - -4. **No Clear Contracts Between Steps** - - Data types change between steps - - Implicit transformations - - Runtime type errors possible - ---- - -## How to Use This Document - -1. **For Planning**: Use Phase 1-5 to plan sprints -2. **For Understanding**: Read ARCHITECTURE_ANALYSIS.md for detailed breakdown -3. **For Implementation**: Follow the refactoring approach in each section -4. **For Maintenance**: Reference this after refactoring to keep architecture clean - ---- - -## Success Criteria - -After refactoring, the codebase should have: - -- [ ] UploadSalesDataStep is <300 lines -- [ ] No imports between onboarding and setup-wizard domains -- [ ] Clear separation of UI state and data state -- [ ] All steps follow same interface contract -- [ ] Data transformations are explicit and testable -- [ ] Unit test coverage >80% for all step components -- [ ] All 8 architectural problems resolved -- [ ] Deprecated files deleted (OnboardingWizard.tsx) - ---- - -## Estimated Effort - -| Phase | Effort | Impact | Timeline | -|-------|--------|--------|----------| -| Phase 1 (Quick Wins) | 2-3 hours | LOW | Week 1 | -| Phase 2 (State Management) | 3-4 hours | MEDIUM | Week 2 | -| Phase 3 (Split Component) | 6-8 hours | CRITICAL | Sprint 2 | -| Phase 4 (Decouple Domains) | 4-6 hours | HIGH | Sprint 3 | -| Phase 5 (Data Contracts) | 4-6 hours | MEDIUM | Sprint 4 | -| **TOTAL** | **19-27 hours** | **HIGH** | **4-5 Weeks** | - ---- - -## Contact & Questions - -For detailed architecture information, see: `ARCHITECTURE_ANALYSIS.md` - -Key sections: -- Section 2: Detailed architectural issues with code examples -- Section 3: Step dependencies and data flow diagrams -- Section 6: Problem statements for each issue -- Section 8: Detailed recommendations for each refactoring task - diff --git a/UNIFIED_WIZARD_IMPLEMENTATION_SUMMARY.md b/UNIFIED_WIZARD_IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index 9e707077..00000000 --- a/UNIFIED_WIZARD_IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,411 +0,0 @@ -# Unified Add Wizard - Implementation Summary - -## 📋 Overview - -Successfully designed and implemented a comprehensive **Unified Add Wizard** system for the bakery management application based on Jobs To Be Done (JTBD) methodology. This wizard consolidates all "add new content" actions into a single, intuitive, step-by-step guided experience. - ---- - -## ✅ What Was Built - -### 1. **JTBD Framework & Strategy Documents** - -Created comprehensive research and design documentation: - -- **`JTBD_UNIFIED_ADD_WIZARD.md`** - Complete JTBD analysis including: - - Main job statement and 9 functional sub-jobs - - Emotional and social jobs - - Forces of progress (push, pull, anxiety, habit) - - User struggles and unmet needs - - Success metrics and design principles - - Prioritization matrix (P0, P1, P2) - -- **`WIZARD_ARCHITECTURE_DESIGN.md`** - Detailed technical design including: - - Component hierarchy and architecture - - UI/UX specifications (mobile-first, responsive) - - Step-by-step flows for all 9 wizards - - State management strategy - - Accessibility checklist - - Implementation roadmap - -### 2. **Core Wizard System Components** - -#### **`UnifiedAddWizard.tsx`** - Main Orchestrator -- Routes to appropriate wizard based on user selection -- Manages overall wizard state -- Integrates with existing `WizardModal` component -- Supports optional `initialItemType` for direct wizard access - -#### **`ItemTypeSelector.tsx`** - Step 0 Selection Screen -- Beautiful, visual card-based selection interface -- 9 item type options with icons, descriptions, and badges -- Highlights most common actions (e.g., Sales Entry ⭐) -- Fully responsive (mobile-first design) -- Clear categorization (Setup, Daily, Common) - -### 3. **Individual Wizard Implementations** - -#### ✅ **Priority 0 (P0) - Fully Implemented** - -1. **`SalesEntryWizard.tsx`** ⭐⭐⭐ **MOST CRITICAL** - - **Step 1:** Entry Method Selection (Manual vs File Upload) - - **Step 2a:** Manual entry with dynamic product list - - Date and payment method selection - - Add multiple products with quantities and prices - - Auto-calculated subtotals and totals - - Notes field - - **Step 2b:** File upload (placeholder for CSV/Excel import) - - **Step 3:** Review and confirm before saving - - **Why critical:** Small bakeries often lack POS systems and need easy sales data entry - -2. **`InventoryWizard.tsx`** - - **Step 1:** Type Selection (Ingredient vs Finished Product) - - **Step 2:** Core Details (name, category, unit, storage, reorder point) - - **Step 3:** Initial Lot Entry (optional - quantity, batch number, expiry, cost) - - Context-aware forms based on inventory type - -#### ✅ **Priority 1 & 2 - Placeholder Implementations** - -Remaining wizards created with proper structure for future enhancement: - -3. **`CustomerOrderWizard.tsx`** (P0) - 3 steps -4. **`SupplierWizard.tsx`** (P1) - 2 steps -5. **`RecipeWizard.tsx`** (P1) - 3 steps -6. **`CustomerWizard.tsx`** (P1) - 2 steps -7. **`QualityTemplateWizard.tsx`** (P2) - 2 steps -8. **`EquipmentWizard.tsx`** (P2) - 2 steps -9. **`TeamMemberWizard.tsx`** (P2) - 2 steps - -All wizards follow the same architecture and can be enhanced incrementally. - -### 4. **Dashboard Integration** - -#### **Updated `DashboardPage.tsx`** -- Added prominent **"Agregar"** button in dashboard header -- Gradient styling with sparkle icon for visual prominence -- Opens UnifiedAddWizard on click -- Refreshes dashboard data after wizard completion -- Mobile-responsive placement - ---- - -## 🎨 Design Highlights - -### Mobile-First & Responsive -- **Touch targets:** Minimum 44px × 44px for easy tapping -- **Full-screen modals** on mobile (<640px) -- **Centered modals** on tablet/desktop -- **Bottom action buttons** for thumb-friendly mobile UX -- **Swipeable** navigation (future enhancement) - -### Visual Design -- Follows existing **color system** (`colors.js`): - - Primary: `#d97706` (Amber-600) - - Secondary: `#16a34a` (Green-600) - - Success: `#10b981` (Emerald) - - Gradients for emphasis -- **Card-based selection** with hover states -- **Progress indicators** showing current step -- **Validation feedback** with inline error messages -- **Success states** with checkmarks and confirmations - -### Accessibility -- Keyboard navigable (Tab, Enter, Escape) -- Screen reader compatible (ARIA labels) -- Clear focus indicators -- Color contrast meets WCAG AA standards -- Touch-friendly for mobile devices - ---- - -## 🗂️ File Structure - -``` -frontend/src/components/domain/unified-wizard/ -├── index.ts # Public exports -├── UnifiedAddWizard.tsx # Main orchestrator component -├── ItemTypeSelector.tsx # Step 0: Choose what to add -└── wizards/ - ├── SalesEntryWizard.tsx # ⭐ P0 - Fully implemented - ├── InventoryWizard.tsx # ⭐ P0 - Fully implemented - ├── CustomerOrderWizard.tsx # P0 - Placeholder - ├── SupplierWizard.tsx # P1 - Placeholder - ├── RecipeWizard.tsx # P1 - Placeholder - ├── CustomerWizard.tsx # P1 - Placeholder - ├── QualityTemplateWizard.tsx # P2 - Placeholder - ├── EquipmentWizard.tsx # P2 - Placeholder - └── TeamMemberWizard.tsx # P2 - Placeholder -``` - ---- - -## 🚀 How to Use - -### From Dashboard (Primary Entry Point) -1. Click the **"Agregar"** button in the dashboard header -2. Select the type of content to add from the visual card grid -3. Follow the step-by-step guided wizard -4. Review and confirm -5. Dashboard automatically refreshes with new data - -### Programmatic Usage -```tsx -import { UnifiedAddWizard } from '@/components/domain/unified-wizard'; - -function MyComponent() { - const [isOpen, setIsOpen] = useState(false); - - const handleComplete = (itemType, data) => { - console.log('Created:', itemType, data); - // Refresh your data here - }; - - return ( - <> - - - setIsOpen(false)} - onComplete={handleComplete} - initialItemType="sales-entry" // Optional: Skip type selection - /> - - ); -} -``` - -### Available Item Types -```typescript -type ItemType = - | 'inventory' - | 'supplier' - | 'recipe' - | 'equipment' - | 'quality-template' - | 'customer-order' - | 'customer' - | 'team-member' - | 'sales-entry'; -``` - ---- - -## 📊 JTBD Key Insights Applied - -### Main Job -> "When I need to expand or update my bakery operations, I want to quickly add new resources to my management system, so I can keep my business running smoothly without interruption." - -### Design Decisions Based on JTBD - -1. **Progressive Disclosure** - - Don't overwhelm with all 9 options at once - - Step-by-step reduces cognitive load - - Clear "what's next" at every step - -2. **Mobile-First** - - Bakery owners are often on their feet - - Limited desk time during production - - Touch-friendly for floury hands - -3. **Sales Entry Priority** ⭐ - - Most small bakeries lack POS systems - - Daily/weekly sales entry is critical - - Both manual (quick) and bulk upload (historical data) - -4. **Forgiving Interactions** - - Can go back without losing data - - Optional steps clearly marked - - Inline error correction - -5. **Relationship Awareness** - - Wizards can suggest related items (e.g., "Add ingredients for this recipe?") - - Reduces context switching - - Smarter workflows - ---- - -## 🎯 Success Metrics (How to Measure) - -Track these metrics to validate JTBD success: - -### Quantitative -- **Task completion rate** > 95% -- **Time to complete** each wizard < 2 minutes -- **Error rate** < 5% -- **Mobile usage** > 40% of total wizard opens -- **Adoption rate** > 80% within 2 weeks - -### Qualitative -- Users report feeling "guided" and "confident" -- Reduction in support requests about "how to add X" -- Positive feedback on mobile usability -- **Sales data completeness improves** (key for non-POS bakeries) - ---- - -## 🔮 Future Enhancements - -### Phase 1 (Immediate) -- [ ] Connect wizards to real API endpoints (currently placeholder) -- [ ] Implement full CSV/Excel upload for Sales Entry -- [ ] Add form validation with Zod or similar -- [ ] Add draft auto-saving to localStorage - -### Phase 2 (Short-term) -- [ ] Enhance P1 wizards (Customer Order, Supplier, Recipe) -- [ ] Add "Recently Added" quick access in dashboard -- [ ] Implement "Repeat Last Action" shortcuts -- [ ] Add keyboard shortcuts (Cmd/Ctrl + K to open) - -### Phase 3 (Advanced) -- [ ] Barcode scanning for inventory -- [ ] Voice input for sales entry -- [ ] Batch operations (add multiple items at once) -- [ ] Smart suggestions based on context -- [ ] Offline support with sync - ---- - -## 📝 Technical Notes - -### Integration Points - -1. **API Calls** - Wizards currently log to console. Connect to: - - `POST /api/v1/{tenant_id}/inventory` - - `POST /api/v1/{tenant_id}/sales` - - etc. - -2. **React Query Hooks** - Use mutation hooks: - ```tsx - const { mutate: createSale } = useCreateSale(); - await createSale({ tenantId, ...data }); - ``` - -3. **i18n** - Wizard text is currently in Spanish. Add translation keys: - ```tsx - const { t } = useTranslation(['wizard']); -

{t('wizard:sales.title')}

- ``` - -### State Management -- Wizard state managed internally via `useState` -- Data passed between steps via `wizardData` object -- Parent component receives final data via `onComplete` callback - -### Styling -- Uses CSS custom properties from `colors.js` -- TailwindCSS utility classes -- Inline styles for theme-aware colors -- Fully responsive with breakpoints - ---- - -## 🐛 Known Limitations - -1. **File Upload** - Placeholder implementation in Sales Entry wizard -2. **Validation** - Basic required field checks, needs comprehensive validation -3. **API Integration** - Mock data, needs real backend connections -4. **Draft Saving** - Not yet implemented (wizards don't save progress) -5. **Bulk Operations** - Can't add multiple items of same type at once - ---- - -## 📚 Related Documentation - -- `JTBD_UNIFIED_ADD_WIZARD.md` - Full JTBD analysis -- `WIZARD_ARCHITECTURE_DESIGN.md` - Technical design details -- `frontend/src/components/ui/WizardModal/` - Base wizard component -- `frontend/src/styles/colors.js` - Design system colors - ---- - -## 👥 For Future Developers - -### Adding a New Wizard Type - -1. Create wizard file in `wizards/` directory: -```tsx -// wizards/MyNewWizard.tsx -import { WizardStep } from '../../../ui/WizardModal/WizardModal'; - -export const MyNewWizardSteps = (data, setData): WizardStep[] => [ - { - id: 'step-1', - title: 'Step Title', - description: 'Step description', - component: (props) => , - }, - // ... more steps -]; -``` - -2. Add to `ItemTypeSelector.tsx`: -```tsx -export const ITEM_TYPES: ItemTypeConfig[] = [ - // ... existing types - { - id: 'my-new-type', - title: 'My New Type', - subtitle: 'Description', - icon: MyIcon, - badge: 'New', - badgeColor: 'bg-blue-100 text-blue-700', - }, -]; -``` - -3. Import and route in `UnifiedAddWizard.tsx`: -```tsx -import { MyNewWizardSteps } from './wizards/MyNewWizard'; - -// In getWizardSteps() switch statement: -case 'my-new-type': - return MyNewWizardSteps(wizardData, setWizardData); -``` - -### Enhancing Existing Wizards - -Placeholder wizards have simple structure. To enhance: -1. Add proper form fields with state management -2. Implement validation logic -3. Add API integration -4. Add success/error handling -5. Follow patterns from `SalesEntryWizard.tsx` and `InventoryWizard.tsx` - ---- - -## ✅ Completion Checklist - -- [x] JTBD framework research and documentation -- [x] Wizard architecture design -- [x] UnifiedAddWizard orchestrator component -- [x] ItemTypeSelector step 0 component -- [x] SalesEntryWizard (P0 - fully functional) -- [x] InventoryWizard (P0 - fully functional) -- [x] 7 placeholder wizards (P0-P2) -- [x] Dashboard integration with "Agregar" button -- [x] Mobile-responsive design -- [x] Design system integration -- [x] Component exports and index file -- [x] Implementation documentation - ---- - -## 🎉 Summary - -Successfully delivered a **comprehensive, user-centered wizard system** that: -- ✅ Consolidates 9 different "add" actions into one unified experience -- ✅ Prioritizes the most critical use case (Sales Entry for non-POS bakeries) -- ✅ Follows JTBD methodology for user-first design -- ✅ Mobile-first, accessible, and visually consistent -- ✅ Scalable architecture for future enhancements -- ✅ Well-documented for future developers - -**Next Steps:** Connect to real APIs, enhance P1 wizards, and gather user feedback to iterate based on actual usage patterns. - ---- - -**Document Version:** 1.0 -**Date:** 2025-11-09 -**Status:** ✅ Implementation Complete - Ready for Testing & API Integration diff --git a/WIZARD_API_INTEGRATION_STATUS.md b/WIZARD_API_INTEGRATION_STATUS.md deleted file mode 100644 index 63b4d343..00000000 --- a/WIZARD_API_INTEGRATION_STATUS.md +++ /dev/null @@ -1,254 +0,0 @@ -# Wizard API Integration Status - UPDATED - -## Summary - -All unified add wizards have been successfully updated with full API integration. No mock data or console.log placeholders remain in production code. - -## ✅ Fully Completed - -### 1. Quality Template Wizard -**File**: `frontend/src/components/domain/unified-wizard/wizards/QualityTemplateWizard.tsx` -**Status**: ✅ **COMPLETE** - -**Implementation Details**: -- ✅ Full API integration using `qualityTemplateService.createTemplate()` -- ✅ Tenant ID retrieval via `useTenant()` hook -- ✅ Loading states with spinner during API calls -- ✅ Error handling with user-friendly error messages -- ✅ No mock data or console.log - -**API Used**: `POST /tenants/{tenant_id}/production/quality-templates` - ---- - -### 2. Equipment Wizard -**File**: `frontend/src/components/domain/unified-wizard/wizards/EquipmentWizard.tsx` -**Status**: ✅ **COMPLETE** - -**Implementation Details**: -- ✅ Full API integration using `equipmentService.createEquipment()` -- ✅ Tenant ID retrieval via `useTenant()` hook -- ✅ Loading states with spinner -- ✅ Error handling -- ✅ No mock data or console.log - -**API Used**: `POST /tenants/{tenant_id}/production/equipment` - ---- - -### 3. Team Member Wizard -**File**: `frontend/src/components/domain/unified-wizard/wizards/TeamMemberWizard.tsx` -**Status**: ✅ **COMPLETE** - -**Implementation Details**: -- ✅ Full API integration using `authService.register()` -- ✅ Creates actual user accounts with roles -- ✅ Generates temporary passwords (should be emailed in production) -- ✅ Loading states and error handling -- ✅ No mock data or console.log - -**API Used**: `POST /auth/register` - ---- - -### 4. Sales Entry Wizard -**File**: `frontend/src/components/domain/unified-wizard/wizards/SalesEntryWizard.tsx` -**Status**: ✅ **COMPLETE** - -**Implementation Details**: -- ✅ Manual entry saves via `salesService.createSalesRecord()` -- ✅ CSV template download via `salesService.downloadImportTemplate()` -- ✅ File validation via `salesService.validateImportFile()` -- ✅ Bulk import via `salesService.importSalesData()` -- ✅ Full file upload UI with drag & drop -- ✅ Loading states for all operations -- ✅ Comprehensive error handling -- ✅ No mock data or console.log - -**APIs Used**: -- `POST /tenants/{tenant_id}/sales/sales` - Create manual sales -- `POST /tenants/{tenant_id}/sales/operations/import` - Import from file -- `POST /tenants/{tenant_id}/sales/operations/import/validate` - Validate file -- `GET /tenants/{tenant_id}/sales/operations/import/template` - Download template - ---- - -### 5. Supplier Wizard -**File**: `frontend/src/components/domain/unified-wizard/wizards/SupplierWizard.tsx` -**Status**: ✅ **COMPLETE** - -**Implementation Details**: -- ✅ Real-time ingredient fetching via `inventoryService.getIngredients()` -- ✅ Supplier creation via `suppliersService.createSupplier()` -- ✅ Price list creation via `suppliersService.createSupplierPriceList()` -- ✅ Loading states while fetching ingredients -- ✅ Error handling for both fetch and save -- ✅ No mock data (mockIngredients removed) -- ✅ No console.log - -**APIs Used**: -- `GET /tenants/{tenant_id}/inventory/ingredients` - Fetch ingredients -- `POST /tenants/{tenant_id}/suppliers` - Create supplier -- `POST /tenants/{tenant_id}/suppliers/{supplier_id}/price-lists` - Create price list - ---- - -### 6. Customer Wizard -**File**: `frontend/src/components/domain/unified-wizard/wizards/CustomerWizard.tsx` -**Status**: ✅ **COMPLETE** - -**Implementation Details**: -- ✅ Full API integration using `OrdersService.createCustomer()` -- ✅ All customer data properly mapped to API format -- ✅ Loading states with spinner -- ✅ Error handling -- ✅ No mock data or console.log - -**API Used**: `POST /tenants/{tenant_id}/orders/customers` - ---- - -## 🔄 In Progress - -### 7. Customer Order Wizard -**File**: `frontend/src/components/domain/unified-wizard/wizards/CustomerOrderWizard.tsx` -**Status**: 🔄 **IN PROGRESS** - -**Remaining Work**: -1. Replace `mockCustomers` with `OrdersService.getCustomers()` in CustomerSelectionStep -2. Update inline customer creation to use `OrdersService.createCustomer()` -3. Replace `mockProducts` with `inventoryService.getIngredients()` in OrderItemsStep -4. Filter for finished products only -5. Replace console.log with `OrdersService.createOrder()` in DeliveryPaymentStep - -**Mock Data to Remove**: -- Line ~35: `mockCustomers` array (4 hardcoded customers) -- Line ~125: `mockProducts` array (6 hardcoded products) - -**APIs to Implement**: -- `GET /tenants/{tenant_id}/orders/customers` - List customers -- `POST /tenants/{tenant_id}/orders/customers` - Create customer inline -- `GET /tenants/{tenant_id}/inventory/ingredients` - List products -- `POST /tenants/{tenant_id}/orders` - Create order - ---- - -### 8. Recipe Wizard -**File**: `frontend/src/components/domain/unified-wizard/wizards/RecipeWizard.tsx` -**Status**: 🔄 **IN PROGRESS** - -**Remaining Work**: -1. Fetch ingredients via `inventoryService.getIngredients()` in IngredientsStep -2. Create ingredient selection UI with search/filter -3. Allow multiple ingredient selection with quantity/unit -4. Replace console.log with `recipesService.createRecipe()` in final step -5. Map ingredient data to RecipeIngredientCreate format - -**Current State**: -- Step 1 (Recipe Details): ✅ Complete with UI -- Step 2 (Ingredients): ⚠️ Shows placeholder message - -**APIs to Implement**: -- `GET /tenants/{tenant_id}/inventory/ingredients` - Fetch ingredients -- `POST /tenants/{tenant_id}/recipes` - Create recipe with ingredients - -**Data Format Needed**: -```typescript -RecipeIngredientCreate { - inventory_product_id: string; - quantity: number; - unit: string; // 'kg', 'g', 'l', 'ml', 'units' - notes?: string; -} -``` - ---- - -## 📊 Implementation Summary - -**Completed**: 6/9 wizards (67%) -**In Progress**: 2/9 wizards (22%) -**Remaining**: 1/9 wizards (11%) - Inventory Wizard (was completed in earlier commits) - -### Completion Checklist - -- ✅ Quality Template Wizard -- ✅ Equipment Wizard -- ✅ Team Member Wizard -- ✅ Sales Entry Wizard (with file upload) -- ✅ Supplier Wizard (with real-time ingredient fetch) -- ✅ Customer Wizard -- 🔄 Customer Order Wizard (high complexity - needs completion) -- 🔄 Recipe Wizard (medium complexity - needs ingredient selection UI) -- ✅ Inventory Wizard (completed in earlier commits) - ---- - -## 🎯 Final Steps - -1. **Customer Order Wizard** - Replace 2 mock data arrays with 4 API calls -2. **Recipe Wizard** - Implement full ingredient selection UI with API -3. **Final Testing** - Verify all wizards work end-to-end -4. **Documentation Update** - Mark all as complete - ---- - -## 🔧 Technical Patterns Used - -All completed wizards follow the same consistent pattern: - -```typescript -// 1. Import required services -import { useTenant } from '../../../../stores/tenant.store'; -import { someService } from '../../../../api/services/someService'; - -// 2. Add state for loading and errors -const [loading, setLoading] = useState(false); -const [error, setError] = useState(null); - -// 3. Get tenant ID -const { currentTenant } = useTenant(); - -// 4. Async API call with error handling -const handleSave = async () => { - if (!currentTenant?.id) { - setError('No se pudo obtener información del tenant'); - return; - } - - setLoading(true); - setError(null); - - try { - await someService.someMethod(currentTenant.id, data); - onComplete(); - } catch (err: any) { - console.error('Error:', err); - setError(err.response?.data?.detail || 'Error message'); - } finally { - setLoading(false); - } -}; - -// 5. UI with loading and error states -{error &&
{error}
} - -``` - ---- - -## 📝 Notes - -- All wizards use the `useTenant()` hook for tenant ID -- All wizards show loading spinners during API calls -- All wizards display error messages in red alert boxes -- All wizards disable submit buttons during save operations -- No `console.log` statements remain (except for error logging in catch blocks) -- No mock data arrays remain in completed wizards - ---- - -**Last Updated**: Current session -**Next Update**: After completing Customer Order and Recipe wizards diff --git a/WIZARD_ARCHITECTURE_DESIGN.md b/WIZARD_ARCHITECTURE_DESIGN.md deleted file mode 100644 index 303fa9d5..00000000 --- a/WIZARD_ARCHITECTURE_DESIGN.md +++ /dev/null @@ -1,747 +0,0 @@ -# Unified Add Wizard: Architecture & Component Design - -## 🏗️ Component Hierarchy - -``` -UnifiedAddWizard (Main Orchestrator) -│ -├── 📱 WizardContainer (Mobile-responsive wrapper) -│ │ -│ ├── WizardHeader (Progress, close button) -│ │ -│ ├── WizardContent (Scrollable main area) -│ │ │ -│ │ ├── Step 0: ItemTypeSelector ⭐ (What do you want to add?) -│ │ │ └── 9 visual cards with icons -│ │ │ -│ │ ├── Step 1+: Specific Wizards (Conditionally rendered) -│ │ │ -│ │ ├── InventoryWizard -│ │ │ ├── Step 1: Type Selection (Ingredient vs Finished Product) -│ │ │ ├── Step 2: Core Details Form -│ │ │ └── Step 3: Initial Lot(s) Entry -│ │ │ -│ │ ├── SupplierWizard (reuse existing) -│ │ │ ├── Step 1: Supplier Information -│ │ │ ├── Step 2: Ingredients & Pricing -│ │ │ └── Step 3: Review & Submit -│ │ │ -│ │ ├── RecipeWizard (reuse existing) -│ │ │ ├── Step 1: Recipe Details -│ │ │ ├── Step 2: Ingredients Selection -│ │ │ ├── Step 3: Quality Templates -│ │ │ └── Step 4: Review -│ │ │ -│ │ ├── EquipmentWizard -│ │ │ ├── Step 1: Equipment Type & Details -│ │ │ └── Step 2: Maintenance Schedule -│ │ │ -│ │ ├── QualityTemplateWizard -│ │ │ ├── Step 1: Template Info -│ │ │ └── Step 2: Quality Checkpoints -│ │ │ -│ │ ├── CustomerOrderWizard -│ │ │ ├── Step 1: Customer Selection/Creation -│ │ │ ├── Step 2: Order Items -│ │ │ └── Step 3: Delivery & Payment -│ │ │ -│ │ ├── CustomerWizard -│ │ │ ├── Step 1: Customer Details -│ │ │ └── Step 2: Preferences & Terms -│ │ │ -│ │ ├── TeamMemberWizard -│ │ │ ├── Step 1: Personal Details -│ │ │ └── Step 2: Role & Permissions -│ │ │ -│ │ └── SalesEntryWizard ⭐⭐⭐ (CRITICAL) -│ │ ├── Step 1: Entry Method (Manual vs Upload) -│ │ ├── Step 2a: Manual Entry Form (if manual) -│ │ ├── Step 2b: File Upload & Mapping (if upload) -│ │ └── Step 3: Review & Confirm -│ │ -│ └── WizardFooter (Actions: Back, Next, Submit) -│ -└── WizardState (Context/hook for state management) - ├── currentStep - ├── selectedItemType - ├── formData - ├── validationErrors - └── draftSaving -``` - ---- - -## 🎨 UI/UX Design Specifications - -### Mobile-First Responsive Behavior - -| Breakpoint | Behavior | Layout | -|------------|----------|--------| -| < 640px (Mobile) | Full-screen modal | Vertical stack, bottom buttons | -| 640-1024px (Tablet) | Centered modal (90% width) | Side-by-side where space allows | -| > 1024px (Desktop) | Drawer-style slide-in | Two-column layouts for forms | - -### Touch Target Sizes (Mobile Optimization) - -- **Minimum touch target:** 44px × 44px -- **Card buttons:** 100% width on mobile, min 120px height -- **Action buttons:** Full width on mobile, auto on desktop -- **Input fields:** min-height 48px (easy to tap) - -### Visual Design System (Based on Existing Codebase) - -#### Colors (from frontend/src/styles/colors.js) -```javascript -Primary: #d97706 (Amber-600) - Main actions, headers -Secondary: #16a34a (Green-600) - Success states -Accent: #0ea5e9 (Sky-500) - Info, links -Danger: #dc2626 (Red-600) - Errors, delete -Background: #ffffff (Light), #1f2937 (Dark) -Surface: #f3f4f6 (Light), #374151 (Dark) -Text: #111827 (Light), #f9fafb (Dark) -``` - -#### Typography -- **Headers (H1):** 24px (mobile), 32px (desktop), font-bold -- **Step titles (H2):** 20px (mobile), 24px (desktop), font-semibold -- **Body:** 16px, font-normal -- **Helper text:** 14px, text-gray-600 - -#### Spacing -- **Section gaps:** 24px (mobile), 32px (desktop) -- **Input gaps:** 16px -- **Card padding:** 16px (mobile), 24px (desktop) -- **Modal padding:** 16px (mobile), 32px (desktop) - ---- - -## 🧩 Step 0: Item Type Selector Design - -### Visual Layout (Mobile-First) - -``` -┌─────────────────────────────────────────┐ -│ What would you like to add? │ -│ ───────────────────────────────────── │ -│ │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │ 📦 Inventory│ │ 🏢 Supplier │ │ -│ │ Ingredient │ │ Relationship│ │ -│ │ or Product │ │ │ │ -│ └──────────────┘ └──────────────┘ │ -│ │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │ 📝 Recipe │ │ 🔧 Equipment│ │ -│ │ Formula │ │ Asset │ │ -│ └──────────────┘ └──────────────┘ │ -│ │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │ ✅ Quality │ │ 🛒 Customer │ │ -│ │ Template │ │ Order │ │ -│ └──────────────┘ └──────────────┘ │ -│ │ -│ ┌──────────────┐ ┌──────────────┐ │ -│ │ 👤 Customer │ │ 👥 Team │ │ -│ │ Profile │ │ Member │ │ -│ └──────────────┘ └──────────────┘ │ -│ │ -│ ┌──────────────────────────────────┐ │ -│ │ 💰 Sales Entry │ │ -│ │ Manual or Upload │ │ -│ │ ⭐ Most Common │ │ -│ └──────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────┘ -``` - -### Card Component Structure - -```javascript - - {/* Emoji or SVG */} - Inventory - Ingredient or Product - Setup {/* Contextual tags: Setup, Daily, Common */} - -``` - -### Interaction States -- **Default:** Light background, border -- **Hover (desktop):** Slight elevation, primary border -- **Active/Selected:** Primary background, white text -- **Focus:** Clear focus ring for keyboard nav - ---- - -## 📋 Detailed Wizard Flows - -### 1. Inventory Wizard (3 Steps) - -#### Step 1: Type Selection -``` -What type of inventory are you adding? - -○ Ingredient - Raw materials used in recipes - Examples: Flour, sugar, eggs, butter - -○ Finished Product - Baked goods ready for sale - Examples: Baguettes, croissants, cakes -``` - -#### Step 2: Core Details -**For Ingredient:** -- Name* (text) -- Category (dropdown: Flour, Dairy, Eggs, Fats, etc.) -- Unit of Measurement* (dropdown: kg, L, units) -- Storage Requirements (dropdown: Dry, Refrigerated, Frozen) -- Reorder Point (number, optional) -- Allergen Info (multi-select) - -**For Finished Product:** -- Name* (text) -- Category (dropdown: Bread, Pastry, Cake, etc.) -- Recipe (dropdown from existing recipes, optional) -- Shelf Life (number + unit) -- Storage Requirements -- Selling Price (optional, can set later) - -#### Step 3: Initial Lot(s) -``` -Add starting inventory (optional but recommended) - -Lot #1: -- Quantity* (number) -- Batch/Lot Number (text, optional) -- Expiry Date (date picker, if applicable) -- Supplier (dropdown, if known) -- Cost per Unit (number, optional) - -[+ Add Another Lot] -``` - ---- - -### 2. Supplier Wizard (Reuse Existing + Enhancements) - -**Already exists at:** `frontend/src/components/domain/suppliers/SupplierWizard/` - -**Enhancements needed:** -- Ensure mobile responsive -- Add clear "Why we need this" helper text -- Allow skipping ingredients initially (can add later) - ---- - -### 3. Recipe Wizard (Reuse Existing + Enhancements) - -**Already exists at:** `frontend/src/components/domain/recipes/RecipeWizard/` - -**Enhancements needed:** -- Check if ingredients exist; offer to add missing ones inline -- Mobile responsive step indicators -- Clearer quality template selection - ---- - -### 4. Equipment Wizard (2 Steps) - -#### Step 1: Equipment Details -- Equipment Type* (dropdown: Oven, Mixer, Proofer, Refrigerator, etc.) -- Brand/Model (text) -- Serial Number (text) -- Purchase Date (date picker) -- Location (text: "Main kitchen", "Prep area") -- Capacity (text: "20L bowl", "5 trays") -- Status (dropdown: Active, Maintenance, Retired) - -#### Step 2: Maintenance Schedule -- Maintenance Frequency (dropdown: Weekly, Monthly, Quarterly, Annually) -- Last Maintenance Date (date picker) -- Next Maintenance Date (auto-calculated or manual) -- Notes (textarea: warranty info, service provider) - ---- - -### 5. Quality Template Wizard (2 Steps) - -#### Step 1: Template Info -- Template Name* (text: "Bread Quality Check", "Hygiene Checklist") -- Scope* (dropdown: Product Quality, Process Hygiene, Equipment, Safety) -- Applies To (multi-select products/recipes, optional) -- Frequency (dropdown: Every batch, Daily, Weekly) - -#### Step 2: Quality Checkpoints -``` -Define checkpoints for this template - -Checkpoint #1: -- Check Name* (text: "Crust color") -- Check Type (dropdown: Visual, Measurement, Pass/Fail) -- Acceptance Criteria (text: "Golden brown, even") -- Critical? (checkbox: failure requires action) - -[+ Add Another Checkpoint] -``` - ---- - -### 6. Customer Order Wizard (3 Steps) - -#### Step 1: Customer Selection -``` -Who is this order for? - -[Search existing customers... 🔍] - -Or create new customer: -- Name* -- Contact (phone or email) -- Type (dropdown: Retail, Wholesale, Event) - -[Quick Add Customer] -``` - -#### Step 2: Order Items -``` -What are they ordering? - -Item #1: -- Product* (dropdown from inventory finished products) -- Quantity* (number + unit) -- Custom Requirements (text: "No nuts", "Extra chocolate") -- Price (pre-filled from product, editable) - -[+ Add Another Item] - -Order Summary: Total: $___ -``` - -#### Step 3: Delivery & Payment -- Delivery Date* (date + time picker) -- Delivery Method (dropdown: Pickup, Delivery, Shipping) -- Delivery Address (if delivery) -- Payment Method (dropdown: Cash, Card, Invoice, Paid) -- Special Instructions (textarea) -- Order Status (auto: Pending, or manual: Confirmed, In Progress) - ---- - -### 7. Customer Wizard (2 Steps) - -#### Step 1: Customer Details -- Customer Name* (text) -- Customer Type* (dropdown: Retail, Wholesale, Event, Restaurant) -- Contact Person (text, for businesses) -- Phone Number (tel input) -- Email (email input) -- Address (textarea) - -#### Step 2: Preferences & Terms -- Payment Terms (dropdown: Immediate, Net 15, Net 30) -- Preferred Delivery Days (multi-select: Mon-Sun) -- Dietary Restrictions/Allergies (multi-select or text) -- Discount Percentage (number, if wholesale) -- Notes (textarea: preferences, history) - ---- - -### 8. Team Member Wizard (2 Steps) - -#### Step 1: Personal Details -- Full Name* (text) -- Email* (email input, for system login) -- Phone Number (tel input) -- Position/Title* (dropdown: Baker, Pastry Chef, Manager, Sales, Delivery) -- Employment Type (dropdown: Full-time, Part-time, Contractor) -- Start Date (date picker) - -#### Step 2: Role & Permissions -- System Role* (dropdown: Admin, Manager, Staff, View-Only) -- Permissions (checkboxes): - - [ ] Manage Inventory - - [ ] View Recipes - - [ ] Create Orders - - [ ] View Financial Data - - [ ] Manage Team -- Schedule/Shift (text or structured input) -- Notes (textarea: certifications, training status) - ---- - -### 9. Sales Entry Wizard ⭐⭐⭐ (CRITICAL - 3 Steps) - -#### Step 1: Entry Method Selection -``` -How would you like to add sales? - -┌─────────────────────────────┐ -│ ✏️ Manual Entry │ -│ Enter one or a few sales │ -│ Best for: Daily totals │ -└─────────────────────────────┘ - -┌─────────────────────────────┐ -│ 📄 Upload File │ -│ Import from Excel/CSV │ -│ Best for: Bulk historical │ -│ ⭐ Recommended for backlog │ -└─────────────────────────────┘ -``` - ---- - -#### Step 2a: Manual Entry (if Manual selected) -``` -Enter sales details - -Sale Date*: [Date Picker - defaults to today] -Time: [Time Picker - optional] - -Items Sold: - -Item #1: -- Product* (dropdown from inventory) -- Quantity* (number) -- Unit Price (pre-filled, editable) -- Subtotal (auto-calculated) - -[+ Add Another Item] - -Payment: -- Payment Method* (Cash, Card, Mobile Pay, Other) -- Total Amount (auto-summed or manual override) - -Notes: (textarea - optional) - -[Save & Add Another] [Save & Close] -``` - -**UX Optimization:** -- Default to today's date -- Remember last payment method used -- Quick "Repeat Last Sale" button for common items -- Show recent sales for reference - ---- - -#### Step 2b: File Upload & Mapping (if Upload selected) - -**Sub-step 1: Upload File** -``` -Upload your sales data - -Supported formats: CSV, Excel (.xlsx, .xls) - -[Drag & drop file here or click to browse] - -Download Template: -[📥 CSV Template] [📥 Excel Template] - -Need help? See formatting guide → -``` - -**Sub-step 2: Column Mapping** -``` -Map your file columns to our fields - -Your File Column → Our Field -───────────────────────────────────────── -[Date ▼] → Sale Date ✓ -[Item ▼] → Product Name ✓ -[Quantity ▼] → Quantity ✓ -[Price ▼] → Unit Price ✓ -[Total ▼] → Total Amount ✓ -[Payment ▼] → Payment Method ✓ - -Rows detected: 127 -Rows with errors: 3 [View Errors →] - -[Skip unmapped columns] -``` - -**Sub-step 3: Data Validation Preview** -``` -Review imported data - -Showing first 10 of 127 rows: - -Date | Product | Qty | Price | Total | Status -───────────────────────────────────────────────────────── -2025-11-01 | Baguette | 15 | $3.50 | $52.50| ✓ Valid -2025-11-01 | Croissant | 22 | $4.00 | $88.00| ✓ Valid -2025-11-01 | Unknown Item | 5 | $5.00 | $25.00| ⚠️ Product not found -... - -⚠️ 3 rows have issues -[View & Fix Errors] - -✓ 124 rows ready to import - -[Cancel] [Import Valid Rows Only] [Fix All First] -``` - -**Error Handling:** -- Show specific errors inline ("Product 'Donut' not found. Did you mean 'Doughnut'?") -- Offer to create missing products on the fly -- Suggest date format corrections -- Allow skipping invalid rows or fixing in bulk - ---- - -#### Step 3: Review & Confirm (Both Methods) - -**For Manual Entry:** -``` -Review your sale - -Date: November 9, 2025 -Items: - • Baguette × 15 @ $3.50 = $52.50 - • Croissant × 8 @ $4.00 = $32.00 - -Total: $84.50 -Payment: Cash - -[← Edit] [✓ Confirm & Save] -``` - -**For File Upload:** -``` -Import Summary - -Successfully imported: 124 sales -Skipped (errors): 3 -Total revenue: $4,567.89 -Date range: Nov 1 - Nov 9, 2025 - -[View Imported Sales] [Add More Sales] [Done] -``` - ---- - -## 🔄 State Management & Data Flow - -### Context Structure - -```javascript -const WizardContext = { - // Navigation - currentStep: 0, - totalSteps: 3, - selectedItemType: null, // 'inventory', 'supplier', etc. - - // Data - formData: {}, // Step-specific data - validationErrors: {}, - - // Actions - goToStep: (step) => {}, - nextStep: () => {}, - prevStep: () => {}, - setItemType: (type) => {}, - updateFormData: (data) => {}, - submitWizard: async () => {}, - - // Draft saving - saveDraft: () => {}, // Auto-save to localStorage - loadDraft: () => {}, - clearDraft: () => {}, - - // Utilities - isStepValid: (step) => boolean, - canProceed: () => boolean, -} -``` - -### API Integration Pattern - -```javascript -// Use existing React Query hooks -const { mutate: createItem, isLoading } = useCreateItem(itemType); - -const handleSubmit = async (formData) => { - try { - await createItem(formData); - showSuccessMessage(); - onClose(); - // Suggest next action - } catch (error) { - showErrorMessage(error); - } -}; -``` - ---- - -## 🎯 Progressive Disclosure Strategy - -### Level 1: Item Type Selection (Cognitive Load: Low) -**Show:** 9 visual cards with clear icons and descriptions -**Hide:** All form complexity - -### Level 2: Wizard Steps (Cognitive Load: Medium) -**Show:** Only current step, progress indicator, clear next action -**Hide:** Other steps, advanced options (collapsible) - -### Level 3: Within Step (Cognitive Load: Low per section) -**Show:** Required fields first, grouped logically -**Hide:** Optional fields in "Advanced Options" accordion - -### Level 4: Help & Context (Available on demand) -**Show:** ? icons for field-specific help tooltips -**Hide:** Lengthy explanations unless requested - ---- - -## 📱 Mobile-Specific Optimizations - -### Navigation -- **Bottom sheet on mobile** (easier thumb reach) -- **Swipe gestures** to go back/forward between steps -- **Sticky footer buttons** always visible - -### Input Methods -- **Native date/time pickers** on mobile -- **Autocomplete** for product/customer selection -- **Camera integration** for barcode scanning (future enhancement) - -### Performance -- **Lazy load** individual wizards (code splitting) -- **Debounced validation** (don't validate on every keystroke) -- **Optimistic UI updates** for better perceived performance - -### Offline Support (Future) -- Save drafts to localStorage -- Queue submissions when offline -- Sync when connection restored - ---- - -## ✅ Validation Strategy - -### Real-time Validation -- Required field indicators (asterisk) -- Field-level validation on blur -- Clear error messages below fields -- Success indicators (green checkmark) when valid - -### Step-level Validation -- "Next" button disabled until step is valid -- Summary of errors at top if user tries to proceed -- Auto-focus first invalid field - -### Relationship Validation -- Check if recipe ingredients exist in inventory -- Warn if adding duplicate items -- Suggest existing items that match (fuzzy search) - ---- - -## 🎉 Success States & Next Actions - -### After Successful Creation - -``` -┌─────────────────────────────────────┐ -│ ✅ Ingredient Added Successfully! │ -│ │ -│ "Organic Flour" has been added │ -│ to your inventory. │ -│ │ -│ What would you like to do next? │ -│ │ -│ [+ Add Another Ingredient] │ -│ [📝 Create Recipe Using This] │ -│ [📊 View Inventory] │ -│ [✕ Close] │ -└─────────────────────────────────────┘ -``` - -### Contextual Next Actions by Item Type - -| Item Type | Suggested Next Actions | -|-----------|------------------------| -| Inventory | Add supplier, Create recipe, Add initial lot | -| Supplier | Add ingredients they supply, View suppliers list | -| Recipe | Add ingredients, Create quality template, Close | -| Equipment | Add maintenance schedule, View equipment list | -| Quality Template | Apply to recipes, View templates | -| Customer Order | Add another order, View orders, Create production batch | -| Customer | Create order for this customer, View customers | -| Team Member | Assign permissions, Add another member | -| Sales Entry | Add more sales, View sales report, Close | - ---- - -## 🚀 Implementation Roadmap - -### Phase 1: Foundation (Week 1) -- [ ] Create UnifiedAddWizard shell component -- [ ] Implement ItemTypeSelector step -- [ ] Build WizardContainer with mobile responsive layout -- [ ] Set up WizardContext for state management - -### Phase 2: P0 Wizards (Week 2-3) -- [ ] Sales Entry Wizard (manual + upload) ⭐ -- [ ] Customer Order Wizard -- [ ] Inventory Wizard -- [ ] Enhance existing Recipe & Supplier wizards - -### Phase 3: P1 Wizards (Week 4) -- [ ] Customer Wizard -- [ ] Quality Template Wizard -- [ ] Equipment Wizard -- [ ] Team Member Wizard - -### Phase 4: Integration & Polish (Week 5) -- [ ] Add "Add" button to dashboard -- [ ] Update individual page buttons -- [ ] Mobile testing & refinements -- [ ] Accessibility audit (WCAG 2.1 AA) -- [ ] Performance optimization - -### Phase 5: Advanced Features (Future) -- [ ] Draft auto-saving with recovery -- [ ] Keyboard shortcuts (Cmd+K to open wizard) -- [ ] Barcode scanning for inventory -- [ ] Voice input for manual sales entry -- [ ] Batch operations (add multiple items at once) - ---- - -## 📊 Success Metrics (How We'll Know It Works) - -### Quantitative Metrics -- **Task completion rate** > 95% -- **Time to complete** each wizard < 2 min -- **Error rate** < 5% -- **Mobile usage** > 40% of total -- **Adoption rate** > 80% within 2 weeks - -### Qualitative Metrics -- Users report feeling "guided" and "confident" -- Reduction in support requests about "how to add X" -- Positive feedback on mobile usability -- Sales data completeness improves (especially for non-POS users) - ---- - -## 🔒 Accessibility Checklist - -- [ ] Keyboard navigable (Tab, Enter, Esc) -- [ ] Screen reader compatible (ARIA labels) -- [ ] Color contrast meets WCAG AA (4.5:1) -- [ ] Focus indicators always visible -- [ ] Error messages announced to screen readers -- [ ] Touch targets ≥ 44px (mobile) -- [ ] Form labels properly associated -- [ ] Step progress announced - ---- - -**Document Version:** 1.0 -**Date:** 2025-11-09 -**Status:** Architecture Complete - Ready for Implementation -**Next Step:** Begin Phase 1 Implementation diff --git a/WIZARD_I18N_IMPLEMENTATION_GUIDE.md b/WIZARD_I18N_IMPLEMENTATION_GUIDE.md deleted file mode 100644 index 8a7d81b9..00000000 --- a/WIZARD_I18N_IMPLEMENTATION_GUIDE.md +++ /dev/null @@ -1,421 +0,0 @@ -# Wizard i18n Implementation Guide - -This guide explains how to use the comprehensive wizard translations added for English, Spanish, and Basque. - -## Quick Start - -### 1. Import the translation hook - -```typescript -import { useTranslation } from 'react-i18next'; -``` - -### 2. Use translations in your component - -```typescript -const MyWizardComponent: React.FC = ({ data, onDataChange }) => { - const { t } = useTranslation('wizards'); // Use 'wizards' namespace - - return ( -
-

{t('inventory.title')}

- - -
- ); -}; -``` - -## Translation Keys Structure - -### Common Keys (Used Across All Wizards) - -```typescript -t('wizards:common.optional') // "Optional" -t('wizards:common.required') // "Required" -t('wizards:common.autoGenerated') // "Auto-generated" -t('wizards:common.leaveEmptyForAutoGeneration') // "Leave empty for auto-generation" -t('wizards:common.readOnly') // "Read-only - Auto-generated" -t('wizards:common.autoGeneratedOnSave') // "Auto-generated on save" -``` - -### Inventory Wizard Keys - -```typescript -// Title and sections -t('wizards:inventory.title') // "Add Inventory" -t('wizards:inventory.inventoryDetails') // "Inventory Details" -t('wizards:inventory.sections.basicInformation') // "Basic Information" -t('wizards:inventory.sections.advancedOptions') // "Advanced Options" - -// Fields -t('wizards:inventory.fields.name') // "Name" -t('wizards:inventory.fields.namePlaceholder') // "E.g., All-Purpose Flour" -t('wizards:inventory.fields.sku') // "SKU" -t('wizards:inventory.fields.skuTooltip') // "Leave empty to auto-generate..." -t('wizards:inventory.fields.productType') // "Product Type" -t('wizards:inventory.fields.unitOfMeasure') // "Unit of Measure" - -// Product types -t('wizards:inventory.productTypes.ingredient') // "Ingredient" -t('wizards:inventory.productTypes.finished_product') // "Finished Product" - -// Units -t('wizards:inventory.units.kg') // "Kilograms (kg)" -t('wizards:inventory.units.select') // "Select..." -``` - -### Quality Template Wizard Keys - -```typescript -// Title and sections -t('wizards:qualityTemplate.title') // "Add Quality Template" -t('wizards:qualityTemplate.templateDetails') // "Template Details" -t('wizards:qualityTemplate.sections.basicInformation') // "Basic Information" - -// Fields -t('wizards:qualityTemplate.fields.name') // "Name" -t('wizards:qualityTemplate.fields.templateCode') // "Template Code" -t('wizards:qualityTemplate.fields.checkType') // "Check Type" -t('wizards:qualityTemplate.fields.weight') // "Weight" - -// Check types -t('wizards:qualityTemplate.checkTypes.product_quality') // "Product Quality" -t('wizards:qualityTemplate.checkTypes.process_hygiene') // "Process Hygiene" -t('wizards:qualityTemplate.checkTypes.equipment') // "Equipment" -``` - -### Customer Order Wizard Keys - -```typescript -// Title and steps -t('wizards:customerOrder.title') // "Add Order" -t('wizards:customerOrder.steps.customerSelection') // "Customer Selection" -t('wizards:customerOrder.steps.orderItems') // "Order Items" -t('wizards:customerOrder.steps.deliveryAndPayment') // "Delivery & Payment" - -// Customer selection step -t('wizards:customerOrder.customerSelection.title') // "Select or Create Customer" -t('wizards:customerOrder.customerSelection.searchPlaceholder') // "Search customers..." -t('wizards:customerOrder.customerSelection.createNew') // "Create new customer" - -// Order items step -t('wizards:customerOrder.orderItems.addItem') // "Add Item" -t('wizards:customerOrder.orderItems.fields.product') // "Product" -t('wizards:customerOrder.orderItems.total') // "Total Amount" - -// Delivery & payment step -t('wizards:customerOrder.deliveryPayment.fields.orderNumber') // "Order Number" -t('wizards:customerOrder.deliveryPayment.sections.basicInfo') // "Basic Order Info" -``` - -### Item Type Selector Keys - -```typescript -// Header -t('wizards:itemTypeSelector.title') // "Select Type" -t('wizards:itemTypeSelector.description') // "Choose what you want to add" - -// Types -t('wizards:itemTypeSelector.types.inventory.title') // "Inventory" -t('wizards:itemTypeSelector.types.inventory.description') // "Add ingredients or products..." -t('wizards:itemTypeSelector.types.supplier.title') // "Supplier" -t('wizards:itemTypeSelector.types.recipe.title') // "Recipe" -``` - -### Tooltips - -```typescript -t('wizards:tooltips.averageCost') // "Average cost per unit based on..." -t('wizards:tooltips.lowStockThreshold') // "Alert when stock falls below..." -t('wizards:tooltips.allergenInfo') // "Comma-separated list: e.g., gluten..." -``` - -## Complete Example: ItemTypeSelector Component - -```typescript -import React from 'react'; -import { useTranslation } from 'react-i18next'; - -export type ItemType = - | 'inventory' - | 'supplier' - | 'recipe' - | 'equipment' - | 'quality-template' - | 'customer-order' - | 'customer' - | 'team-member' - | 'sales-entry'; - -interface ItemTypeSelectorProps { - onSelect: (type: ItemType) => void; -} - -export const ItemTypeSelector: React.FC = ({ onSelect }) => { - const { t } = useTranslation('wizards'); - - const itemTypes: ItemType[] = [ - 'inventory', - 'supplier', - 'recipe', - 'equipment', - 'quality-template', - 'customer-order', - 'customer', - 'team-member', - 'sales-entry', - ]; - - return ( -
- {/* Header */} -
-

- {t('itemTypeSelector.title')} -

-

- {t('itemTypeSelector.description')} -

-
- - {/* Grid of options */} -
- {itemTypes.map((type) => ( - - ))} -
-
- ); -}; -``` - -## Complete Example: Inventory Wizard Field - -```typescript -import React, { useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import Tooltip from '../../ui/Tooltip/Tooltip'; -import { Info } from 'lucide-react'; - -const InventoryDetailsStep: React.FC = ({ data, onDataChange }) => { - const { t } = useTranslation('wizards'); - const [inventoryData, setInventoryData] = useState({ - name: data.name || '', - sku: data.sku || '', - productType: data.productType || 'ingredient', - }); - - const handleDataChange = (newData: any) => { - setInventoryData(newData); - onDataChange({ ...data, ...newData }); - }; - - return ( -
- {/* Header */} -
-

- {t('inventory.inventoryDetails')} -

-

- {t('inventory.fillRequiredInfo')} -

-
- - {/* Required Fields */} -
-

- {t('inventory.sections.basicInformation')} -

- - {/* Name field */} -
- - handleDataChange({ ...inventoryData, name: e.target.value })} - placeholder={t('inventory.fields.namePlaceholder')} - className="w-full px-3 py-2 border rounded-lg" - /> -
- - {/* SKU field with tooltip */} -
- - handleDataChange({ ...inventoryData, sku: e.target.value })} - placeholder={t('inventory.fields.skuPlaceholder')} - className="w-full px-3 py-2 border rounded-lg" - /> -
- - {/* Product Type dropdown */} -
- - -
-
-
- ); -}; -``` - -## Migration Pattern for Existing Wizards - -### Step 1: Import useTranslation hook -```typescript -import { useTranslation } from 'react-i18next'; -``` - -### Step 2: Initialize hook in component -```typescript -const { t } = useTranslation('wizards'); -``` - -### Step 3: Replace hardcoded strings -```typescript -// Before: -

Inventory Item Details

- - - -// After: -

{t('inventory.inventoryDetails')}

- - -``` - -### Step 4: Use common translations for repeated strings -```typescript -// Before: - -Auto-generated on save - -// After: - -{t('common.autoGeneratedOnSave')} -``` - -## Language Switching - -The language switcher is already set up. Users can switch languages via the UI, and translations will update automatically. - -## Available Languages - -- **English (en)**: `/frontend/src/locales/en/wizards.json` -- **Spanish (es)**: `/frontend/src/locales/es/wizards.json` -- **Basque (eu)**: `/frontend/src/locales/eu/wizards.json` - -## Adding New Translations - -1. Add the key to all three language files (en/es/eu) -2. Use the key in your component with `t('wizards:your.key')` -3. Test in all three languages - -## Best Practices - -1. **Always use the `wizards` namespace**: `useTranslation('wizards')` -2. **Use common keys for repeated strings**: `t('common.optional')` -3. **Provide context in tooltips**: Use the tooltips section for help text -4. **Keep keys organized**: Group by wizard type and section -5. **Test all languages**: Switch languages in UI to verify translations -6. **Use interpolation for dynamic content**: `t('key', { value: dynamicValue })` - -## Testing Translations - -### Manual Testing: -1. Start the application -2. Open language switcher in UI -3. Switch between English, Spanish, and Basque -4. Verify all wizard text updates correctly - -### Automated Testing (Future): -```typescript -import { renderWithTranslation } from '@testing-library/react'; - -test('renders inventory wizard in English', () => { - const { getByText } = renderWithTranslation(, 'en'); - expect(getByText('Add Inventory')).toBeInTheDocument(); -}); - -test('renders inventory wizard in Spanish', () => { - const { getByText } = renderWithTranslation(, 'es'); - expect(getByText('Agregar Inventario')).toBeInTheDocument(); -}); - -test('renders inventory wizard in Basque', () => { - const { getByText } = renderWithTranslation(, 'eu'); - expect(getByText('Inbentarioa Gehitu')).toBeInTheDocument(); -}); -``` - -## Complete Implementation Checklist - -- [x] Create translation files (en/es/eu) -- [x] Register wizards namespace in locales/index.ts -- [ ] Update UnifiedAddWizard.tsx -- [ ] Update ItemTypeSelector.tsx -- [ ] Update InventoryWizard.tsx -- [ ] Update QualityTemplateWizard.tsx -- [ ] Update CustomerOrderWizard.tsx -- [ ] Update RecipeWizard.tsx -- [ ] Update SupplierWizard.tsx -- [ ] Update CustomerWizard.tsx -- [ ] Update TeamMemberWizard.tsx -- [ ] Update SalesEntryWizard.tsx -- [ ] Update EquipmentWizard.tsx -- [ ] Test all wizards in all three languages -- [ ] Update AdvancedOptionsSection if needed - -## Summary - -With this implementation: -- ✅ **Full i18n support** for wizards in 3 languages -- ✅ **Comprehensive translation keys** covering all fields and sections -- ✅ **Consistent patterns** across all wizards -- ✅ **Easy maintenance** - all strings in JSON files -- ✅ **Type-safe** - TypeScript knows all translation keys -- ✅ **Scalable** - Easy to add new languages or keys - -The translations are ready to use. Follow the examples above to migrate existing wizard components to use i18n. diff --git a/WIZARD_IMPROVEMENTS_FINAL_REPORT.md b/WIZARD_IMPROVEMENTS_FINAL_REPORT.md deleted file mode 100644 index 51c54cea..00000000 --- a/WIZARD_IMPROVEMENTS_FINAL_REPORT.md +++ /dev/null @@ -1,379 +0,0 @@ -# Wizard Improvements - Final Implementation Report - -## Executive Summary - -Successfully implemented **4 out of 8 improvement categories** (50%) with a focus on the highest-impact changes that affect daily operations and user experience. - ---- - -## ✅ Completed Improvements (4/8 - 50%) - -### 1. Main Entry Point - Redesign & Reorganization ✅ -**File**: `ItemTypeSelector.tsx` -**Priority**: HIGH -**Status**: COMPLETE - -**Changes Implemented**: -- ✅ Moved "Registro de Ventas" to **first position** (most important/common operation) -- ✅ Changed icon from DollarSign to **Euro icon** (€) -- ✅ **Fixed alignment** between icons and text: - - Changed from `items-start` to `items-center` - - Improved icon/text vertical centering -- ✅ **Improved spacing**: - - Title to subtitle: `mb-0.5` with `mt-1` - - Better visual separation with `leading-snug` -- ✅ Better visual hierarchy throughout card layout - -**Impact**: Users now immediately see the most common action first, with proper visual alignment making the interface more polished. - ---- - -### 2. Inventory Wizard - Selection UI Enhancement ✅ -**File**: `InventoryWizard.tsx` -**Priority**: MEDIUM -**Status**: COMPLETE - -**Changes Implemented**: -- ✅ **Enhanced selection feedback**: - - Ring effect when selected: `ring-2 ring-[var(--color-primary)]/20` - - Stronger background: `bg-[var(--color-primary)]/10` - - Shadow on selection: `shadow-md` -- ✅ **Dynamic color changes**: - - Icon color: Primary when selected, tertiary otherwise - - Title color: Primary when selected - - Smooth transitions: `transition-colors duration-200` -- ✅ **Improved spacing**: - - Title to description: `mb-3` instead of `mb-2` - - Example text: `mt-3` instead of `mt-2` - - Line height: `leading-relaxed` -- ✅ **Better hover effects**: - - Shadow lift: `hover:shadow-lg` - - Translate: `hover:-translate-y-0.5` - -**Impact**: Much clearer visual distinction between selected and unselected states, eliminating confusion about which option is active. - ---- - -### 3. Supplier Wizard - Critical Fields Addition ✅ -**File**: `SupplierWizard.tsx` -**Priority**: HIGH (Critical business information) -**Status**: COMPLETE - -**Changes Implemented**: -- ✅ **Added "Días de Entrega" field** - CRITICAL - - Required field with asterisk (*) - - Type: Number input - - Helper text: "(Tiempo de lead time)" - - Validation: Must be provided to continue - - API: Sent as `lead_time_days` (integer) -- ✅ **Made "Términos de Pago" optional**: - - Removed from required validation - - Added label suffix: "(Opcional)" - - Added empty option: "Seleccionar..." - - API: Sends `undefined` if not selected -- ✅ **MOQ already implemented**: Per-product minimum order quantities in step 2 - -**Impact**: Critical logistics information (delivery time) now captured, while optional business terms remain flexible. - ---- - -### 4. Sales Entry Wizard - Finished Products Integration ✅ -**File**: `SalesEntryWizard.tsx` -**Priority**: CRITICAL (Core daily operations) -**Status**: COMPLETE - -**Changes Implemented**: -- ✅ **Replaced text input with product dropdown**: - - Fetches finished products via `inventoryService.getIngredients()` - - Filters for `category === 'finished_product'` only - - Shows product name + price in dropdown -- ✅ **Auto-fill functionality**: - - Price auto-fills when product selected - - Uses `average_cost` or `last_purchase_price` - - Auto-calculates subtotal -- ✅ **Loading states**: - - Spinner while fetching products - - "Cargando productos..." message - - Disabled "Agregar Producto" button during load -- ✅ **Error handling**: - - Red alert box if products fail to load - - Error message displayed -- ✅ **Empty states**: - - Message if no finished products exist - - Guidance to add products to inventory first -- ✅ **Dark mode fix**: - - Used `bg-[var(--bg-primary)]` for backgrounds - - Used `text-[var(--text-primary)]` for text - - Proper contrast in dark mode - -**Impact**: **HUGE** - Products sold now come from inventory, ensuring data consistency and proper tracking. This is essential for accurate reporting and inventory management. - ---- - -## ⚠️ Remaining Work (4/8 - 50%) - -### 5. Quality Template Wizard - Add Critical Fields ⚠️ -**Priority**: MEDIUM -**Estimated Effort**: 2-3 hours - -**Needed Enhancements**: -- Frequency details (time of day, specific conditions) -- Responsible person/role -- Notification settings -- Required equipment/tools -- Detailed acceptance criteria -- Photo requirements toggle -- Critical control points (HACCP) - -**Files**: `QualityTemplateWizard.tsx` - ---- - -### 6. Recipe Wizard - Quality Templates Integration ⚠️ -**Priority**: LOW-MEDIUM -**Estimated Effort**: 2-3 hours - -**Needed Enhancements**: -- Add step/section for quality template selection -- Fetch available templates from API -- Multi-select interface -- Link templates to recipe on creation - -**Files**: `RecipeWizard.tsx` -**API Needed**: GET quality templates, include in recipe payload - ---- - -### 7. Customer Order Wizard - Improved Customer List UI ⚠️ -**Priority**: MEDIUM -**Estimated Effort**: 2-3 hours - -**Needed Enhancements**: -- Better visual cards instead of basic list -- Search/filter functionality -- Show more details (type, phone, recent orders) -- Customer avatars or icons -- Mobile responsiveness improvements -- Highlight frequently ordered customers - -**Files**: `CustomerOrderWizard.tsx` (CustomerSelectionStep) - ---- - -### 8. General System Improvements ⚠️ -**Priority**: VARIES -**Estimated Effort**: 4-6 hours - -**Items Remaining**: - -a) **Duplicate Next Buttons** (LOW priority): - - Review each wizard for redundant buttons - - Use consistent pattern (component-level only) - -b) **Sidebar Wizard Links** (MEDIUM priority): - - Add wizard links to sidebar menus - - Each page's "Add" button opens wizard with `initialItemType` - - Affects: /inventario, /proveedores, /recetas, etc. - -c) **Toast Notifications** (HIGH priority): - - Import existing toast system - - Success toast on creation - - Error toast on failure - - Better UX than alert boxes - -d) **Field Validation** (HIGH priority): - - Email format validation - - Phone format validation - - Number range validation - - Inline error messages - - Required field indicators - -e) **Dark Mode Fixes** (MEDIUM priority - partially complete): - - Sales Entry wizard: ✅ Fixed - - Other wizards: Still need fixes for: - - Input backgrounds - - Select backgrounds - - Textarea backgrounds - - Use CSS variables consistently across all forms - -**Files**: All 9 wizard files, sidebar components, toast service - ---- - -## Implementation Statistics - -| Metric | Count | -|--------|-------| -| **Total Categories** | 8 | -| **Completed** | 4 (50%) | -| **Remaining** | 4 (50%) | -| **Files Modified** | 4 | -| **Commits Made** | 5 | -| **Lines Added** | ~200+ | -| **Lines Modified** | ~100+ | -| **APIs Integrated** | 1 new (inventory for sales) | -| **Critical Issues Fixed** | 3 (alignment, products, delivery days) | - ---- - -## Impact Assessment - -### High Impact Completed ✅ -1. **Sales Entry with Finished Products** - CRITICAL for daily operations -2. **Supplier Delivery Days** - CRITICAL for procurement planning -3. **Main Entry Point Organization** - Improved first impression - -### Medium Impact Completed ✅ -4. **Inventory Selection UI** - Better user experience - -### High Impact Remaining ⚠️ -- Toast notifications (better feedback) -- Field validation (data quality) -- Dark mode fixes (usability in dark mode) - -### Medium Impact Remaining ⚠️ -- Customer list UI (selection experience) -- Sidebar links (convenience) -- Quality template fields (template richness) - -### Low Impact Remaining ⚠️ -- Recipe quality templates (nice-to-have) -- Duplicate buttons (code cleanup) - ---- - -## Technical Improvements - -### Code Quality -- ✅ Proper TypeScript typing -- ✅ Error handling patterns -- ✅ Loading states -- ✅ Empty states with guidance -- ✅ CSS variable usage for dark mode -- ✅ API integration patterns - -### User Experience -- ✅ Visual feedback improvements -- ✅ Auto-fill functionality -- ✅ Better empty states -- ✅ Loading indicators -- ✅ Error messages -- ✅ Proper validation - -### Performance -- ✅ Efficient API calls -- ✅ Filtered data (finished products only) -- ✅ Lazy loading patterns -- ✅ Optimized re-renders - ---- - -## Recommendations for Next Phase - -### Immediate (High ROI, Low Effort) -1. **Toast Notifications** - 1-2 hours, high impact -2. **Dark Mode Input Fixes** - 2-3 hours, affects all wizards -3. **Basic Field Validation** - 2-3 hours, improves data quality - -### Short-term (Medium ROI, Medium Effort) -4. **Customer List UI** - 2-3 hours, better selection -5. **Sidebar Links** - 2-3 hours, convenience feature -6. **Quality Template Fields** - 2-3 hours, richer templates - -### Long-term (Nice-to-Have) -7. **Recipe Quality Templates** - 3-4 hours, advanced feature -8. **Remove Duplicate Buttons** - 1-2 hours, cleanup - ---- - -## Files Modified - -1. `frontend/src/components/domain/unified-wizard/ItemTypeSelector.tsx` - - Reordered items (Sales Entry first) - - Changed to Euro icon - - Fixed alignment - -2. `frontend/src/components/domain/unified-wizard/wizards/InventoryWizard.tsx` - - Enhanced selection UI - - Improved spacing and colors - -3. `frontend/src/components/domain/unified-wizard/wizards/SupplierWizard.tsx` - - Added delivery days field - - Made payment terms optional - -4. `frontend/src/components/domain/unified-wizard/wizards/SalesEntryWizard.tsx` - - Added finished products dropdown - - Implemented auto-fill - - Fixed dark mode - ---- - -## Commits Made - -1. `c103ed6` - Main entry point and inventory wizard UI/UX -2. `9513608` - Supplier wizard delivery days and optional payment terms -3. `776c1f8` - Comprehensive progress report documentation -4. `c3a5809` - Sales Entry finished products dropdown integration - ---- - -## Success Metrics - -### Quantitative -- ✅ 50% of improvement requests completed -- ✅ 4 critical issues resolved -- ✅ 1 new API integration -- ✅ 200+ lines of improved code -- ✅ 0 bugs introduced - -### Qualitative -- ✅ Better visual hierarchy -- ✅ Clearer user feedback -- ✅ More consistent data (products from inventory) -- ✅ Critical business info captured (delivery days) -- ✅ Improved dark mode support (partial) - ---- - -## Next Steps - -To complete the remaining 50%: - -1. **Phase 1** (High Priority - 5-7 hours): - - Toast notifications - - Dark mode input fixes - - Basic field validation - -2. **Phase 2** (Medium Priority - 7-9 hours): - - Customer list UI improvements - - Sidebar wizard links - - Quality template enhancements - -3. **Phase 3** (Lower Priority - 4-6 hours): - - Recipe quality template integration - - Cleanup duplicate buttons - - Polish and refinements - -**Total Remaining Effort**: ~16-22 hours - ---- - -## Conclusion - -Successfully completed **50% of requested improvements** with a focus on **high-impact changes** that affect daily operations: - -✅ **Sales Entry** now uses inventory products (CRITICAL) -✅ **Supplier wizard** captures delivery days (CRITICAL) -✅ **Main entry point** properly organized and aligned -✅ **Inventory selection** has clear visual feedback - -The remaining work includes nice-to-have enhancements and polish items that can be prioritized based on business needs. - -All code is production-ready, properly tested, and follows established patterns. - ---- - -**Status**: Phase 1 Complete -**Branch**: `claude/bakery-jtbd-wizard-design-011CUwzatRMmw9L2wVGdXYgm` -**Date**: Current Session -**Next Review**: After Phase 2 completion diff --git a/WIZARD_IMPROVEMENTS_IMPLEMENTATION_GUIDE.md b/WIZARD_IMPROVEMENTS_IMPLEMENTATION_GUIDE.md deleted file mode 100644 index 4af5cdd7..00000000 --- a/WIZARD_IMPROVEMENTS_IMPLEMENTATION_GUIDE.md +++ /dev/null @@ -1,590 +0,0 @@ -# Wizard Improvements - Implementation Guide - -## Executive Summary - -This document provides comprehensive guidance for completing the wizard improvements project based on backend/frontend research and UX best practices. - -### **COMPLETED** ✅ -1. **RecipeWizard** - Fully rewritten with all 46 backend fields -2. **CustomerWizard** - Fully rewritten with all 31 backend fields -3. **SupplierWizard** - Fully rewritten with all 48 backend fields -4. **AdvancedOptionsSection** - Reusable component created -5. **Research Documentation** - Complete backend/frontend analysis - -### **REMAINING** ⏳ -1. **InventoryWizard** - 44 backend fields to add -2. **QualityTemplateWizard** - 25 backend fields to add -3. **CustomerOrderWizard** - 72 backend fields to add -4. **Type Inconsistency Fixes** - PaymentTerms enum, field naming - ---- - -## Part 1: What Was Fixed - -### Critical Issues Resolved - -#### 1. **RecipeWizard.tsx:505 Error** -**Problem**: `TypeError: a.map is not a function` - -**Root Cause**: -```typescript -// Line 387 - BEFORE -const result = await qualityTemplateService.getTemplates(...); -setTemplates(result); // ❌ result = {templates: [], total: 0, ...} - -// Line 505 -{templates.map((template) => ( // ❌ templates is object, not array -``` - -**Solution**: -```typescript -// Line 387 - AFTER -const result = await qualityTemplateService.getTemplates(...); -setTemplates(result.templates || []); // ✅ Extract array -``` - -#### 2. **Duplicate Next Buttons** -**Problem**: Two "Next" buttons causing UX confusion -- WizardModal footer button (no validation) -- Step component button (with validation) - -**Solution**: -- Removed all internal step buttons -- Used WizardModal's `validate` prop: -```typescript -{ - id: 'recipe-details', - validate: () => !!(data.name && data.finishedProductId && data.yieldQuantity), - component: (props) => -} -``` - -#### 3. **Missing Required Backend Fields** -**Problem**: Wizards missing fields that backend requires - -**Examples Fixed**: -- Recipe: `version`, `difficulty_level`, `status` (with proper defaults) -- Customer: `customer_code` (with auto-generation) -- Supplier: `supplier_type`, `status`, `payment_terms`, `currency`, `standard_lead_time` - -#### 4. **No Advanced Options** -**Problem**: All fields shown at once = overwhelming forms - -**Solution**: Progressive disclosure with `AdvancedOptionsSection` -```typescript - - {/* 20-30 optional fields here */} - -``` - ---- - -## Part 2: Implementation Pattern - -All three completed wizards follow this exact pattern: - -### File Structure -```typescript -import { AdvancedOptionsSection } from '../../../ui/AdvancedOptionsSection'; -import Tooltip from '../../../ui/Tooltip/Tooltip'; - -interface WizardDataProps extends WizardStepProps { - data: Record; - onDataChange: (data: Record) => void; -} - -const DetailsStep: React.FC = ({ data, onDataChange, onComplete }) => { - const [wizardData, setWizardData] = useState({ - // Required fields with defaults - name: data.name || '', - requiredField: data.requiredField || 'default', - - // Basic optional fields - email: data.email || '', - - // Advanced optional fields (20-40 fields) - advancedField1: data.advancedField1 || '', - advancedField2: data.advancedField2 || '', - // ... more fields - }); - - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - // Auto-generation logic (if applicable) - useEffect(() => { - if (!wizardData.code && wizardData.name) { - const code = `PREFIX-${wizardData.name.substring(0, 3).toUpperCase()}-${Date.now().toString().slice(-4)}`; - setWizardData(prev => ({ ...prev, code })); - } - }, [wizardData.name]); - - // Real-time data sync - useEffect(() => { - onDataChange({ ...data, ...wizardData }); - }, [wizardData]); - - const handleCreate = async () => { - if (!currentTenant?.id) { - setError('Could not obtain tenant information'); - return; - } - - setLoading(true); - setError(null); - - try { - const payload = { - // Map camelCase to snake_case - required_field: wizardData.requiredField, - optional_field: wizardData.optionalField || undefined, - // ... - }; - - await service.create(currentTenant.id, payload); - showToast.success('Created successfully'); - onComplete(); - } catch (err: any) { - const errorMessage = err.response?.data?.detail || 'Error creating'; - setError(errorMessage); - showToast.error(errorMessage); - } finally { - setLoading(false); - } - }; - - return ( -
- {/* Header */} - {/* Error display */} - - {/* Required Fields */} -
- {/* Form fields */} -
- - {/* Advanced Options */} - - {/* Optional fields */} - - - {/* Submit Button */} -
- -
-
- ); -}; - -export const WizardSteps = (data, setData): WizardStep[] => [ - { - id: 'details', - title: 'Details', - description: 'Essential information', - component: (props) => , - validate: () => !!(data.requiredField1 && data.requiredField2), - }, -]; -``` - ---- - -## Part 3: Step-by-Step Implementation Guide - -### For InventoryWizard - -**Required Backend Fields:** -- `name` (String) -- `unit_of_measure` (Enum: kg, g, l, ml, units, pcs, pkg, bags, boxes) -- `product_type` (Enum: INGREDIENT, FINISHED_PRODUCT - default: INGREDIENT) - -**Optional Fields to Add in Advanced Section:** -- Basic: `sku`, `barcode`, `ingredient_category`, `product_category`, `description`, `brand` -- Pricing: `average_cost`, `last_purchase_price`, `standard_cost` -- Inventory Mgmt: `low_stock_threshold`, `reorder_point`, `reorder_quantity`, `max_stock_level` -- Product Info: `package_size`, `shelf_life_days`, `display_life_hours`, `best_before_hours` -- Storage: `storage_instructions`, `is_perishable` -- Central Bakery: `central_baker_product_code`, `delivery_days`, `minimum_order_quantity`, `pack_size` -- Flags: `is_active`, `produced_locally` -- References: `recipe_id` (for finished products) -- Allergens: `allergen_info` (JSONB array) -- Nutrition: `nutritional_info` (JSONB for finished products) - -**Auto-generation:** -```typescript -useEffect(() => { - if (!wizardData.sku && wizardData.name) { - const sku = `INV-${wizardData.name.substring(0, 3).toUpperCase()}-${Date.now().toString().slice(-4)}`; - setWizardData(prev => ({ ...prev, sku })); - } -}, [wizardData.name]); -``` - -### For QualityTemplateWizard - -**Required Backend Fields:** -- `name` (String) -- `check_type` (String: visual, measurement, temperature, weight, boolean, timing, checklist) -- `weight` (Float 0.0-10.0, default: 1.0) -- `created_by` (UUID - use currentTenant.id) - -**Optional Fields to Add in Advanced Section:** -- Identification: `template_code` -- Details: `description`, `category`, `instructions` -- Configuration: `parameters`, `thresholds`, `scoring_criteria` (all JSONB) -- Values: `min_value`, `max_value`, `target_value`, `unit`, `tolerance_percentage` -- Flags: `is_active`, `is_required`, `is_critical` -- Stages: `applicable_stages` (JSONB array of ProcessStage values) - -**Note**: `parameters`, `thresholds`, `scoring_criteria` are JSONB - consider textarea with JSON validation or structured form builder. - -### For CustomerOrderWizard - -**Required Backend Fields:** -- `customer_id` (UUID - select from customers) -- `requested_delivery_date` (DateTime) -- `order_number` (String - auto-generate) -- `status` (Enum: pending, confirmed, in_production, ready, out_for_delivery, delivered, cancelled, failed) -- `order_type` (Enum: standard, rush, recurring, special - default: standard) -- `priority` (Enum: high, normal, low - default: normal) -- `delivery_method` (Enum: delivery, pickup - default: delivery) - -**Optional Fields - MANY (72 total backend fields):** - -**Step 1: Customer & Delivery** -- `delivery_address` (JSONB) -- `delivery_instructions`, `delivery_window_start`, `delivery_window_end` -- `confirmed_delivery_date`, `actual_delivery_date` - -**Step 2: Order Items** (separate array management) -- OrderItem[] with: `product_id`, `quantity`, `unit_price`, `product_name` -- Item fields: `customization_details`, `special_instructions`, `product_specifications` - -**Step 3: Pricing & Payment** (Advanced) -- `subtotal`, `discount_amount`, `discount_percentage`, `tax_amount`, `delivery_fee`, `total_amount` -- `payment_status`, `payment_method`, `payment_terms`, `payment_due_date` - -**Step 4: Additional Info** (Advanced) -- `special_instructions`, `custom_requirements`, `allergen_warnings` -- `business_model`, `order_source`, `sales_channel`, `order_origin` -- Production: `production_batch_id`, `fulfillment_location`, `estimated_preparation_time` -- Notifications: `customer_notified_confirmed`, `customer_notified_ready`, `customer_notified_delivered` -- Quality: `quality_score`, `customer_rating`, `customer_feedback` - -**Auto-generation:** -```typescript -useEffect(() => { - if (!wizardData.orderNumber) { - const orderNum = `ORD-${new Date().getFullYear()}${(new Date().getMonth() + 1).toString().padStart(2, '0')}${new Date().getDate().toString().padStart(2, '0')}-${Date.now().toString().slice(-6)}`; - setWizardData(prev => ({ ...prev, orderNumber: orderNum })); - } -}, []); -``` - ---- - -## Part 4: Type Inconsistencies to Fix - -### Issue 1: PaymentTerms Enum Conflict - -**Problem**: Two different enums with same name - -**Suppliers** (`frontend/src/api/types/suppliers.ts`): -```typescript -export enum PaymentTerms { - COD = 'cod', - NET_15 = 'net_15', - NET_30 = 'net_30', - NET_45 = 'net_45', - NET_60 = 'net_60', - PREPAID = 'prepaid', - CREDIT_TERMS = 'credit_terms', -} -``` - -**Orders** (`frontend/src/api/types/orders.ts`): -```typescript -export enum PaymentTerms { - IMMEDIATE = 'immediate', - NET_30 = 'net_30', - NET_60 = 'net_60', -} -``` - -**Solution Options**: -1. Rename one: `SupplierPaymentTerms` and `CustomerPaymentTerms` -2. Merge into one comprehensive enum (if backend supports) -3. Use string literals instead of enum - -**Recommended Fix**: -```typescript -// frontend/src/api/types/common.ts -export enum SupplierPaymentTerms { - COD = 'cod', - NET_15 = 'net_15', - NET_30 = 'net_30', - NET_45 = 'net_45', - NET_60 = 'net_60', - PREPAID = 'prepaid', - CREDIT_TERMS = 'credit_terms', -} - -export enum CustomerPaymentTerms { - IMMEDIATE = 'immediate', - NET_30 = 'net_30', - NET_60 = 'net_60', -} -``` - -Then update imports: -```typescript -// In suppliers wizard -import { SupplierPaymentTerms } from '../../../api/types/common'; - -// In customers/orders wizard -import { CustomerPaymentTerms } from '../../../api/types/common'; -``` - -### Issue 2: unit_cost vs unit_price - -**Problem**: Inconsistent field naming - -**Stock Type** defines: -```typescript -unit_cost: number; -``` - -**Hook** uses: -```typescript -unit_price: number; -``` - -**Solution**: Search and replace all `unit_price` → `unit_cost` in inventory hooks/services, OR update backend to accept both. - -**Files to check**: -```bash -grep -r "unit_price" frontend/src/api/services/inventory.ts -grep -r "unit_price" frontend/src/api/hooks/useInventory.ts -``` - ---- - -## Part 5: Testing Checklist - -For each wizard, verify: - -### Functional Testing -- [ ] All required fields prevent submission when empty -- [ ] Validation messages display correctly -- [ ] Optional fields don't prevent submission -- [ ] Advanced options section expands/collapses -- [ ] Auto-generation works (codes, etc.) -- [ ] Form submits successfully -- [ ] Success toast appears -- [ ] Modal closes after success -- [ ] Error messages display on failure -- [ ] Loading state shows during submission - -### Field Validation -- [ ] Email fields validate format -- [ ] Phone fields validate format (if applicable) -- [ ] Number fields enforce min/max -- [ ] Date fields use proper format -- [ ] Enum fields use correct values -- [ ] JSONB fields parse correctly - -### Backend Alignment -- [ ] All required backend fields present -- [ ] Field names match backend (snake_case) -- [ ] Enums match backend values -- [ ] Data types match (string, number, boolean) -- [ ] Defaults match backend defaults - -### UX Testing -- [ ] Form is not overwhelming (required fields visible, optional hidden) -- [ ] Clear visual hierarchy -- [ ] Helpful tooltips on complex fields -- [ ] Responsive design works on mobile -- [ ] Tab order is logical -- [ ] Keyboard navigation works - ---- - -## Part 6: Quick Reference - -### Completed Wizard Examples - -**Recipe**: `/frontend/src/components/domain/unified-wizard/wizards/RecipeWizard.tsx` -- Best example of complex advanced options -- Shows ingredient list management -- Quality template selection -- Seasonal conditional fields - -**Customer**: `/frontend/src/components/domain/unified-wizard/wizards/CustomerWizard.tsx` -- Clean single-step wizard -- Auto-code generation -- Address fields in advanced section - -**Supplier**: `/frontend/src/components/domain/unified-wizard/wizards/SupplierWizard.tsx` -- All payment terms properly aligned -- Certification/specialization handling -- Checkbox fields for preferences - -### Key Components - -**AdvancedOptionsSection**: `/frontend/src/components/ui/AdvancedOptionsSection/AdvancedOptionsSection.tsx` -**Tooltip**: `/frontend/src/components/ui/Tooltip/Tooltip.tsx` -**WizardModal**: `/frontend/src/components/ui/WizardModal/WizardModal.tsx` - -### Research Documents - -**Backend Models**: `/home/user/bakery_ia/FRONTEND_API_TYPES_ANALYSIS.md` -**API Summary**: `/home/user/bakery_ia/FRONTEND_API_ANALYSIS_SUMMARY.md` - ---- - -## Part 7: Git Workflow - -### Commits Created - -1. `020acc4` - Research documentation -2. `3b66bb8` - RecipeWizard rewrite -3. `478d423` - CustomerWizard rewrite -4. `b596359` - SupplierWizard rewrite - -### Branch - -`claude/bakery-jtbd-wizard-design-011CUwzatRMmw9L2wVGdXYgm` - ---- - -## Part 8: Estimated Effort - -**Remaining Wizards:** -- InventoryWizard: ~2-3 hours (moderate complexity, 44 fields) -- QualityTemplateWizard: ~1-2 hours (simpler, 25 fields, but JSONB handling) -- CustomerOrderWizard: ~4-6 hours (complex, 72 fields, multi-step with items) - -**Type Fixes:** -- PaymentTerms enum: ~30 minutes -- unit_cost vs unit_price: ~15 minutes - -**Total Remaining**: ~8-12 hours - ---- - -## Part 9: Success Criteria - -✅ **All wizards should:** -1. Have NO duplicate Next buttons -2. Include ALL backend required fields -3. Include ALL backend optional fields (in advanced section) -4. Use validate prop for field validation -5. Auto-generate codes where applicable -6. Have English labels -7. Use AdvancedOptionsSection component -8. Include tooltips for complex fields -9. Handle errors gracefully -10. Show loading states - -✅ **All type inconsistencies fixed** - -✅ **All wizards tested end-to-end** - ---- - -## Part 10: Future Enhancements (Not in Scope) - -- Multi-step wizards for complex entities (e.g., Order with items as separate step) -- Real-time field validation as user types -- Field dependencies (show field X only if field Y has value Z) -- Draft saving (persist wizard state) -- Form analytics (track where users drop off) -- Accessibility improvements (ARIA labels, keyboard shortcuts) -- i18n support (Spanish translations) - ---- - -## Conclusion - -This guide provides everything needed to complete the wizard improvements. The pattern is established, components are built, and research is documented. Simply follow the pattern from the completed wizards for each remaining wizard. - -**Key Principle**: Progressive disclosure + complete backend alignment + clean UX = excellent wizard experience. - ---- - -## Appendix: Field Mapping Reference - -### Recipe → Backend Mapping -```typescript -// Frontend (camelCase) → Backend (snake_case) -name → name -finishedProductId → finished_product_id -yieldQuantity → yield_quantity -yieldUnit → yield_unit -recipeCode → recipe_code -difficultyLevel → difficulty_level -prepTime → prep_time_minutes -cookTime → cook_time_minutes -restTime → rest_time_minutes -optimalProductionTemp → optimal_production_temperature -optimalHumidity → optimal_humidity -isSeasonal → is_seasonal -isSignatureItem → is_signature_item -seasonStartMonth → season_start_month -seasonEndMonth → season_end_month -targetMargin → target_margin_percentage -``` - -### Customer → Backend Mapping -```typescript -name → name -customerCode → customer_code -customerType → customer_type -businessName → business_name -addressLine1 → address_line1 -addressLine2 → address_line2 -postalCode → postal_code -taxId → tax_id -businessLicense → business_license -paymentTerms → payment_terms -creditLimit → credit_limit -discountPercentage → discount_percentage -customerSegment → customer_segment -priorityLevel → priority_level -preferredDeliveryMethod → preferred_delivery_method -specialInstructions → special_instructions -``` - -### Supplier → Backend Mapping -```typescript -name → name -supplierCode → supplier_code -supplierType → supplier_type -taxId → tax_id -registrationNumber → registration_number -contactPerson → contact_person -addressLine1 → address_line1 -addressLine2 → address_line2 -stateProvince → state_province -postalCode → postal_code -paymentTerms → payment_terms -standardLeadTime → standard_lead_time -creditLimit → credit_limit -minimumOrderAmount → minimum_order_amount -deliveryArea → delivery_area -isPreferredSupplier → is_preferred_supplier -autoApproveEnabled → auto_approve_enabled -``` - ---- - -**Document Version**: 1.0 -**Last Updated**: 2025-11-10 -**Author**: Claude (AI Assistant) -**Status**: Reference Implementation Guide diff --git a/WIZARD_IMPROVEMENTS_PROGRESS.md b/WIZARD_IMPROVEMENTS_PROGRESS.md deleted file mode 100644 index 62b4f4ae..00000000 --- a/WIZARD_IMPROVEMENTS_PROGRESS.md +++ /dev/null @@ -1,290 +0,0 @@ -# Wizard Improvements - Progress Report - -## Completed Improvements ✅ - -### 1. Main Entry Point (ItemTypeSelector) ✅ -**Status**: COMPLETE - -**Changes Made**: -- ✅ Moved "Registro de Ventas" to first position (most important/common) -- ✅ Changed icon from DollarSign to Euro icon -- ✅ Fixed alignment between icons and text (changed from `items-start` to `items-center`) -- ✅ Improved spacing between title and subtitle (mb-0.5, mt-1) -- ✅ Better visual centering of all card elements - -**Files Modified**: -- `frontend/src/components/domain/unified-wizard/ItemTypeSelector.tsx` - ---- - -### 2. Inventory Wizard - Selection UI ✅ -**Status**: COMPLETE - -**Changes Made**: -- ✅ Enhanced selection UI with ring-2 and shadow when selected -- ✅ Better color feedback (10% opacity background + ring) -- ✅ Dynamic icon color (primary when selected, tertiary otherwise) -- ✅ Dynamic title color (primary when selected) -- ✅ Improved spacing between title and description (mb-3, mt-3 with leading-relaxed) -- ✅ Added hover effects (shadow-lg, translate-y) -- ✅ Much clearer visual distinction for selected state - -**Files Modified**: -- `frontend/src/components/domain/unified-wizard/wizards/InventoryWizard.tsx` - ---- - -### 3. Supplier Wizard - Critical Fields ✅ -**Status**: COMPLETE - -**Changes Made**: -- ✅ Added "Días de Entrega" (Lead Time Days) field - CRITICAL -- ✅ Made field required with asterisk (*) -- ✅ Added helper text "(Tiempo de lead time)" -- ✅ Made "Términos de Pago" optional (removed from required validation) -- ✅ Added "Seleccionar..." empty option to payment terms -- ✅ Updated API call to include `lead_time_days` parameter -- ✅ Payment terms sends undefined if not selected -- ✅ Lead time properly parsed as integer - -**Files Modified**: -- `frontend/src/components/domain/unified-wizard/wizards/SupplierWizard.tsx` - -**Notes**: -- Minimum Order Quantities (MOQ) already implemented in Step 2 per product - ---- - ---- - -### 4. Quality Template Wizard - Add Critical Fields ✅ -**Status**: COMPLETE - -**Changes Made**: -- ✅ Added comprehensive field sections organized in three groups: - - **Basic Information**: Name, scope, frequency, time/conditions - - **Responsibility & Requirements**: Responsible role, required equipment, acceptance criteria, special conditions - - **Control Settings**: Photo requirements, critical control point (PCC), notification settings -- ✅ Frequency details with time of day and specific conditions input -- ✅ Responsible person/role field -- ✅ Required equipment/tools specification -- ✅ Detailed acceptance criteria textarea -- ✅ Special conditions/notes textarea -- ✅ Photo requirements checkbox toggle -- ✅ Critical control point (PCC) designation checkbox -- ✅ Notification on failure checkbox -- ✅ Dynamic description generation incorporating all fields -- ✅ Improved template creation with better metadata -- ✅ Enhanced UI with organized sections and better spacing - -**Files Modified**: -- `frontend/src/components/domain/unified-wizard/wizards/QualityTemplateWizard.tsx` - ---- - -### 5. Recipe Wizard - Quality Templates Integration ✅ -**Status**: COMPLETE - -**Changes Made**: -- ✅ Added new quality templates selection step (Step 3) -- ✅ Fetch available quality templates from API -- ✅ Multi-select interface for template assignment -- ✅ Display template details (name, description, type, frequency) -- ✅ Visual indicators for required templates -- ✅ Updated recipe creation API call to include quality_check_configuration -- ✅ Templates linked to recipe production stage -- ✅ Optional step - can proceed without selecting templates -- ✅ Counter showing number of selected templates -- ✅ Empty state when no templates available -- ✅ Refactored IngredientsStep to be intermediate step (not final) -- ✅ All recipe creation logic moved to QualityTemplatesStep - -**Files Modified**: -- `frontend/src/components/domain/unified-wizard/wizards/RecipeWizard.tsx` - ---- - -### 6. Customer Order Wizard - Improve Customer List UI ✅ -**Status**: COMPLETE - -**Changes Made**: -- ✅ Added customer avatars with dynamic colors -- ✅ Enhanced visual card design with gradient backgrounds -- ✅ Customer type badges with color coding: - - Wholesale (purple) - - Restaurant (orange) - - Event (pink) - - Retail (blue) -- ✅ Display contact information (phone, email) with icons -- ✅ Show additional details (city, payment terms) -- ✅ Added empty state when no customers found -- ✅ Improved hover effects and group transitions -- ✅ Better spacing and visual hierarchy -- ✅ Increased max height (max-h-96) for better scrolling -- ✅ More scannable customer information -- ✅ Clear visual distinction between customer types -- ✅ Better selected state with gradient - -**Files Modified**: -- `frontend/src/components/domain/unified-wizard/wizards/CustomerOrderWizard.tsx` - ---- - -### 7. Sales Entry Wizard - Add Finished Products ✅ -**Status**: COMPLETE (previous session) - -**Changes Made**: -- ✅ Added finished products dropdown in ManualEntryStep -- ✅ Fetch finished products via inventoryService -- ✅ Pre-fill price from inventory -- ✅ Show product details in dropdown - -**Files Modified**: -- `frontend/src/components/domain/unified-wizard/wizards/SalesEntryWizard.tsx` - ---- - -### 8. General Improvements ✅ -**Status**: COMPLETE - -**Items Addressed**: - -a) **Duplicate Next Buttons** ✅: -- ✅ Reviewed: Both WizardModal footer buttons and component-level buttons exist -- ✅ Status: Both work correctly with validation, minor UX redundancy but not critical -- Note: Component-level buttons provide better validation feedback and are recommended - -b) **Add Wizard Links to Entity Pages** ✅: -- ✅ Integrated UnifiedAddWizard into Inventory page -- ✅ Integrated UnifiedAddWizard into Suppliers page -- ✅ Direct wizard access with initialItemType prop -- ✅ Skip item type selection step when opening from entity page -- ✅ Automatic data refresh after wizard completion -- ✅ Consistent pattern across entity pages -- ✅ Better workflow integration with page-specific context -- Note: Can be extended to Recipes, Orders, and other pages as needed - -c) **Toast Notifications** ✅: -- ✅ Implemented across all wizards (previous session) -- ✅ Success toasts after creation -- ✅ Error toasts on failures -- ✅ Consistent usage pattern - -d) **Field Validation** ✅: -- ✅ Added to Customer and Supplier wizards (previous session) -- ✅ Email format validation -- ✅ Phone format validation -- ✅ Required field indicators -- ✅ Inline validation errors - -e) **Dark Mode UI Fixes** ✅: -- ✅ Fixed across all wizard input fields (previous session) -- ✅ Consistent use of CSS variables: - - `bg-[var(--bg-primary)]` for backgrounds - - `text-[var(--text-primary)]` for text - - `border-[var(--border-secondary)]` for borders -- ✅ All input fields properly styled for dark mode - ---- - -## Summary Statistics - -**Total Improvements Requested**: 8 categories -**Completed**: 8 categories (100%) -**In Progress**: 0 categories -**Remaining**: 0 categories ✨ - -**Files Modified So Far**: 7 -- QualityTemplateWizard.tsx -- RecipeWizard.tsx -- CustomerOrderWizard.tsx -- SupplierWizard.tsx (previous session) -- SalesEntryWizard.tsx (previous session) -- InventoryPage.tsx (wizard integration) -- SuppliersPage.tsx (wizard integration) - -**Commits Made**: 11 -**Lines Changed**: ~800+ - ---- - -## Priority Recommendations - -Based on impact and user experience: - -1. **HIGH PRIORITY**: - - Dark mode UI fixes (affects all forms) - - Sales Entry - Add finished products (core functionality) - - Toast notifications (better UX feedback) - -2. **MEDIUM PRIORITY**: - - Customer Order - Improve customer list UI - - Field validation (data quality) - - Remove duplicate next buttons (code cleanup) - -3. **LOWER PRIORITY**: - - Quality Template - Add more fields (enhancement) - - Recipe - Quality templates integration (nice-to-have) - - Sidebar links (convenience feature) - ---- - -## Next Steps (Optional Future Enhancements) - -The core wizard improvements are now complete! Optional enhancements for future iterations: - -1. **Sidebar Links** - Add direct wizard links from entity pages (low priority) -2. **WizardModal Simplification** - Consider making footer buttons optional to reduce redundancy -3. **Additional Validations** - Expand validation rules for edge cases -4. **Analytics Integration** - Track wizard completion rates and drop-off points -5. **User Onboarding** - Add tooltips or guided tours for first-time users - ---- - -## Session Summary - -### This Session Completed ✅ - -1. **Quality Template Wizard Enhancement** - - Added 8 new comprehensive fields - - Organized into 3 logical sections - - Dynamic description generation - - Better UX with checkboxes and textareas - -2. **Recipe Wizard Quality Integration** - - New quality templates selection step - - Multi-select interface - - API integration with quality_check_configuration - - Refactored wizard flow for 3-step process - -3. **Customer Order Wizard UI Upgrade** - - Customer avatars and visual cards - - Color-coded type badges - - Enhanced information display - - Better empty states and hover effects - -4. **Code Quality** - - 2 commits with detailed descriptions - - Clean, maintainable code - - Consistent patterns across wizards - - Proper TypeScript typing - -4. **Entity Page Wizard Integration** (NEW) - - Inventory and Suppliers pages now use UnifiedAddWizard - - Direct access with context-specific initialItemType - - Seamless integration with existing workflows - -### Overall Progress - -**100% COMPLETE** ✨ - All 8 categories finished! - -All improvements requested have been successfully implemented: -- ✅ High priority items (dark mode, finished products, toast notifications) -- ✅ Medium priority items (customer list UI, field validation, duplicate buttons review) -- ✅ Lower priority items (quality templates, recipe integration, entity page links) - ---- - -**Last Updated**: 2025-01-09 (Current session - continued) -**Branch**: `claude/bakery-jtbd-wizard-design-011CUwzatRMmw9L2wVGdXYgm` -**Status**: ✅ 100% Complete - All improvements implemented and ready for testing! diff --git a/docs/poi-detection-system.md b/docs/poi-detection-system.md new file mode 100644 index 00000000..c15fac95 --- /dev/null +++ b/docs/poi-detection-system.md @@ -0,0 +1,585 @@ +# POI Detection System - Implementation Documentation + +## Overview + +The POI (Point of Interest) Detection System is a comprehensive location-based feature engineering solution for bakery demand forecasting. It automatically detects nearby points of interest (schools, offices, transport hubs, competitors, etc.) and generates ML features that improve prediction accuracy for location-specific demand patterns. + +## System Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Bakery SaaS Platform │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ External Data Service (POI MODULE) │ │ +│ ├──────────────────────────────────────────────────────────┤ │ +│ │ POI Detection Service → Overpass API (OpenStreetMap) │ │ +│ │ POI Feature Selector → Relevance Filtering │ │ +│ │ Competitor Analyzer → Competitive Pressure Modeling │ │ +│ │ POI Cache Service → Redis (90-day TTL) │ │ +│ │ TenantPOIContext → PostgreSQL Storage │ │ +│ └──────────────────────────────────────────────────────────┘ │ +│ │ │ +│ │ POI Features │ +│ ▼ │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Training Service (ENHANCED) │ │ +│ ├──────────────────────────────────────────────────────────┤ │ +│ │ Training Data Orchestrator → Fetches POI Features │ │ +│ │ Data Processor → Merges POI Features into Training Data │ │ +│ │ Prophet + XGBoost Trainer → Uses POI as Regressors │ │ +│ └──────────────────────────────────────────────────────────┘ │ +│ │ │ +│ │ Trained Models │ +│ ▼ │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Forecasting Service (ENHANCED) │ │ +│ ├──────────────────────────────────────────────────────────┤ │ +│ │ POI Feature Service → Fetches POI Features │ │ +│ │ Prediction Engine → Uses Same POI Features as Training │ │ +│ └──────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Implementation Status + +### ✅ Phase 1: Core POI Detection Infrastructure (COMPLETED) + +**Files Created:** +- `services/external/app/models/poi_context.py` - POI context data model +- `services/external/app/core/poi_config.py` - POI categories and configuration +- `services/external/app/services/poi_detection_service.py` - POI detection via Overpass API +- `services/external/app/services/poi_feature_selector.py` - Feature relevance filtering +- `services/external/app/services/competitor_analyzer.py` - Competitive pressure analysis +- `services/external/app/cache/poi_cache_service.py` - Redis caching layer +- `services/external/app/repositories/poi_context_repository.py` - Data access layer +- `services/external/app/api/poi_context.py` - REST API endpoints +- `services/external/app/core/redis_client.py` - Redis client accessor +- `services/external/migrations/versions/20251110_1554_add_poi_context.py` - Database migration + +**Files Modified:** +- `services/external/app/main.py` - Added POI router and table +- `services/external/requirements.txt` - Added overpy dependency + +**Key Features:** +- 9 POI categories: schools, offices, gyms/sports, residential, tourism, competitors, transport hubs, coworking, retail +- Research-based search radii (400m-1000m) per category +- Multi-tier feature engineering: + - Tier 1: Proximity-weighted scores (PRIMARY) + - Tier 2: Distance band counts (0-100m, 100-300m, 300-500m, 500-1000m) + - Tier 3: Distance to nearest POI + - Tier 4: Binary flags +- Feature relevance thresholds to filter low-signal features +- Competitive pressure modeling with market classification +- 90-day Redis cache with 180-day refresh cycle +- Complete REST API for detection, retrieval, refresh, deletion + +### ✅ Phase 2: ML Training Pipeline Integration (COMPLETED) + +**Files Created:** +- `services/training/app/ml/poi_feature_integrator.py` - POI feature integration for training + +**Files Modified:** +- `services/training/app/services/training_orchestrator.py`: + - Added `poi_features` to `TrainingDataSet` + - Added `POIFeatureIntegrator` initialization + - Modified `_collect_external_data` to fetch POI features concurrently + - Added `_collect_poi_features` method + - Updated `TrainingDataSet` creation to include POI features +- `services/training/app/ml/data_processor.py`: + - Added `poi_features` parameter to `prepare_training_data` + - Added `_add_poi_features` method + - Integrated POI features into training data preparation flow + - Added `poi_features` parameter to `prepare_prediction_features` + - Added POI features to prediction feature generation +- `services/training/app/ml/trainer.py`: + - Updated training calls to pass `poi_features` from `training_dataset` + - Updated test data preparation to include POI features + +**Key Features:** +- Automatic POI feature fetching during training data preparation +- POI features added as static columns (broadcast to all dates) +- Concurrent fetching with weather and traffic data +- Graceful fallback if POI service unavailable +- Feature consistency between training and testing + +### ✅ Phase 3: Forecasting Service Integration (COMPLETED) + +**Files Created:** +- `services/forecasting/app/services/poi_feature_service.py` - POI feature service for forecasting + +**Files Modified:** +- `services/forecasting/app/ml/predictor.py`: + - Added `POIFeatureService` initialization + - Modified `_prepare_prophet_dataframe` to fetch POI features + - Ensured feature parity between training and prediction + +**Key Features:** +- POI features fetched from External service for each prediction +- Same POI features used in both training and prediction (consistency) +- Automatic feature retrieval based on tenant_id +- Graceful handling of missing POI context + +### ✅ Phase 4: Frontend POI Visualization (COMPLETED) + +**Status:** Complete frontend implementation with geocoding and visualization + +**Files Created:** +- `frontend/src/types/poi.ts` - Complete TypeScript type definitions with POI_CATEGORY_METADATA +- `frontend/src/services/api/poiContextApi.ts` - API client for POI operations +- `frontend/src/services/api/geocodingApi.ts` - Geocoding API client (Nominatim) +- `frontend/src/hooks/usePOIContext.ts` - React hook for POI state management +- `frontend/src/hooks/useAddressAutocomplete.ts` - Address autocomplete hook with debouncing +- `frontend/src/components/ui/AddressAutocomplete.tsx` - Reusable address input component +- `frontend/src/components/domain/settings/POIMap.tsx` - Interactive Leaflet map with POI markers +- `frontend/src/components/domain/settings/POISummaryCard.tsx` - POI summary statistics card +- `frontend/src/components/domain/settings/POICategoryAccordion.tsx` - Expandable category details +- `frontend/src/components/domain/settings/POIContextView.tsx` - Main POI management view +- `frontend/src/components/domain/onboarding/steps/POIDetectionStep.tsx` - Onboarding wizard step + +**Key Features:** +- Address autocomplete with real-time suggestions (Nominatim API) +- Interactive map with color-coded POI markers by category +- Distance rings visualization (100m, 300m, 500m) +- Detailed category analysis with distance distribution +- Automatic POI detection during onboarding +- POI refresh functionality with competitive insights +- Full TypeScript type safety +- Map with bakery marker at center +- Color-coded POI markers by category +- Distance rings (100m, 300m, 500m) +- Expandable category accordions with details +- Refresh button for manual POI re-detection +- Integration into Settings page and Onboarding wizard + +### ✅ Phase 5: Background Refresh Jobs & Geocoding (COMPLETED) + +**Status:** Complete implementation of periodic POI refresh and address geocoding + +**Files Created (Background Jobs):** +- `services/external/app/models/poi_refresh_job.py` - POI refresh job data model +- `services/external/app/services/poi_refresh_service.py` - POI refresh job management service +- `services/external/app/services/poi_scheduler.py` - Background scheduler for periodic refresh +- `services/external/app/api/poi_refresh_jobs.py` - REST API for job management +- `services/external/migrations/versions/20251110_1801_df9709132952_add_poi_refresh_jobs_table.py` - Database migration + +**Files Created (Geocoding):** +- `services/external/app/services/nominatim_service.py` - Nominatim geocoding service +- `services/external/app/api/geocoding.py` - Geocoding REST API endpoints + +**Files Modified:** +- `services/external/app/main.py` - Integrated scheduler startup/shutdown, added routers +- `services/external/app/api/poi_context.py` - Auto-schedules refresh job after POI detection + +**Key Features - Background Refresh:** +- **Automatic 6-month refresh cycle**: Jobs scheduled 180 days after initial POI detection +- **Hourly scheduler**: Checks for pending jobs every hour and executes them +- **Change detection**: Analyzes differences between old and new POI results +- **Retry logic**: Up to 3 attempts with 1-hour retry delay +- **Concurrent execution**: Configurable max concurrent jobs (default: 5) +- **Job tracking**: Complete audit trail with status, timestamps, results, errors +- **Manual triggers**: API endpoints for immediate job execution +- **Auto-scheduling**: Next refresh automatically scheduled on completion + +**Key Features - Geocoding:** +- **Address autocomplete**: Real-time suggestions from Nominatim API +- **Forward geocoding**: Convert address to coordinates +- **Reverse geocoding**: Convert coordinates to address +- **Rate limiting**: Respects 1 req/sec for public Nominatim API +- **Production ready**: Easy switch to self-hosted Nominatim instance +- **Country filtering**: Default to Spain (configurable) + +**Background Job API Endpoints:** +- `POST /api/v1/poi-refresh-jobs/schedule` - Schedule a refresh job +- `GET /api/v1/poi-refresh-jobs/{job_id}` - Get job details +- `GET /api/v1/poi-refresh-jobs/tenant/{tenant_id}` - Get tenant's jobs +- `POST /api/v1/poi-refresh-jobs/{job_id}/execute` - Manually execute job +- `GET /api/v1/poi-refresh-jobs/pending` - Get pending jobs +- `POST /api/v1/poi-refresh-jobs/process-pending` - Process all pending jobs +- `POST /api/v1/poi-refresh-jobs/trigger-scheduler` - Trigger immediate scheduler check +- `GET /api/v1/poi-refresh-jobs/scheduler/status` - Get scheduler status + +**Geocoding API Endpoints:** +- `GET /api/v1/geocoding/search?q={query}` - Address search/autocomplete +- `GET /api/v1/geocoding/geocode?address={address}` - Forward geocoding +- `GET /api/v1/geocoding/reverse?lat={lat}&lon={lon}` - Reverse geocoding +- `GET /api/v1/geocoding/validate?lat={lat}&lon={lon}` - Coordinate validation +- `GET /api/v1/geocoding/health` - Service health check + +**Scheduler Lifecycle:** +- **Startup**: Scheduler automatically starts with External service +- **Runtime**: Runs in background, checking every 3600 seconds (1 hour) +- **Shutdown**: Gracefully stops when service shuts down +- **Immediate check**: Can be triggered via API for testing/debugging + +## POI Categories & Configuration + +### Detected Categories + +| Category | OSM Query | Search Radius | Weight | Impact | +|----------|-----------|---------------|--------|--------| +| **Schools** | `amenity~"school\|kindergarten\|university"` | 500m | 1.5 | Morning drop-off rush | +| **Offices** | `office` | 800m | 1.3 | Weekday lunch demand | +| **Gyms/Sports** | `leisure~"fitness_centre\|sports_centre"` | 600m | 0.8 | Morning/evening activity | +| **Residential** | `building~"residential\|apartments"` | 400m | 1.0 | Base demand | +| **Tourism** | `tourism~"attraction\|museum\|hotel"` | 1000m | 1.2 | Tourist foot traffic | +| **Competitors** | `shop~"bakery\|pastry"` | 1000m | -0.5 | Competition pressure | +| **Transport Hubs** | `railway~"station\|subway_entrance"` | 800m | 1.4 | Commuter traffic | +| **Coworking** | `amenity="coworking_space"` | 600m | 1.1 | Flexible workers | +| **Retail** | `shop` | 500m | 0.9 | General foot traffic | + +### Feature Relevance Thresholds + +Features are only included in ML models if they pass relevance criteria: + +**Example - Schools:** +- `min_proximity_score`: 0.5 (moderate proximity required) +- `max_distance_to_nearest_m`: 500 (must be within 500m) +- `min_count`: 1 (at least 1 school) + +If a bakery has no schools within 500m → school features NOT added (prevents noise) + +## Feature Engineering Strategy + +### Hybrid Multi-Tier Approach + +**Research Basis:** Academic studies (2023-2024) show single-method approaches underperform + +**Tier 1: Proximity-Weighted Scores (PRIMARY)** +```python +proximity_score = Σ(1 / (1 + distance_km)) for each POI +weighted_proximity_score = proximity_score × category.weight +``` + +**Example:** +- Bakery 200m from 5 schools: score = 5 × (1/1.2) = 4.17 +- Bakery 100m from 1 school: score = 1 × (1/1.1) = 0.91 +- First bakery has higher school impact despite further distance! + +**Tier 2: Distance Band Counts** +```python +count_0_100m = count(POIs within 100m) +count_100_300m = count(POIs within 100-300m) +count_300_500m = count(POIs within 300-500m) +count_500_1000m = count(POIs within 500-1000m) +``` + +**Tier 3: Distance to Nearest** +```python +distance_to_nearest_m = min(distances) +``` + +**Tier 4: Binary Flags** +```python +has_within_100m = any(distance <= 100m) +has_within_300m = any(distance <= 300m) +has_within_500m = any(distance <= 500m) +``` + +### Competitive Pressure Modeling + +Special treatment for competitor bakeries: + +**Zones:** +- **Direct** (<100m): -1.0 multiplier per competitor (strong negative) +- **Nearby** (100-500m): -0.5 multiplier (moderate negative) +- **Market** (500-1000m): + - If 5+ bakeries → +0.3 (bakery district = destination area) + - If 2-4 bakeries → -0.2 (competitive market) + +## API Endpoints + +### POST `/api/v1/poi-context/{tenant_id}/detect` + +Detect POIs for a tenant's bakery location. + +**Query Parameters:** +- `latitude` (float, required): Bakery latitude +- `longitude` (float, required): Bakery longitude +- `force_refresh` (bool, optional): Force re-detection, skip cache + +**Response:** +```json +{ + "status": "success", + "source": "detection", // or "cache" + "poi_context": { + "id": "uuid", + "tenant_id": "uuid", + "location": {"latitude": 40.4168, "longitude": -3.7038}, + "total_pois_detected": 42, + "high_impact_categories": ["schools", "transport_hubs"], + "ml_features": { + "poi_schools_proximity_score": 3.45, + "poi_schools_count_0_100m": 2, + "poi_schools_distance_to_nearest_m": 85.0, + // ... 81+ more features + } + }, + "feature_selection": { + "relevant_categories": ["schools", "transport_hubs", "offices"], + "relevance_report": [...] + }, + "competitor_analysis": { + "competitive_pressure_score": -1.5, + "direct_competitors_count": 1, + "competitive_zone": "high_competition", + "market_type": "competitive_market" + }, + "competitive_insights": [ + "⚠️ High competition: 1 direct competitor(s) within 100m. Focus on differentiation and quality." + ] +} +``` + +### GET `/api/v1/poi-context/{tenant_id}` + +Retrieve stored POI context for a tenant. + +**Response:** +```json +{ + "poi_context": {...}, + "is_stale": false, + "needs_refresh": false +} +``` + +### POST `/api/v1/poi-context/{tenant_id}/refresh` + +Refresh POI context (re-detect POIs). + +### DELETE `/api/v1/poi-context/{tenant_id}` + +Delete POI context for a tenant. + +### GET `/api/v1/poi-context/{tenant_id}/feature-importance` + +Get feature importance summary. + +### GET `/api/v1/poi-context/{tenant_id}/competitor-analysis` + +Get detailed competitor analysis. + +### GET `/api/v1/poi-context/health` + +Check POI detection service health (Overpass API accessibility). + +### GET `/api/v1/poi-context/cache/stats` + +Get cache statistics (key count, memory usage). + +## Database Schema + +### Table: `tenant_poi_contexts` + +```sql +CREATE TABLE tenant_poi_contexts ( + id UUID PRIMARY KEY, + tenant_id UUID UNIQUE NOT NULL, + + -- Location + latitude FLOAT NOT NULL, + longitude FLOAT NOT NULL, + + -- POI Detection Data + poi_detection_results JSONB NOT NULL DEFAULT '{}', + ml_features JSONB NOT NULL DEFAULT '{}', + total_pois_detected INTEGER DEFAULT 0, + high_impact_categories JSONB DEFAULT '[]', + relevant_categories JSONB DEFAULT '[]', + + -- Detection Metadata + detection_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + detection_source VARCHAR(50) DEFAULT 'overpass_api', + detection_status VARCHAR(20) DEFAULT 'completed', + detection_error VARCHAR(500), + + -- Refresh Strategy + next_refresh_date TIMESTAMP WITH TIME ZONE, + refresh_interval_days INTEGER DEFAULT 180, + last_refreshed_at TIMESTAMP WITH TIME ZONE, + + -- Timestamps + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() +); + +CREATE INDEX idx_tenant_poi_location ON tenant_poi_contexts (latitude, longitude); +CREATE INDEX idx_tenant_poi_refresh ON tenant_poi_contexts (next_refresh_date); +CREATE INDEX idx_tenant_poi_status ON tenant_poi_contexts (detection_status); +``` + +## ML Model Integration + +### Training Pipeline + +POI features are automatically fetched and integrated during training: + +```python +# TrainingDataOrchestrator fetches POI features +poi_features = await poi_feature_integrator.fetch_poi_features( + tenant_id=tenant_id, + latitude=lat, + longitude=lon +) + +# Features added to TrainingDataSet +training_dataset = TrainingDataSet( + sales_data=filtered_sales, + weather_data=weather_data, + traffic_data=traffic_data, + poi_features=poi_features, # NEW + ... +) + +# Data processor merges POI features into training data +daily_sales = self._add_poi_features(daily_sales, poi_features) + +# Prophet model uses POI features as regressors +for feature_name in poi_features.keys(): + model.add_regressor(feature_name, mode='additive') +``` + +### Forecasting Pipeline + +POI features are fetched and used for predictions: + +```python +# POI Feature Service retrieves features +poi_features = await poi_feature_service.get_poi_features(tenant_id) + +# Features added to prediction dataframe +df = await data_processor.prepare_prediction_features( + future_dates=future_dates, + weather_forecast=weather_df, + poi_features=poi_features, # SAME features as training + ... +) + +# Prophet generates forecast with POI features +forecast = model.predict(df) +``` + +### Feature Consistency + +**Critical:** POI features MUST be identical in training and prediction! + +- Training: POI features fetched from External service +- Prediction: POI features fetched from External service (same tenant) +- Features are static (location-based, don't vary by date) +- Stored in `TenantPOIContext` ensures consistency + +## Performance Optimizations + +### Caching Strategy + +**Redis Cache:** +- TTL: 90 days +- Cache key: Rounded coordinates (4 decimals ≈ 10m precision) +- Allows reuse for bakeries in close proximity +- Reduces Overpass API load + +**Database Storage:** +- POI context stored in PostgreSQL +- Refresh cycle: 180 days (6 months) +- Background job refreshes stale contexts + +### API Rate Limiting + +**Overpass API:** +- Public endpoint: Rate limited +- Retry logic: 3 attempts with 2-second delay +- Timeout: 30 seconds per query +- Concurrent queries: All POI categories fetched in parallel + +**Recommendation:** Self-host Overpass API instance for production + +## Testing & Validation + +### Model Performance Impact + +Expected improvements with POI features: +- MAPE improvement: 5-10% for bakeries with significant POI presence +- Accuracy maintained: For bakeries with no relevant POIs (features filtered out) +- Feature count: 81+ POI features per bakery (if all categories relevant) + +### A/B Testing + +Compare models with and without POI features: + +```python +# Model A: Without POI features +model_a = train_model(sales, weather, traffic) + +# Model B: With POI features +model_b = train_model(sales, weather, traffic, poi_features) + +# Compare MAPE, MAE, R² score +``` + +## Troubleshooting + +### Common Issues + +**1. No POI context found** +- **Cause:** POI detection not run during onboarding +- **Fix:** Call `/api/v1/poi-context/{tenant_id}/detect` endpoint + +**2. Overpass API timeout** +- **Cause:** API overload or network issues +- **Fix:** Retry mechanism handles this automatically; check health endpoint + +**3. POI features not in model** +- **Cause:** Feature relevance thresholds filter out low-signal features +- **Fix:** Expected behavior; check relevance report + +**4. Feature count mismatch between training and prediction** +- **Cause:** POI context refreshed between training and prediction +- **Fix:** Models store feature manifest; prediction uses same features + +## Future Enhancements + +1. **Neighborhood Clustering** + - Group bakeries by neighborhood type (business district, residential, tourist) + - Reduce from 81+ individual features to 4-5 cluster features + - Enable transfer learning across similar neighborhoods + +2. **Automated POI Verification** + - User confirmation of auto-detected POIs + - Manual addition/removal of POIs + +3. **Temporal POI Features** + - School session times (morning vs. afternoon) + - Office hours variations (hybrid work) + - Event-based POIs (concerts, sports matches) + +4. **Multi-City Support** + - City-specific POI weights + - Regional calendar integration (school holidays vary by region) + +5. **POI Change Detection** + - Monitor for new POIs (e.g., new school opens) + - Automatic re-training when significant POI changes detected + +## References + +### Academic Research + +1. "Gravity models for potential spatial healthcare access measurement" (2023) +2. "What determines travel time and distance decay in spatial interaction" (2024) +3. "Location Profiling for Retail-Site Recommendation Using Machine Learning" (2024) +4. "Predicting ride-hailing passenger demand: A POI-based adaptive clustering" (2024) + +### Technical Documentation + +- Overpass API: https://wiki.openstreetmap.org/wiki/Overpass_API +- OpenStreetMap Tags: https://wiki.openstreetmap.org/wiki/Map_features +- Facebook Prophet: https://facebook.github.io/prophet/ + +## License & Attribution + +POI data from OpenStreetMap contributors (© OpenStreetMap contributors) +Licensed under Open Database License (ODbL) diff --git a/frontend/README.md b/frontend/README.md index 4c5327a0..d7f64d5e 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -51,6 +51,13 @@ The **Bakery-IA Frontend Dashboard** is a modern, responsive React-based web app - **POS Integration** - Automatic sales data sync from Square/Toast/Lightspeed - **Sales History** - Complete historical sales data with filtering and export +### Onboarding Wizard +- **Multi-Step Onboarding** - Guided 15-step setup process for new bakeries +- **POI Detection Step** - Automatic detection of nearby Points of Interest using bakery location +- **Progress Tracking** - Visual progress indicators and step completion +- **Data Persistence** - Save progress at each step +- **Smart Navigation** - Dynamic step dependencies and validation + ### Multi-Tenant Administration - **Tenant Settings** - Configure bakery-specific preferences - **User Management** - Invite team members and assign roles @@ -205,7 +212,15 @@ frontend/ │ │ ├── ui/ # Base UI components (buttons, inputs, etc.) │ │ ├── charts/ # Chart components │ │ ├── forms/ # Form components -│ │ └── layout/ # Layout components (header, sidebar, etc.) +│ │ ├── layout/ # Layout components (header, sidebar, etc.) +│ │ └── domain/ # Domain-specific components +│ │ └── onboarding/ # Onboarding wizard components +│ │ ├── steps/ # Individual step components +│ │ │ ├── POIDetectionStep.tsx # POI detection UI +│ │ │ ├── SetupStep.tsx +│ │ │ └── ... +│ │ ├── context/ # Onboarding wizard context +│ │ └── WizardLayout.tsx │ ├── pages/ # Page components (routes) │ │ ├── Dashboard/ # Main dashboard │ │ ├── Forecasting/ # Forecast management @@ -226,7 +241,12 @@ frontend/ │ │ ├── alertStore.ts # Alert state │ │ └── uiStore.ts # UI state (sidebar, theme, etc.) │ ├── api/ # API client functions -│ │ ├── client.ts # Axios client setup +│ │ ├── client/ # API client configuration +│ │ │ └── apiClient.ts # Axios client with tenant injection +│ │ ├── services/ # Service API modules +│ │ │ ├── onboarding.ts # Onboarding API +│ │ │ ├── geocodingApi.ts # Geocoding/address API +│ │ │ └── poiContextApi.ts # POI detection API │ │ ├── auth.ts # Auth API │ │ ├── forecasting.ts # Forecasting API │ │ ├── inventory.ts # Inventory API @@ -263,6 +283,21 @@ frontend/ - `/register` - User registration - `/forgot-password` - Password reset +### Onboarding Routes +- `/onboarding` - Multi-step onboarding wizard (15 steps) +- `/onboarding/bakery-type-selection` - Choose bakery type +- `/onboarding/setup` - Basic bakery setup +- `/onboarding/poi-detection` - **POI Detection** - Automatic location context detection +- `/onboarding/upload-sales-data` - Upload historical sales +- `/onboarding/inventory-review` - Review detected products +- `/onboarding/initial-stock-entry` - Initial inventory levels +- `/onboarding/product-categorization` - Product categories +- `/onboarding/suppliers-setup` - Supplier configuration +- `/onboarding/recipes-setup` - Recipe management +- `/onboarding/ml-training` - AI model training +- `/onboarding/setup-review` - Review configuration +- `/onboarding/completion` - Onboarding complete + ### Protected Routes (Require Authentication) - `/dashboard` - Main operational dashboard - `/forecasting` - Demand forecasting management diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ab49e917..1b2db7ec 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,9 +9,11 @@ "version": "2.0.0", "dependencies": { "@hookform/resolvers": "^3.3.2", + "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-progress": "^1.0.3", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tabs": "^1.0.4", @@ -27,7 +29,7 @@ "date-fns-tz": "^2.0.0", "driver.js": "^1.3.6", "event-source-polyfill": "^1.0.31", - "framer-motion": "^10.16.0", + "framer-motion": "^10.18.0", "i18next": "^23.7.0", "immer": "^10.0.3", "lucide-react": "^0.294.0", @@ -134,6 +136,7 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2682,6 +2685,7 @@ "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2946,6 +2950,37 @@ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", "license": "MIT" }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", @@ -2999,6 +3034,36 @@ } } }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", @@ -3363,6 +3428,86 @@ } } }, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz", + "integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-context": "1.1.3", + "@radix-ui/react-primitive": "2.1.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", + "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", + "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-slot": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", + "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-roving-focus": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", @@ -5827,6 +5972,7 @@ "resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-3.5.0.tgz", "integrity": "sha512-pKS3wZnJoL1iTyGBXAvCwduNNeghJHY6QSRSNNvpYnrrQrLZ6Owsazjyynu0e0ObRgks0i7Rv+pe2M7/MBTZpQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=12.16" } @@ -5916,6 +6062,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.89.0.tgz", "integrity": "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/query-core": "5.89.0" }, @@ -6408,6 +6555,7 @@ "integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -6419,6 +6567,7 @@ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -6560,6 +6709,7 @@ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -6898,6 +7048,7 @@ "integrity": "sha512-xa57bCPGuzEFqGjPs3vVLyqareG8DX0uMkr5U/v5vLv5/ZUrBrPL7gzxzTJedEyZxFMfsozwTIbbYfEQVo3kgg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/utils": "1.6.1", "fast-glob": "^3.3.2", @@ -6995,6 +7146,7 @@ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7537,6 +7689,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001741", @@ -7742,6 +7895,7 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz", "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==", "license": "MIT", + "peer": true, "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -8106,7 +8260,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/d3-array": { "version": "3.2.4", @@ -8288,6 +8443,7 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -8808,6 +8964,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -8911,6 +9068,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -10336,6 +10494,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.23.2" } @@ -10375,6 +10534,7 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.3.tgz", "integrity": "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -12473,6 +12633,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -12639,6 +12800,7 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -12911,6 +13073,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -12983,6 +13146,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -13036,6 +13200,7 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.63.0.tgz", "integrity": "sha512-ZwueDMvUeucovM2VjkCf7zIHcs1aAlDimZu2Hvel5C5907gUzMpm4xCrQXtRzCvsBqFjonB4m3x4LzCFI1ZKWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" }, @@ -13627,6 +13792,7 @@ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -14509,6 +14675,7 @@ "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -15040,6 +15207,7 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15452,6 +15620,7 @@ "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -16015,6 +16184,7 @@ "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "1.6.1", "@vitest/runner": "1.6.1", @@ -16396,6 +16566,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/frontend/package.json b/frontend/package.json index c5905532..f50b3824 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,9 +19,11 @@ }, "dependencies": { "@hookform/resolvers": "^3.3.2", + "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", + "@radix-ui/react-progress": "^1.0.3", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tabs": "^1.0.4", @@ -37,7 +39,7 @@ "date-fns-tz": "^2.0.0", "driver.js": "^1.3.6", "event-source-polyfill": "^1.0.31", - "framer-motion": "^10.16.0", + "framer-motion": "^10.18.0", "i18next": "^23.7.0", "immer": "^10.0.3", "lucide-react": "^0.294.0", diff --git a/frontend/src/api/client/apiClient.ts b/frontend/src/api/client/apiClient.ts index 40b6c8c9..15f4bca0 100644 --- a/frontend/src/api/client/apiClient.ts +++ b/frontend/src/api/client/apiClient.ts @@ -87,6 +87,7 @@ class ApiClient { '/auth/me', // User profile endpoints '/auth/register', // Registration '/auth/login', // Login + '/geocoding', // Geocoding/address search - utility service, no tenant context ]; const isPublicEndpoint = publicEndpoints.some(endpoint => diff --git a/frontend/src/api/hooks/orders.ts b/frontend/src/api/hooks/orders.ts index dcf5a358..8bf41f1b 100644 --- a/frontend/src/api/hooks/orders.ts +++ b/frontend/src/api/hooks/orders.ts @@ -169,11 +169,11 @@ export const useCreateOrder = ( queryKey: ordersKeys.orders(), predicate: (query) => { const queryKey = query.queryKey as string[]; - return queryKey.includes('list') && + return queryKey.includes('list') && JSON.stringify(queryKey).includes(variables.tenant_id); }, }); - + // Invalidate dashboard queryClient.invalidateQueries({ queryKey: ordersKeys.dashboard(variables.tenant_id), @@ -189,6 +189,39 @@ export const useCreateOrder = ( }); }; +export const useUpdateOrder = ( + options?: UseMutationOptions +) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: ({ tenantId, orderId, data }) => OrdersService.updateOrder(tenantId, orderId, data), + onSuccess: (data, variables) => { + // Update the specific order in cache + queryClient.setQueryData( + ordersKeys.order(variables.tenantId, variables.orderId), + data + ); + + // Invalidate orders list for this tenant + queryClient.invalidateQueries({ + queryKey: ordersKeys.orders(), + predicate: (query) => { + const queryKey = query.queryKey as string[]; + return queryKey.includes('list') && + JSON.stringify(queryKey).includes(variables.tenantId); + }, + }); + + // Invalidate dashboard + queryClient.invalidateQueries({ + queryKey: ordersKeys.dashboard(variables.tenantId), + }); + }, + ...options, + }); +}; + export const useUpdateOrderStatus = ( options?: UseMutationOptions ) => { diff --git a/frontend/src/api/hooks/purchase-orders.ts b/frontend/src/api/hooks/purchase-orders.ts index 85b97c93..bdc28bab 100644 --- a/frontend/src/api/hooks/purchase-orders.ts +++ b/frontend/src/api/hooks/purchase-orders.ts @@ -10,7 +10,9 @@ import type { PurchaseOrderDetail, PurchaseOrderSearchParams, PurchaseOrderUpdateData, - PurchaseOrderStatus + PurchaseOrderStatus, + CreateDeliveryInput, + DeliveryResponse } from '../services/purchase_orders'; import { listPurchaseOrders, @@ -21,7 +23,8 @@ import { approvePurchaseOrder, rejectPurchaseOrder, bulkApprovePurchaseOrders, - deletePurchaseOrder + deletePurchaseOrder, + createDelivery } from '../services/purchase_orders'; // Query Keys @@ -257,3 +260,33 @@ export const useDeletePurchaseOrder = ( ...options, }); }; + +/** + * Hook to create a delivery for a purchase order + */ +export const useCreateDelivery = ( + options?: UseMutationOptions< + DeliveryResponse, + ApiError, + { tenantId: string; poId: string; deliveryData: CreateDeliveryInput } + > +) => { + const queryClient = useQueryClient(); + + return useMutation< + DeliveryResponse, + ApiError, + { tenantId: string; poId: string; deliveryData: CreateDeliveryInput } + >({ + mutationFn: ({ tenantId, poId, deliveryData }) => createDelivery(tenantId, poId, deliveryData), + onSuccess: (data, variables) => { + // Invalidate all PO queries to refresh status + queryClient.invalidateQueries({ queryKey: purchaseOrderKeys.all }); + // Invalidate detail for this specific PO + queryClient.invalidateQueries({ + queryKey: purchaseOrderKeys.detail(variables.tenantId, variables.poId) + }); + }, + ...options, + }); +}; diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 6038c569..2a853726 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -629,6 +629,7 @@ export { useBusinessModelDetection, useOrdersServiceStatus, useCreateOrder, + useUpdateOrder, useUpdateOrderStatus, useCreateCustomer, useUpdateCustomer, diff --git a/frontend/src/api/services/onboarding.ts b/frontend/src/api/services/onboarding.ts index 6bf5c92c..35bb97d8 100644 --- a/frontend/src/api/services/onboarding.ts +++ b/frontend/src/api/services/onboarding.ts @@ -10,11 +10,12 @@ export const BACKEND_ONBOARDING_STEPS = [ 'user_registered', // Phase 0: User account created (auto-completed) 'bakery-type-selection', // Phase 1: Choose bakery type 'setup', // Phase 2: Basic bakery setup and tenant creation - 'upload-sales-data', // Phase 2a: File upload, validation, AI classification - 'inventory-review', // Phase 2a: Review AI-detected products with type selection - 'initial-stock-entry', // Phase 2a: Capture initial stock levels - 'product-categorization', // Phase 2b: Advanced categorization (optional) - 'suppliers-setup', // Phase 2c: Suppliers configuration + 'poi-detection', // Phase 2a: POI Detection (Location Context) + 'upload-sales-data', // Phase 2b: File upload, validation, AI classification + 'inventory-review', // Phase 2b: Review AI-detected products with type selection + 'initial-stock-entry', // Phase 2b: Capture initial stock levels + 'product-categorization', // Phase 2c: Advanced categorization (optional) + 'suppliers-setup', // Phase 2d: Suppliers configuration 'recipes-setup', // Phase 3: Production recipes (optional) 'production-processes', // Phase 3: Finishing processes (optional) 'quality-setup', // Phase 3: Quality standards (optional) @@ -28,11 +29,12 @@ export const BACKEND_ONBOARDING_STEPS = [ export const FRONTEND_STEP_ORDER = [ 'bakery-type-selection', // Phase 1: Choose bakery type 'setup', // Phase 2: Basic bakery setup and tenant creation - 'upload-sales-data', // Phase 2a: File upload and AI classification - 'inventory-review', // Phase 2a: Review AI-detected products - 'initial-stock-entry', // Phase 2a: Initial stock levels - 'product-categorization', // Phase 2b: Advanced categorization (optional) - 'suppliers-setup', // Phase 2c: Suppliers configuration + 'poi-detection', // Phase 2a: POI Detection (Location Context) + 'upload-sales-data', // Phase 2b: File upload and AI classification + 'inventory-review', // Phase 2b: Review AI-detected products + 'initial-stock-entry', // Phase 2b: Initial stock levels + 'product-categorization', // Phase 2c: Advanced categorization (optional) + 'suppliers-setup', // Phase 2d: Suppliers configuration 'recipes-setup', // Phase 3: Production recipes (optional) 'production-processes', // Phase 3: Finishing processes (optional) 'quality-setup', // Phase 3: Quality standards (optional) diff --git a/frontend/src/api/services/orders.ts b/frontend/src/api/services/orders.ts index 593b028d..73fc62f3 100644 --- a/frontend/src/api/services/orders.ts +++ b/frontend/src/api/services/orders.ts @@ -103,20 +103,28 @@ export class OrdersService { return apiClient.get(`/tenants/${tenant_id}/orders?${queryParams.toString()}`); } + /** + * Update order details + * PUT /tenants/{tenant_id}/orders/{order_id} + */ + static async updateOrder(tenantId: string, orderId: string, orderData: OrderUpdate): Promise { + return apiClient.put(`/tenants/${tenantId}/orders/${orderId}`, orderData); + } + /** * Update order status * PUT /tenants/{tenant_id}/orders/{order_id}/status */ static async updateOrderStatus(params: UpdateOrderStatusParams): Promise { const { tenant_id, order_id, new_status, reason } = params; - + const queryParams = new URLSearchParams(); if (reason) { queryParams.append('reason', reason); } const url = `/tenants/${tenant_id}/orders/${order_id}/status${queryParams.toString() ? `?${queryParams.toString()}` : ''}`; - + return apiClient.put(url, { status: new_status }); } diff --git a/frontend/src/api/services/purchase_orders.ts b/frontend/src/api/services/purchase_orders.ts index eb40bee8..00616b4b 100644 --- a/frontend/src/api/services/purchase_orders.ts +++ b/frontend/src/api/services/purchase_orders.ts @@ -242,3 +242,68 @@ export async function deletePurchaseOrder( `/tenants/${tenantId}/procurement/purchase-orders/${poId}` ); } + +// ================================================================ +// DELIVERY TYPES AND METHODS +// ================================================================ + +export interface DeliveryItemInput { + purchase_order_item_id: string; + inventory_product_id: string; + ordered_quantity: number; + delivered_quantity: number; + accepted_quantity: number; + rejected_quantity: number; + batch_lot_number?: string; + expiry_date?: string; + quality_grade?: string; + quality_issues?: string; + rejection_reason?: string; + item_notes?: string; +} + +export interface CreateDeliveryInput { + purchase_order_id: string; + supplier_id: string; + supplier_delivery_note?: string; + scheduled_date?: string; + estimated_arrival?: string; + carrier_name?: string; + tracking_number?: string; + inspection_passed?: boolean; + inspection_notes?: string; + notes?: string; + items: DeliveryItemInput[]; +} + +export interface DeliveryResponse { + id: string; + tenant_id: string; + purchase_order_id: string; + supplier_id: string; + delivery_number: string; + status: string; + scheduled_date?: string; + estimated_arrival?: string; + actual_arrival?: string; + completed_at?: string; + inspection_passed?: boolean; + inspection_notes?: string; + notes?: string; + created_at: string; + updated_at: string; +} + +/** + * Create delivery for purchase order + */ +export async function createDelivery( + tenantId: string, + poId: string, + deliveryData: CreateDeliveryInput +): Promise { + return apiClient.post( + `/tenants/${tenantId}/procurement/purchase-orders/${poId}/deliveries`, + deliveryData + ); +} diff --git a/frontend/src/api/types/production.ts b/frontend/src/api/types/production.ts index fa34c820..7dc46cdb 100644 --- a/frontend/src/api/types/production.ts +++ b/frontend/src/api/types/production.ts @@ -120,6 +120,13 @@ export interface ProductionBatchResponse { actual_duration_minutes: number | null; status: ProductionStatus; priority: ProductionPriority; + + // Process stage tracking (replaces frontend mock data) + current_process_stage?: string | null; + process_stage_history?: Array> | null; + pending_quality_checks?: Array> | null; + completed_quality_checks?: Array> | null; + estimated_cost: number | null; actual_cost: number | null; yield_percentage: number | null; diff --git a/frontend/src/components/dashboard/ActionQueueCard.tsx b/frontend/src/components/dashboard/ActionQueueCard.tsx index dd68f4fb..afacac56 100644 --- a/frontend/src/components/dashboard/ActionQueueCard.tsx +++ b/frontend/src/components/dashboard/ActionQueueCard.tsx @@ -19,17 +19,25 @@ import { Euro, ChevronDown, ChevronUp, + X, + Package, + Building2, + Calendar, + Truck, } from 'lucide-react'; import { ActionItem, ActionQueue } from '../../api/hooks/newDashboard'; import { useReasoningFormatter } from '../../hooks/useReasoningTranslation'; import { useTranslation } from 'react-i18next'; +import { usePurchaseOrder } from '../../api/hooks/purchase-orders'; interface ActionQueueCardProps { actionQueue: ActionQueue; loading?: boolean; onApprove?: (actionId: string) => void; + onReject?: (actionId: string, reason: string) => void; onViewDetails?: (actionId: string) => void; onModify?: (actionId: string) => void; + tenantId?: string; } const urgencyConfig = { @@ -62,20 +70,34 @@ const urgencyConfig = { function ActionItemCard({ action, onApprove, + onReject, onViewDetails, onModify, + tenantId, }: { action: ActionItem; onApprove?: (id: string) => void; + onReject?: (id: string, reason: string) => void; onViewDetails?: (id: string) => void; onModify?: (id: string) => void; + tenantId?: string; }) { const [expanded, setExpanded] = useState(false); + const [showDetails, setShowDetails] = useState(false); + const [showRejectModal, setShowRejectModal] = useState(false); + const [rejectionReason, setRejectionReason] = useState(''); const config = urgencyConfig[action.urgency as keyof typeof urgencyConfig] || urgencyConfig.normal; const UrgencyIcon = config.icon; const { formatPOAction } = useReasoningFormatter(); const { t } = useTranslation('reasoning'); + // Fetch PO details if this is a PO action and details are expanded + const { data: poDetail } = usePurchaseOrder( + tenantId || '', + action.id, + { enabled: !!tenantId && showDetails && action.type === 'po_approval' } + ); + // Translate reasoning_data (or fallback to deprecated text fields) // Memoize to prevent undefined values from being created on each render const { reasoning, consequence, severity } = useMemo(() => { @@ -166,6 +188,157 @@ function ActionItemCard({ )} + {/* Inline PO Details (expandable) */} + {action.type === 'po_approval' && ( + <> + + + {showDetails && poDetail && ( +
+ {/* Supplier Info */} +
+ +
+

+ {poDetail.supplier?.name || 'Supplier'} +

+ {poDetail.supplier?.contact_person && ( +

+ Contact: {poDetail.supplier.contact_person} +

+ )} + {poDetail.supplier?.email && ( +

+ {poDetail.supplier.email} +

+ )} +
+
+ + {/* Delivery Date & Tracking */} + {poDetail.required_delivery_date && ( +
+
+ +
+

+ Required Delivery +

+

+ {new Date(poDetail.required_delivery_date).toLocaleDateString()} +

+
+
+ + {/* Estimated Delivery Date (shown after approval) */} + {poDetail.estimated_delivery_date && ( +
+ +
+

+ Expected Arrival +

+

+ {new Date(poDetail.estimated_delivery_date).toLocaleDateString()} +

+
+ {(() => { + const now = new Date(); + const estimatedDate = new Date(poDetail.estimated_delivery_date); + const daysUntil = Math.ceil((estimatedDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); + + let statusColor = 'var(--color-success-600)'; + let statusText = 'On Track'; + + if (daysUntil < 0) { + statusColor = 'var(--color-error-600)'; + statusText = `${Math.abs(daysUntil)}d Overdue`; + } else if (daysUntil === 0) { + statusColor = 'var(--color-warning-600)'; + statusText = 'Due Today'; + } else if (daysUntil <= 2) { + statusColor = 'var(--color-warning-600)'; + statusText = `${daysUntil}d Left`; + } else { + statusText = `${daysUntil}d Left`; + } + + return ( + + {statusText} + + ); + })()} +
+ )} +
+ )} + + {/* Line Items */} + {poDetail.items && poDetail.items.length > 0 && ( +
+

+ Order Items ({poDetail.items.length}) +

+
+ {poDetail.items.map((item, idx) => ( +
+
+

+ {item.product_name || item.product_code || 'Product'} +

+

+ {item.ordered_quantity} {item.unit_of_measure} × €{parseFloat(item.unit_price).toFixed(2)} +

+
+

+ €{parseFloat(item.line_total).toFixed(2)} +

+
+ ))} +
+
+ )} + + {/* Total Amount */} +
+

Total Amount

+

+ €{parseFloat(poDetail.total_amount).toFixed(2)} +

+
+
+ )} + + )} + {/* Time Estimate */}
@@ -174,6 +347,79 @@ function ActionItemCard({
+ {/* Rejection Modal */} + {showRejectModal && ( +
setShowRejectModal(false)} + > +
e.stopPropagation()} + > +
+

+ Reject Purchase Order +

+ +
+ +

+ Please provide a reason for rejecting this purchase order: +

+ +