# SIMCO: OPERACIONES FRONTEND (React/TypeScript) **Versión:** 1.0.0 **Fecha:** 2025-12-08 **Aplica a:** Todo agente que trabaje con código frontend React **Prioridad:** OBLIGATORIA para operaciones de frontend --- ## RESUMEN EJECUTIVO > **Types alineados con Backend + Componentes tipados + Hooks para lógica = Frontend robusto.** --- ## PRINCIPIO FUNDAMENTAL ``` ╔══════════════════════════════════════════════════════════════════════╗ ║ ALINEACIÓN BACKEND ↔ FRONTEND ║ ║ ║ ║ • Types/Interfaces DEBEN coincidir con DTOs del backend ║ ║ • Endpoints DEBEN consumirse según Swagger ║ ║ • Estados de error DEBEN manejarse consistentemente ║ ║ • Si Backend cambia, Frontend DEBE cambiar ║ ╚══════════════════════════════════════════════════════════════════════╝ ``` --- ## ESTRUCTURA DE FRONTEND ``` {FRONTEND_SRC}/ ├── apps/ # Aplicaciones │ └── {app}/ │ ├── pages/ # Páginas/rutas │ │ └── {Nombre}Page.tsx │ ├── components/ # Componentes de la app │ │ └── {Nombre}.tsx │ ├── hooks/ # Hooks de la app │ │ └── use{Nombre}.ts │ └── layouts/ # Layouts de la app │ └── {Nombre}Layout.tsx ├── shared/ # Compartido entre apps │ ├── components/ # Componentes compartidos │ │ ├── ui/ # Componentes UI base │ │ └── common/ # Componentes comunes │ ├── hooks/ # Hooks compartidos │ │ └── use{Nombre}.ts │ ├── services/ # Servicios │ │ └── api/ # Servicios de API │ │ └── {nombre}.api.ts │ ├── stores/ # State management │ │ └── {nombre}Store.ts │ ├── types/ # Tipos/Interfaces │ │ └── {nombre}.types.ts │ └── utils/ # Utilidades │ └── {nombre}.utils.ts └── config/ # Configuraciones └── api.config.ts ``` --- ## CONVENCIONES DE NOMENCLATURA ### Archivos ```typescript // Componentes: PascalCase.tsx UserProfile.tsx LoginForm.tsx DashboardCard.tsx // Páginas: PascalCase + Page.tsx DashboardPage.tsx UserProfilePage.tsx SettingsPage.tsx // Hooks: use + PascalCase.ts useUser.ts useAuth.ts useDashboard.ts // Types: camelCase.types.ts user.types.ts auth.types.ts dashboard.types.ts // API services: camelCase.api.ts user.api.ts auth.api.ts // Stores: camelCase + Store.ts userStore.ts authStore.ts ``` ### Componentes y Funciones ```typescript // Componentes: PascalCase export const UserProfile: React.FC = () => {} export const LoginForm: React.FC = () => {} // Hooks: use + PascalCase export const useUser = () => {} export const useAuth = () => {} // Funciones helper: camelCase export const formatDate = () => {} export const validateEmail = () => {} // Constantes: UPPER_SNAKE_CASE export const API_BASE_URL = '' export const MAX_RETRIES = 3 ``` ### Types e Interfaces ```typescript // Interfaces para props: PascalCase + Props interface UserProfileProps {} interface LoginFormProps {} // Types de dominio: PascalCase type User = {} type AuthState = {} // Types de API response: PascalCase + Response type UserResponse = {} type LoginResponse = {} // Enums: PascalCase enum UserStatus { Active = 'active', Inactive = 'inactive', } ``` --- ## TEMPLATES ### Types (alineados con Backend) ```typescript // shared/types/user.types.ts /** * User Types * * Tipos alineados con DTOs del backend. * @see {BACKEND_SRC}/modules/users/dto/ */ /** * User entity type * Alineado con: UserEntity del backend */ export interface User { id: string; email: string; username: string; firstName: string; lastName: string; status: UserStatus; createdAt: string; updatedAt: string; } /** * Estado del usuario */ export enum UserStatus { Active = 'active', Inactive = 'inactive', Suspended = 'suspended', } /** * DTO para crear usuario * Alineado con: CreateUserDto del backend */ export interface CreateUserInput { email: string; username: string; password: string; firstName: string; lastName: string; } /** * DTO para actualizar usuario * Alineado con: UpdateUserDto del backend */ export interface UpdateUserInput { email?: string; username?: string; firstName?: string; lastName?: string; status?: UserStatus; } /** * Respuesta de lista de usuarios */ export interface UsersListResponse { data: User[]; total: number; page: number; limit: number; } ``` ### API Service ```typescript // shared/services/api/user.api.ts import { apiClient } from '@/config/api.config'; import type { User, CreateUserInput, UpdateUserInput, UsersListResponse, } from '@/shared/types/user.types'; /** * User API Service * * Servicios para interactuar con endpoints de usuarios. * @see Swagger: /api/docs#/Users */ const BASE_PATH = '/users'; /** * Obtiene lista de usuarios */ export const getUsers = async ( page = 1, limit = 20, ): Promise => { const response = await apiClient.get(BASE_PATH, { params: { page, limit }, }); return response.data; }; /** * Obtiene un usuario por ID */ export const getUserById = async (id: string): Promise => { const response = await apiClient.get(`${BASE_PATH}/${id}`); return response.data; }; /** * Crea un nuevo usuario */ export const createUser = async (data: CreateUserInput): Promise => { const response = await apiClient.post(BASE_PATH, data); return response.data; }; /** * Actualiza un usuario */ export const updateUser = async ( id: string, data: UpdateUserInput, ): Promise => { const response = await apiClient.put(`${BASE_PATH}/${id}`, data); return response.data; }; /** * Elimina un usuario */ export const deleteUser = async (id: string): Promise => { await apiClient.delete(`${BASE_PATH}/${id}`); }; ``` ### Hook ```typescript // shared/hooks/useUser.ts import { useState, useEffect, useCallback } from 'react'; import type { User } from '@/shared/types/user.types'; import * as userApi from '@/shared/services/api/user.api'; /** * Hook para gestión de usuario * * Proporciona estado y operaciones para un usuario. * * @example * ```tsx * const { user, loading, error, refetch } = useUser(userId); * ``` */ export const useUser = (userId: string | null) => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); /** * Carga el usuario */ const fetchUser = useCallback(async () => { if (!userId) { setUser(null); return; } setLoading(true); setError(null); try { const data = await userApi.getUserById(userId); setUser(data); } catch (err) { setError(err instanceof Error ? err : new Error('Unknown error')); setUser(null); } finally { setLoading(false); } }, [userId]); /** * Actualiza el usuario */ const updateUser = useCallback( async (data: Partial) => { if (!userId) return; setLoading(true); setError(null); try { const updated = await userApi.updateUser(userId, data); setUser(updated); return updated; } catch (err) { setError(err instanceof Error ? err : new Error('Update failed')); throw err; } finally { setLoading(false); } }, [userId], ); // Cargar usuario al montar o cambiar ID useEffect(() => { fetchUser(); }, [fetchUser]); return { user, loading, error, refetch: fetchUser, updateUser, }; }; ``` ### Componente ```typescript // apps/{app}/components/UserProfile.tsx import React from 'react'; import type { User } from '@/shared/types/user.types'; /** * Props del componente UserProfile */ interface UserProfileProps { /** Usuario a mostrar */ user: User; /** Si mostrar avatar */ showAvatar?: boolean; /** Callback al editar */ onEdit?: (user: User) => void; /** Clases CSS adicionales */ className?: string; } /** * UserProfile - Muestra información del perfil de usuario * * @component * @example * ```tsx * * ``` */ export const UserProfile: React.FC = ({ user, showAvatar = true, onEdit, className = '', }) => { const handleEditClick = () => { onEdit?.(user); }; return (
{showAvatar && (
{/* Avatar implementation */}
)}

{user.firstName} {user.lastName}

{user.email}

{user.status}
{onEdit && ( )}
); }; export default UserProfile; ``` ### Página ```typescript // apps/{app}/pages/UserProfilePage.tsx import React from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useUser } from '@/shared/hooks/useUser'; import { UserProfile } from '../components/UserProfile'; import { LoadingSpinner } from '@/shared/components/ui/LoadingSpinner'; import { ErrorMessage } from '@/shared/components/ui/ErrorMessage'; /** * UserProfilePage - Página de perfil de usuario * * @page * @route /users/:id */ export const UserProfilePage: React.FC = () => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { user, loading, error, refetch } = useUser(id ?? null); const handleEdit = () => { navigate(`/users/${id}/edit`); }; if (loading) { return ; } if (error) { return ( ); } if (!user) { return ; } return (

User Profile

); }; export default UserProfilePage; ``` --- ## VALIDACIONES OBLIGATORIAS ```bash # 1. Build (OBLIGATORIO) cd @FRONTEND_ROOT npm run build # ✅ Debe completar sin errores # 2. Lint (OBLIGATORIO) npm run lint # ✅ Debe pasar # 3. Type check npm run typecheck # o tsc --noEmit # ✅ Debe pasar # 4. Iniciar aplicación npm run dev # ✅ Debe iniciar sin errores # 5. Verificar en navegador # - Sin errores en consola # - Componentes renderizan correctamente # - Interacciones funcionan ``` --- ## CHECKLIST FRONTEND ``` TYPES ├── [ ] Alineados con DTOs del backend ├── [ ] Interfaces para props documentadas ├── [ ] Enums para valores fijos ├── [ ] Types de API response └── [ ] JSDoc en types públicos API SERVICE ├── [ ] Endpoints según Swagger ├── [ ] Manejo de errores ├── [ ] Tipos de request/response └── [ ] Documentación de cada función HOOKS ├── [ ] Estados: data, loading, error ├── [ ] useCallback para funciones ├── [ ] useEffect para side effects ├── [ ] Cleanup si necesario └── [ ] JSDoc con ejemplo COMPONENTES ├── [ ] Props tipadas e interface ├── [ ] Props documentadas con JSDoc ├── [ ] defaultProps donde aplique ├── [ ] Accesibilidad (aria-*, roles) ├── [ ] Manejo de estados (loading, error) └── [ ] className para estilos externos PÁGINAS ├── [ ] Manejo de parámetros de ruta ├── [ ] Estados de carga y error ├── [ ] Layout apropiado └── [ ] SEO (title, meta) si aplica VALIDACIÓN ├── [ ] npm run build pasa ├── [ ] npm run lint pasa ├── [ ] npm run typecheck pasa ├── [ ] Sin errores en consola del navegador └── [ ] Interacciones funcionan ``` --- ## ERRORES COMUNES | Error | Causa | Solución | |-------|-------|----------| | Types desalineados | Backend cambió | Actualizar types según Swagger | | Infinite loop | useEffect sin deps | Agregar dependencias correctas | | Memory leak | Sin cleanup | Agregar cleanup en useEffect | | Props any | Falta tipar | Crear interface de props | | Build falla | Errores TypeScript | Corregir antes de continuar | --- ## REFERENCIAS - **Crear archivos:** @CREAR (SIMCO-CREAR.md) - **Validar:** @VALIDAR (SIMCO-VALIDAR.md) - **Backend:** @OP_BACKEND (SIMCO-BACKEND.md) - **Guías Frontend:** @GUIAS_FE - **Nomenclatura:** @DIRECTIVAS/ESTANDARES-NOMENCLATURA-BASE.md --- **Versión:** 1.0.0 | **Sistema:** SIMCO | **Mantenido por:** Tech Lead