# ═══════════════════════════════════════════════════════════════════════════════ # FRONTEND-STORES-PLAN.yml - Stores & Services Analysis # ═══════════════════════════════════════════════════════════════════════════════ version: "1.0.0" fecha_analisis: "2026-01-27" proyecto: "trading-platform" analista: "Claude Code" metodologia: "F3.2 - Stores & Services Gap Analysis" # ═══════════════════════════════════════════════════════════════════════════════ # RESUMEN EJECUTIVO # ═══════════════════════════════════════════════════════════════════════════════ resumen: total_stores_existentes: 9 total_stores_faltantes: 8 total_services_existentes: 14 total_services_faltantes: 12 cobertura_stores: "53%" cobertura_services: "54%" websocket_connections_requeridas: 6 esfuerzo_estimado_total: "890h" # ═══════════════════════════════════════════════════════════════════════════════ # ANALYSIS SECTION 1: ZUSTAND STORES # ═══════════════════════════════════════════════════════════════════════════════ stores: framework: "Zustand v4.4.7" ubicacion: "apps/frontend/src/stores/" pattern: "devtools + persist middleware" # ═══════════════════════════════════════════════════════════════════════════════ # STORES EXISTENTES # ═══════════════════════════════════════════════════════════════════════════════ existentes: auth_store: archivo: "auth.store.ts" epicAssociated: "OQI-001" estado: "FUNCIONAL" lineas: 420 descripcion: "Global authentication state, user data, tokens" state_fields: - nombre: "user" tipo: "User | null" descripcion: "Current authenticated user" persistido: true - nombre: "accessToken" tipo: "string | null" descripcion: "JWT access token (15 min TTL)" persistido: true persistencia_tipo: "localStorage (INSECURO)" - nombre: "refreshToken" tipo: "string | null" descripcion: "JWT refresh token (7d TTL)" persistido: true persistencia_tipo: "httpOnly cookie (when backend ready)" - nombre: "isAuthenticated" tipo: "boolean" descripcion: "Login state" persistido: false - nombre: "isLoading" tipo: "boolean" descripcion: "Auth operation loading state" persistido: false - nombre: "error" tipo: "string | null" descripcion: "Last auth error message" persistido: false acciones_principales: - "setUser(user: User)" - "setAccessToken(token: string)" - "setRefreshToken(token: string)" - "logout()" - "clearError()" - "setLoading(loading: boolean)" dependencias: - "axios (para API calls)" - "localStorage (tokens)" gaps: - nombre: "Auto-refresh mechanism" severidad: "P0" descripcion: "Tokens se refrescan manualmente, not automatic" notas: "Usuarios pierden acceso cuando token expira" - nombre: "Role-based access control" severidad: "P1" descripcion: "No hay roles stored en state" notas: "RBAC debe agregarse para menus y permisos" - nombre: "Device tracking" severidad: "P1" descripcion: "No hay device ID para multi-session management" notas: "Necessary para session management" middleware: - devtools - persist (localStorage) test_coverage: "70%" --- trading_store: archivo: "trading.store.ts" epicAssociated: "OQI-003" estado: "FUNCIONAL" lineas: 350 descripcion: "Trading module state: symbol, market data, orderbook" state_fields: - nombre: "selectedSymbol" tipo: "string" descripcion: "Currently selected trading pair (e.g. BTCUSDT)" default: "BTCUSDT" persistido: true - nombre: "ticker" tipo: "Ticker | null" descripcion: "Current ticker data (price, change, high, low)" persistido: false ultima_actualizacion: "API / WebSocket" - nombre: "orderBook" tipo: "OrderBook | null" descripcion: "Current market orderbook (bids/asks)" persistido: false actualizado_por: "WebSocket (POLLING actualmente - LAG)" - nombre: "klines" tipo: "Kline[]" descripcion: "OHLCV candle data" persistido: false cantidad_maxima: "500 candles" - nombre: "watchlists" tipo: "Watchlist[]" descripcion: "User's custom symbol watchlists" persistido: true relacion: "ONE-TO-MANY" - nombre: "selectedWatchlistId" tipo: "string | null" descripcion: "Currently selected watchlist" persistido: true - nombre: "isLoadingTicker" tipo: "boolean" persistido: false - nombre: "isLoadingKlines" tipo: "boolean" persistido: false - nombre: "isLoadingOrderBook" tipo: "boolean" persistido: false acciones_principales: - "setSelectedSymbol(symbol: string)" - "setTicker(ticker: Ticker)" - "setOrderBook(orderBook: OrderBook)" - "setKlines(klines: Kline[])" - "appendKline(kline: Kline)" - "setWatchlists(watchlists: Watchlist[])" - "setSelectedWatchlistId(id: string | null)" - "reset()" dependencias: - "axios para fetch inicial" - "WebSocket service para updates en tiempo real" gaps: - nombre: "No WebSocket para orderbook" severidad: "P1" descripcion: "OrderBook se actualiza via polling (1-2 seg lag)" impacto: "Traders ven precios atrasados" solucion: "Integrar websocket.service" - nombre: "No multi-symbol concurrent subscriptions" severidad: "P2" descripcion: "Solo puedes ver un símbolo a la vez" impacto: "No puedes comparar múltiples pares" solucion: "Extender store para multi-symbol" - nombre: "Falta indicators state" severidad: "P2" descripcion: "Indicators solo en chartStore, no en trading" impacto: "Dificil sincronizar entre componentes" solucion: "Agregar indicators array al store" middleware: - devtools - persist test_coverage: "65%" --- order_store: archivo: "order.store.ts" epicAssociated: "OQI-003" estado: "FUNCIONAL" lineas: 380 descripcion: "Order placement form state and positions management" state_fields: - nombre: "balances" tipo: "Balance[]" descripcion: "User's paper trading balances" persistido: false campos_del_balance: - "asset: string (e.g., USDT, BTC)" - "total: number" - "available: number" - "locked: number" - nombre: "orders" tipo: "Order[]" descripcion: "Open and filled orders" persistido: false - nombre: "positions" tipo: "Position[]" descripcion: "Open positions" persistido: false campos_de_position: - "id, symbol, side, status" - "currentQuantity, averageEntryPrice" - "unrealizedPnl, realizedPnl, totalPnl" - nombre: "orderSide" tipo: "'buy' | 'sell'" descripcion: "Order form current side" persistido: false default: "buy" - nombre: "orderType" tipo: "'market' | 'limit' | 'stop_loss'" descripcion: "Order form current type" persistido: false default: "market" - nombre: "orderQuantity" tipo: "string" descripcion: "Order form quantity input" persistido: false - nombre: "orderPrice" tipo: "string" descripcion: "Order form price input (for limit orders)" persistido: false - nombre: "stopLoss" tipo: "string" descripcion: "Order form SL price" persistido: false - nombre: "takeProfit" tipo: "string" descripcion: "Order form TP price" persistido: false acciones_principales: - "setBalances(balances: Balance[])" - "getBalance(asset: string): Balance | undefined" - "setOrders(orders: Order[])" - "addOrder(order: Order)" - "updateOrder(orderId: string, updates: Partial)" - "removeOrder(orderId: string)" - "setPositions(positions: Position[])" - "updatePosition(positionId: string, updates: Partial)" - "setOrderSide, setOrderType, setOrderQuantity, setOrderPrice, setStopLoss, setTakeProfit" - "resetOrderForm()" dependencias: - "trading.service.ts para API calls" gaps: - nombre: "No order validation en store" severidad: "P1" descripcion: "Validaciones son solo en componentes" impacto: "Código duplicado, inconsistent" solucion: "Mover validaciones al store action" - nombre: "No undo/redo capability" severidad: "P2" descripcion: "No puedes revertir cambios de forma" impacto: "UX friction" solucion: "Implementar history stack" - nombre: "No order templates" severidad: "P2" descripcion: "No puedes guardar ordenes frecuentes" impacto: "Traders deben reescribir cada vez" solucion: "Agregar saveTemplate/loadTemplate" middleware: - devtools (without persist) test_coverage: "60%" --- chart_store: archivo: "chart.store.ts" epicAssociated: "OQI-003" estado: "FUNCIONAL" lineas: 320 descripcion: "Chart UI settings and technical indicators" state_fields: - nombre: "interval" tipo: "TimeInterval ('1m' | '5m' | '15m' | '1h' | '4h' | '1d')" descripcion: "Current chart timeframe" persistido: true default: "1h" - nombre: "chartType" tipo: "'candlestick' | 'line' | 'area'" descripcion: "Chart rendering type" persistido: true default: "candlestick" - nombre: "indicators" tipo: "ChartIndicator[]" descripcion: "Active chart indicators" persistido: true estructura: id: "string" type: "'SMA' | 'EMA' | 'RSI' | 'MACD' | 'BB'" params: "Record" visible: "boolean" color: "string (optional)" - nombre: "drawingsEnabled" tipo: "boolean" descripcion: "Is drawing mode active" persistido: true default: false - nombre: "showVolume" tipo: "boolean" default: true persistido: true - nombre: "showGrid" tipo: "boolean" default: true persistido: true - nombre: "theme" tipo: "'light' | 'dark'" persistido: true default: "dark" acciones_principales: - "setInterval(interval: TimeInterval)" - "setChartType(type: ChartType)" - "addIndicator(indicator: ChartIndicator)" - "removeIndicator(id: string)" - "updateIndicator(id: string, updates: Partial)" - "toggleIndicator(id: string)" - "setDrawingsEnabled(enabled: boolean)" - "toggleVolume()" - "toggleGrid()" - "setTheme(theme: 'light' | 'dark')" dependencias: - "Lightweight Charts para rendering" gaps: - nombre: "No saved chart layouts" severidad: "P2" descripcion: "Usuarios no pueden guardar layouts favoritos" impacto: "Deben reconfigurare cada sesión" solucion: "Agregar saveLayout/loadLayout actions" - nombre: "No drawing persistence" severidad: "P2" descripcion: "Drawings se pierden al refresca página" impacto: "Análisis técnico se pierde" solucion: "Serializar drawings y persistir" - nombre: "No indicator parameters persistence" severidad: "P1" descripcion: "Parámetros de SMA(20) se resetean" impacto: "Traders deben reconfigurar" solucion: "Mejorar persist logic" middleware: - devtools - persist test_coverage: "75%" --- education_store: archivo: "educationStore.ts" epicAssociated: "OQI-002" estado: "FUNCIONAL" lineas: 300 descripcion: "Education module state: courses, enrollments, progress" state_fields: - nombre: "courses" tipo: "Course[]" persistido: false - nombre: "enrollments" tipo: "Enrollment[]" persistido: false - nombre: "currentCourse" tipo: "Course | null" persistido: false - nombre: "currentLesson" tipo: "Lesson | null" persistido: false - nombre: "isLoading" tipo: "boolean" persistido: false acciones_principales: - "setCourses(courses: Course[])" - "setEnrollments(enrollments: Enrollment[])" - "setCurrentCourse(course: Course | null)" - "setCurrentLesson(lesson: Lesson | null)" gaps: - nombre: "Falta gamification state" severidad: "P1" descripcion: "XP, levels, achievements no están en store" impacto: "Gamification desconectada" solucion: "Crear gamificationStore" - nombre: "Falta quiz state" severidad: "P1" descripcion: "Quiz attempt state no persisted" impacto: "Usuarios pierden respuestas al refrescar" solucion: "Crear quizStore" middleware: - devtools test_coverage: "55%" --- payment_store: archivo: "paymentStore.ts" epicAssociated: "OQI-005" estado: "FUNCIONAL" lineas: 280 descripcion: "Payment methods, subscriptions, invoices" state_fields: - nombre: "paymentMethods" tipo: "PaymentMethod[]" persistido: false - nombre: "subscriptions" tipo: "Subscription[]" persistido: false - nombre: "invoices" tipo: "Invoice[]" persistido: false gaps: - nombre: "No Stripe Elements state" severidad: "P0" descripcion: "No hay state para cardElement, paymentIntent" impacto: "PCI compliance issues" solucion: "Crear stripeStore" middleware: - devtools test_coverage: "50%" --- portfolio_store: archivo: "portfolioStore.ts" epicAssociated: "OQI-008" estado: "FUNCIONAL" lineas: 300 descripcion: "Portfolio management: allocations, goals, rebalancing" state_fields: - nombre: "portfolios" tipo: "Portfolio[]" persistido: true - nombre: "goals" tipo: "FinancialGoal[]" persistido: false - nombre: "allocations" tipo: "Allocation[]" persistido: true gaps: - nombre: "No WebSocket para real-time updates" severidad: "P1" descripcion: "Portfolio values lag detrás" impacto: "Users no ven actualización en tiempo real" solucion: "Integrar websocket.service" middleware: - devtools - persist test_coverage: "45%" --- notification_store: archivo: "notificationStore.ts" epicAssociated: "ALL" estado: "FUNCIONAL" lineas: 200 descripcion: "System notifications/toasts" gaps: [] middleware: - devtools test_coverage: "80%" --- sessions_store: archivo: "sessionsStore.ts" epicAssociated: "OQI-001" estado: "FUNCIONAL" lineas: 250 descripcion: "Active user sessions, device management" state_fields: - nombre: "activeSessions" tipo: "Session[]" persistido: false - nombre: "currentDeviceId" tipo: "string" persistido: true gaps: - nombre: "Incompleto - falta sincronización backend" severidad: "P1" descripcion: "No hay API para actualizar sessions" impacto: "Device management no funciona" solucion: "Crear sessionService.ts" middleware: - devtools - persist test_coverage: "40%" # ═══════════════════════════════════════════════════════════════════════════════ # STORES FALTANTES # ═══════════════════════════════════════════════════════════════════════════════ faltantes: session_store: epicAssociated: "OQI-001" prioridad: "P1" esfuerzo_estimado: "30h" descripcion: "Active sessions, device management, challenge auth" state_requerido: - "activeSessions: Session[]" - "currentDeviceId: string" - "challenges: Challenge[]" - "isSwitchingDevice: boolean" acciones_requeridas: - "setActiveSessions(sessions: Session[])" - "terminateSession(sessionId: string)" - "setCurrentDeviceId(deviceId: string)" - "addChallenge(challenge: Challenge)" - "approveChallenge(challengeId: string)" dependencias_bloqueantes: - "sessionService.ts (para API calls)" - "websocket.service.ts (para push notifications)" --- quiz_store: epicAssociated: "OQI-002" prioridad: "P1" esfuerzo_estimado: "35h" descripcion: "Quiz attempt state, answers, results" state_requerido: - "currentQuiz: Quiz | null" - "currentAttempt: QuizAttempt | null" - "answers: Map" - "isSubmitting: boolean" - "attemptHistory: QuizAttempt[]" acciones_requeridas: - "startQuiz(quizId: string)" - "answerQuestion(questionId: string, answer: Answer)" - "submitAttempt()" - "endQuiz()" - "saveProgress()" # For resumable quizzes persistencia: - "answers MUST persist para quizzes resumibles" - "Usar localStorage con encryption para security" --- gamification_store: epicAssociated: "OQI-002" prioridad: "P1" esfuerzo_estimado: "40h" descripcion: "User XP, levels, achievements, streaks" state_requerido: - "profile: GamificationProfile" - "achievements: Achievement[]" - "streaks: StreakData" - "leaderboardPosition: number" - "showLevelUpModal: boolean" - "showAchievementModal: Achievement | null" campos_de_profile: - "userId: string" - "totalXP: number" - "currentLevel: number" - "xpForNextLevel: number" - "xpProgressPercentage: number" - "currentStreakDays: number" - "longestStreak: number" - "lastActivityDate: Date" acciones_requeridas: - "addXP(amount: number, reason: string)" - "unlockAchievement(achievementId: string)" - "setStreakDays(days: number)" - "getLevel(): number" - "checkLevelUp(): boolean" - "resetStreak()" conexiones_requeridas: - "WebSocket para notificaciones de level-up" - "Backend: gamification events" --- certificate_store: epicAssociated: "OQI-002" prioridad: "P2" esfuerzo_estimado: "35h" descripcion: "User certificates, templates, generation status" state_requerido: - "certificates: Certificate[]" - "templates: CertificateTemplate[]" - "isGenerating: boolean" - "generationProgress: number" - "lastGenerated: Certificate | null" --- stripe_store: epicAssociated: "OQI-005" prioridad: "P0" esfuerzo_estimado: "45h" descripcion: "Stripe Elements state, payment intents, errors" state_requerido: - "clientSecret: string | null" - "isProcessing: boolean" - "stripeError: StripeError | null" - "cardElement: StripeCardElement | null" - "paymentMethodId: string | null" acciones_requeridas: - "setClientSecret(secret: string)" - "setIsProcessing(processing: boolean)" - "setStripeError(error: StripeError | null)" - "clearError()" CRITICO: - "NUNCA almacenar card data en state" - "NUNCA loguear sensitive data" - "Use Stripe Elements EXCLUSIVAMENTE" --- kyc_store: epicAssociated: "OQI-004" prioridad: "P1" esfuerzo_estimado: "40h" descripcion: "KYC verification status, documents, verification state" state_requerido: - "status: 'pending' | 'submitted' | 'verified' | 'rejected'" - "documents: KYCDocument[]" - "verificationSteps: VerificationStep[]" - "currentStep: number" - "rejectionReason: string | null" --- agent_store: epicAssociated: "OQI-007" prioridad: "P1" esfuerzo_estimado: "35h" descripcion: "LLM agent state, available strategies, execution status" state_requerido: - "agentStatus: 'ready' | 'thinking' | 'executing' | 'error'" - "strategies: Strategy[]" - "activeExecution: Execution | null" - "executionHistory: Execution[]" - "tokenUsage: TokenUsageMetrics" campos_token_usage: - "tokensUsedThisMonth: number" - "tokenLimit: number" - "percentageUsed: number" - "estimatedCost: number" --- ml_signal_store: epicAssociated: "OQI-006" prioridad: "P1" esfuerzo_estimado: "35h" descripcion: "ML predictions, signals, confidence, ensemble state" state_requerido: - "currentSignal: Signal | null" - "signals: Signal[]" - "confidence: number" - "ensembleVote: EnsembleVote | null" - "individualModelScores: Map" - "isUpdating: boolean" conexiones_requeridas: - "WebSocket para predicciones en tiempo real" - "Backend: ml-engine signals" # ═══════════════════════════════════════════════════════════════════════════════ # ANALYSIS SECTION 2: SERVICES / API CLIENTS # ═══════════════════════════════════════════════════════════════════════════════ services: framework: "Axios with interceptors" ubicacion: "apps/frontend/src/services/" pattern: "RESTful API client" # ═══════════════════════════════════════════════════════════════════════════════ # SERVICES EXISTENTES # ═══════════════════════════════════════════════════════════════════════════════ existentes: auth_service: archivo: "auth.service.ts" epicAssociated: "OQI-001" estado: "FUNCIONAL" lineas: 380 descripcion: "Authentication API endpoints" endpoints_implementados: - "POST /auth/register" - "POST /auth/login" - "POST /auth/oauth/:provider" - "GET /auth/oauth/callback/:provider" - "POST /auth/logout" - "POST /auth/refresh-token" - "POST /auth/2fa/setup" - "POST /auth/2fa/verify" - "POST /auth/phone/send" - "POST /auth/phone/verify" - "POST /auth/forgot-password" - "POST /auth/reset-password/:token" - "GET /auth/verify-email/:token" funcionalidad_actual: "85% (missing session endpoints)" gaps: - endpoint: "GET /auth/sessions" severidad: "P1" descripcion: "Get active user sessions" - endpoint: "DELETE /auth/sessions/:sessionId" severidad: "P1" descripcion: "Terminate specific session" - endpoint: "POST /auth/device/verify" severidad: "P1" descripcion: "Verify new device challenge" --- trading_service: archivo: "trading.service.ts" epicAssociated: "OQI-003" estado: "FUNCIONAL" lineas: 420 descripcion: "Market data, orders, positions API" endpoints_implementados: - "GET /market/klines" - "GET /market/ticker/:symbol" - "GET /market/orderbook/:symbol" - "POST /paper/orders" - "GET /paper/orders" - "POST /paper/orders/:id/cancel" - "GET /paper/positions" - "POST /paper/positions/:id/close" - "GET /paper/balance" gaps: - endpoint: "GET /market/symbols" descripcion: "List all available symbols" - endpoint: "WS /market/klines/:symbol" severidad: "P1" descripcion: "WebSocket kline updates" - endpoint: "WS /market/orderbook/:symbol" severidad: "P1" descripcion: "WebSocket orderbook updates" - endpoint: "GET /paper/statistics" descripcion: "Trading statistics (win rate, avg loss, etc)" - endpoint: "POST /paper/backtest" severidad: "P2" descripcion: "Backtest strategy" --- education_service: archivo: "education.service.ts" epicAssociated: "OQI-002" estado: "FUNCIONAL" lineas: 350 descripcion: "Courses, lessons, enrollments, progress" endpoints_implementados: - "GET /education/courses" - "GET /education/courses/:id" - "POST /education/enrollments" - "GET /education/enrollments" - "POST /education/progress" - "GET /education/progress/:lessonId" - "POST /education/certificates/generate" gaps: - endpoint: "POST /education/quizzes/:id/attempts" severidad: "P1" descripcion: "Start quiz attempt" - endpoint: "POST /education/attempts/:id/submit" severidad: "P1" descripcion: "Submit quiz attempt" - endpoint: "GET /education/attempts/:id/results" severidad: "P1" descripcion: "Get quiz results" - endpoint: "WS /education/lessons/:id/stream" severidad: "P1" descripcion: "Live lesson streaming" --- payment_service: archivo: "payment.service.ts" epicAssociated: "OQI-005" estado: "FUNCIONAL" lineas: 300 descripcion: "Stripe integration, payments, subscriptions" endpoints_implementados: - "POST /payments/create-intent" - "POST /payments/confirm" - "GET /payments/methods" - "POST /payments/methods" - "DELETE /payments/methods/:id" - "GET /payments/subscriptions" - "POST /payments/subscriptions" - "POST /payments/subscriptions/:id/cancel" - "GET /payments/invoices" - "GET /payments/invoices/:id" gaps: - endpoint: "POST /payments/refunds" descripcion: "Initiate refund" - endpoint: "GET /payments/refunds" descripcion: "Get refund history" - endpoint: "POST /payments/webhooks" severidad: "P1" descripcion: "Handle Stripe webhook events" --- investment_service: archivo: "investment.service.ts" epicAssociated: "OQI-004" estado: "FUNCIONAL" lineas: 380 descripcion: "Investment accounts, products, transactions" endpoints_implementados: - "POST /investment/accounts" - "GET /investment/accounts" - "GET /investment/accounts/:id" - "GET /investment/products" - "POST /investment/accounts/:id/deposit" - "POST /investment/accounts/:id/withdraw" - "GET /investment/accounts/:id/transactions" - "GET /investment/accounts/:id/distributions" gaps: - endpoint: "POST /investment/kyc" severidad: "P0" descripcion: "Submit KYC documents" - endpoint: "GET /investment/kyc/status" severidad: "P0" descripcion: "Get KYC verification status" - endpoint: "POST /investment/accounts/:id/transfer" descripcion: "Inter-account transfer" --- ml_service: archivo: "mlService.ts" epicAssociated: "OQI-006" estado: "FUNCIONAL" lineas: 280 descripcion: "ML predictions, signals, model management" endpoints_implementados: - "GET /ml/predict/:symbol" - "GET /ml/signals/:symbol" - "GET /ml/indicators/:symbol" - "GET /ml/models" - "POST /ml/models/:id/select" - "GET /ml/ensemble/vote/:symbol" gaps: - endpoint: "WS /ml/predictions/:symbol" severidad: "P1" descripcion: "Real-time prediction updates" - endpoint: "GET /ml/backtests" descripcion: "Get backtest results" --- chat_service: archivo: "chat.service.ts" epicAssociated: "OQI-007" estado: "FUNCIONAL" lineas: 200 descripcion: "Chat/conversation API" endpoints_implementados: - "POST /chat/messages" - "GET /chat/conversations" - "GET /chat/conversations/:id" gaps: [] --- admin_service: archivo: "adminService.ts" epicAssociated: "Admin" estado: "FUNCIONAL" lineas: 250 descripcion: "Admin dashboard APIs" endpoints_implementados: - "GET /admin/models" - "GET /admin/agents" - "POST /admin/agents/:id/start" - "POST /admin/agents/:id/stop" --- video_upload_service: archivo: "video-upload.service.ts" epicAssociated: "OQI-002" estado: "FUNCIONAL" lineas: 320 descripcion: "Multi-part video upload to S3/R2" funcionalidad: - "Progress tracking" - "Resumable uploads" - "Multi-part upload" - "Validation (size, codec, duration)" fecha_creacion: "2026-01-26" --- portfolio_service: archivo: "portfolio.service.ts" epicAssociated: "OQI-008" estado: "FUNCIONAL" lineas: 300 descripcion: "Portfolio management API" endpoints_implementados: - "POST /portfolio" - "GET /portfolio" - "GET /portfolio/:id" - "PUT /portfolio/:id" - "GET /portfolio/:id/allocations" - "POST /portfolio/:id/allocations" gaps: - endpoint: "POST /portfolio/:id/optimize" severidad: "P2" descripcion: "Run portfolio optimization" - endpoint: "POST /portfolio/:id/backtest" descripcion: "Backtest portfolio strategy" --- notification_service: archivo: "notification.service.ts" epicAssociated: "ALL" estado: "FUNCIONAL" lineas: 150 descripcion: "In-app notifications, push, email" --- websocket_service: archivo: "websocket.service.ts" epicAssociated: "ALL" estado: "PARCIAL" lineas: 400 descripcion: "WebSocket connection management" streams_implementados: - "trading/klines/:symbol" - "trading/ticker/:symbol" - "trading/orderbook/:symbol" - "portfolio/updates" streams_faltantes: - "ml/predictions/:symbol (P1)" - "chat/messages (P1)" - "education/live-stream (P1)" - "auth/sessions (P1)" notas: - "Base infrastructure OK" - "Falta completar handlers para LLM, education, auth" - "Falta error recovery y reconnection logic" # ═══════════════════════════════════════════════════════════════════════════════ # SERVICES FALTANTES # ═══════════════════════════════════════════════════════════════════════════════ faltantes: session_service: epicAssociated: "OQI-001" prioridad: "P1" esfuerzo_estimado: "25h" descripcion: "Session management, device verification" endpoints_requeridos: - "GET /auth/sessions" - "DELETE /auth/sessions/:sessionId" - "POST /auth/device/verify" - "GET /auth/device/challenges" - "POST /auth/device/challenges/:id/approve" --- quiz_service: epicAssociated: "OQI-002" prioridad: "P1" esfuerzo_estimado: "35h" descripcion: "Quiz API" endpoints_requeridos: - "GET /education/quizzes/:id" - "POST /education/quizzes/:id/attempts" - "POST /education/attempts/:id/submit" - "GET /education/attempts/:id/results" - "GET /education/questions/:id" --- certificate_service: epicAssociated: "OQI-002" prioridad: "P2" esfuerzo_estimado: "30h" descripcion: "Certificate generation and management" endpoints_requeridos: - "GET /education/certificates" - "POST /education/courses/:id/certificate/generate" - "GET /education/certificates/:id/download" - "POST /education/certificates/:id/verify" --- kyc_service: epicAssociated: "OQI-004" prioridad: "P0" esfuerzo_estimado: "40h" descripcion: "KYC document upload and verification" endpoints_requeridos: - "POST /investment/kyc" - "POST /investment/kyc/documents" - "GET /investment/kyc/status" - "PUT /investment/kyc/documents/:id" - "DELETE /investment/kyc/documents/:id" --- backtest_service: epicAssociated: "OQI-003" prioridad: "P2" esfuerzo_estimado: "45h" descripcion: "Strategy backtesting" endpoints_requeridos: - "POST /backtest/run" - "GET /backtest/:id" - "GET /backtest/:id/results" - "GET /backtest/:id/trades" - "DELETE /backtest/:id" --- agent_service: epicAssociated: "OQI-007" prioridad: "P1" esfuerzo_estimado: "50h" descripcion: "LLM agent APIs" endpoints_requeridos: - "POST /agent/analyze/:symbol" - "POST /agent/strategy/build" - "POST /agent/strategy/execute" - "GET /agent/token-usage" - "GET /agent/strategies" - "GET /agent/execution/:id" - "POST /agent/execution/:id/cancel" --- refund_service: epicAssociated: "OQI-005" prioridad: "P1" esfuerzo_estimado: "30h" descripcion: "Refund request and processing" endpoints_requeridos: - "POST /payments/refunds" - "GET /payments/refunds" - "GET /payments/refunds/:id" - "PUT /payments/refunds/:id" - "DELETE /payments/refunds/:id" --- watchlist_service: epicAssociated: "OQI-003" prioridad: "P1" esfuerzo_estimado: "25h" descripcion: "Watchlist CRUD operations" endpoints_requeridos: - "GET /trading/watchlists" - "POST /trading/watchlists" - "PUT /trading/watchlists/:id" - "DELETE /trading/watchlists/:id" - "POST /trading/watchlists/:id/symbols" - "DELETE /trading/watchlists/:id/symbols/:symbol" --- portfolio_optimization_service: epicAssociated: "OQI-008" prioridad: "P2" esfuerzo_estimado: "50h" descripcion: "Portfolio optimization algorithms" endpoints_requeridos: - "POST /portfolio/:id/optimize" - "POST /portfolio/:id/optimize/efficient-frontier" - "GET /portfolio/:id/recommendations" --- stripe_webhook_service: epicAssociated: "OQI-005" prioridad: "P1" esfuerzo_estimado: "40h" descripcion: "Handle Stripe webhook events" eventos_requeridos: - "payment_intent.succeeded" - "payment_intent.payment_failed" - "invoice.paid" - "invoice.payment_failed" - "customer.subscription.created" - "customer.subscription.deleted" --- market_alerts_service: epicAssociated: "OQI-003" prioridad: "P1" esfuerzo_estimado: "35h" descripcion: "Price alerts management" endpoints_requeridos: - "GET /trading/alerts" - "POST /trading/alerts" - "PUT /trading/alerts/:id" - "DELETE /trading/alerts/:id" - "WS /trading/alerts/realtime" # ═══════════════════════════════════════════════════════════════════════════════ # WEBSOCKET CONNECTIONS REQUIRED # ═══════════════════════════════════════════════════════════════════════════════ websocket_requirements: framework: "Socket.io v4.5+ (recomendado)" ubicacion: "apps/frontend/src/services/websocket.service.ts" conexiones_requeridas: - stream: "trading/klines/:symbol" estado: "IMPLEMENTADO" tasa_actualizacion: "1s" tamaño_mensaje: "~500 bytes" - stream: "trading/ticker/:symbol" estado: "IMPLEMENTADO" tasa_actualizacion: "100ms" tamaño_mensaje: "~200 bytes" - stream: "trading/orderbook/:symbol" estado: "NO IMPLEMENTADO" tasa_actualizacion: "500ms" tamaño_mensaje: "~2KB" prioridad: "P1" esfuerzo: "20h" - stream: "ml/predictions/:symbol" estado: "NO IMPLEMENTADO" tasa_actualizacion: "5min" tamaño_mensaje: "~500 bytes" prioridad: "P1" esfuerzo: "15h" - stream: "portfolio/updates" estado: "IMPLEMENTADO" tasa_actualizacion: "1s" tamaño_mensaje: "~1KB" - stream: "education/live-stream/:sessionId" estado: "NO IMPLEMENTADO" tasa_actualizacion: "30fps" tamaño_mensaje: "STREAMING" prioridad: "P1" esfuerzo: "40h" - stream: "chat/messages" estado: "NO IMPLEMENTADO" tasa_actualizacion: "REAL-TIME" tamaño_mensaje: "~500 bytes per message" prioridad: "P1" esfuerzo: "25h" - stream: "auth/sessions" estado: "NO IMPLEMENTADO" tasa_actualizacion: "ON CHANGE" tamaño_mensaje: "~200 bytes" prioridad: "P1" esfuerzo: "15h" - stream: "agent/execution/:executionId" estado: "NO IMPLEMENTADO" tasa_actualizacion: "REAL-TIME" tamaño_mensaje: "~300 bytes per update" prioridad: "P1" esfuerzo: "20h" resiliencia: - "Auto-reconnect con exponential backoff" - "Message queuing durante desconexión" - "State reconciliation post-reconnect" - "Fallback a polling si WebSocket falla" performance: - "Usar message compression (gzip) para payloads > 1KB" - "Batch updates cuando sea posible" - "Client-side debouncing/throttling" # ═══════════════════════════════════════════════════════════════════════════════ # RESUMEN DE ESTIMACIONES Y ROADMAP # ═══════════════════════════════════════════════════════════════════════════════ estimaciones_totales: stores_por_hacer: "8 stores × 30-45h = 290h" services_por_hacer: "12 services × 25-50h = 420h" websocket_streams: "6 streams × 15-40h = 150h" total_aproximado: "890h" breakdown_por_trimestre: q1_2026: enfoque: "P0 blockers + core stores" items: - "auth stores (sessionStore)" - "payment stores (stripeStore, kycStore)" - "session service + kyc service" estimado: "120h" q2_2026: enfoque: "Education + Trading stores/services" items: - "quizStore, gamificationStore" - "watchlistService, backtestService" - "WebSocket order book y ML predictions" estimado: "220h" q3_2026: enfoque: "Advanced features" items: - "agentStore + agentService" - "certificateStore + service" - "portfolio optimization" - "Live streaming WebSocket" estimado: "280h" q4_2026: enfoque: "Polish + edge cases" items: - "Error boundaries + recovery" - "Performance optimizations" - "Additional tests" estimado: "190h" # ═══════════════════════════════════════════════════════════════════════════════ # DEPENDENCIES Y BLOQUEADORES # ═══════════════════════════════════════════════════════════════════════════════ dependencies: bloqueadores: - store: "stripeStore" bloqueado_por: "Backend Stripe webhook implementation" impacto: "Payments cannot work without webhook handling" solucion: "Coordinate with backend team Q1" - store: "kycStore" bloqueado_por: "Backend KYC verification API" impacto: "Investment accounts cannot open without KYC" solucion: "Coordinate with backend team Q1" - service: "quizService" bloqueado_por: "Backend quiz grading logic" impacto: "Quizzes cannot be submitted" solucion: "Coordinate with education team Q1" - websocket: "orderbook stream" bloqueado_por: "WebSocket stream en trading backend" impacto: "Order book lags detrás de mercado" solucion: "Coordinate with trading backend Q1" # ═══════════════════════════════════════════════════════════════════════════════ # FIN FRONTEND-STORES-PLAN.yml # ═══════════════════════════════════════════════════════════════════════════════