ibanking-api-ai/docs/guia-4-implemented-pattern.md

4.4 KiB

Guía 4 — Patrones Arquitectónicos Aprobados

Catálogo de patrones de desarrollo seguro y limpio para Next.js App Router

Propósito: Esta guía documenta los patrones de código oficiales del proyecto. Cualquier desvío de estos patrones debe estar debidamente motivado y registrado en Engram.


1. El Patrón Server-First (Server Components por defecto)

En Next.js App Router, todos los componentes de la carpeta app/ son React Server Components por defecto. Esto significa que se renderizan en el servidor, reduciendo el tamaño del bundle de JavaScript en el cliente y protegiendo accesos a base de datos o APIs downstream.

Reglas del Patrón:

  1. Fetching Directo: Las peticiones al backend Spring Boot se realizan directamente en la función asíncrona del componente, sin necesidad de usar useEffect o estados de React en el cliente.
  2. Seguridad Integrada: Se verifica la sesión del usuario al inicio del renderizado usando serverRequireAuth().
// app/dashboard/page.tsx
import { serverRequireAuth } from '@/lib/auth/middleware';
import { fetchCuentasUsuario } from '@/standards/03-headers-contract';

export default async function DashboardPage() {
  // 1. Validar sesión en servidor
  const user = await serverRequireAuth();

  // 2. Fetching asíncrono seguro
  const cuentas = await fetchCuentasUsuario(user.sessionReference);

  return (
    <div>
      <h1>Portal de Cuentas de {user.name}</h1>
      <ul className="space-y-4">
        {cuentas.map((cta) => (
          <li key={cta.id} className="p-4 bg-base-100 rounded-box shadow">
            Cuenta: {cta.numero} - Saldo: ${cta.saldo}
          </li>
        ))}
      </ul>
    </div>
  );
}

2. El Patrón de Hidratación de Componentes del Cliente

Cuando requerimos interactividad del usuario (clicks, formularios reactivos, modales dinámicos), declaramos un Client Component usando la directiva 'use client' al principio del archivo.

Reglas de Diseño:

  • Área Limpia: Mantén el Client Component lo más atómico y libre de fetching posible. Pasa los datos iniciales obtenidos en el Server Component como Props.
  • Estado Global: Si el componente altera el estado de la sesión, actualiza el store de Zustand.
// components/BotonTransferencia.tsx
'use client';
import { useState } from 'react';
import { logInfo } from '@/lib/logger/client-logger';
import { useAuthStore } from '@/lib/auth/client/useAuthStore';

interface BotonProps {
  cuentaOrigenId: string;
}

export default function BotonTransferencia({ cuentaOrigenId }: BotonProps) {
  const [loading, setLoading] = useState(false);
  const { user } = useAuthStore();

  const handleTransfer = async () => {
    setLoading(true);
    logInfo('Acción de transferencia disparada', { cuentaOrigenId, userId: user?.id });
    
    // Simular llamada de API local
    await new Promise((r) => setTimeout(r, 1000));
    setLoading(false);
  };

  return (
    <button 
      onClick={handleTransfer}
      disabled={loading}
      className="btn btn-primary"
    >
      {loading ? 'Procesando...' : 'Transferir Saldo'}
    </button>
  );
}

3. Gobernanza de Estado Cliente con Zustand

Evitamos el uso de React Context APIs redundantes o Redux pesado. El estado de la sesión cliente y configuraciones UI se centralizan en Zustand stores ubicados en lib/auth/client/useAuthStore.ts.

Reglas del Patrón:

  1. Reactividad Fina: Usa selectores en tus componentes para suscribirte solo a las propiedades requeridas (evita re-renders innecesarios).
  2. Acciones Claras: Toda lógica que muta el estado debe encapsularse en las acciones del store.
// lib/auth/client/useAuthStore.ts
import { create } from 'zustand';

interface User {
  id: string;
  name: string;
}

interface AuthState {
  user: User | null;
  isAuthenticated: boolean;
  login: (user: User) => void;
  logout: () => void;
}

export const useAuthStore = create<AuthState>((set) => ({
  user: null,
  isAuthenticated: false,
  login: (user) => set({ user, isAuthenticated: true }),
  logout: () => set({ user: null, isAuthenticated: false }),
}));

4. El Patrón de Logging Proxy para el Cliente

Como el cliente no tiene acceso al sistema de archivos local (logs/app.log), canalizamos todas las trazas de Client Components mediante el proxy seguro de Next.js /api/logs.

  • Ver standards/01-log-tracing.md para el flujo de llamadas y enrutamiento técnico de este patrón.