inventschario/especificaciones.md
pikaos ee849eb9a8 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
2026-08-03 01:34:56 +01:00

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.*