diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md new file mode 100644 index 0000000..1057eea --- /dev/null +++ b/DOCUMENTATION.md @@ -0,0 +1,611 @@ +# 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(() => { + return Boolean(localStorage.getItem(AUTH_KEY)); +}); +const [currentPage, setCurrentPage] = useState("home"); +const [currentSubpage, setCurrentSubpage] = useState(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 + +// Crear medidor +export async function createMeter(meterData: Partial): Promise + +// Actualizar medidor +export async function updateMeter( + id: string, + meterData: Partial +): Promise + +// Eliminar medidor +export async function deleteMeter(id: string): Promise +``` + +### Funciones de API - Concentradores + +```typescript +// concentrators.ts + +export async function fetchConcentrators(): Promise +export async function createConcentrator(data: Partial): Promise +export async function updateConcentrator(id: string, data: Partial): Promise +export async function deleteConcentrator(id: string): Promise +``` + +### Funciones de API - Proyectos + +```typescript +// projects.ts + +export async function fetchProjects(): Promise +export async function fetchProjectNames(): Promise +export async function createProject(data: Partial): Promise +export async function updateProject(id: string, data: Partial): Promise +export async function deleteProject(id: string): Promise +``` + +### 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; + + // CRUD + handleCreate: (data: Partial) => Promise; + handleUpdate: (id: string, data: Partial) => Promise; + handleDelete: (id: string) => Promise; +} + +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 ; +} + +// Si esta autenticado, renderiza la aplicacion +return ( +
+ +
{renderPage()}
+
+); +``` + +--- + +## 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([]); +const [selectedMeter, setSelectedMeter] = useState(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 ( +
+

Nueva Pagina

+
+ ); +} +``` + +2. **Agregar al Sidebar** + +```typescript +// Sidebar.tsx - agregar al menuItems +{ + label: "Nueva Pagina", + page: "nueva", + icon: , +} +``` + +3. **Agregar al renderizado en App.tsx** + +```typescript +// App.tsx - agregar case en renderPage() +case "nueva": + return ; +``` + +### 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 { + 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([]); + 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 ( +
+

{title}

+ {children} + +
+ ); +} +``` + +### 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 diff --git a/README.md b/README.md index 0d6babe..9ae7b0f 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,375 @@ -# React + TypeScript + Vite +# Water Project - Sistema de Gestion de Recursos Hidricos (GRH) -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +Sistema de gestion y monitoreo de infraestructura hidrica desarrollado con React, TypeScript y Vite. -Currently, two official plugins are available: +## Descripcion General -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +El **Sistema de Gestion de Recursos Hidricos (GRH)** es una aplicacion web frontend disenada para el monitoreo, administracion y control de infraestructura de toma de agua. Permite gestionar medidores, concentradores, proyectos, usuarios y roles a traves de una interfaz moderna y responsiva. -## Expanding the ESLint configuration +### Caracteristicas Principales -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: +- **Dashboard interactivo** con KPIs, alertas e historial de actividades +- **Gestion de Medidores (Tomas de Agua)** - CRUD completo con filtros por proyecto +- **Gestion de Concentradores** - Configuracion de gateways LoRa/LoRaWAN +- **Gestion de Proyectos** - Administracion de proyectos de infraestructura +- **Gestion de Usuarios y Roles** - Control de acceso al sistema +- **Tema claro/oscuro** - Personalizacion de la interfaz +- **Diseno responsive** - Compatible con desktop, tablet y movil -- Configure the top-level `parserOptions` property like this: +--- -```js -export default { - // other rules... - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['./tsconfig.json', './tsconfig.node.json'], - tsconfigRootDir: __dirname, - }, +## Stack Tecnologico + +### Frontend +| Tecnologia | Version | Proposito | +|------------|---------|-----------| +| React | 18.2.0 | Framework UI | +| TypeScript | 5.2.2 | Type safety | +| Vite | 5.2.0 | Build tool y dev server | +| Tailwind CSS | 4.1.18 | Estilos utility-first | +| Material-UI | 7.3.6 | Componentes UI | +| Recharts | 3.6.0 | Visualizacion de datos | +| Lucide React | 0.559.0 | Iconos SVG | + +### Herramientas de Desarrollo +- **ESLint** - Linting de codigo +- **TypeScript ESLint** - Analisis estatico + +--- + +## Instalacion + +### Prerrequisitos + +- Node.js >= 18.x +- npm >= 9.x o yarn >= 1.22 + +### Pasos de Instalacion + +1. **Clonar el repositorio** +```bash +git clone +cd water-project +``` + +2. **Instalar dependencias** +```bash +npm install +``` + +3. **Configurar variables de entorno** +```bash +cp .env.example .env +``` + +Editar el archivo `.env`: +```env +VITE_API_BASE_URL=https://tu-api-url.com +VITE_API_TOKEN=tu-token-de-api +``` + +4. **Iniciar servidor de desarrollo** +```bash +npm run dev +``` + +La aplicacion estara disponible en `http://localhost:5173` + +--- + +## Scripts Disponibles + +| Comando | Descripcion | +|---------|-------------| +| `npm run dev` | Inicia el servidor de desarrollo | +| `npm run build` | Compila TypeScript y genera build de produccion | +| `npm run preview` | Previsualiza el build de produccion | +| `npm run lint` | Ejecuta ESLint en el codigo | + +--- + +## Estructura del Proyecto + +``` +water-project/ +├── public/ # Assets estaticos +│ └── grhWatermark.jpg +│ +├── src/ +│ ├── api/ # Capa de comunicacion con API +│ │ ├── me.ts # Endpoints de perfil +│ │ ├── meters.ts # CRUD de medidores +│ │ ├── concentrators.ts # CRUD de concentradores +│ │ └── projects.ts # CRUD de proyectos +│ │ +│ ├── components/ +│ │ ├── layout/ # Componentes de layout +│ │ │ ├── Sidebar.tsx # Menu lateral +│ │ │ ├── TopMenu.tsx # Barra superior +│ │ │ └── common/ # Componentes reutilizables +│ │ │ ├── ProfileModal.tsx +│ │ │ ├── ConfirmModal.tsx +│ │ │ └── Watermark.tsx +│ │ └── SettingsModals.tsx +│ │ +│ ├── pages/ # Paginas principales +│ │ ├── Home.tsx # Dashboard +│ │ ├── LoginPage.tsx # Login +│ │ ├── UsersPage.tsx # Gestion de usuarios +│ │ ├── RolesPage.tsx # Gestion de roles +│ │ ├── projects/ +│ │ │ └── ProjectsPage.tsx +│ │ ├── meters/ # Modulo de medidores +│ │ │ ├── MeterPage.tsx +│ │ │ ├── useMeters.ts # Hook personalizado +│ │ │ ├── MetersTable.tsx +│ │ │ ├── MetersModal.tsx +│ │ │ └── MetersSidebar.tsx +│ │ └── concentrators/ # Modulo de concentradores +│ │ ├── ConcentratorsPage.tsx +│ │ ├── useConcentrators.ts +│ │ ├── ConcentratorsTable.tsx +│ │ ├── ConcentratorsModal.tsx +│ │ └── ConcentratorsSidebar.tsx +│ │ +│ ├── assets/ +│ │ └── images/ +│ │ +│ ├── App.tsx # Componente raiz +│ ├── main.tsx # Punto de entrada +│ └── index.css # Estilos globales +│ +├── index.html +├── package.json +├── tsconfig.json +├── vite.config.ts +└── .env.example +``` + +--- + +## Modulos Funcionales + +### 1. Dashboard (Home) + +El dashboard principal ofrece: +- Selector de organismos operadores (CESPT TIJUANA, TECATE, MEXICALI) +- Grafico de barras: "Numero de Medidores por Proyecto" +- Tarjetas de acceso rapido: Tomas, Alertas, Mantenimiento, Reportes +- Historial reciente de actividades +- Panel de ultimas alertas + +### 2. Gestion de Medidores + +Modulo completo para administrar medidores/tomas de agua: + +**Funcionalidades:** +- Listado con busqueda y filtros +- Filtrado por proyecto +- Tipos de toma: GENERAL, LORA, LORAWAN, GRANDES +- CRUD completo (Crear, Leer, Actualizar, Eliminar) + +**Campos principales:** +- Area, Numero de cuenta, Usuario, Direccion +- Serial del medidor, Nombre, Estado +- Tipo de protocolo, Particion DMA +- Configuracion de dispositivo (Device EUI, AppKey, etc.) + +### 3. Gestion de Concentradores + +Administracion de concentradores y gateways: + +**Funcionalidades:** +- Listado con filtros por proyecto +- Configuracion de Gateway (ID, EUI, Nombre) +- Seleccion de ubicacion de antena (Indoor/Outdoor) +- CRUD completo + +### 4. Gestion de Proyectos + +Administracion de proyectos de infraestructura: +- Tabla con busqueda integrada +- Estados: ACTIVE/INACTIVE +- Informacion de operador y tiempos + +### 5. Gestion de Usuarios + +Control de usuarios del sistema: +- Listado de usuarios +- Asignacion de roles +- Estados: ACTIVE/INACTIVE + +### 6. Gestion de Roles + +Administracion de roles de acceso: +- Roles predefinidos: SUPER_ADMIN, USER +- Descripcion de permisos + +--- + +## API y Comunicacion + +### Configuracion + +La aplicacion se conecta a una API REST externa. Configurar en `.env`: + +```env +VITE_API_BASE_URL=https://tu-api.com +VITE_API_TOKEN=tu-token +``` + +### Endpoints Principales + +| Recurso | Endpoint Base | +|---------|---------------| +| Medidores | `/api/v3/data/.../m4hzpnopjkppaav/records` | +| Concentradores | `/api/v3/data/.../mheif1vdgnyt8x2/records` | +| Proyectos | `/api/v3/data/.../m9882vn3xb31e29/records` | + +### Estructura de Respuesta + +```typescript +interface ApiResponse { + records: Array<{ + id: string; + fields: T; + }>; + next?: string; + prev?: string; } ``` -- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` -- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list +--- + +## Modelos de Datos + +### Meter (Medidor) + +```typescript +interface Meter { + id: string; + createdAt: string; + updatedAt: string; + areaName: string; + accountNumber: string | null; + userName: string | null; + userAddress: string | null; + meterSerialNumber: string; + meterName: string; + meterStatus: string; + protocolType: string; + priceNo: string | null; + priceName: string | null; + dmaPartition: string | null; + supplyTypes: string; + deviceId: string; + deviceName: string; + deviceType: string; + usageAnalysisType: string; + installedTime: string; +} +``` + +### Concentrator + +```typescript +interface Concentrator { + id: string; + "Area Name": string; + "Device S/N": string; + "Device Name": string; + "Device Time": string; + "Device Status": string; + "Operator": string; + "Installed Time": string; + "Communication Time": string; + "Instruction Manual": string; +} +``` + +### Project + +```typescript +interface Project { + id: string; + areaName: string; + deviceSN: string; + deviceName: string; + deviceType: string; + deviceStatus: "ACTIVE" | "INACTIVE"; + operator: string; + installedTime: string; + communicationTime: string; +} +``` + +--- + +## Autenticacion + +### Flujo de Login + +1. Usuario ingresa credenciales +2. Validacion del checkbox "No soy un robot" +3. Token almacenado en `localStorage` (`grh_auth`) +4. Redireccion al Dashboard + +### Almacenamiento + +```javascript +// localStorage keys +grh_auth: { token: string, ts: number } +water_project_settings_v1: { theme: string, compactMode: boolean } +``` + +--- + +## Configuracion de Temas + +El sistema soporta tres modos de tema: +- **Sistema** - Detecta preferencia del OS +- **Claro** - Tema light +- **Oscuro** - Tema dark + +Configuracion persistida en `localStorage` bajo `water_project_settings_v1`. + +--- + +## Despliegue + +### Build de Produccion + +```bash +npm run build +``` + +Los archivos compilados se generan en la carpeta `dist/`. + +### Configuracion de Vite + +El servidor de desarrollo esta configurado para: +- Puerto: 5173 +- Host: habilitado para acceso remoto +- Hosts permitidos: localhost, 127.0.0.1, dominios personalizados + +--- + +## Contribucion + +1. Fork del repositorio +2. Crear rama feature (`git checkout -b feature/nueva-funcionalidad`) +3. Commit de cambios (`git commit -m 'Agregar nueva funcionalidad'`) +4. Push a la rama (`git push origin feature/nueva-funcionalidad`) +5. Crear Pull Request + +--- + +## Licencia + +Este proyecto es privado y pertenece a GRH - Gestion de Recursos Hidricos. + +--- + +## Contacto + +Para soporte o consultas sobre el sistema, contactar al equipo de desarrollo.