Inventario de dispositivos electrónicos no prestables para administración pública. Esta primera iteración contiene el diseño y la planificación antes de contactar con el usuario para su validación. Contenido: - especificaciones.md: requisitos detallados del programa - docs/arquitectura.md: propuesta de arquitectura con alternativas - docs/roadmap-iteracion-1.md: plan de desarrollo iteración 1 - docs/arquitectura-diagrama.html: diagrama visual de arquitectura - sketches/: mockups de las 4 pantallas principales - 001-dashboard: vista resumen - 002-inventario: tabla de dispositivos - 003-formulario: alta/edición de dispositivos - 004-configuracion: ajustes generales Stack propuesto: Python + Flask + SQLite + Alpine.js Distribución: PyInstaller → un único .exe autocontenido Entorno: Windows 11 Pro unida a dominio, sin privilegios de admin
836 lines
36 KiB
Markdown
836 lines
36 KiB
Markdown
# Inventschario — Especificaciones del Programa
|
|
|
|
**Versión:** 1.0.0-iteracion1
|
|
**Fecha:** 2026-08-03
|
|
**Estado:** Borrador para feedback del usuario
|
|
|
|
---
|
|
|
|
## 1. Resumen del Producto
|
|
|
|
**Inventschario** es una aplicación de inventario de dispositivos electrónicos no
|
|
prestables (ordenadores, monitores, periféricos, equipos de red, etc.) diseñada
|
|
para ejecutarse en una única máquina Windows 11 Pro unida a un dominio. La
|
|
aplicación se distribuye como un único paquete, se ejecuta en el navegador por
|
|
defecto del usuario y almacena sus datos en una base de datos SQLite local.
|
|
|
|
El usuario tiene privilegios de instalador pero NO de administrador. La
|
|
aplicación se instala únicamente en el directorio del usuario y aparece solo en
|
|
el Menú Inicio de dicho usuario.
|
|
|
|
---
|
|
|
|
## 2. Restricciones del Entorno
|
|
|
|
| Restricción | Detalle |
|
|
|------------------------------|-------------------------------------------------------------------------|
|
|
| SO | Windows 11 Pro |
|
|
| Dominio | Unida a dominio corporativo |
|
|
| Privilegios del usuario | Instalador (puede instalar software en su perfil), NO administrador |
|
|
| Distribución | Un único paquete autocontenido (sin dependencias externas en runtime) |
|
|
| Interfaz | Navegador por defecto del sistema (Edge), se abre al doble clic |
|
|
| Instalación | Solo en el directorio del usuario, Menú Inicio del usuario |
|
|
| Red | Mínima latencia (frontend y backend en la misma máquina) |
|
|
| Copias de seguridad | Automáticas diarias, recordatorio para limpieza de antiguas |
|
|
|
|
---
|
|
|
|
## 3. Funcionalidades Principales
|
|
|
|
### 3.1 Gestión de Dispositivos
|
|
|
|
#### 3.1.1 Campos de Identificación (Renombrables)
|
|
|
|
La aplicación debe soportar múltiples campos de registro para cada dispositivo.
|
|
El usuario puede renombrar la etiqueta visible de cada campo en la interfaz,
|
|
pero el nombre interno en la base de datos permanece constante.
|
|
|
|
| Campo BD (interno) | Etiqueta por defecto | Tipo | Obligatorio |
|
|
|------------------------|-------------------------------|------------|-------------|
|
|
| `serial_number` | Número de Serie | Texto | Sí |
|
|
| `service_tag` | Service Tag | Texto | No |
|
|
| `catalog_number` | Número de Catálogo Interno | Texto | Sí |
|
|
| `additional_registry` | Registro Adicional | Texto | No |
|
|
|
|
El sistema de renombrado se almacena en una tabla de configuración:
|
|
|
|
```sql
|
|
CREATE TABLE field_labels (
|
|
field_key TEXT PRIMARY KEY, -- e.g. 'serial_number'
|
|
label TEXT NOT NULL, -- e.g. 'Número de Serie'
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
#### 3.1.2 Campos Descriptivos del Dispositivo
|
|
|
|
| Campo BD | Etiqueta por defecto | Tipo | Obligatorio |
|
|
|-------------------------|----------------------------|------------|-------------|
|
|
| `device_name` | Nombre / Descripción | Texto | Sí |
|
|
| `device_type` | Tipo de Dispositivo | Enum | Sí |
|
|
| `brand` | Marca | Texto | No |
|
|
| `model` | Modelo | Texto | No |
|
|
| `serial_internal` | Número de Serie Interno | Texto | No |
|
|
| `purchase_date` | Fecha de Compra | Fecha | No |
|
|
| `warranty_expiry` | Fin de Garantía | Fecha | No |
|
|
| `purchase_price` | Precio de Compra (€) | Decimal | No |
|
|
| `assigned_location` | Ubicación Asignada | Texto | No |
|
|
| `assigned_user` | Usuario Asignado | Texto | No |
|
|
| `department` | Departamento | Texto | No |
|
|
| `status` | Estado | Enum | Sí |
|
|
| `condition` | Estado Físico | Enum | No |
|
|
| `notes` | Notas | Texto | No |
|
|
| `photo_path` | Ruta Foto | Texto | No |
|
|
|
|
#### 3.1.3 Tipos de Dispositivo (Enum)
|
|
|
|
- `computer` — Ordenador de sobremesa
|
|
- `laptop` — Portátil
|
|
- `monitor` — Monitor / Pantalla
|
|
- `printer` — Impresora
|
|
- `scanner` — Escáner
|
|
- `network_device` — Dispositivo de red (switch, router, AP)
|
|
- `peripheral` — Periférico (teclado, ratón, auriculares)
|
|
- `server` — Servidor
|
|
- `ups` — SAI / Regulador
|
|
- `storage` — Almacenamiento externo
|
|
- `other` — Otro
|
|
|
|
#### 3.1.4 Estados del Dispositivo (Enum)
|
|
|
|
| Estado | Descripción |
|
|
|-----------------|------------------------------------------------|
|
|
| `active` | En uso, asignado y operativo |
|
|
| `available` | Disponible, sin asignar |
|
|
| `maintenance` | En mantenimiento / reparación |
|
|
| `decommissioned`| Dado de baja |
|
|
| `disposed` | Enajenado / desechado |
|
|
| `lost` | Extraviado / no localizado |
|
|
| `reserved` | Reservado para asignación futura |
|
|
|
|
#### 3.1.5 Estado Físico (Enum)
|
|
|
|
- `excellent` — Excelente
|
|
- `good` — Bueno
|
|
- `fair` — Regular
|
|
- `poor` — Malo
|
|
- `damaged` — Dañado
|
|
|
|
### 3.2 Ciclo de Vida del Dispositivo (Administración Pública)
|
|
|
|
La aplicación debe gestionar el ciclo de vida completo de cada dispositivo,
|
|
incluyendo trámites de administración pública:
|
|
|
|
#### 3.2.1 Altas
|
|
|
|
- Registro manual de un nuevo dispositivo
|
|
- Importación masiva desde CSV
|
|
- Asignación automática de número de inventario interno
|
|
|
|
#### 3.2.2 Modificaciones
|
|
|
|
- Edición de cualquier campo del dispositivo
|
|
- Historial de cambios (quién, cuándo, qué cambió)
|
|
- Reasignación de ubicación / usuario / departamento
|
|
|
|
#### 3.2.3 Bajas
|
|
|
|
- Baja por obsolescencia
|
|
- Baja por avería irreversible
|
|
- Baja por robo / extravío
|
|
- Baja por fin de garantía sin renovación
|
|
- Registro del motivo de baja
|
|
- Fecha efectiva de baja
|
|
- Responsable que autoriza la baja
|
|
|
|
#### 3.2.4 Enajenación
|
|
|
|
- Enajenación por venta
|
|
- Enajenación por donación
|
|
- Enajenación por transferencia a otro organismo
|
|
- Registro del destinatario / adquirente
|
|
- Documento de enajenación (referencia)
|
|
- Importe de enajenación si aplica
|
|
- Fecha efectiva de enajenación
|
|
|
|
#### 3.2.5 Historial de Cambios
|
|
|
|
```sql
|
|
CREATE TABLE device_history (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
device_id INTEGER NOT NULL,
|
|
action TEXT NOT NULL, -- 'created', 'modified', 'decommissioned', 'disposed', ...
|
|
field_changed TEXT, -- NULL para acciones de ciclo completo
|
|
old_value TEXT,
|
|
new_value TEXT,
|
|
performed_by TEXT NOT NULL,
|
|
performed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
notes TEXT,
|
|
FOREIGN KEY (device_id) REFERENCES devices(id)
|
|
);
|
|
```
|
|
|
|
### 3.3 Copias de Seguridad
|
|
|
|
#### 3.3.1 Backup Automático Diario
|
|
|
|
- Se ejecuta una vez al día (configurable la hora)
|
|
- Copia completa de la base de datos SQLite
|
|
- Almacena en `%APPDATA%/inventschario/backups/`
|
|
- Formato de nombre: `inventschario_YYYYMMDD_HHMMSS.db`
|
|
- Comprimido en formato `.gz` para ahorrar espacio
|
|
|
|
#### 3.3.2 Gestión de Backups
|
|
|
|
- Al iniciar la aplicación, comprueba si hay backups con más de N días (configurable)
|
|
- Muestra un recordatorio al usuario indicando cuántos backups antiguos existen
|
|
- El usuario decide eliminar los antiguos o mantenerlos
|
|
- Opción para crear un backup manual en cualquier momento
|
|
- Opción para restaurar desde un backup específico
|
|
|
|
#### 3.3.3 Configuración de Backups
|
|
|
|
| Parámetro | Valor por defecto | Descripción |
|
|
|------------------------------|-------------------|---------------------------------------|
|
|
| `backup_enabled` | `true` | Habilitar backups automáticos |
|
|
| `backup_hour` | `02:00` | Hora diaria del backup |
|
|
| `backup_retention_days` | `30` | Días antes de sugerir eliminación |
|
|
| `backup_max_keep` | `90` | Máximo de backups a conservar |
|
|
| `backup_path` | `%APPDATA%/inventschario/backups/` | Ruta de almacenamiento |
|
|
|
|
### 3.4 Importación y Exportación
|
|
|
|
#### 3.4.1 Exportación a CSV
|
|
|
|
- Exporta todos los dispositivos o una selección filtrada
|
|
- Usa las etiquetas renombradas como cabeceras del CSV
|
|
- Separador configurable (coma, punto y coma, tabulador)
|
|
- Codificación UTF-8 con BOM para compatibilidad con Excel
|
|
- Opción de incluir solo columnas visibles
|
|
|
|
#### 3.4.2 Importación desde CSV
|
|
|
|
Sistema modular diseñado para ser extensible:
|
|
|
|
**Fase 1 (Implementación inicial):**
|
|
- Selección del archivo CSV
|
|
- Mapeo automático de columnas por posición o nombre
|
|
- Vista previa de los primeros 10 registros
|
|
- Detección de duplicados (por serial_number o catalog_number)
|
|
- Opciones ante duplicados: saltar, sobrescribir, crear como nuevo
|
|
- Registro de errores por fila
|
|
|
|
**Fase 2 (Extensibilidad futura):**
|
|
- Interfaz de mapeo visual de campos (drag & drop)
|
|
- Guardar perfiles de importación (plantillas)
|
|
- Transformaciones de datos durante la importación (regex, lookup)
|
|
- Importación desde Excel (.xlsx) directamente
|
|
|
|
#### 3.4.3 Arquitectura Modular de Importación/Exportación
|
|
|
|
```
|
|
import_export/
|
|
├── __init__.py
|
|
├── base.py # Clases abstractas ImporterBase, ExporterBase
|
|
├── csv_importer.py # Implementación CSV
|
|
├── csv_exporter.py # Implementación CSV
|
|
├── field_mapper.py # Motor de mapeo de campos
|
|
├── validator.py # Validación de datos importados
|
|
└── profiles/ # Perfiles de importación guardados
|
|
```
|
|
|
|
### 3.5 Interfaz de Usuario
|
|
|
|
#### 3.5.1 Requisitos de Usabilidad y Accesibilidad
|
|
|
|
- Navegación por teclado completa (Tab, Enter, Escape, atajos)
|
|
- Contraste de color WCAG 2.1 AA mínimo (4.5:1 texto, 3:1 elementos UI)
|
|
- Tamaño mínimo de objetivo de clic: 44x44 px
|
|
- Labels asociados a todos los inputs
|
|
- Mensajes de error claros y posicionados junto al campo
|
|
- Feedback visual en hover, focus, y active states
|
|
- Responsive (aunque el uso principal es escritorio)
|
|
- Modo de alto contraste soportado
|
|
- Texto alternativo en iconos decorativos
|
|
|
|
#### 3.5.2 Pantallas / Pestañas
|
|
|
|
1. **Dashboard** — Vista resumen con estadísticas clave
|
|
2. **Inventario** — Tabla de dispositivos con búsqueda, filtros, ordenación
|
|
3. **Agregar Dispositivo** — Formulario de alta
|
|
4. **Detalle / Edición** — Ficha completa del dispositivo con historial
|
|
5. **Baja / Enajenación** — Formulario de ciclo de vida
|
|
6. **Importar / Exportar** — Interfaz de importación y exportación CSV
|
|
7. **Configuración** — Parámetros generales, labels de campos, backups
|
|
8. **Configuración Inicial** — Wizard de primera ejecución
|
|
|
|
#### 3.5.3 Configuración Inicial (Primera Ejecución)
|
|
|
|
Al detectar que no existe base de datos, se muestra un wizard:
|
|
|
|
1. **Paso 1:** Bienvenida y nombre de la institución / organismo
|
|
2. **Paso 2:** Configuración de campos de registro (renombrar etiquetas)
|
|
3. **Paso 3:** Tipos de dispositivo a gestionar (seleccionar cuáles activar)
|
|
4. **Paso 4:** Configuración de copias de seguridad
|
|
5. **Paso 5:** Ubicaciones / Departamentos predefinidos (opcional)
|
|
6. **Paso 6:** Confirmación y creación de la base de datos
|
|
|
|
---
|
|
|
|
## 4. Modelo de Datos (SQLite)
|
|
|
|
### 4.1 Diagrama Entidad-Relación
|
|
|
|
```
|
|
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
|
│ devices │ │ device_history │ │ field_labels │
|
|
├─────────────────┤ ├──────────────────┤ ├─────────────────┤
|
|
│ id (PK) │◄────│ device_id (FK) │ │ field_key (PK) │
|
|
│ serial_number │ │ id (PK) │ │ label │
|
|
│ service_tag │ │ action │ │ updated_at │
|
|
│ catalog_number │ │ field_changed │ └─────────────────┘
|
|
│ additional_reg │ │ old_value │
|
|
│ device_name │ │ new_value │ ┌──────────────────┐
|
|
│ device_type │ │ performed_by │ │ app_config │
|
|
│ brand │ │ performed_at │ ├──────────────────┤
|
|
│ model │ │ notes │ │ key (PK) │
|
|
│ serial_internal │ └──────────────────┘ │ value │
|
|
│ purchase_date │ │ updated_at │
|
|
│ warranty_expiry │ ┌──────────────────┐ └──────────────────┘
|
|
│ purchase_price │ │ locations │
|
|
│ assigned_loc │ ├──────────────────┤ ┌──────────────────┐
|
|
│ assigned_user │ │ id (PK) │ │ departments │
|
|
│ department │ │ name │ ├──────────────────┤
|
|
│ status │ │ building │ │ id (PK) │
|
|
│ condition │ │ floor │ │ name │
|
|
│ notes │ │ room │ └──────────────────┘
|
|
│ photo_path │ └──────────────────┘
|
|
│ created_at │
|
|
│ updated_at │ ┌──────────────────┐
|
|
└─────────────────┘ │ backup_log │
|
|
├──────────────────┤
|
|
│ id (PK) │
|
|
│ filename │
|
|
│ size_bytes │
|
|
│ created_at │
|
|
│ is自動 │
|
|
└──────────────────┘
|
|
```
|
|
|
|
### 4.2 Script de Creación de la Base de Datos
|
|
|
|
```sql
|
|
-- Inventschario v1.0.0
|
|
-- Base de datos de inventario de dispositivos electrónicos
|
|
|
|
PRAGMA journal_mode=WAL;
|
|
PRAGMA foreign_keys=ON;
|
|
|
|
CREATE TABLE devices (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
serial_number TEXT NOT NULL,
|
|
service_tag TEXT,
|
|
catalog_number TEXT NOT NULL,
|
|
additional_registry TEXT,
|
|
device_name TEXT NOT NULL,
|
|
device_type TEXT NOT NULL DEFAULT 'other',
|
|
brand TEXT,
|
|
model TEXT,
|
|
serial_internal TEXT,
|
|
purchase_date DATE,
|
|
warranty_expiry DATE,
|
|
purchase_price DECIMAL(10,2),
|
|
assigned_location TEXT,
|
|
assigned_user TEXT,
|
|
department TEXT,
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
condition TEXT DEFAULT 'good',
|
|
notes TEXT,
|
|
photo_path TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE UNIQUE INDEX idx_devices_catalog ON devices(catalog_number);
|
|
CREATE INDEX idx_devices_serial ON devices(serial_number);
|
|
CREATE INDEX idx_devices_status ON devices(status);
|
|
CREATE INDEX idx_devices_type ON devices(device_type);
|
|
|
|
CREATE TABLE device_history (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
device_id INTEGER NOT NULL,
|
|
action TEXT NOT NULL,
|
|
field_changed TEXT,
|
|
old_value TEXT,
|
|
new_value TEXT,
|
|
performed_by TEXT NOT NULL,
|
|
performed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
notes TEXT,
|
|
FOREIGN KEY (device_id) REFERENCES devices(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX idx_history_device ON device_history(device_id);
|
|
CREATE INDEX idx_history_date ON device_history(performed_at);
|
|
|
|
CREATE TABLE field_labels (
|
|
field_key TEXT PRIMARY KEY,
|
|
label TEXT NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE app_config (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE TABLE locations (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
building TEXT,
|
|
floor TEXT,
|
|
room TEXT
|
|
);
|
|
|
|
CREATE TABLE departments (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE
|
|
);
|
|
|
|
CREATE TABLE backup_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
filename TEXT NOT NULL,
|
|
size_bytes INTEGER,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
is_auto BOOLEAN DEFAULT 1
|
|
);
|
|
|
|
-- Valores por defecto para field_labels
|
|
INSERT INTO field_labels (field_key, label) VALUES
|
|
('serial_number', 'Número de Serie'),
|
|
('service_tag', 'Service Tag'),
|
|
('catalog_number', 'Número de Catálogo Interno'),
|
|
('additional_registry', 'Registro Adicional'),
|
|
('device_name', 'Nombre / Descripción'),
|
|
('device_type', 'Tipo de Dispositivo'),
|
|
('brand', 'Marca'),
|
|
('model', 'Modelo'),
|
|
('purchase_date', 'Fecha de Compra'),
|
|
('warranty_expiry', 'Fin de Garantía'),
|
|
('purchase_price', 'Precio de Compra (€)'),
|
|
('assigned_location', 'Ubicación Asignada'),
|
|
('assigned_user', 'Usuario Asignado'),
|
|
('department', 'Departamento'),
|
|
('status', 'Estado'),
|
|
('condition', 'Estado Físico');
|
|
|
|
-- Valores por defecto para app_config
|
|
INSERT INTO app_config (key, value) VALUES
|
|
('institution_name', ''),
|
|
('backup_enabled', 'true'),
|
|
('backup_hour', '02:00'),
|
|
('backup_retention_days', '30'),
|
|
('backup_max_keep', '90'),
|
|
('csv_separator', ';'),
|
|
('csv_encoding', 'utf-8-sig'),
|
|
('setup_complete', 'false');
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Arquitectura del Sistema
|
|
|
|
### 5.1 Requisitos Arquitectónicos
|
|
|
|
- **Modularidad total:** Separación frontend / backend con pasarela (API)
|
|
- **Independencia de interfaz:** Cambiar el frontend no afecta al backend
|
|
- **Autocontenido:** Todas las dependencias empaquetadas en un solo ejecutable
|
|
- **Sin privilegios de admin:** Instalación y ejecución en perfil de usuario
|
|
- **Baja latencia:** Frontend y backend en la misma máquina
|
|
|
|
### 5.2 Capas
|
|
|
|
```
|
|
┌─────────────────────────────────────────────┐
|
|
│ NAVEGADOR (Edge) │
|
|
│ ┌───────────────────────────────────────┐ │
|
|
│ │ FRONTEND (HTML/CSS/JS) │ │
|
|
│ │ Framework ligero: Alpine.js o Vanilla│ │
|
|
│ └──────────────────┬────────────────────┘ │
|
|
│ │ HTTP/localhost │
|
|
├─────────────────────┼───────────────────────┤
|
|
│ SERVIDOR LOCAL │
|
|
│ ┌──────────────────┴────────────────────┐ │
|
|
│ │ API GATEWAY (REST/JSON) │ │
|
|
│ │ Endpoints: /api/devices, /api/... │ │
|
|
│ └──────────────────┬────────────────────┘ │
|
|
│ │ │
|
|
│ ┌──────────────────┴────────────────────┐ │
|
|
│ │ CAPA DE SERVICIOS │ │
|
|
│ │ DeviceService, BackupService, etc. │ │
|
|
│ └──────────────────┬────────────────────┘ │
|
|
│ │ │
|
|
│ ┌──────────────────┴────────────────────┐ │
|
|
│ │ CAPA DE DATOS (SQLite) │ │
|
|
│ │ Repository pattern, migraciones │ │
|
|
│ └───────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 5.3 API REST (Especificación)
|
|
|
|
Todas las rutas comienzan con `/api/v1/`.
|
|
|
|
#### Dispositivos
|
|
|
|
| Método | Ruta | Descripción |
|
|
|--------|------------------------------|-----------------------------------|
|
|
| GET | `/api/v1/devices` | Listar dispositivos (con filtros) |
|
|
| GET | `/api/v1/devices/:id` | Obtener dispositivo por ID |
|
|
| POST | `/api/v1/devices` | Crear dispositivo |
|
|
| PUT | `/api/v1/devices/:id` | Actualizar dispositivo |
|
|
| DELETE | `/api/v1/devices/:id` | Eliminar dispositivo (soft delete)|
|
|
| POST | `/api/v1/devices/:id/decommission` | Dar de baja |
|
|
| POST | `/api/v1/devices/:id/dispose` | Enajenar |
|
|
| GET | `/api/v1/devices/:id/history` | Historial de cambios |
|
|
|
|
#### Importación / Exportación
|
|
|
|
| Método | Ruta | Descripción |
|
|
|--------|------------------------------|-----------------------------------|
|
|
| GET | `/api/v1/export/csv` | Exportar a CSV |
|
|
| POST | `/api/v1/import/csv` | Importar desde CSV |
|
|
| GET | `/api/v1/import/preview` | Vista previa de importación |
|
|
|
|
#### Configuración
|
|
|
|
| Método | Ruta | Descripción |
|
|
|--------|------------------------------|-----------------------------------|
|
|
| GET | `/api/v1/config` | Obtener configuración |
|
|
| PUT | `/api/v1/config` | Actualizar configuración |
|
|
| GET | `/api/v1/config/labels` | Obtener etiquetas de campos |
|
|
| PUT | `/api/v1/config/labels` | Actualizar etiquetas de campos |
|
|
| POST | `/api/v1/config/initialize` | Ejecutar wizard de configuración |
|
|
|
|
#### Backups
|
|
|
|
| Método | Ruta | Descripción |
|
|
|--------|------------------------------|-----------------------------------|
|
|
| GET | `/api/v1/backups` | Listar backups |
|
|
| POST | `/api/v1/backups/create` | Crear backup manual |
|
|
| POST | `/api/v1/backups/:id/restore`| Restaurar desde backup |
|
|
| DELETE | `/api/v1/backups/:id` | Eliminar backup |
|
|
| GET | `/api/v1/backups/check-aging`| Verificar backups antiguos |
|
|
|
|
#### Ubicaciones y Departamentos
|
|
|
|
| Método | Ruta | Descripción |
|
|
|--------|------------------------------|-----------------------------------|
|
|
| GET | `/api/v1/locations` | Listar ubicaciones |
|
|
| POST | `/api/v1/locations` | Crear ubicación |
|
|
| GET | `/api/v1/departments` | Listar departamentos |
|
|
| POST | `/api/v1/departments` | Crear departamento |
|
|
|
|
---
|
|
|
|
## 6. Alternativas Tecnológicas
|
|
|
|
### Opción A: Python + Flask + SQLite (Recomendada)
|
|
|
|
| Aspecto | Detalle |
|
|
|------------------|-----------------------------------------------------------|
|
|
| Backend | Python 3.11+ con Flask |
|
|
| Base de datos | SQLite3 (incluido en Python stdlib) |
|
|
| Frontend | HTML/CSS/JS + Alpine.js (ligero, sin build step) |
|
|
| Empaquetado | PyInstaller → un único `.exe` |
|
|
| Tamaño aprox. | 25-40 MB |
|
|
| Ventajas | Ecosistema rico, fácil de desarrollar, SQLite nativo |
|
|
| Desventajas | PyInstaller a veces tiene problemas con antimalware |
|
|
| Dependencias | Flask, schedule (para backups) — todo empaquetado |
|
|
|
|
### Opción B: .NET 8 Self-Contained
|
|
|
|
| Aspecto | Detalle |
|
|
|------------------|-----------------------------------------------------------|
|
|
| Backend | ASP.NET Core minimal API |
|
|
| Base de datos | Microsoft.Data.Sqlite |
|
|
| Frontend | HTML/CSS/JS embebido en wwwroot |
|
|
| Empaquetado | `dotnet publish -r win-x64 --self-contained` |
|
|
| Tamaño aprox. | 60-80 MB |
|
|
| Ventajas | Nativo Windows, sin runtime externo, excelente rendimiento|
|
|
| Desventajas | Más verboso que Python, curva de aprendizaje mayor |
|
|
| Dependencias | Ninguna en runtime (self-contained) |
|
|
|
|
### Opción C: Go + SQLite
|
|
|
|
| Aspecto | Detalle |
|
|
|------------------|-----------------------------------------------------------|
|
|
| Backend | Go stdlib `net/http` + `mattn/go-sqlite3` |
|
|
| Base de datos | SQLite via CGO |
|
|
| Frontend | HTML/CSS/JS embebido via `embed` |
|
|
| Empaquetado | Binario compilado estático |
|
|
| Tamaño aprox. | 10-15 MB |
|
|
| Ventajas | Binario más pequeño, rendimiento excepcional |
|
|
| Desventajas | CGO complicationa el build cross-platform, menos ecosistema web |
|
|
| Dependencias | Ninguna en runtime |
|
|
|
|
### Opción D: Electron + SQLite
|
|
|
|
| Aspecto | Detalle |
|
|
|------------------|-----------------------------------------------------------|
|
|
| Backend | Node.js (embebido en Electron) |
|
|
| Base de datos | better-sqlite3 |
|
|
| Frontend | React/Vue/Svelte dentro de Electron |
|
|
| Empaquetado | electron-builder → instalador .exe |
|
|
| Tamaño aprox. | 150-200 MB |
|
|
| Ventajas | UI rica, familiar para devs frontend |
|
|
| Desventajas | Muy pesado para una app de inventario, innecesario |
|
|
| Dependencias | Chromium embebido |
|
|
|
|
### Comparativa Resumen
|
|
|
|
| Criterio | Python+Flask | .NET 8 | Go | Electron |
|
|
|------------------------|:------------:|:---------:|:---------:|:---------:|
|
|
| Tamaño del paquete | ★★★★ | ★★★ | ★★★★★ | ★★ |
|
|
| Facilidad de desarrollo| ★★★★★ | ★★★ | ★★★ | ★★★★ |
|
|
| Rendimiento | ★★★ | ★★★★★ | ★★★★★ | ★★★ |
|
|
| Sin dependencias RT | ★★★ (PyInst)| ★★★★★ | ★★★★★ | ★★★ |
|
|
| Ecosistema web | ★★★★★ | ★★★★ | ★★★ | ★★★★★ |
|
|
| Compatibilidad AV | ★★★ | ★★★★★ | ★★★★★ | ★★★★ |
|
|
| Modularidad frontend | ★★★★★ | ★★★★★ | ★★★★ | ★★★★★ |
|
|
|
|
**Recomendación:** Python + Flask (Opción A) para la iteración inicial. Si el
|
|
tamaño o la detección por antivirus se convierten en problemas, migrar a .NET 8.
|
|
|
|
---
|
|
|
|
## 7. Estructura de Directorios
|
|
|
|
```
|
|
inventschario/
|
|
├── especificaciones.md # Este documento
|
|
├── docs/
|
|
│ ├── arquitectura.md # Documento de arquitectura detallada
|
|
│ └── roadmap-iteracion-1.md # Roadmap de la primera iteración
|
|
├── sketches/ # Mockups de diseño de interfaz
|
|
│ ├── 001-dashboard/
|
|
│ ├── 002-inventario/
|
|
│ ├── 003-formulario/
|
|
│ └── 004-configuracion/
|
|
├── src/
|
|
│ ├── __init__.py
|
|
│ ├── main.py # Punto de entrada
|
|
│ ├── server.py # Servidor Flask
|
|
│ ├── config.py # Configuración de la aplicación
|
|
│ ├── database/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── connection.py # Conexión SQLite
|
|
│ │ ├── models.py # Modelos de datos
|
|
│ │ ├── migrations.py # Migraciones de esquema
|
|
│ │ └── schema.sql # Esquema inicial
|
|
│ ├── services/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── device_service.py # Lógica de dispositivos
|
|
│ │ ├── backup_service.py # Gestión de backups
|
|
│ │ ├── import_service.py # Importación CSV
|
|
│ │ ├── export_service.py # Exportación CSV
|
|
│ │ └── config_service.py # Configuración general
|
|
│ ├── api/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── devices.py # Rutas API de dispositivos
|
|
│ │ ├── imports.py # Rutas API de importación
|
|
│ │ ├── exports.py # Rutas API de exportación
|
|
│ │ ├── backups.py # Rutas API de backups
|
|
│ │ └── config.py # Rutas API de configuración
|
|
│ ├── import_export/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── base.py # Clases abstractas
|
|
│ │ ├── csv_importer.py # Importador CSV
|
|
│ │ ├── csv_exporter.py # Exportador CSV
|
|
│ │ ├── field_mapper.py # Motor de mapeo
|
|
│ │ └── validator.py # Validación de datos
|
|
│ └── utils/
|
|
│ ├── __init__.py
|
|
│ ├── scheduler.py # Programador de backups
|
|
│ └── paths.py # Rutas de archivos
|
|
├── frontend/
|
|
│ ├── index.html # Página principal (SPA)
|
|
│ ├── css/
|
|
│ │ └── styles.css # Estilos globales
|
|
│ ├── js/
|
|
│ │ ├── app.js # Router y estado global
|
|
│ │ ├── api.js # Cliente HTTP para la API
|
|
│ │ ├── components/ # Componentes reutilizables
|
|
│ │ │ ├── table.js
|
|
│ │ │ ├── form.js
|
|
│ │ │ ├── modal.js
|
|
│ │ │ ├── toast.js
|
|
│ │ │ └── sidebar.js
|
|
│ │ └── pages/ # Páginas / vistas
|
|
│ │ ├── dashboard.js
|
|
│ │ ├── inventory.js
|
|
│ │ ├── device-form.js
|
|
│ │ ├── device-detail.js
|
|
│ │ ├── lifecycle.js
|
|
│ │ ├── import-export.js
|
|
│ │ ├── settings.js
|
|
│ │ └── setup-wizard.js
|
|
│ └── assets/
|
|
│ └── icons/ # Iconos SVG
|
|
├── tests/
|
|
│ ├── test_devices.py
|
|
│ ├── test_import.py
|
|
│ ├── test_backup.py
|
|
│ └── test_config.py
|
|
├── pyproject.toml
|
|
├── requirements.txt
|
|
└── README.md
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Requisitos No Funcionales
|
|
|
|
### 8.1 Rendimiento
|
|
|
|
- Tiempo de respuesta API: < 100ms (local)
|
|
- Carga de página inicial: < 2 segundos
|
|
- Búsqueda en inventario: < 500ms con 10,000 dispositivos
|
|
- Importación CSV: < 5 segundos para 1,000 registros
|
|
|
|
### 8.2 Seguridad
|
|
|
|
- El servidor solo escucha en `127.0.0.1` (localhost)
|
|
- No se exponen puertos a la red
|
|
- No se almacenan credenciales en texto plano
|
|
- Backups cifrados (futuro, iteración 2)
|
|
- Logs de auditoría para acciones críticas
|
|
|
|
### 8.3 Fiabilidad
|
|
|
|
- WAL mode en SQLite para concurrencia de lectura
|
|
- Backups automáticos diarios
|
|
- Integridad referencial con foreign keys
|
|
- Validación de datos tanto en backend como frontend
|
|
|
|
### 8.4 Mantenibilidad
|
|
|
|
- Código modular con separation of concerns
|
|
- API REST bien documentada
|
|
- Tests unitarios y de integración
|
|
- Migraciones de esquema versionadas
|
|
|
|
---
|
|
|
|
## 9. Flujo de Usuario — Escenarios Principales
|
|
|
|
### 9.1 Primera Ejecución
|
|
|
|
```
|
|
Doble clic en icono del Menú Inicio
|
|
→ Se abre Edge en http://localhost:PORT
|
|
→ Detector: no hay DB → Wizard de configuración
|
|
→ Paso 1: Nombre de institución
|
|
→ Paso 2: Etiquetas de campos de registro
|
|
→ Paso 3: Tipos de dispositivo a gestionar
|
|
→ Paso 4: Configuración de backups
|
|
→ Paso 5: Ubicaciones y departamentos (opcional)
|
|
→ Paso 6: Confirmación → Crear DB
|
|
→ Redirige al Dashboard
|
|
```
|
|
|
|
### 9.2 Alta de Dispositivo
|
|
|
|
```
|
|
Click "Agregar Dispositivo" (sidebar o botón)
|
|
→ Formulario con campos obligatorios marcados
|
|
→ Autocompletado de campos numéricos de registro
|
|
→ Validación en tiempo real
|
|
→ Submit → Guarda en BD → Historial "created"
|
|
→ Toast de confirmación → permanece en formulario para siguiente alta
|
|
```
|
|
|
|
### 9.3 Búsqueda y Edición
|
|
|
|
```
|
|
En pestaña Inventario:
|
|
→ Barra de búsqueda (búsqueda full-text)
|
|
→ Filtros: tipo, estado, departamento, ubicación
|
|
→ Click en fila → Detalle del dispositivo
|
|
→ Click "Editar" → Modo edición inline
|
|
→ Cambios guardados → Historial "modified"
|
|
```
|
|
|
|
### 9.4 Baja / Enajenación
|
|
|
|
```
|
|
En detalle del dispositivo:
|
|
→ Click "Dar de Baja" o "Enajenar"
|
|
→ Modal con:
|
|
- Tipo de baja/enajenación
|
|
- Fecha efectiva
|
|
- Motivo / observaciones
|
|
- Responsable autorizador
|
|
→ Confirmar → Estado cambia → Historial actualizado
|
|
→ Dispositivo aparece como "Baja" / "Enajenado" en el inventario
|
|
```
|
|
|
|
### 9.5 Backup Diario
|
|
|
|
```
|
|
Servidor inicia → Scheduler programado a las 02:00
|
|
→ BackupService.crear_backup():
|
|
- Copia el archivo .db
|
|
- Comprime con gzip
|
|
- Registra en backup_log
|
|
→ Al iniciar la app, BackupService.verificar_antiguos():
|
|
- Si hay backups > retention_days → Toast informativo
|
|
- "Hay X backups con más de N días. ¿Desea eliminarlos?"
|
|
- Botones: "Eliminar antiguos" / "Mantener"
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Criterios de Aceptación — Iteración 1
|
|
|
|
- [ ] El usuario puede instalar la aplicación en su perfil de Windows
|
|
- [ ] El icono aparece en el Menú Inicio del usuario
|
|
- [ ] Al doble clic, se abre Edge con la aplicación
|
|
- [ ] El wizard de configuración initial crea la BD correctamente
|
|
- [ ] Se pueden crear, editar, y dar de baja dispositivos
|
|
- [ ] La tabla de inventario muestra búsqueda, filtros y ordenación
|
|
- [ ] Se pueden renombrar las etiquetas de los campos de registro
|
|
- [ ] Las copias de seguridad se ejecutan diariamente
|
|
- [ ] Se muestra recordatorio de backups antiguos al iniciar
|
|
- [ ] Se pueden exportar dispositivos a CSV
|
|
- [ ] Se pueden importar dispositivos desde CSV
|
|
- [ ] El historial de cambios se registra correctamente
|
|
- [ ] La interfaz es navegable por teclado
|
|
- [ ] Los colores cumplen WCAG 2.1 AA
|
|
|
|
---
|
|
|
|
## 11. Futuras Iteraciones (Roadmap)
|
|
|
|
### Iteración 2
|
|
- Cifrado de backups
|
|
- Autenticación de usuario (si se necesita multi-usuario)
|
|
- Informes y gráficos (distribución por tipo, estado, departamento)
|
|
- Impresión de etiquetas de inventario
|
|
|
|
### Iteración 3
|
|
- Escáner de códigos de barras / QR
|
|
- Sincronización con Active Directory
|
|
- API para integración con otros sistemas
|
|
- Importación desde Excel (.xlsx)
|
|
|
|
### Iteración 4
|
|
- Multi-idioma (i18n)
|
|
- Modo oscuro
|
|
- Notificaciones de garantía próxima a vencer
|
|
- Dashboard con métricas avanzadas
|
|
|
|
---
|
|
|
|
*Documento generado como parte de la primera iteración del proyecto Inventschario.
|
|
Sujeto a revisión y feedback del usuario.*
|