# ═══════════════════════════════════════════════════════════════════════════════
# 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<Order>)"
        - "removeOrder(orderId: string)"
        - "setPositions(positions: Position[])"
        - "updatePosition(positionId: string, updates: Partial<Position>)"
        - "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<string, any>"
            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<ChartIndicator>)"
        - "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<QuestionId, Answer>"
        - "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<ModelId, number>"
        - "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
# ═══════════════════════════════════════════════════════════════════════════════
