feat: roadmap y diseño inicial — iteración 1 antes de feedback del usuario
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
This commit is contained in:
commit
ee849eb9a8
14 changed files with 3761 additions and 0 deletions
836
especificaciones.md
Normal file
836
especificaciones.md
Normal file
|
|
@ -0,0 +1,836 @@
|
|||
# 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.*
|
||||
Loading…
Add table
Add a link
Reference in a new issue