- Add section 9 to TECHNICAL_SPECIFICATIONS.md with:
- Migration criteria (DB size, connections, users, transactions)
- Proposed repository pattern architecture
- Migration steps overview
- Benefits of PostgreSQL
- Create docs/MIGRATION_TO_POSTGRES.md with comprehensive guide:
- When to migrate (detailed thresholds)
- Architecture overview (repository pattern)
- Step-by-step migration process (10 steps)
- Complete code examples:
* Base repository interfaces
* SQLite implementation
* PostgreSQL implementation
* Repository factory
* Migration script
- Docker Compose configuration
- Rollback plan
- Monitoring and maintenance
- Performance optimization
- Troubleshooting guide
This enables future migration when database grows beyond SQLite capabilities.
200 lines
6.4 KiB
Markdown
200 lines
6.4 KiB
Markdown
# Especificaciones Técnicas
|
|
|
|
Documento complementario a `REQUIREMENTS.md` con propuestas concretas de implementación técnica.
|
|
|
|
---
|
|
|
|
## 1. Concurrencia en Base de Datos
|
|
|
|
| Opción | Descripción | Ventajas | Desventajas |
|
|
|--------|-------------|---------|-------------|
|
|
| **SQLite + WAL** | Modo Write-Ahead Logging | Zero-config, embebido, buena para <100 conexiones | Limitado a 1 escritor simultáneo |
|
|
| **PostgreSQL** | Base de datos relacional | Concurrencia completa, transacciones ACID | Requiere servidor |
|
|
| **Transacciones** | Aislamiento READ COMMITTED | Previene lecturas sucias | Bloqueos temporales |
|
|
| **Locking optimista** | Versión de fila en actualizaciones | Sin bloqueos | Conflictos requieren reintento |
|
|
|
|
**Recomendación**: SQLite con WAL para prototipos, PostgreSQL para producción. Usar transacciones para operaciones críticas (préstamo/devolución).
|
|
|
|
---
|
|
|
|
## 2. Autenticación Básica
|
|
|
|
| Opción | Descripción | Complejidad |
|
|
|--------|-------------|-------------|
|
|
| **Sesiones (Flask)** | Cookies firmadas | Baja |
|
|
| **JWT** | Tokens sin estado | Media |
|
|
| **OAuth 2.0** | Delegación a proveedores | Alta |
|
|
| **Basic Auth** | HTTP Basic Authentication | Mínima |
|
|
|
|
**Flujo mínimo**:
|
|
```
|
|
Login (user/pass) → Session/JWT → Middleware verifica rol → Acceso a endpoints
|
|
```
|
|
|
|
**Roles sugeridos**:
|
|
- `admin`: CRUD completo, gestión de usuarios
|
|
- `staff`: Préstamos/devoluciones
|
|
- `viewer`: Solo consulta
|
|
|
|
---
|
|
|
|
## 3. Separación Frontend/Backend
|
|
|
|
| Arquitectura | Descripción | Stack Ejemplo |
|
|
|--------------|-------------|---------------|
|
|
| **Monolítica + Templates** | Servidor renderiza HTML | Flask+Jinja2, Django |
|
|
| **API + SPA** | Backend API, frontend dinámico | FastAPI + React/Vue |
|
|
| **API + SSR** | Backend API + renderizado servidor | Next.js + API |
|
|
| **Microservicios** | Servicios independientes | Backend API + Frontend estático |
|
|
|
|
**Para este proyecto**:
|
|
- **Opción A**: Flask + Jinja2 (simple, suficiente para requisitos)
|
|
- **Opción B**: FastAPI + React (escalable, separable)
|
|
|
|
---
|
|
|
|
## 4. Búsqueda Eficiente (500+ elementos)
|
|
|
|
| Opción | Descripción | Implementación |
|
|
|--------|-------------|----------------|
|
|
| **Índices DB** | B-tree en columnas buscadas | `CREATE INDEX idx_brand ON tablets(brand)` |
|
|
| **Búsqueda full-text** | Búsqueda en texto | SQLite FTS5, PostgreSQL tsvector |
|
|
| **Filtrado cliente** | JavaScript filtra datos | Ideal para <2000 elementos |
|
|
| **Paginación** | Dividir resultados | `LIMIT 50 OFFSET 0` |
|
|
|
|
**Recomendación**: Índices en `serial_number`, `brand`, `model`, `user.name`, `user.identification`.
|
|
|
|
---
|
|
|
|
## 5. Estructura de Proyecto Propuesta
|
|
|
|
```
|
|
project/
|
|
├── backend/
|
|
│ ├── models/ # Entidades (Device, User, Loan)
|
|
│ ├── services/ # Lógica de negocio
|
|
│ ├── repositories/ # Acceso a datos
|
|
│ ├── routes/ # Endpoints/API
|
|
│ └── app.py # Configuración
|
|
├── frontend/ # Opcional para opción B
|
|
│ ├── public/
|
|
│ └── src/
|
|
├── migrations/ # Control de cambios DB
|
|
├── tests/
|
|
└── docs/
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Decisiones Clave por Tomar
|
|
|
|
| Decisión | Opciones | Impacto |
|
|
|----------|----------|---------|
|
|
| Base de datos | SQLite / PostgreSQL | Concurrencia, despliegue |
|
|
| Autenticación | Sesiones / JWT / Ninguna | Seguridad, complejidad |
|
|
| Frontend | Templates / SPA / Ninguno | Experiencia usuario |
|
|
| Despliegue | Local / Docker / Cloud | Escalabilidad |
|
|
|
|
---
|
|
|
|
## 7. Ejemplo de Implementación Mínima (Pseudocódigo)
|
|
|
|
```python
|
|
# modelos.py
|
|
class Device:
|
|
id: int (PK)
|
|
serial_number: str (unique)
|
|
status: str (available/loaned)
|
|
loans: List[Loan] (one-to-many)
|
|
|
|
class User:
|
|
id: int (PK)
|
|
identification: str (unique)
|
|
loans: List[Loan] (one-to-many)
|
|
|
|
class Loan:
|
|
id: int (PK)
|
|
device_id: int (FK)
|
|
user_id: int (FK)
|
|
loan_date: datetime
|
|
return_date: datetime (nullable)
|
|
status: str (active/returned)
|
|
|
|
# servicios/loan_service.py
|
|
def loan_device(device_id: int, user_id: int) -> Loan:
|
|
with transaction(): # Atomicidad
|
|
device = get_device_for_update(device_id)
|
|
if device.status != 'available':
|
|
raise DeviceNotAvailableError()
|
|
|
|
loan = Loan.create(
|
|
device_id=device_id,
|
|
user_id=user_id,
|
|
loan_date=now(),
|
|
status='active'
|
|
)
|
|
device.status = 'loaned'
|
|
return loan
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Consideraciones Adicionales
|
|
|
|
- **Validaciones**: Únicas (serial_number, identification) a nivel de base de datos
|
|
- **Auditoría**: Campos `created_at`, `updated_at` en todas las entidades
|
|
- **Backups**: Script para exportar base de datos periódicamente
|
|
- **Logging**: Registrar préstamos/devoluciones para auditoría
|
|
- **Versionado API**: `/api/v1/...` para compatibilidad futura
|
|
- **Pruebas**: Cubrir flujos críticos (préstamo con dispositivo no disponible, devolución de préstamo inexistente)
|
|
|
|
---
|
|
|
|
## 9. Migración a PostgreSQL (Futuro)
|
|
|
|
### Contexto
|
|
|
|
El sistema actualmente utiliza **SQLite** como base de datos embebida, ideal para prototipos y aplicaciones pequeñas. Sin embargo, SQLite tiene limitaciones para escalar.
|
|
|
|
### Criterios para Migración
|
|
|
|
Considerar migrar a **PostgreSQL** cuando:
|
|
- Tamaño DB > 1GB
|
|
- Más de 50 conexiones simultáneas
|
|
- Más de 200 usuarios activos
|
|
- Más de 500 transacciones por minuto
|
|
- Necesidad de múltiples servidores
|
|
|
|
### Arquitectura Propuesta
|
|
|
|
Usar un patrón de **Repository** para abstraer la base de datos:
|
|
```
|
|
backend/
|
|
├── repositories/
|
|
│ ├── base_repository.py # Interfaz abstracta
|
|
│ ├── sqlite_repository.py # Implementación SQLite
|
|
│ └── postgres_repository.py # Implementación PostgreSQL
|
|
└── config/
|
|
└── database.py # Fábrica de repositorios
|
|
```
|
|
|
|
### Schema PostgreSQL
|
|
|
|
El schema es similar al de SQLite pero con tipos de datos más específicos y índices adicionales para rendimiento.
|
|
|
|
### Pasos para Migración
|
|
|
|
1. Instalar dependencias: `pip install psycopg2-binary sqlalchemy alembic`
|
|
2. Configurar PostgreSQL y crear base de datos
|
|
3. Ejecutar script de migración: `python scripts/migrate_to_postgres.py`
|
|
4. Cambiar configuración: `DB_TYPE=postgres`
|
|
5. Iniciar aplicación
|
|
|
|
### Beneficios
|
|
|
|
- Concurrencia ilimitada (múltiples escritores)
|
|
- Escalabilidad a miles de conexiones
|
|
- Mejor rendimiento con índices
|
|
- Seguridad integrada (autenticación, roles)
|
|
- Backups automáticos
|
|
- Replicación y clustering
|