diff --git a/docs/HISTORIA_PROYECTO_IVAN.md b/docs/HISTORIA_PROYECTO_IVAN.md new file mode 100644 index 0000000..ded8f21 --- /dev/null +++ b/docs/HISTORIA_PROYECTO_IVAN.md @@ -0,0 +1,637 @@ +# Historia del Proyecto GestionTablets + +*Un relato técnico para Iván sobre el desarrollo del Sistema de Gestión de Tablets* + +--- + +## 📖 Índice + +1. [Los Inicios](#los-inicios) +2. [La Arquitectura Base](#la-arquitectura-base) +3. [Proveedores y Tecnologías](#proveedores-y-tecnologías) +4. [Hitos del Desarrollo](#hitos-del-desarrollo) +5. [Internacionalización (i18n)](#internacionalización-i18n) +6. [Identidad Corporativa](#identidad-corporativa) +7. [Lecciones Aprendidas](#lecciones-aprendidas) +8. [Estado Actual](#estado-actual) + +--- + +## 🚀 Los Inicios + +El proyecto **GestionTablets** nació como una herramienta interna para gestionar el préstamo de tablets y otros dispositivos en un entorno de equipo pequeño (5 usuarios técnicos). La idea inicial era simple: llevar un control claro de qué dispositivo estaba con qué persona, cuándo se prestó y cuándo se devolvió. + +### Contexto Inicial +- **Tipo de proyecto**: Herramienta interna (no aplicación pública) +- **Usuarios objetivo**: 5 usuarios técnicos +- **Requisitos principales**: + - Registrar tablets y otros dispositivos + - Gestionar préstamos a usuarios + - Historial de transacciones + - Interfaz sencilla y funcional + +### Primera Versión: CLI + +El proyecto comenzó con una versión **CLI (Command Line Interface)** en Python puro con SQLite. Esta versión, aunque funcional, tenía limitaciones: + +```python +# Ejemplo de la versión CLI inicial +import sqlite3 +from datetime import datetime + +def add_tablet(brand, model, serial_number): + """Añadir una nueva tablet al inventario""" + conn = sqlite3.connect('tablets.db') + cursor = conn.cursor() + cursor.execute(''' + INSERT INTO tablets (brand, model, serial_number, status) + VALUES (?, ?, ?, 'available') + ''', (brand, model, serial_number)) + conn.commit() + print(f"✓ Tablet añadida: {brand} {model} ({serial_number})") +``` + +**Limitaciones de la CLI:** +- Interfaz no intuitiva para usuarios no técnicos +- Sin visualización de datos en formato amigable +- Dificultad para ver el estado actual de préstamos + +--- + +## 🏗️ La Arquitectura Base + +### Transición a Web: Flask + +Se decidió migrar a una **aplicación web** usando **Flask**, un micro-framework de Python, para proporcionar una interfaz más amigable. + +**Estructura del proyecto:** +``` +GestionTablets/ +├── app.py # Aplicación principal Flask +├── minimal_app.py # Versión CLI (deprecada) +├── templates/ # Plantillas HTML (Jinja2) +│ ├── base.html # Plantilla base +│ ├── index.html # Página principal +│ ├── add_tablet.html # Formulario añadir tablet +│ ├── add_user.html # Formulario añadir usuario +│ ├── loan_tablet.html # Formulario préstamo +│ └── ... +├── static/ # Archivos estáticos +│ └── Schamann.png # Logo corporativo +├── translations/ # Archivos de traducción +│ ├── es/LC_MESSAGES.mo +│ └── es/LC_MESSAGES.po +├── docs/ # Documentación +│ ├── CORPORATE_DESIGN.md # Diseño corporativo +│ ├── FRONTEND_OPTIONS.md # Opciones de frontend +│ ├── MIGRATION_TO_POSTGRES.md +│ └── RESPONSIVE_CSS.md +├── tests/ # Suite de pruebas +│ ├── conftest.py +│ ├── test_core.py +│ ├── test_edge_cases.py +│ └── test_minimal_app.py +├── tablets.db # Base de datos SQLite +├── pyproject.toml # Configuración del proyecto +├── requirements.txt # Dependencias +└── README.md # Documentación principal +``` + +### Base de Datos: SQLite + +Se optó por **SQLite** como base de datos por su simplicidad y porque es perfecta para: +- Aplicaciones internas con pocos usuarios +- No requiere servidor de base de datos +- Fácil de mantener y hacer backup +- Incluida en Python (sin dependencias adicionales) + +**Esquema de la base de datos:** + +```sql +-- Tablets +CREATE TABLE tablets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + brand TEXT NOT NULL, + model TEXT NOT NULL, + serial_number TEXT UNIQUE NOT NULL, + status TEXT DEFAULT 'available', + notes TEXT +); + +-- Usuarios +CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + email TEXT, + phone TEXT, + identification TEXT UNIQUE +); + +-- Préstamos +CREATE TABLE loans ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + tablet_id INTEGER NOT NULL, + user_id INTEGER NOT NULL, + loan_date TEXT NOT NULL, + return_date TEXT, + status TEXT DEFAULT 'active', + FOREIGN KEY (tablet_id) REFERENCES tablets(id), + FOREIGN KEY (user_id) REFERENCES users(id) +); + +-- Dispositivos no prestables +CREATE TABLE non_loanable_devices ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + brand TEXT NOT NULL, + model TEXT NOT NULL, + serial_number TEXT UNIQUE NOT NULL, + device_type TEXT NOT NULL, + location TEXT, + status TEXT DEFAULT 'available', + notes TEXT, + purchase_date TEXT, + purchase_cost REAL +); +``` + +--- + +## 🛠️ Proveedores y Tecnologías + +### Lenguaje y Framework +- **Python 3.14+**: Lenguaje principal del proyecto +- **Flask 3.x**: Framework web principal +- **Flask-Babel 4.0.0**: Para internacionalización (i18n) +- **Jinja2**: Motor de plantillas + +### Frontend +- **Tailwind CSS**: Framework CSS para estilos (vía CDN) +- **HTMX**: Para interactividad sin JavaScript (en algunas partes) +- **Alpine.js**: Considerado pero no implementado + +### Base de Datos +- **SQLite**: Base de datos principal (embebida) +- **PostgreSQL**: Opción futura documentada (ver `docs/MIGRATION_TO_POSTGRES.md`) + +### Herramientas de Desarrollo +- **pytest**: Framework de pruebas +- **pytest-cov**: Cobertura de código +- **Git**: Control de versiones +- **GitHub/GitLab**: Hosting del repositorio (servidor propio en `hq.ijuanes.ovh:3333`) + +### Infraestructura +- **Servidor Git**: `http://hq.ijuanes.ovh:3333` +- **Usuario**: `ijuanes` +- **Repositorio**: `GestionTablets` + +--- + +## 🎯 Hitos del Desarrollo + +### Fase 1: Versión CLI Inicial +**Fecha**: Junio 2026 (inicio) + +- Creación de `minimal_app.py` con funciones básicas +- Implementación de CRUD para tablets y usuarios +- Gestión básica de préstamos +- Base de datos SQLite + +**Commit representativo**: Versión inicial del proyecto + +--- + +### Fase 2: Migración a Web +**Fecha**: Mediados de Junio 2026 + +- Creación de `app.py` con Flask +- Diseño de plantillas HTML con Jinja2 +- Implementación de rutas web: + - `/` - Página principal con tablets disponibles + - `/add_tablet` - Añadir nueva tablet + - `/add_user` - Añadir nuevo usuario + - `/loan_tablet` - Prestar tablet + - `/return_tablet/` - Devolver tablet + - `/history` - Historial de préstamos + +**Mejoras:** +- Interfaz visual más intuitiva +- Navegación entre páginas +- Visualización de datos en tablas + +--- + +### Fase 3: Internacionalización (i18n) +**Fecha**: Junio 2026 + +#### Problema Inicial +La aplicación solo estaba en inglés y no tenía soporte para múltiples idiomas. + +#### Solución Implementada +1. **Flask-Babel 4.0.0**: Integración con Flask +2. **Estructura de traducción**: + ``` + translations/ + └── es/ + ├── LC_MESSAGES.mo # Archivo binario + └── LC_MESSAGES.po # Archivo fuente + ``` +3. **Configuración**: + ```python + app.config['BABEL_DEFAULT_LOCALE'] = 'es' + app.config['LANGUAGES'] = {'en': 'English', 'es': 'Español'} + app.config['BABEL_TRANSLATION_DIRECTORIES'] = 'translations' + ``` + +#### Problemas y Soluciones + +**Problema 1**: Flask-Babel 4.0.0 cambió su API +- ❌ `@babel.localeselector` - Eliminado +- ❌ `@babel.locale_selector` - No existe +- ✅ `Babel(app, locale_selector=func)` - Enfoque correcto + +**Solución**: Reescribir la configuración para usar el nuevo API. + +**Commit**: `49e4562` - fix(i18n): define get_locale function before passing to Babel constructor + +**Problema 2**: Las plantillas no usaban el sistema de traducción +- Muchas plantillas tenían texto en inglés hardcodeado +- Ejemplo: `add_tablet.html`, `add_user.html`, `loan_tablet.html` + +**Solución**: Actualizar todas las plantillas para usar `{{ _('texto') }}` + +**Commit**: `2248237` - fix(i18n): enable translations in all templates + +**Problema 3**: No se guardaba la preferencia de idioma +- El idioma se perdía al navegar entre páginas +- No había cookies ni sesión para persistir la selección + +**Solución**: Implementar persistencia con cookies + sesión + +```python +# En app.py +from flask import session, make_response + +def get_locale(): + # 1. Intentar obtener de cookie + lang = request.cookies.get('language') + if lang and lang in app.config['LANGUAGES']: + return lang + # 2. Intentar obtener de sesión + if hasattr(request, 'session') and 'language' in request.session: + return request.session['language'] + # 3. Default a Español + return 'es' + +@app.route('/set_language') +def set_language(): + lang = request.args.get('lang') + if lang and lang in app.config['LANGUAGES']: + session['language'] = lang + resp = make_response(redirect(request.referrer or '/')) + resp.set_cookie('language', lang, max_age=31536000) # 1 año + return resp + return redirect(request.referrer or '/') +``` + +**Commit**: `2248237` - Cookie-based language persistence + +--- + +### Fase 4: Pruebas Unitarias +**Fecha**: Junio 2026 + +Se implementó una **suite completa de pruebas** con pytest: + +**Estructura:** +``` +tests/ +├── __init__.py +├── conftest.py # Fixtures de pytest +├── test_core.py # 21 pruebas de funcionalidad principal +├── test_edge_cases.py # 14 pruebas de casos límite +└── test_minimal_app.py # 11 pruebas de funciones de aplicación +``` + +**Cobertura:** +- Pruebas de funciones CRUD +- Casos límite (prestar tablet ya prestada, devolver préstamo inexistente) +- Validación de datos (números de serie duplicados) +- Manejo de errores + +**Resultado**: 46 pruebas, todas pasando ✅ + +**Commits:** +- `83ac67f` - test: add comprehensive unit test suite +- `dea2f23` - docs(ui): update RESPONSIVE_CSS.md with bug fix documentation + +--- + +### Fase 5: Diseño Responsive +**Fecha**: Junio 2026 + +**Problema**: La navegación desbordaba en pantallas pequeñas o al hacer zoom. + +**Solución**: Implementar CSS responsive con Tailwind CSS + +**Cambios:** +- Añadir `overflow-x: hidden` a body y contenedores +- Envolver tablas en contenedores con scroll horizontal +- Añadir breakpoints para móvil, tablet y desktop +- Crear `docs/RESPONSIVE_CSS.md` con documentación + +**Commits:** +- `28232db` - fix(ui): add missing `` tag in base.html +- `927c323` - feat(ui): add responsive CSS for mobile accessibility +- `26b77cf` - fix(ui): prevent navigation overflow on zoom and small screens + +--- + +### Fase 6: Documentación de Migración a PostgreSQL +**Fecha**: Junio 2026 + +Aunque el proyecto usa SQLite, se documentó el camino para migrar a PostgreSQL: + +**Archivo**: `docs/MIGRATION_TO_POSTGRES.md` + +**Contenido:** +- Comparación SQLite vs PostgreSQL +- Pasos de migración +- Cambios en el código +- Configuración de conexión +- Scripts SQL para crear tablas + +**Commit**: `dea2f23` - docs: add PostgreSQL migration guide + +--- + +### Fase 7: Identidad Corporativa +**Fecha**: 20 Junio 2026 + +#### Logo Corporativo +- **Archivo**: `assets/Schamann.png` (175x161 píxeles) +- **Ubicación web**: `/static/Schamann.png` +- **Integración**: Añadido al header de la aplicación +- **Estilo**: Forzado a 40px de altura con `object-contain` + +**Commit**: `c233040` - Add corporative logo + +#### Paleta de Colores Corporativos +Se reemplazó la paleta de colores genérica por los colores corporativos: + +| Color | Código Hex | RGB | Uso | +|-------|------------|-----|-----| +| **Azul Cobalto** | `#1338BE` | rgb(19, 56, 190) | Headers, navegación | +| **Naranja Tigre** | `#FC6A03` | rgb(252, 106, 3) | Acentos, indicadores de carga | +| **Verde Esmeralda** | `#028A0F` | rgb(2, 138, 15) | Estados de éxito | + +**Configuración en Tailwind:** +```javascript +tailwind.config = { + theme: { + extend: { + colors: { + cobalt: { + 50: '#f0f5ff', + 500: '#1338BE', + // ... todas las sombras + }, + tiger: { + 50: '#fff8f0', + 500: '#FC6A03', + // ... + }, + emerald: { + 50: '#f0fdf4', + 500: '#028A0F', + // ... + } + } + } + } +} +``` + +**Documentación**: `docs/CORPORATE_DESIGN.md` + +**Commit**: `8c1d12a` - feat(ui): add corporate logo and update colors + +--- + +## 🌍 Internacionalización (i18n) + +### Estado Actual + +✅ **Completo**: +- Flask-Babel 4.0.0 configurado correctamente +- Archivos de traducción creados (es/LC_MESSAGES.po, es/LC_MESSAGES.mo) +- Todas las plantillas usan `{{ _('texto') }}` +- Persistencia de idioma con cookies (1 año) + sesión +- Español como idioma por defecto +- Cambiador de idioma funcional en el header + +### Cómo Funciona + +1. **Selección de idioma**: + - Por defecto: Español + - URL: `?lang=en` o `?lang=es` + - Cookie: `language` (1 año de expiración) + - Sesión: `session['language']` + +2. **Uso en plantillas**: + ```html +

{{ _('Tablet Management System') }}

+

{{ _('Available Tablets') }}: {{ count }}

+ ``` + +3. **Traducciones**: + - Los archivos `.po` contienen las traducciones + - Se compilan a `.mo` para uso en producción + - Comando para actualizar: `pybabel extract -o translations/messages.pot .` + +### Idiomas Soportados +- **Español (es)**: Idioma por defecto +- **Inglés (en)**: Alternativa + +--- + +## 🎨 Identidad Corporativa + +### Logo +- **Archivo**: `Schamann.png` +- **Dimensiones**: 175x161 píxeles +- **Formato**: PNG con transparencia +- **Ubicación**: `/static/Schamann.png` +- **Visualización**: 40px de altura, manteniendo proporciones + +### Colores + +#### Azul Cobalto (#1338BE) +- **Uso principal**: Headers, navegación, acciones principales +- **Significado**: Profesionalismo, confianza +- **Contraste**: Texto blanco sobre fondos oscuros + +#### Naranja Tigre (#FC6A03) +- **Uso principal**: Acentos, indicadores de carga, acciones secundarias +- **Significado**: Energía, acción +- **Contraste**: Texto blanco sobre fondos + +#### Verde Esmeralda (#028A0F) +- **Uso principal**: Estados de éxito, confirmaciones +- **Significado**: Éxito, positividad +- **Contraste**: Texto blanco sobre fondos + +### Documentación +Todo el diseño corporativo está documentado en `docs/CORPORATE_DESIGN.md`: +- Paleta de colores completa con sombras +- Guías de uso +- Ejemplos de implementación +- Accesibilidad + +--- + +## 📚 Lecciones Aprendidas + +### 1. Versiones de Librerías +**Lección**: Siempre verificar la compatibilidad de versiones. + +**Ejemplo**: Flask-Babel 4.0.0 cambió su API completamente. Lo que funcionaba en la versión 3.x no funcionaba en 4.x. + +**Solución**: Leer la documentación de la versión específica que se está usando. + +--- + +### 2. Internacionalización desde el Inicio +**Lección**: Implementar i18n desde el principio, no como un afterthought. + +**Problema**: Muchas plantillas tenían texto hardcodeado en inglés. + +**Solución**: Revisar todas las plantillas y envolver todo el texto visible con `{{ _('...') }}`. + +--- + +### 3. Persistencia de Preferencias +**Lección**: Para aplicaciones internas, las cookies son suficientes. + +**Decisión**: No implementar consentimiento de cookies (es una app interna). + +**Implementación**: Cookie de 1 año + sesión para persistencia de idioma. + +--- + +### 4. Diseño Responsive +**Lección**: Probar en diferentes tamaños de pantalla y niveles de zoom. + +**Problema**: La navegación desbordaba al hacer zoom o en pantallas pequeñas. + +**Solución**: Usar `overflow-x: hidden` y contenedores con scroll. + +--- + +### 5. Pruebas Unitarias +**Lección**: Las pruebas dan confianza para hacer refactorización. + +**Beneficio**: Al tener 46 pruebas pasando, pudimos hacer cambios en la configuración de i18n sin miedo a romper algo. + +--- + +## 🎯 Estado Actual + +### Versión +- **Branch principal**: `develop` +- **Commits recientes**: + - `2248237` - fix(i18n): enable translations in all templates and implement cookie-based language persistence + - `8c1d12a` - feat(ui): add corporate logo and update colors to Cobalt Blue, Tiger Orange, Emerald Green + - `c233040` - Add corporative logo + - `49e4562` - fix(i18n): define get_locale function before passing to Babel constructor + +### Funcionalidades + +| Funcionalidad | Estado | Notas | +|---------------|--------|-------| +| Gestión de tablets | ✅ | CRUD completo | +| Gestión de usuarios | ✅ | CRUD completo | +| Préstamos | ✅ | Prestar y devolver | +| Historial | ✅ | Visualización completa | +| Internacionalización | ✅ | Español/Inglés | +| Persistencia de idioma | ✅ | Cookies + sesión | +| Diseño responsive | ✅ | Móvil, tablet, desktop | +| Logo corporativo | ✅ | Integración completa | +| Colores corporativos | ✅ | Paleta aplicada | +| Pruebas unitarias | ✅ | 46 pruebas pasando | + +### Próximos Pasos (Opcionales) + +1. **Migración a PostgreSQL**: Documentación lista, solo falta implementar +2. **Más idiomas**: Añadir francés, alemán, etc. +3. **Autenticación**: Implementar login para usuarios +4. **Notificaciones**: Recordatorios de devoluciones +5. **Exportación**: Exportar datos a CSV/Excel + +--- + +## 📞 Cómo Ejecutar el Proyecto + +### Requisitos +- Python 3.14+ +- pip o uv (gestor de paquetes) + +### Instalación + +```bash +# Clonar el repositorio +git clone http://hq.ijuanes.ovh:3333/ijuanes/GestionTablets.git +cd GestionTablets + +# Crear entorno virtual +python3 -m venv .venv +source .venv/bin/activate # Linux/Mac +# .venv\Scripts\activate # Windows + +# Instalar dependencias +pip install -r requirements.txt + +# Inicializar base de datos +python3 app.py # La base de datos se crea automáticamente +``` + +### Ejecutar + +```bash +# Desarrollo +python3 app.py + +# Acceder a: +# http://localhost:5000 - Español (por defecto) +# http://localhost:5000?lang=en - Inglés +``` + +### Pruebas + +```bash +# Ejecutar todas las pruebas +python3 -m pytest tests/ -v + +# Con cobertura +python3 -m pytest tests/ --cov=. --cov-report=html +``` + +--- + +## 🏁 Conclusión + +El proyecto **GestionTablets** ha evolucionado de una simple CLI a una aplicación web completa con: +- ✅ Internacionalización funcional +- ✅ Identidad corporativa integrada +- ✅ Diseño responsive +- ✅ Suite de pruebas completa +- ✅ Documentación exhaustiva + +Es un ejemplo de cómo una herramienta interna puede ser profesional, mantenible y escalable, incluso con recursos limitados. + +**Para Iván**: Este proyecto demuestra que con Python, Flask y SQLite se pueden crear aplicaciones robustas para equipos pequeños, y que la internacionalización y el diseño corporativo son importantes incluso en herramientas internas. + +--- + +*Documento generado el 20 de Junio de 2026* +*Para: Iván* +*Proyecto: GestionTablets*