trading-platform/orchestration/tareas/_archive/2026-01/TASK-2026-01-26-ANALYSIS-INTEGRATION-PLAN/ST4.2-PCI-DSS-CONTEXT-ANALYSIS.md
Adrian Flores Cortes df43dd90cb [F0-F2] feat: Coherence analysis baseline + entity types + frontend stores
FASE 0 - Preparación y Purga:
- Archived 21 completed tasks to _archive/2026-01/
- Marked 4 docs as DEPRECATED
- Created 3 baseline coherence reports

FASE 1 - DDL-Backend Coherence:
- audit.types.ts: +4 types (SystemEvent, TradingAudit, ApiRequestLog, DataAccessLog)
- investment.types.ts: +4 types (RiskQuestionnaire, WithdrawalRequest, DailyPerformance, DistributionHistory)
- entity.types.ts: +5 types (Symbol, TradingBot, TradingSignal, TradingMetrics, PaperBalance)

FASE 2 - Backend-Frontend Coherence:
- investmentStore.ts: New Zustand store with 20+ actions
- mlStore.ts: New Zustand store with signal caching
- alerts.service.ts: New service with 15 functions

FASE 3 - Documentation:
- OQI-009: Updated to 100% coverage, added ET-MKT-004-productos.md
- OQI-010: Created full structure (STATUS.md, ROADMAP-MT4.md, ET-MT4-001-gateway.md)

Coherence Baseline Established:
- DDL-Backend: 31% (target 95%)
- Backend-Frontend: 72% (target 85%)
- Global: 39.6% (target 90%)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 22:08:04 -06:00

14 KiB

ST4.2: PCI-DSS Compliance - Context & Analysis

Blocker: BLOCKER-002 Prioridad: P0 - CRÍTICO Esfuerzo Estimado: 80h Fecha: 2026-01-26 Estado: 🔄 ANÁLISIS EN PROGRESO


C: CONTEXTO - Revisión Implementación Actual

Backend ( PCI-DSS Compliant)

1. Payment Intents Implementation

Archivo: apps/backend/src/modules/payments/services/stripe.service.ts

Métodos encontrados:

  • createPaymentIntent() (línea 336)

    • Crea Payment Intent en Stripe
    • Retorna clientSecret al frontend
    • No maneja datos de tarjeta directamente
  • confirmPaymentIntent() (línea 361)

    • Confirma Payment Intent server-side
    • Usado para flujos sin cliente
async createPaymentIntent(
  userId: string,
  amount: number,
  currency: string = 'usd',
  metadata: Record<string, string> = {}
): Promise<Stripe.PaymentIntent> {
  const customer = await this.getOrCreateCustomer(userId, userResult.rows[0].email);

  const paymentIntent = await stripe.paymentIntents.create({
    amount: Math.round(amount * 100),
    currency,
    customer: customer.stripeCustomerId,
    metadata: { userId, ...metadata },
  });

  return paymentIntent;
}

Estado: Implementación correcta PCI-DSS compliant


2. Webhook Handler

Archivo: apps/backend/src/modules/payments/controllers/payments.controller.ts

Método: handleStripeWebhook() (líneas 391-490)

Eventos procesados:

  • checkout.session.completed
  • customer.subscription.created
  • customer.subscription.updated
  • customer.subscription.deleted
  • invoice.paid
  • invoice.payment_failed
export async function handleStripeWebhook(req: Request, res: Response, next: NextFunction): Promise<void> {
  try {
    const signature = req.headers['stripe-signature'] as string;
    const event = stripeService.constructWebhookEvent(req.body, signature);

    switch (event.type) {
      case 'checkout.session.completed': {
        await handleCheckoutComplete(session);
        break;
      }
      // ... more cases
    }

    res.json({ received: true });
  } catch (error) {
    next(error);
  }
}

Estado: Webhook handler completo y funcional


3. Routes

Archivo: apps/backend/src/modules/payments/payments.routes.ts

Rutas encontradas:

  • POST /payments/webhook - Stripe webhook endpoint
  • POST /payments/checkout - Create checkout session
  • POST /payments/wallet/deposit - Wallet deposit (usado por DepositForm)

Estado: Rutas configuradas correctamente


Frontend - Análisis de Componentes

1. CORRECTO: DepositForm (PCI-DSS Compliant)

Archivo: apps/frontend/src/modules/investment/components/DepositForm.tsx

Implementación:

import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js';

// Renderiza CardElement (NO maneja datos de tarjeta)
<CardElement options={cardElementOptions} />

// Confirma pago con Stripe
const { error, paymentIntent } = await stripe.confirmCardPayment(
  clientSecret,
  {
    payment_method: {
      card: cardElement,  // ← Stripe.js maneja datos
    },
  }
);

Flujo:

  1. Usuario completa formulario (monto, cuenta)
  2. Frontend llama POST /api/v1/payments/wallet/deposit
  3. Backend crea Payment Intent → devuelve clientSecret
  4. Frontend usa stripe.confirmCardPayment(clientSecret, { payment_method: { card: cardElement } })
  5. Stripe procesa pago sin que frontend toque datos sensibles

Estado: 100% PCI-DSS compliant

Mensaje en UI (línea 260):

"Your payment is secured by Stripe. We never store your card details."


2. CORRECTO: StripeElementsWrapper (PCI-DSS Compliant)

Archivo: apps/frontend/src/components/payments/StripeElementsWrapper.tsx

Implementación:

import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';

// Carga Stripe.js
const stripe = loadStripe(stripeConfig.publicKey, {
  locale: stripeConfig.locale,
});

// Renderiza Elements provider
<Elements stripe={stripePromise} options={elementsOptions}>
  {children}
</Elements>

Comentario en código (línea 6):

"IMPORTANT: This component is required for PCI-DSS compliance. All payment forms must be wrapped with this provider."

Features:

  • Carga Stripe.js desde CDN
  • Configura tema oscuro personalizado
  • Manejo de errores y loading states
  • HOC withStripeElements() para wrapping

Estado: Infraestructura correcta para PCI-DSS


3. VIOLACIÓN CRÍTICA: PaymentMethodForm

Archivo: apps/frontend/src/components/payments/PaymentMethodForm.tsx

🚨 VIOLACIONES DETECTADAS:

Violación 1: Estado local almacena datos sensibles (líneas 30-32)

const [cardNumber, setCardNumber] = useState('');  // ❌ PAN completo en memoria
const [expiry, setExpiry] = useState('');          // ❌ Fecha expiración
const [cvc, setCvc] = useState('');                // ❌ CVV/CVC

Violación 2: Inputs directos para datos de tarjeta (líneas 151-202)

<input
  type="text"
  value={cardNumber}
  onChange={(e) => setCardNumber(formatCardNumber(e.target.value))}
  placeholder="1234 5678 9012 3456"
/>

Violación 3: Envío de datos sensibles al backend (líneas 116-128)

const result = await addPaymentMethod({
  type: 'card',
  card: {
    number: cardNumber.replace(/\s/g, ''),           // ❌ Envía PAN completo
    exp_month: parseInt(expiry.split('/')[0]),       // ❌ Envía mes expiración
    exp_year: 2000 + parseInt(expiry.split('/')[1]), // ❌ Envía año expiración
    cvc,                                              // ❌ Envía CVV
  },
  billing_details: {
    name: cardholderName,
  },
  setAsDefault: makeDefault,
});

Comentario en código (línea 114):

"In a real implementation, this would use Stripe.js to create a PaymentMethod"

PCI-DSS Requirements Violated:

  • Requirement 3: Protect stored cardholder data
  • Requirement 4: Encrypt transmission of cardholder data
  • Requirement 6: Develop secure systems and applications

Nivel de Severidad: 🔴 CRÍTICO

Estado de Uso:

  • NO está siendo usado en ninguna página actualmente
  • Solo exportado en components/payments/index.ts
  • Parece ser código legacy/demo

4. CORRECTO: Billing Page

Archivo: apps/frontend/src/modules/payments/pages/Billing.tsx

Gestión de métodos de pago:

  • Usa Stripe Customer Portal para agregar métodos de pago (líneas 214-220)
  • Llama openBillingPortal() que redirige a portal hosted por Stripe
  • NO usa PaymentMethodForm
<button onClick={openBillingPortal}>
  <Plus className="w-4 h-4" />
  Agregar
</button>

Estado: PCI-DSS compliant (usa portal hosted por Stripe)


5. Frontend payment.service.ts

Archivo: apps/frontend/src/services/payment.service.ts

Problemas encontrados:

Problema 1: No usa apiClient centralizado (líneas 29-43)

// ❌ PROBLEMA: Axios local, no usa apiClient de ST4.1
const api = axios.create({
  baseURL: API_BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
});

// ❌ Interceptor duplicado
api.interceptors.request.use((config) => {
  const token = localStorage.getItem('auth_token'); // ❌ Clave diferente: 'auth_token' vs 'token'
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

Impacto:

  • NO se beneficia del auto-refresh de ST4.1
  • Puede causar 401 y logout inesperado
  • Inconsistencia con otros servicios

Prioridad: ⚠️ ALTA (debe migrarse a apiClient como parte de ST4.1.3)


A: ANÁLISIS - Gaps y Riesgos

1. Estado Actual PCI-DSS

Componente Estado Compliance
Backend Payment Intents Implementado Compliant
Backend Webhooks Implementado Compliant
Frontend DepositForm Usa CardElement Compliant
Frontend StripeElementsWrapper Implementado Compliant
Frontend Billing Page Usa Customer Portal Compliant
Frontend PaymentMethodForm Manejo directo datos VIOLATION

Nivel de Riesgo Global: 🟡 MEDIO-BAJO

Razón:

  • El componente inseguro NO está en uso actualmente
  • Los flujos de producción usan implementaciones seguras
  • Riesgo: Developer podría usar PaymentMethodForm sin saber que es inseguro

2. Gaps Identificados

Gap 1: Código Legacy Inseguro

Descripción: PaymentMethodForm existe pero no cumple PCI-DSS

Impacto:

  • Riesgo de uso accidental por developers
  • Confusión en código base (2 formas de agregar métodos de pago)

Remediación:

  • ELIMINAR PaymentMethodForm.tsx
  • DOCUMENTAR que debe usarse Stripe Customer Portal o CardElement

Gap 2: payment.service.ts no usa apiClient

Descripción: Usa axios local en lugar de apiClient centralizado de ST4.1

Impacto:

  • NO se beneficia de auto-refresh tokens
  • Inconsistencia con otros servicios
  • Puede causar 401 inesperados

Remediación:

  • ⚠️ Migrar a apiClient (parte de ST4.1.3)

Gap 3: Falta documentación PCI-DSS

Descripción: No hay documento técnico que explique arquitectura PCI-DSS

Impacto:

  • Developers no saben qué componentes usar
  • Riesgo de implementaciones inseguras futuras

Remediación:

  • 📄 Crear ET-PAY-006: PCI-DSS Architecture & Guidelines

3. Arquitectura Actual vs Ideal

Arquitectura Actual (Flujos en Uso)

┌─────────────────────────────────────────────────────────────┐
│                    FLUJO ACTUAL (SEGURO)                     │
└─────────────────────────────────────────────────────────────┘

1. AGREGAR MÉTODO DE PAGO:
   User → Billing Page → openBillingPortal() → Stripe Customer Portal
                                                  ↓
                                           User adds card
                                                  ↓
                                           Webhook → Backend
                                                  ↓
                                           Store PaymentMethod

2. DEPOSIT TO WALLET:
   User → DepositForm → <CardElement> → stripe.confirmCardPayment()
                            ↓                      ↓
                    (Stripe.js handles)    Backend Payment Intent
                            ↓                      ↓
                       Success/Error         Webhook updates DB

✅ AMBOS FLUJOS SON PCI-DSS COMPLIANT

Código Legacy (No Usado)

┌─────────────────────────────────────────────────────────────┐
│              CÓDIGO LEGACY (INSEGURO - NO USADO)            │
└─────────────────────────────────────────────────────────────┘

PaymentMethodForm:
   User → <input type="text" cardNumber> → addPaymentMethod()
              ↓                                    ↓
       (PAN en memoria)                    POST /api con datos raw
              ↓                                    ↓
         ❌ VIOLATION                         ❌ VIOLATION

❌ NO DEBE USARSE - ELIMINAR

P: PLANEACIÓN - Estrategia de Remediación

Opción 1: ELIMINAR Código Inseguro (RECOMENDADA)

Acción:

  1. Eliminar PaymentMethodForm.tsx
  2. Remover export de components/payments/index.ts
  3. Documentar en ET-PAY-006 que se debe usar:
    • Stripe Customer Portal (para métodos de pago)
    • CardElement (para pagos one-time)

Ventajas:

  • Elimina riesgo de uso accidental
  • Simplifica codebase
  • Clarifica arquitectura PCI-DSS

Desventajas:

  • Ninguna (código no está en uso)

Esfuerzo: 0.5h


Opción 2: REFACTOR a Stripe Elements (No Recomendada)

Acción:

  1. Refactorizar PaymentMethodForm para usar CardElement
  2. Integrar con Payment Intents backend
  3. Mantener ambas opciones (Portal + Form)

Ventajas:

  • Permite agregar métodos sin salir de la app

Desventajas:

  • Más código a mantener
  • Stripe Customer Portal ya cubre este caso
  • Duplicación de funcionalidad

Esfuerzo: 8h

Decisión: NO RECOMENDADA


Opción 3: MANTENER Status Quo (No Recomendada)

Acción:

  • No tocar PaymentMethodForm
  • Confiar en que no se usará

Ventajas:

  • Ninguna

Desventajas:

  • Riesgo de uso accidental
  • Código legacy confunde a developers
  • No cumple con best practices

Decisión: NO RECOMENDADA


Recomendación Final

OPCIÓN 1: Eliminar Código Inseguro + Documentar Arquitectura

Justificación:

  1. PaymentMethodForm NO está en uso → Eliminar es seguro
  2. Flujos actuales (Customer Portal + CardElement) YA cumplen PCI-DSS
  3. Eliminar código inseguro previene riesgos futuros
  4. Documentación clara guía a developers

Tareas ST4.2:

ID Tarea Esfuerzo Prioridad
ST4.2.1 ELIMINAR PaymentMethodForm.tsx 0.25h P0
ST4.2.2 📄 CREAR ET-PAY-006 PCI-DSS Architecture 4h P0
ST4.2.3 Validar flujos actuales (tests) 8h P1
ST4.2.4 🔍 Security audit PCI-DSS SAQ-A 8h P1
ST4.2.5 📄 ACTUALIZAR developer guidelines 2h P2

Total Esfuerzo Revisado: ~22h (en lugar de 80h originales)

Ahorro: 58h (73% reducción) debido a que backend ya está completo y frontend usa implementaciones seguras


Próximos Pasos

  1. Aprobar plan (Opción 1)
  2. 🔄 Ejecutar ST4.2.1: Eliminar PaymentMethodForm
  3. 📄 Ejecutar ST4.2.2: Crear ET-PAY-006
  4. Ejecutar ST4.2.3: Tests E2E de flujos de pago
  5. 🔍 Ejecutar ST4.2.4: Security audit
  6. Marcar ST4.2 como COMPLETADO

Estado: Pendiente aprobación de usuario Última actualización: 2026-01-26 Autor: Claude Opus 4.5