# Phase 6: Foundation & Integration - Detailed Implementation Plan ## Overview This phase merges the existing AI-powered onboarding with the new comprehensive setup wizard into a unified, intelligent system with conditional flows based on bakery type and data source. **Duration:** 2 weeks **Team:** 1 senior developer + 1 mid-level developer **Dependencies:** Analysis complete ✅ --- ## Week 1: Core Components & Context System ### Day 1-2: Bakery Type Selection Step **File:** `/frontend/src/components/domain/onboarding/steps/BakeryTypeSelectionStep.tsx` **Component Structure:** ```typescript import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { SetupStepProps } from '../SetupWizard'; interface BakeryType { id: 'production' | 'retail' | 'mixed'; icon: string; name: string; description: string; features: string[]; examples: string[]; color: string; } export const BakeryTypeSelectionStep: React.FC = ({ onUpdate, onComplete }) => { const { t } = useTranslation(); const [selectedType, setSelectedType] = useState(null); const bakeryTypes: BakeryType[] = [ { id: 'production', icon: '🥖', name: t('bakery_type.production.name', 'Panadería de Producción'), description: t('bakery_type.production.desc', 'Producimos desde cero usando ingredientes'), features: [ t('bakery_type.production.feature1', 'Gestión completa de recetas'), t('bakery_type.production.feature2', 'Control de ingredientes'), t('bakery_type.production.feature3', 'Procesos de producción completos'), t('bakery_type.production.feature4', 'Cálculo de costos detallado') ], examples: [ t('bakery_type.production.example1', 'Pan artesanal'), t('bakery_type.production.example2', 'Bollería'), t('bakery_type.production.example3', 'Repostería') ], color: 'from-amber-500 to-orange-600' }, { id: 'retail', icon: '🛒', name: t('bakery_type.retail.name', 'Panadería de Reventa/Acabado'), description: t('bakery_type.retail.desc', 'Recibimos productos terminados o semi-elaborados'), features: [ t('bakery_type.retail.feature1', 'Gestión de productos terminados'), t('bakery_type.retail.feature2', 'Procesos de horneado simple'), t('bakery_type.retail.feature3', 'Gestión de proveedores'), t('bakery_type.retail.feature4', 'Control de calidad') ], examples: [ t('bakery_type.retail.example1', 'Hornear productos precocidos'), t('bakery_type.retail.example2', 'Venta de productos terminados'), t('bakery_type.retail.example3', 'Acabado de productos par-baked') ], color: 'from-blue-500 to-indigo-600' }, { id: 'mixed', icon: '🏭', name: t('bakery_type.mixed.name', 'Panadería Mixta'), description: t('bakery_type.mixed.desc', 'Combinamos producción propia y reventa'), features: [ t('bakery_type.mixed.feature1', 'Todas las funcionalidades'), t('bakery_type.mixed.feature2', 'Máxima flexibilidad'), t('bakery_type.mixed.feature3', 'Gestión completa de operaciones'), t('bakery_type.mixed.feature4', 'Ideal para negocios en crecimiento') ], examples: [ t('bakery_type.mixed.example1', 'Producción propia + Reventa'), t('bakery_type.mixed.example2', 'Combinación de modelos') ], color: 'from-purple-500 to-pink-600' } ]; const handleSelect = (typeId: string) => { setSelectedType(typeId); onUpdate?.({ itemsCount: 1, canContinue: true, }); }; const handleContinue = async () => { if (!selectedType) return; // Save bakery type to context and tenant await onComplete?.({ bakeryType: selectedType }); }; return (
{/* Header */}

{t('bakery_type.title', '¿Qué tipo de panadería tienes?')}

{t('bakery_type.subtitle', 'Esto nos ayudará a personalizar tu experiencia')}

{/* Bakery Type Cards */}
{bakeryTypes.map((type) => ( ))}
{/* Help Text */}

{t('bakery_type.help_title', '¿No estás seguro?')}

{t('bakery_type.help_desc', 'Puedes elegir "Panadería Mixta" si combinas producción propia con reventa de productos. Podrás personalizar más adelante.')}

); }; ``` **API Integration:** ```typescript // Update tenant with bakery type const updateTenantBakeryType = async (tenantId: string, bakeryType: string) => { await apiClient.put(`/api/v1/tenants/${tenantId}/settings`, { bakery_type: bakeryType }); }; ``` **Tasks:** - [ ] Create component file - [ ] Implement UI with 3 cards - [ ] Add hover/selected states - [ ] Integrate with API to save bakery type - [ ] Add unit tests - [ ] Add Storybook story --- ### Day 3-4: Data Source Choice Step **File:** `/frontend/src/components/domain/onboarding/steps/DataSourceChoiceStep.tsx` **Component Structure:** ```typescript import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { SetupStepProps } from '../SetupWizard'; interface DataSourceOption { id: 'ai' | 'manual'; icon: React.ReactNode; name: string; description: string; duration: string; benefits: string[]; recommended?: boolean; } export const DataSourceChoiceStep: React.FC = ({ onUpdate, onComplete }) => { const { t } = useTranslation(); const [selectedSource, setSelectedSource] = useState(null); const dataSources: DataSourceOption[] = [ { id: 'ai', icon: ( ), name: t('data_source.ai.name', 'Subir datos de ventas (Recomendado)'), description: t('data_source.ai.desc', 'Deja que la IA analice tus ventas y configure automáticamente tu inventario'), duration: t('data_source.ai.duration', '~5 minutos'), benefits: [ t('data_source.ai.benefit1', 'Configuración automática basada en tus datos reales'), t('data_source.ai.benefit2', 'Recomendaciones inteligentes de productos'), t('data_source.ai.benefit3', 'Análisis de patrones de venta'), t('data_source.ai.benefit4', 'Mucho más rápido que la configuración manual') ], recommended: true }, { id: 'manual', icon: ( ), name: t('data_source.manual.name', 'Configuración manual'), description: t('data_source.manual.desc', 'Configura todo desde cero usando nuestras plantillas y guías'), duration: t('data_source.manual.duration', '~15 minutos'), benefits: [ t('data_source.manual.benefit1', 'Control total sobre cada detalle'), t('data_source.manual.benefit2', 'No necesitas datos históricos'), t('data_source.manual.benefit3', 'Plantillas predefinidas incluidas'), t('data_source.manual.benefit4', 'Ideal para negocios nuevos') ], recommended: false } ]; const handleSelect = (sourceId: string) => { setSelectedSource(sourceId); onUpdate?.({ itemsCount: 1, canContinue: true, }); }; const handleContinue = async () => { if (!selectedSource) return; await onComplete?.({ dataSource: selectedSource }); }; return (
{/* Header */}

{t('data_source.title', '¿Cómo quieres configurar tu inventario?')}

{t('data_source.subtitle', 'Elige el método que mejor se adapte a tu situación')}

{/* Data Source Cards */}
{dataSources.map((source) => ( ))}
{/* Additional Info */}
{/* AI Path Info */}

{t('data_source.ai_info_title', 'Ruta con IA')}

{t('data_source.ai_info', 'Necesitarás un archivo CSV, Excel o JSON con tus datos de ventas históricos. La IA analizará tus productos y configurará automáticamente el inventario.')}

{/* Manual Path Info */}

{t('data_source.manual_info_title', 'Ruta Manual')}

{t('data_source.manual_info', 'Te guiaremos paso a paso para agregar proveedores, ingredientes y recetas. Incluimos plantillas para facilitar el proceso.')}

); }; ``` **Tasks:** - [ ] Create component file - [ ] Implement UI with 2 cards - [ ] Add recommended badge for AI path - [ ] Add info boxes - [ ] Integrate with wizard context - [ ] Add unit tests - [ ] Add Storybook story --- ### Day 5: Production Processes Step (for Retail Bakeries) **File:** `/frontend/src/components/domain/onboarding/steps/ProductionProcessesStep.tsx` **Component Structure:** (See PHASE_6_DETAILED_SPEC.md for full implementation) **API Endpoints:** ```typescript // Backend: Create production process endpoint POST /api/v1/tenants/{tenant_id}/production/processes Body: { product_id: string; process_name: string; description: string; steps: Array<{ order: number; instruction: string; duration_minutes: number; temperature_celsius?: number; }>; duration_minutes: number; temperature_celsius?: number; } ``` **Tasks:** - [ ] Create component file - [ ] Implement process form - [ ] Add process templates library - [ ] Create backend API endpoint - [ ] Create database table - [ ] Add unit tests - [ ] Add integration tests --- ## Week 2: Context System & Integration ### Day 6-7: Wizard Context Provider **File:** `/frontend/src/contexts/WizardContext.tsx` ```typescript import React, { createContext, useContext, useState, useCallback } from 'react'; interface WizardContextType { // Discovery bakeryType?: 'production' | 'retail' | 'mixed'; dataSource?: 'ai' | 'manual'; // AI Path Data salesDataUploaded: boolean; aiSuggestions: ProductSuggestion[]; selectedSuggestions: string[]; // Setup Data suppliers: Supplier[]; inventory: InventoryItem[]; recipes: Recipe[]; processes: ProductionProcess[]; qualityTemplates: QualityTemplate[]; teamMembers: TeamMember[]; // ML Training mlTrainingJobId?: string; mlTrainingStatus?: 'pending' | 'in_progress' | 'completed' | 'failed'; mlTrainingProgress?: number; // Actions setBakeryType: (type: 'production' | 'retail' | 'mixed') => void; setDataSource: (source: 'ai' | 'manual') => void; setAISuggestions: (suggestions: ProductSuggestion[]) => void; addSupplier: (supplier: Supplier) => void; addInventoryItem: (item: InventoryItem) => void; addRecipe: (recipe: Recipe) => void; addProcess: (process: ProductionProcess) => void; reset: () => void; } const WizardContext = createContext(undefined); export const WizardProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [bakeryType, setBakeryType] = useState<'production' | 'retail' | 'mixed'>(); const [dataSource, setDataSource] = useState<'ai' | 'manual'>(); const [salesDataUploaded, setSalesDataUploaded] = useState(false); const [aiSuggestions, setAISuggestions] = useState([]); const [selectedSuggestions, setSelectedSuggestions] = useState([]); const [suppliers, setSuppliers] = useState([]); const [inventory, setInventory] = useState([]); const [recipes, setRecipes] = useState([]); const [processes, setProcesses] = useState([]); const [qualityTemplates, setQualityTemplates] = useState([]); const [teamMembers, setTeamMembers] = useState([]); const [mlTrainingJobId, setMLTrainingJobId] = useState(); const [mlTrainingStatus, setMLTrainingStatus] = useState(); const [mlTrainingProgress, setMLTrainingProgress] = useState(0); const addSupplier = useCallback((supplier: Supplier) => { setSuppliers(prev => [...prev, supplier]); }, []); const addInventoryItem = useCallback((item: InventoryItem) => { setInventory(prev => [...prev, item]); }, []); const addRecipe = useCallback((recipe: Recipe) => { setRecipes(prev => [...prev, recipe]); }, []); const addProcess = useCallback((process: ProductionProcess) => { setProcesses(prev => [...prev, process]); }, []); const reset = useCallback(() => { setBakeryType(undefined); setDataSource(undefined); setSalesDataUploaded(false); setAISuggestions([]); setSelectedSuggestions([]); setSuppliers([]); setInventory([]); setRecipes([]); setProcesses([]); setQualityTemplates([]); setTeamMembers([]); setMLTrainingJobId(undefined); setMLTrainingStatus(undefined); setMLTrainingProgress(0); }, []); const value: WizardContextType = { bakeryType, dataSource, salesDataUploaded, aiSuggestions, selectedSuggestions, suppliers, inventory, recipes, processes, qualityTemplates, teamMembers, mlTrainingJobId, mlTrainingStatus, mlTrainingProgress, setBakeryType, setDataSource, setAISuggestions, addSupplier, addInventoryItem, addRecipe, addProcess, reset }; return ( {children} ); }; export const useWizardContext = () => { const context = useContext(WizardContext); if (context === undefined) { throw new Error('useWizardContext must be used within a WizardProvider'); } return context; }; ``` **Tasks:** - [ ] Create context file - [ ] Implement state management - [ ] Add persistence to localStorage - [ ] Add TypeScript types - [ ] Add hooks for context consumption - [ ] Add unit tests --- ### Day 8-9: Conditional Step Logic **File:** `/frontend/src/components/domain/onboarding/SetupWizard.tsx` (update existing) **Add Step Visibility Logic:** ```typescript import { useWizardContext } from '../../../contexts/WizardContext'; const getVisibleSteps = ( bakeryType?: string, dataSource?: string, hasSalesData?: boolean ): StepConfig[] => { const steps: StepConfig[] = []; // Phase 1: Discovery steps.push( { id: 'bakery-type', title: t('steps.bakery_type.title', 'Tipo de Panadería'), description: t('steps.bakery_type.description', 'Selecciona tu modelo de negocio'), component: BakeryTypeSelectionStep, weight: 5, estimatedMinutes: 2 }, { id: 'data-choice', title: t('steps.data_choice.title', 'Fuente de Datos'), description: t('steps.data_choice.description', 'Elige cómo configurar'), component: DataSourceChoiceStep, weight: 5, estimatedMinutes: 1 } ); // Phase 2a: AI-Assisted Path (conditional) if (dataSource === 'ai') { steps.push( { id: 'upload-sales', title: t('steps.upload_sales.title', 'Subir Datos'), description: t('steps.upload_sales.description', 'Datos históricos de ventas'), component: UploadSalesDataStep, // Reuse existing weight: 15, estimatedMinutes: 5 } ); } // Phase 2b: Core Setup (always shown) steps.push( { id: 'suppliers-setup', title: t('steps.suppliers.title', 'Proveedores'), description: t('steps.suppliers.description', 'Tus proveedores'), component: SuppliersSetupStep, // From new wizard minRequired: 1, weight: 10, estimatedMinutes: 5 }, { id: 'inventory-setup', title: t('steps.inventory.title', 'Inventario'), description: t('steps.inventory.description', 'Ingredientes y productos'), component: InventorySetupStep, // Enhanced from new wizard minRequired: 3, weight: 20, estimatedMinutes: 10 } ); // Step 8a: Recipes (conditional - production/mixed only) if (bakeryType === 'production' || bakeryType === 'mixed') { steps.push({ id: 'recipes-setup', title: t('steps.recipes.title', 'Recetas'), description: t('steps.recipes.description', 'Tus fórmulas de producción'), component: RecipesSetupStep, // From new wizard minRequired: 1, weight: 20, estimatedMinutes: 10 }); } // Step 8b: Production Processes (conditional - retail/mixed only) if (bakeryType === 'retail' || bakeryType === 'mixed') { steps.push({ id: 'production-processes', title: t('steps.processes.title', 'Procesos de Producción'), description: t('steps.processes.description', 'Instrucciones de horneado'), component: ProductionProcessesStep, // New component minRequired: 1, weight: 15, estimatedMinutes: 7 }); } // Phase 3: Advanced Features (optional) steps.push( { id: 'quality-setup', title: t('steps.quality.title', 'Calidad'), description: t('steps.quality.description', 'Estándares de calidad'), component: QualitySetupStep, // From new wizard isOptional: true, weight: 15, estimatedMinutes: 7 }, { id: 'team-setup', title: t('steps.team.title', 'Equipo'), description: t('steps.team.description', 'Miembros del equipo'), component: TeamSetupStep, // From new wizard isOptional: true, weight: 10, estimatedMinutes: 5 } ); // Phase 4: ML & Finalization if (hasSalesData) { steps.push({ id: 'ml-training', title: t('steps.ml_training.title', 'Entrenamiento IA'), description: t('steps.ml_training.description', 'Entrenar modelos predictivos'), component: MLTrainingStep, // Reuse existing weight: 10, estimatedMinutes: 5 }); } steps.push( { id: 'review', title: t('steps.review.title', 'Revisar'), description: t('steps.review.description', 'Confirma tu configuración'), component: ReviewSetupStep, // From new wizard weight: 5, estimatedMinutes: 2 }, { id: 'completion', title: t('steps.completion.title', '¡Listo!'), description: t('steps.completion.description', 'Sistema configurado'), component: CompletionStep, // From new wizard weight: 5, estimatedMinutes: 2 } ); return steps; }; ``` **Update SetupWizard Component:** ```typescript export const SetupWizard: React.FC = () => { const { bakeryType, dataSource } = useWizardContext(); const [currentStepIndex, setCurrentStepIndex] = useState(0); // Dynamically calculate visible steps const visibleSteps = useMemo(() => { return getVisibleSteps(bakeryType, dataSource, salesDataUploaded); }, [bakeryType, dataSource, salesDataUploaded]); // ... rest of wizard logic }; ``` **Tasks:** - [ ] Implement getVisibleSteps function - [ ] Update SetupWizard to use dynamic steps - [ ] Add step dependency validation - [ ] Update progress calculation - [ ] Test all conditional paths - [ ] Add integration tests --- ### Day 10: Backend Integration **Backend Tasks:** **1. Add bakery_type to tenants table:** ```sql ALTER TABLE tenants ADD COLUMN bakery_type VARCHAR(50); ALTER TABLE tenants ADD COLUMN data_source VARCHAR(50); ``` **2. Create production_processes table:** ```sql CREATE TABLE production_processes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), tenant_id UUID NOT NULL REFERENCES tenants(id) ON DELETE CASCADE, product_id UUID NOT NULL REFERENCES inventory_items(id) ON DELETE CASCADE, process_name VARCHAR(200) NOT NULL, description TEXT, steps JSONB NOT NULL DEFAULT '[]', duration_minutes INTEGER, temperature_celsius INTEGER, created_at TIMESTAMP NOT NULL DEFAULT NOW(), updated_at TIMESTAMP NOT NULL DEFAULT NOW(), created_by UUID REFERENCES users(id), CONSTRAINT fk_tenant FOREIGN KEY (tenant_id) REFERENCES tenants(id), CONSTRAINT fk_product FOREIGN KEY (product_id) REFERENCES inventory_items(id) ); CREATE INDEX idx_production_processes_tenant ON production_processes(tenant_id); CREATE INDEX idx_production_processes_product ON production_processes(product_id); ``` **3. Create API endpoint for production processes:** **File:** `/services/production/app/api/production_processes.py` ```python from fastapi import APIRouter, Depends, HTTPException from uuid import UUID from typing import List from app.models.production_process import ProductionProcess, ProductionProcessCreate from app.services.auth import get_current_user from app.database import get_db router = APIRouter() @router.post("/tenants/{tenant_id}/production/processes") async def create_production_process( tenant_id: UUID, process: ProductionProcessCreate, current_user = Depends(get_current_user), db = Depends(get_db) ): # Validate tenant access # Create production process # Return created process pass @router.get("/tenants/{tenant_id}/production/processes") async def get_production_processes( tenant_id: UUID, current_user = Depends(get_current_user), db = Depends(get_db) ) -> List[ProductionProcess]: # Validate tenant access # Fetch processes # Return processes pass ``` **4. Update onboarding step dependencies:** **File:** `/services/auth/app/api/onboarding_progress.py` Update STEP_DEPENDENCIES to include new steps: ```python STEP_DEPENDENCIES = { "bakery-type": ["user_registered"], "data-choice": ["user_registered", "bakery-type"], "upload-sales": ["user_registered", "bakery-type", "data-choice"], "suppliers-setup": ["user_registered", "bakery-type", "data-choice"], "inventory-setup": ["user_registered", "bakery-type", "suppliers-setup"], "recipes-setup": ["user_registered", "bakery-type", "inventory-setup"], "production-processes": ["user_registered", "bakery-type", "inventory-setup"], "quality-setup": ["user_registered", "bakery-type", "inventory-setup"], "team-setup": ["user_registered", "bakery-type"], "ml-training": ["user_registered", "bakery-type", "inventory-setup"], "review": ["user_registered", "bakery-type", "inventory-setup"], "completion": ["user_registered", "bakery-type", "review"] } ``` **Tasks:** - [ ] Add database migrations - [ ] Create production processes API - [ ] Update tenant settings endpoint - [ ] Update step dependencies - [ ] Add backend unit tests - [ ] Add API integration tests --- ## Testing Strategy ### Unit Tests **Component Tests:** - [ ] BakeryTypeSelectionStep - 3 type cards render, selection works - [ ] DataSourceChoiceStep - 2 option cards render, selection works - [ ] ProductionProcessesStep - Form renders, validation works - [ ] WizardContext - State management works correctly - [ ] Conditional step logic - Steps show/hide based on context **API Tests:** - [ ] POST /tenants/{id}/settings - Saves bakery type - [ ] POST /production/processes - Creates process - [ ] GET /production/processes - Fetches processes - [ ] Step dependencies - Validates correctly ### Integration Tests **End-to-End Flows:** - [ ] Production + AI path: Full flow works - [ ] Production + Manual path: Full flow works - [ ] Retail + AI path: Full flow works - [ ] Retail + Manual path: Full flow works - [ ] Mixed + AI path: Full flow works - [ ] Mixed + Manual path: Full flow works ### Manual Testing Checklist - [ ] All step transitions work - [ ] Context persists across navigation - [ ] Backend saves data correctly - [ ] Progress tracking works - [ ] Can go back and change selections - [ ] Conditional steps appear/disappear correctly - [ ] All UI states (loading, error, success) work - [ ] Mobile responsive - [ ] Accessibility (keyboard navigation, screen readers) --- ## Deliverables ✅ **Week 1:** 1. BakeryTypeSelectionStep component 2. DataSourceChoiceStep component 3. ProductionProcessesStep component 4. Component tests 5. Storybook stories ✅ **Week 2:** 6. WizardContext provider 7. Conditional step logic 8. Backend database changes 9. Backend API endpoints 10. Integration tests --- ## Success Criteria - [ ] All 6 onboarding paths work end-to-end - [ ] Context persists correctly - [ ] Backend stores all new data - [ ] Tests have >80% coverage - [ ] No TypeScript errors - [ ] Build succeeds - [ ] Performance: Wizard loads in <2s - [ ] Accessibility: WCAG AA compliant --- ## Next Phase Preview **Phase 7: Spanish Translations** - Comprehensive Spanish i18n - 1000+ translation strings - Translation review by native speaker - Default language set to Spanish --- ## Resources Needed - **Senior Developer** (Days 1-10): Architecture, context system, integration - **Mid Developer** (Days 1-10): Component implementation, testing - **Backend Developer** (Days 10): Database migrations, API endpoints - **Designer** (Days 1-3): Review mockups for new steps - **QA** (Days 8-10): Integration testing --- **Ready to start? Let's build Phase 6! 🚀**