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

130 lines
4.4 KiB
Markdown

# 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()`.
```typescript
// 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.
```typescript
// 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.
```typescript
// 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.