# Patrones de Frontend - GAMILIT

**Documento:** Analisis de Patrones de Frontend React + TypeScript
**Proyecto de Referencia:** GAMILIT
**Fecha:** 2025-11-23
**Analista:** Architecture-Analyst Agent

---

## 1. VISION GENERAL

GAMILIT implementa un **frontend moderno con React 18+, Vite 5+ y TypeScript 5+** siguiendo la arquitectura Feature-Sliced Design (FSD) con 180+ componentes reutilizables.

**Stack tecnologico:**
- **Framework:** React 18+ con hooks
- **Build Tool:** Vite 5+ (HMR rapido)
- **Lenguaje:** TypeScript 5+ (strict mode)
- **Styling:** Tailwind CSS 3+ (utility-first)
- **Router:** React Router v6
- **State:** Zustand (8 stores especializados)
- **Forms:** React Hook Form + Zod validation
- **HTTP:** Axios con interceptors
- **Animations:** Framer Motion
- **Testing:** Vitest + React Testing Library (13% coverage - GAP)
- **Docs:** Storybook 7+

**Metricas:**
- **LOC:** ~85,000 lineas (65% del proyecto)
- **Componentes:** 180+ componentes reutilizables
- **Paginas:** ~50 vistas
- **Hooks personalizados:** ~30
- **Zustand Stores:** 8 stores
- **Tests:** 15 tests (13% coverage - GAP CRITICO)

---

## 2. FEATURE-SLICED DESIGN (FSD)

### 2.1 Arquitectura de Capas

```
frontend/src/
├── shared/            # Capa compartida (180+ componentes)
│   ├── components/    # UI components genericos
│   ├── hooks/         # Custom React hooks
│   ├── utils/         # Utilidades generales
│   ├── types/         # Tipos TypeScript compartidos
│   └── constants/     # Constantes (sincronizadas con backend)
│
├── features/          # Features de negocio por dominio/rol
│   ├── student/       # Portal estudiante
│   ├── teacher/       # Portal profesor
│   └── admin/         # Portal administrador
│
├── pages/             # Paginas/Vistas (composicion de features)
│   ├── student/
│   ├── teacher/
│   └── admin/
│
├── services/          # Servicios externos
│   ├── api/           # API clients (Axios)
│   └── websocket/     # Socket.IO client
│
└── app/               # Capa de aplicacion
    ├── providers/     # Context providers
    ├── layouts/       # Layouts principales
    └── router/        # Configuracion de rutas
```

### 2.2 Principios de FSD Aplicados

1. **Layered Architecture:**
   - `shared` - Codigo reutilizable sin dependencias de negocio
   - `features` - Logica de negocio por dominio
   - `pages` - Composicion de features
   - `app` - Configuracion global

2. **Public API:** Cada feature expone API publica via `index.ts`

3. **Low Coupling:** Features no dependen entre si

4. **High Cohesion:** Todo relacionado a una feature esta junto

### 2.3 Aplicabilidad a ERP Generico

⭐⭐⭐⭐ (ALTA)

**Decision:** ✅ **ADOPTAR Y ADAPTAR**

**Propuesta para ERP:**
```
frontend/src/
├── shared/            # Componentes reutilizables
├── features/
│   ├── administrator/ # Portal administrador
│   ├── accountant/    # Portal contador
│   ├── supervisor/    # Portal supervisor de obra
│   ├── purchaser/     # Portal comprador
│   └── hr/            # Portal RRHH
├── pages/
├── services/
└── app/
```

---

## 3. SHARED COMPONENTS (180+)

### 3.1 Categorias de Componentes

**1. Atomos (Elementos basicos):**
```
shared/components/atoms/
├── Button/
│   ├── Button.tsx
│   ├── Button.stories.tsx
│   ├── Button.test.tsx
│   └── index.ts
├── Input/
├── Label/
├── Badge/
├── Avatar/
└── Icon/
```

**2. Moleculas (Combinaciones de atomos):**
```
shared/components/molecules/
├── FormField/          # Label + Input + Error
├── SearchBar/          # Input + Icon + Button
├── UserCard/           # Avatar + Name + Badge
└── Notification/       # Icon + Title + Message
```

**3. Organismos (Componentes complejos):**
```
shared/components/organisms/
├── Navbar/
├── Sidebar/
├── DataTable/
├── Modal/
├── Dropdown/
└── Pagination/
```

**4. Templates (Layouts):**
```
shared/components/templates/
├── DashboardLayout/
├── AuthLayout/
├── SettingsLayout/
└── EmptyState/
```

### 3.2 Patron de Componente

**Ejemplo:** `shared/components/atoms/Button/Button.tsx`

```typescript
import { ButtonHTMLAttributes, ReactNode } from 'react';
import { cva, type VariantProps } from 'class-variance-authority';

// Variants con Tailwind CSS
const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-md font-medium transition-colors',
  {
    variants: {
      variant: {
        primary: 'bg-blue-600 text-white hover:bg-blue-700',
        secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
        outline: 'border border-gray-300 hover:bg-gray-100',
        ghost: 'hover:bg-gray-100',
        danger: 'bg-red-600 text-white hover:bg-red-700',
      },
      size: {
        sm: 'h-8 px-3 text-sm',
        md: 'h-10 px-4',
        lg: 'h-12 px-6 text-lg',
      },
      fullWidth: {
        true: 'w-full',
      },
    },
    defaultVariants: {
      variant: 'primary',
      size: 'md',
    },
  }
);

export interface ButtonProps
  extends ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  children: ReactNode;
  isLoading?: boolean;
}

export function Button({
  children,
  variant,
  size,
  fullWidth,
  isLoading,
  disabled,
  className,
  ...props
}: ButtonProps) {
  return (
    <button
      className={buttonVariants({ variant, size, fullWidth, className })}
      disabled={disabled || isLoading}
      {...props}
    >
      {isLoading ? <Spinner className="mr-2" /> : null}
      {children}
    </button>
  );
}
```

### 3.3 Aplicabilidad a ERP Generico

⭐⭐⭐⭐⭐ (MAXIMA)

**Decision:** ✅ **ADOPTAR COMPLETAMENTE**

**Componentes criticos para ERP:**
- Button, Input, Select, Checkbox (atomos)
- FormField, SearchBar, DateRangePicker (moleculas)
- DataTable, Modal, Sidebar, Navbar (organismos)
- DashboardLayout, ReportLayout (templates)

---

## 4. PATH ALIASES FRONTEND

### 4.1 Configuracion

**tsconfig.json:**
```json
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@/*": ["./*"],
      "@shared/*": ["shared/*"],
      "@components/*": ["shared/components/*"],
      "@hooks/*": ["shared/hooks/*"],
      "@utils/*": ["shared/utils/*"],
      "@types/*": ["shared/types/*"],
      "@services/*": ["services/*"],
      "@app/*": ["app/*"],
      "@features/*": ["features/*"],
      "@pages/*": ["pages/*"]
    }
  }
}
```

**vite.config.ts:**
```typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@shared': path.resolve(__dirname, './src/shared'),
      '@components': path.resolve(__dirname, './src/shared/components'),
      '@hooks': path.resolve(__dirname, './src/shared/hooks'),
      '@utils': path.resolve(__dirname, './src/shared/utils'),
      '@types': path.resolve(__dirname, './src/shared/types'),
      '@services': path.resolve(__dirname, './src/services'),
      '@app': path.resolve(__dirname, './src/app'),
      '@features': path.resolve(__dirname, './src/features'),
      '@pages': path.resolve(__dirname, './src/pages'),
    },
  },
});
```

### 4.2 Uso

```typescript
// ❌ Sin aliases
import { Button } from '../../../shared/components/atoms/Button';
import { useAuth } from '../../../shared/hooks/useAuth';

// ✅ Con aliases
import { Button } from '@components/atoms/Button';
import { useAuth } from '@hooks/useAuth';
```

### 4.3 Aplicabilidad a ERP Generico

⭐⭐⭐⭐⭐ (MAXIMA)

**Decision:** ✅ **ADOPTAR COMPLETAMENTE**

---

## 5. STATE MANAGEMENT CON ZUSTAND

### 5.1 Los 8 Stores de GAMILIT

```
stores/
├── useAuthStore.ts           # Autenticacion (user, token, logout)
├── useGamificationStore.ts   # Gamificacion (XP, coins, logros)
├── useProgressStore.ts       # Progreso de aprendizaje
├── useExerciseStore.ts       # Estado de ejercicios actuales
├── useNotificationStore.ts   # Notificaciones en tiempo real
├── useSocialStore.ts         # Features sociales
├── useTenantStore.ts         # Multi-tenancy
└── useUIStore.ts             # Estado UI (modals, sidebar, theme)
```

### 5.2 Patron de Store (ejemplo: useAuthStore)

```typescript
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface AuthState {
  // Estado
  user: User | null;
  token: string | null;
  isAuthenticated: boolean;

  // Acciones
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
  refreshToken: () => Promise<void>;
  updateProfile: (data: Partial<User>) => Promise<void>;
}

export const useAuthStore = create<AuthState>()(
  persist(
    (set, get) => ({
      // Estado inicial
      user: null,
      token: null,
      isAuthenticated: false,

      // Acciones
      login: async (email, password) => {
        const response = await authApi.login({ email, password });
        set({
          user: response.user,
          token: response.token,
          isAuthenticated: true,
        });
      },

      logout: () => {
        set({
          user: null,
          token: null,
          isAuthenticated: false,
        });
      },

      refreshToken: async () => {
        const { token } = get();
        const response = await authApi.refresh(token);
        set({ token: response.token });
      },

      updateProfile: async (data) => {
        const { user } = get();
        const updated = await userApi.update(user!.id, data);
        set({ user: updated });
      },
    }),
    {
      name: 'auth-storage', // Key en localStorage
      partialize: (state) => ({
        token: state.token,
        user: state.user,
      }),
    }
  )
);
```

### 5.3 Uso en Componentes

```typescript
function UserProfile() {
  const { user, logout, updateProfile } = useAuthStore();

  if (!user) return <LoginPrompt />;

  return (
    <div>
      <h1>Welcome, {user.name}!</h1>
      <button onClick={logout}>Logout</button>
    </div>
  );
}
```

### 5.4 Aplicabilidad a ERP Generico

⭐⭐⭐⭐⭐ (MAXIMA)

**Decision:** ✅ **ADOPTAR COMPLETAMENTE**

**Stores propuestos para ERP:**
```
stores/
├── useAuthStore.ts           # Autenticacion
├── useCompanyStore.ts        # Empresa actual (multi-tenant)
├── useProjectStore.ts        # Proyecto actual
├── useBudgetStore.ts         # Presupuesto actual
├── useNotificationStore.ts   # Notificaciones
├── useUIStore.ts             # Estado UI
└── usePermissionsStore.ts    # Permisos del usuario
```

---

## 6. CUSTOM HOOKS (~30)

### 6.1 Categorias de Hooks

**1. Hooks de Estado:**
```typescript
// hooks/useLocalStorage.ts
export function useLocalStorage<T>(key: string, initialValue: T) {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch {
      return initialValue;
    }
  });

  const setValue = (value: T | ((val: T) => T)) => {
    const valueToStore = value instanceof Function ? value(storedValue) : value;
    setStoredValue(valueToStore);
    window.localStorage.setItem(key, JSON.stringify(valueToStore));
  };

  return [storedValue, setValue] as const;
}
```

**2. Hooks de Fetch:**
```typescript
// hooks/useQuery.ts
export function useQuery<T>(
  queryFn: () => Promise<T>,
  deps: any[] = []
) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  useEffect(() => {
    setLoading(true);
    queryFn()
      .then(setData)
      .catch(setError)
      .finally(() => setLoading(false));
  }, deps);

  return { data, loading, error, refetch: () => queryFn().then(setData) };
}
```

**3. Hooks de Utilidad:**
```typescript
// hooks/useDebounce.ts
export function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => setDebouncedValue(value), delay);
    return () => clearTimeout(handler);
  }, [value, delay]);

  return debouncedValue;
}
```

### 6.2 Aplicabilidad a ERP Generico

⭐⭐⭐⭐⭐ (MAXIMA)

**Decision:** ✅ **ADOPTAR COMPLETAMENTE**

**Hooks criticos para ERP:**
- `useQuery` - Fetching de datos
- `useMutation` - Operaciones CRUD
- `useDebounce` - Busquedas optimizadas
- `useLocalStorage` - Persistencia local
- `usePermissions` - Verificacion de permisos

---

## 7. FORMS CON REACT HOOK FORM + ZOD

### 7.1 Patron de Form

```typescript
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

// Schema de validacion con Zod
const loginSchema = z.object({
  email: z.string().email('Email invalido'),
  password: z.string().min(8, 'Minimo 8 caracteres'),
});

type LoginFormData = z.infer<typeof loginSchema>;

export function LoginForm() {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm<LoginFormData>({
    resolver: zodResolver(loginSchema),
  });

  const onSubmit = async (data: LoginFormData) => {
    await authApi.login(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <FormField
        label="Email"
        error={errors.email?.message}
        {...register('email')}
      />

      <FormField
        label="Password"
        type="password"
        error={errors.password?.message}
        {...register('password')}
      />

      <Button type="submit" isLoading={isSubmitting}>
        Login
      </Button>
    </form>
  );
}
```

### 7.2 Aplicabilidad a ERP Generico

⭐⭐⭐⭐⭐ (MAXIMA)

**Decision:** ✅ **ADOPTAR COMPLETAMENTE**

---

## 8. API CLIENTS CON AXIOS

### 8.1 Configuracion de Axios Instance

```typescript
// services/api/axios-instance.ts
import axios from 'axios';
import { useAuthStore } from '@stores/useAuthStore';

const api = axios.create({
  baseURL: import.meta.env.VITE_API_URL,
  timeout: 10000,
});

// Interceptor de request (agregar token)
api.interceptors.request.use((config) => {
  const { token } = useAuthStore.getState();
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// Interceptor de response (refresh token)
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    if (error.response?.status === 401) {
      const { refreshToken, logout } = useAuthStore.getState();
      try {
        await refreshToken();
        return api.request(error.config);
      } catch {
        logout();
      }
    }
    return Promise.reject(error);
  }
);

export default api;
```

### 8.2 API Clients por Modulo

```typescript
// services/api/auth.api.ts
import api from './axios-instance';
import { API_ENDPOINTS } from '@shared/constants';

export const authApi = {
  login: (data: LoginDto) =>
    api.post(API_ENDPOINTS.AUTH.LOGIN, data).then((r) => r.data),

  register: (data: RegisterDto) =>
    api.post(API_ENDPOINTS.AUTH.REGISTER, data).then((r) => r.data),

  logout: () =>
    api.post(API_ENDPOINTS.AUTH.LOGOUT).then((r) => r.data),

  refresh: (token: string) =>
    api.post(API_ENDPOINTS.AUTH.REFRESH, { token }).then((r) => r.data),
};
```

### 8.3 Aplicabilidad a ERP Generico

⭐⭐⭐⭐⭐ (MAXIMA)

**Decision:** ✅ **ADOPTAR COMPLETAMENTE**

---

## 9. TESTING PATTERNS (GAP CRITICO)

### 9.1 Metricas de Testing

| Metrica | Actual | Objetivo | Gap |
|---------|--------|----------|-----|
| **Tests Frontend** | 15 | 60 | **-45 (75%)** |
| **Coverage** | 13% | 70% | **-57pp** |

**Critica:** Coverage extremadamente bajo. NO copiar este anti-patron.

### 9.2 Ejemplo de Test

```typescript
// components/Button/Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';

describe('Button', () => {
  it('renders with children', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByText('Click me')).toBeInTheDocument();
  });

  it('calls onClick when clicked', () => {
    const onClick = vi.fn();
    render(<Button onClick={onClick}>Click</Button>);
    fireEvent.click(screen.getByText('Click'));
    expect(onClick).toHaveBeenCalledTimes(1);
  });

  it('shows loading state', () => {
    render(<Button isLoading>Loading</Button>);
    expect(screen.getByRole('button')).toBeDisabled();
  });
});
```

### 9.3 Recomendacion para ERP Generico

⭐⭐⭐⭐⭐ (MAXIMA - CRITICO)

**Decision:** ✅ **IMPLEMENTAR TESTING DESDE EL INICIO**

**Objetivos:**
- **Coverage:** 70%+ desde el inicio
- **Tests por componente:** Unit tests
- **Integration tests:** Features completas
- **E2E tests:** Flujos criticos (Playwright/Cypress)

---

## 10. MATRIZ DE DECISION

### 10.1 ADOPTAR COMPLETAMENTE ✅

| Patron | Prioridad |
|--------|-----------|
| Feature-Sliced Design (FSD) | P0 |
| Shared Components (180+) | P0 |
| Path Aliases | P0 |
| Zustand State Management | P0 |
| Custom Hooks | P0 |
| React Hook Form + Zod | P0 |
| Axios Interceptors | P0 |
| Tailwind CSS | P1 |
| Storybook | P1 |

### 10.2 MEJORAR 🔧

| Patron | Estado Actual | Mejora | Prioridad |
|--------|---------------|--------|-----------|
| Testing | 13% coverage | 70%+ coverage | P0 CRITICO |
| Type Safety | Parcial | Completa | P1 |
| E2E Tests | Inexistentes | Playwright/Cypress | P1 |

### 10.3 EVITAR ❌

| Patron | Razon |
|--------|-------|
| Coverage bajo (13%) | Inaceptable para produccion |
| Sin E2E tests | Flujos criticos sin validar |

---

## 11. PROPUESTA PARA ERP GENERICO

```
frontend/src/
├── shared/
│   ├── components/      # 100+ componentes reutilizables
│   ├── hooks/           # Custom hooks
│   └── constants/       # Constantes (sync con backend)
│
├── features/
│   ├── administrator/   # Portal admin
│   ├── accountant/      # Portal contador
│   ├── supervisor/      # Portal supervisor
│   ├── purchaser/       # Portal compras
│   └── hr/              # Portal RRHH
│
├── pages/
├── services/
│   └── api/
│       ├── budgets.api.ts
│       ├── purchasing.api.ts
│       └── projects.api.ts
│
└── app/
    ├── providers/
    ├── layouts/
    └── router/
```

---

**Documento creado:** 2025-11-23
**Version:** 1.0
**Estado:** Completado
**Proximo documento:** `ssot-system.md`
