Files
GRH/DOCUMENTATION.md
Exteban08 2b5735d78d Agregar documentacion completa del proyecto
- README.md actualizado con descripcion detallada del sistema
- DOCUMENTATION.md con documentacion tecnica exhaustiva

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 04:58:02 +00:00

612 lines
15 KiB
Markdown

# Documentacion Tecnica - Water Project GRH
Documentacion tecnica detallada del Sistema de Gestion de Recursos Hidricos.
---
## Tabla de Contenidos
1. [Arquitectura del Sistema](#arquitectura-del-sistema)
2. [Componentes Principales](#componentes-principales)
3. [Capa de API](#capa-de-api)
4. [Hooks Personalizados](#hooks-personalizados)
5. [Sistema de Autenticacion](#sistema-de-autenticacion)
6. [Gestion de Estado](#gestion-de-estado)
7. [Sistema de Temas](#sistema-de-temas)
8. [Guia de Desarrollo](#guia-de-desarrollo)
---
## Arquitectura del Sistema
### Vision General
El proyecto sigue una arquitectura **frontend SPA (Single Page Application)** con las siguientes capas:
```
┌─────────────────────────────────────────────────────────┐
│ Capa de Presentacion │
│ (React Components, Pages, Layout) │
├─────────────────────────────────────────────────────────┤
│ Capa de Logica │
│ (Custom Hooks, State Management) │
├─────────────────────────────────────────────────────────┤
│ Capa de Datos │
│ (API Services, localStorage) │
├─────────────────────────────────────────────────────────┤
│ API Externa │
│ (REST API Backend) │
└─────────────────────────────────────────────────────────┘
```
### Patron de Diseno
El proyecto utiliza varios patrones de diseno:
1. **Container/Presentational Pattern**: Separacion entre componentes con logica (pages) y componentes de UI puros (components)
2. **Custom Hooks Pattern**: Encapsulacion de logica reutilizable en hooks (`useMeters`, `useConcentrators`)
3. **Module Pattern**: Organizacion de codigo relacionado en modulos (meters/, concentrators/)
---
## Componentes Principales
### App.tsx - Componente Raiz
El componente raiz maneja:
- Autenticacion global
- Routing interno (sin react-router)
- Estado de pagina actual
- Modales globales (perfil, configuracion, logout)
```typescript
// Estados principales
const [isAuth, setIsAuth] = useState<boolean>(() => {
return Boolean(localStorage.getItem(AUTH_KEY));
});
const [currentPage, setCurrentPage] = useState("home");
const [currentSubpage, setCurrentSubpage] = useState<string | null>(null);
```
### Sidebar.tsx - Menu Lateral
Caracteristicas:
- Estados: colapsado/expandido
- Hover expansion con delay
- Pin/unpin para mantener expandido
- Menu jerarquico con submenus
```typescript
interface SidebarProps {
currentPage: string;
setCurrentPage: (page: string) => void;
currentSubpage: string | null;
setCurrentSubpage: (subpage: string | null) => void;
}
```
### TopMenu.tsx - Barra Superior
Funcionalidades:
- Breadcrumb de navegacion
- Notificaciones (placeholder)
- Menu de usuario con dropdown
- Acciones: perfil, configuracion, logout
---
## Capa de API
### Estructura de Archivos
```
src/api/
├── me.ts # Perfil de usuario
├── meters.ts # Operaciones CRUD de medidores
├── concentrators.ts # Operaciones CRUD de concentradores
└── projects.ts # Operaciones CRUD de proyectos
```
### Configuracion
```typescript
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
const API_TOKEN = import.meta.env.VITE_API_TOKEN;
```
### Funciones de API - Medidores
```typescript
// meters.ts
// Obtener todos los medidores
export async function fetchMeters(): Promise<Meter[]>
// Crear medidor
export async function createMeter(meterData: Partial<Meter>): Promise<Meter>
// Actualizar medidor
export async function updateMeter(
id: string,
meterData: Partial<Meter>
): Promise<Meter>
// Eliminar medidor
export async function deleteMeter(id: string): Promise<void>
```
### Funciones de API - Concentradores
```typescript
// concentrators.ts
export async function fetchConcentrators(): Promise<Concentrator[]>
export async function createConcentrator(data: Partial<Concentrator>): Promise<Concentrator>
export async function updateConcentrator(id: string, data: Partial<Concentrator>): Promise<Concentrator>
export async function deleteConcentrator(id: string): Promise<void>
```
### Funciones de API - Proyectos
```typescript
// projects.ts
export async function fetchProjects(): Promise<Project[]>
export async function fetchProjectNames(): Promise<string[]>
export async function createProject(data: Partial<Project>): Promise<Project>
export async function updateProject(id: string, data: Partial<Project>): Promise<Project>
export async function deleteProject(id: string): Promise<void>
```
### Manejo de Errores
Todas las funciones de API siguen el patron:
```typescript
try {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error("API Error:", error);
throw error;
}
```
---
## Hooks Personalizados
### useMeters.ts
Hook para gestion completa del modulo de medidores.
```typescript
interface UseMetersReturn {
// Data
meters: Meter[];
filteredMeters: Meter[];
projectNames: string[];
// State
loading: boolean;
selectedMeter: Meter | null;
selectedProject: string | null;
searchTerm: string;
// Actions
setSelectedMeter: (meter: Meter | null) => void;
setSelectedProject: (project: string | null) => void;
setSearchTerm: (term: string) => void;
refreshData: () => Promise<void>;
// CRUD
handleCreate: (data: Partial<Meter>) => Promise<void>;
handleUpdate: (id: string, data: Partial<Meter>) => Promise<void>;
handleDelete: (id: string) => Promise<void>;
}
export function useMeters(): UseMetersReturn
```
### useConcentrators.ts
Hook similar para concentradores con estructura equivalente.
```typescript
interface UseConcentratorsReturn {
concentrators: Concentrator[];
filteredConcentrators: Concentrator[];
projectNames: string[];
loading: boolean;
selectedConcentrator: Concentrator | null;
// ... similar a useMeters
}
export function useConcentrators(): UseConcentratorsReturn
```
---
## Sistema de Autenticacion
### Flujo de Autenticacion
```
┌──────────────┐ ┌─────────────┐ ┌──────────────┐
│ LoginPage │────>│ Validacion │────>│ localStorage│
└──────────────┘ └─────────────┘ └──────────────┘
┌─────────────┐
│ App.tsx │
│ (isAuth) │
└─────────────┘
```
### Almacenamiento de Token
```typescript
const AUTH_KEY = "grh_auth";
interface AuthData {
token: string;
ts: number; // timestamp de login
}
// Guardar
localStorage.setItem(AUTH_KEY, JSON.stringify({ token: "demo", ts: Date.now() }));
// Verificar
const isAuth = Boolean(localStorage.getItem(AUTH_KEY));
// Eliminar (logout)
localStorage.removeItem(AUTH_KEY);
```
### Proteccion de Rutas
```typescript
// App.tsx
if (!isAuth) {
return <LoginPage onSuccess={handleLogin} />;
}
// Si esta autenticado, renderiza la aplicacion
return (
<div className="flex h-screen">
<Sidebar {...props} />
<main>{renderPage()}</main>
</div>
);
```
---
## Gestion de Estado
### Estado Local (useState)
La aplicacion utiliza principalmente `useState` de React para gestion de estado local:
```typescript
// Ejemplo en MeterPage.tsx
const [meters, setMeters] = useState<Meter[]>([]);
const [selectedMeter, setSelectedMeter] = useState<Meter | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [modalMode, setModalMode] = useState<"add" | "edit">("add");
```
### Estado Persistente (localStorage)
Para datos que deben persistir entre sesiones:
```typescript
// Configuraciones de usuario
const SETTINGS_KEY = "water_project_settings_v1";
interface Settings {
theme: "system" | "light" | "dark";
compactMode: boolean;
}
// Guardar
localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
// Cargar
const settings = JSON.parse(localStorage.getItem(SETTINGS_KEY) || "{}");
```
### Flujo de Datos en Modulos
```
┌─────────────┐
│ API Layer │
└──────┬──────┘
┌─────────────┐
│ Custom Hook │ (useMeters, useConcentrators)
└──────┬──────┘
┌─────────────┐
│ Page │ (MeterPage, ConcentratorsPage)
└──────┬──────┘
├────────────────┬────────────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Sidebar │ │ Table │ │ Modal │
└───────────┘ └───────────┘ └───────────┘
```
---
## Sistema de Temas
### Configuracion de Tema
```typescript
type Theme = "system" | "light" | "dark";
const applyTheme = (theme: Theme) => {
if (theme === "system") {
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
document.documentElement.classList.toggle("dark", prefersDark);
} else {
document.documentElement.classList.toggle("dark", theme === "dark");
}
};
```
### Clases CSS con Tailwind
```css
/* Ejemplo de clases con soporte dark mode */
.card {
@apply bg-white dark:bg-gray-800;
@apply text-gray-900 dark:text-white;
@apply border-gray-200 dark:border-gray-700;
}
```
### Modal de Configuracion
```typescript
// SettingsModals.tsx
interface SettingsModalsProps {
open: boolean;
onClose: () => void;
}
// Opciones de tema
const themeOptions = [
{ value: "system", label: "Sistema" },
{ value: "light", label: "Claro" },
{ value: "dark", label: "Oscuro" },
];
```
---
## Guia de Desarrollo
### Agregar una Nueva Pagina
1. **Crear el archivo de pagina**
```typescript
// src/pages/nueva/NuevaPage.tsx
export default function NuevaPage() {
return (
<div className="p-6">
<h1>Nueva Pagina</h1>
</div>
);
}
```
2. **Agregar al Sidebar**
```typescript
// Sidebar.tsx - agregar al menuItems
{
label: "Nueva Pagina",
page: "nueva",
icon: <IconComponent className="w-5 h-5" />,
}
```
3. **Agregar al renderizado en App.tsx**
```typescript
// App.tsx - agregar case en renderPage()
case "nueva":
return <NuevaPage />;
```
### Agregar un Nuevo Endpoint de API
1. **Crear archivo de API**
```typescript
// src/api/nuevo.ts
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
const API_TOKEN = import.meta.env.VITE_API_TOKEN;
export interface NuevoItem {
id: string;
// ... campos
}
export async function fetchNuevos(): Promise<NuevoItem[]> {
const response = await fetch(`${API_BASE_URL}/endpoint`, {
headers: {
Authorization: `Bearer ${API_TOKEN}`,
"Content-Type": "application/json",
},
});
if (!response.ok) throw new Error("Error fetching data");
const data = await response.json();
return data.records.map((r: any) => ({ id: r.id, ...r.fields }));
}
```
2. **Crear hook personalizado (opcional)**
```typescript
// src/pages/nuevo/useNuevo.ts
export function useNuevo() {
const [items, setItems] = useState<NuevoItem[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchNuevos()
.then(setItems)
.finally(() => setLoading(false));
}, []);
return { items, loading };
}
```
### Agregar un Nuevo Componente Reutilizable
```typescript
// src/components/layout/common/NuevoComponente.tsx
interface NuevoComponenteProps {
title: string;
onAction: () => void;
children?: React.ReactNode;
}
export default function NuevoComponente({
title,
onAction,
children,
}: NuevoComponenteProps) {
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
<h3 className="text-lg font-semibold">{title}</h3>
{children}
<button onClick={onAction}>Accion</button>
</div>
);
}
```
### Convenios de Codigo
1. **Nombres de archivos**: PascalCase para componentes, camelCase para utilidades
2. **Interfaces**: Prefijo descriptivo (ej: `MeterFormData`, `UserSettings`)
3. **Hooks**: Prefijo `use` (ej: `useMeters`, `useAuth`)
4. **Constantes**: UPPER_SNAKE_CASE (ej: `API_BASE_URL`)
5. **CSS**: Utilizar Tailwind CSS, evitar CSS custom
### Testing (Pendiente de Implementacion)
El proyecto actualmente no tiene tests configurados. Para agregar:
```bash
npm install -D vitest @testing-library/react @testing-library/jest-dom
```
```typescript
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "jsdom",
globals: true,
},
});
```
---
## Variables de Entorno
| Variable | Descripcion | Requerida |
|----------|-------------|-----------|
| `VITE_API_BASE_URL` | URL base de la API | Si |
| `VITE_API_TOKEN` | Token de autenticacion API | Si |
### Ejemplo .env
```env
VITE_API_BASE_URL=https://api.example.com
VITE_API_TOKEN=your-api-token-here
```
---
## Dependencias Principales
| Paquete | Version | Uso |
|---------|---------|-----|
| react | 18.2.0 | Framework UI |
| react-dom | 18.2.0 | Renderizado DOM |
| typescript | 5.2.2 | Type safety |
| vite | 5.2.0 | Build tool |
| tailwindcss | 4.1.18 | Estilos |
| @mui/material | 7.3.6 | Componentes UI |
| @material-table/core | 6.5.2 | Tablas avanzadas |
| recharts | 3.6.0 | Graficas |
| lucide-react | 0.559.0 | Iconos |
---
## Comandos Utiles
```bash
# Desarrollo
npm run dev
# Build produccion
npm run build
# Preview del build
npm run preview
# Linting
npm run lint
# Type check
npx tsc --noEmit
```
---
## Troubleshooting
### Error: CORS al conectar con API
Verificar que el backend tenga configurados los headers CORS correctos o usar un proxy en desarrollo.
### Error: Module not found
```bash
rm -rf node_modules
npm install
```
### Error: TypeScript type errors
```bash
npx tsc --noEmit
```
Revisar los errores y corregir los tipos.
### La aplicacion no carga
1. Verificar que las variables de entorno estan configuradas
2. Verificar la consola del navegador por errores
3. Verificar que la API esta accesible