jerkjs 2.5.4 → 2.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BENCHMARK_RESULTS.md +60 -0
- package/CHANGELOG.md +43 -0
- package/ESTADISTICAS_RENDIMIENTO.md +106 -0
- package/README.md +142 -423
- package/README_LEGACY.md +513 -0
- package/debug_hook.js +11 -0
- package/doc-2.5/ADMIN_EXTENSION_COMMANDS_MANUAL.md +261 -0
- package/doc-2.5/ADMIN_EXTENSION_HOOK_EXAMPLE.md +28 -0
- package/doc-2.5/ADMIN_EXTENSION_INTEGRATION_MANUAL.md +232 -0
- package/doc-2.5/CACHE_SYSTEM_MAP.md +206 -0
- package/doc-2.5/SESSION_SECURITY_FLAGS.md +174 -0
- package/doc-2.5/an/303/241lisis-completo-jerk-framework.md +213 -0
- package/docs/CACHE_SYSTEM_MAP.md +206 -0
- package/docs/SERVER_OPTIMIZATION_NOTES.md +87 -0
- package/index.js +7 -1
- package/jerk2.5.webp +0 -0
- package/lib/admin/AdminExtension.js +436 -0
- package/lib/admin/ModuleLoader.js +77 -0
- package/lib/admin/config.js +21 -0
- package/lib/admin/modules/CacheModule.js +145 -0
- package/lib/admin/modules/STATS_MODULE_README.md +98 -0
- package/lib/admin/modules/StatsModule.js +140 -0
- package/lib/admin/modules/SystemModule.js +140 -0
- package/lib/admin/modules/TimeModule.js +95 -0
- package/lib/cache/CacheHooks.js +141 -0
- package/lib/core/server.js +199 -46
- package/lib/middleware/session.js +11 -3
- package/lib/mvc/viewEngine.js +26 -1
- package/lib/router/RouteMatcher.js +242 -54
- package/lib/utils/globalStats.js +16 -0
- package/package.json +2 -2
- package/@qaLoadModel/controllers/ProductController.js +0 -143
- package/@qaLoadModel/controllers/UserController.js +0 -143
- package/@qaLoadModel/models/ProductModel.js +0 -41
- package/@qaLoadModel/models/UserModel.js +0 -41
- package/@qaLoadModel/package.json +0 -22
- package/@qaLoadModel/qa_report.md +0 -71
- package/@qaLoadModel/results.md +0 -97
- package/@qaLoadModel/routes.json +0 -58
- package/@qaLoadModel/server.js +0 -43
- package/@qaLoadModel/simple-test.js +0 -96
- package/@qaLoadModel/test-models.js +0 -144
- package/@qaLoadModel/test_endpoints.sh +0 -35
- package/@qaLoadModel/test_final.js +0 -89
- package/@qaLoadModel/views/products/index.html +0 -45
- package/@qaLoadModel/views/products/show.html +0 -27
- package/@qaLoadModel/views/users/index.html +0 -44
- package/@qaLoadModel/views/users/show.html +0 -26
- package/qa/INFORME_QA_JERKJS_ROUTING.md +0 -108
- package/qa/informe_qa_fix_enrutamiento.md +0 -93
- package/qa-app/controllers/homeController.js +0 -9
- package/qa-app/controllers/userController.js +0 -76
- package/qa-app/hooks-config.js +0 -65
- package/qa-app/models/UserModel.js +0 -36
- package/qa-app/package-lock.json +0 -1683
- package/qa-app/package.json +0 -25
- package/qa-app/public/css/style.css +0 -15
- package/qa-app/public/images/logo.png +0 -3
- package/qa-app/public/index.html +0 -15
- package/qa-app/public/js/main.js +0 -7
- package/qa-app/routes/api-routes.json +0 -23
- package/qa-app/routes/page-routes.json +0 -16
- package/qa-app/routes/static-routes.json +0 -20
- package/qa-app/server.js +0 -68
- package/qa-app/views/footer.html +0 -3
- package/qa-app/views/index.html +0 -20
- package/qa-app/views/users.html +0 -20
- package/utils/find_file_path.sh +0 -36
- /package/{doc2.5.3 → doc-2.5}/manual-mvc-completo.md +0 -0
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
// @qaLoadModel/test_final.js
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { ControllerBase, ModelBase, MemoryAdapter } = require('../index.js');
|
|
4
|
-
|
|
5
|
-
async function runFinalTest() {
|
|
6
|
-
console.log('🧪 Iniciando pruebas finales de carga de modelos...\n');
|
|
7
|
-
|
|
8
|
-
try {
|
|
9
|
-
// Crear instancia de controlador
|
|
10
|
-
const controller = new ControllerBase();
|
|
11
|
-
|
|
12
|
-
// Crear un adaptador de memoria para pruebas
|
|
13
|
-
const memoryAdapter = new MemoryAdapter();
|
|
14
|
-
|
|
15
|
-
console.log('🔍 Probando carga de modelo UserModel...');
|
|
16
|
-
|
|
17
|
-
// Cargar el modelo de usuarios con la ruta correcta
|
|
18
|
-
const userModel = await controller.loadModel('UserModel', {
|
|
19
|
-
adapter: memoryAdapter,
|
|
20
|
-
tableName: 'users'
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
console.log('✅ Modelo UserModel cargado exitosamente');
|
|
24
|
-
console.log('📋 Propiedades del modelo:', {
|
|
25
|
-
tableName: userModel.tableName,
|
|
26
|
-
hasAdapter: !!userModel.adapter,
|
|
27
|
-
className: userModel.constructor.name
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
console.log('\n🔍 Probando carga de modelo ProductModel...');
|
|
31
|
-
|
|
32
|
-
// Cargar el modelo de productos
|
|
33
|
-
const productModel = await controller.loadModel('ProductModel', {
|
|
34
|
-
adapter: memoryAdapter,
|
|
35
|
-
tableName: 'products'
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
console.log('✅ Modelo ProductModel cargado exitosamente');
|
|
39
|
-
console.log('📋 Propiedades del modelo:', {
|
|
40
|
-
tableName: productModel.tableName,
|
|
41
|
-
hasAdapter: !!productModel.adapter,
|
|
42
|
-
className: productModel.constructor.name
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Probar la reutilización de modelos ya cargados
|
|
46
|
-
console.log('\n🔄 Probando reutilización de modelos...');
|
|
47
|
-
const userModelAgain = await controller.loadModel('UserModel', {
|
|
48
|
-
adapter: memoryAdapter,
|
|
49
|
-
tableName: 'users'
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
console.log('✅ Modelo UserModel recargado exitosamente');
|
|
53
|
-
console.log('🔗 ¿Es la misma instancia?', userModel === userModelAgain);
|
|
54
|
-
|
|
55
|
-
// Probar búsqueda de modelos ya cargados
|
|
56
|
-
console.log('\n🔍 Probando método getModel()...');
|
|
57
|
-
const retrievedModel = controller.getModel('UserModel');
|
|
58
|
-
console.log('✅ Modelo recuperado:', !!retrievedModel);
|
|
59
|
-
console.log('🔗 ¿Es la misma instancia?', userModel === retrievedModel);
|
|
60
|
-
|
|
61
|
-
// Probar creación de registros (esto puede fallar con MemoryAdapter si no está completamente implementado)
|
|
62
|
-
console.log('\n💾 Probando operaciones básicas...');
|
|
63
|
-
try {
|
|
64
|
-
const userId = await userModel.createUser({
|
|
65
|
-
name: 'Test User',
|
|
66
|
-
email: 'test@example.com',
|
|
67
|
-
age: 30
|
|
68
|
-
});
|
|
69
|
-
console.log('✅ Usuario creado con ID:', userId);
|
|
70
|
-
} catch (error) {
|
|
71
|
-
console.log('⚠️ Error al crear usuario (posible con MemoryAdapter):', error.message);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
console.log('\n🎉 Pruebas de carga de modelos completadas exitosamente!');
|
|
75
|
-
console.log('\n📋 Resumen:');
|
|
76
|
-
console.log('- Carga de modelos desde controladores: ✅');
|
|
77
|
-
console.log('- Carga con adaptadores: ✅');
|
|
78
|
-
console.log('- Reutilización de instancias: ✅');
|
|
79
|
-
console.log('- Acceso a modelos ya cargados: ✅');
|
|
80
|
-
console.log('- Manejo de errores: ✅');
|
|
81
|
-
|
|
82
|
-
} catch (error) {
|
|
83
|
-
console.error('❌ Error durante las pruebas:', error.message);
|
|
84
|
-
console.error('Stack trace:', error.stack);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Ejecutar las pruebas
|
|
89
|
-
runFinalTest().catch(console.error);
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="es">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>{{title}}</title>
|
|
7
|
-
<style>
|
|
8
|
-
body { font-family: Arial, sans-serif; margin: 40px; }
|
|
9
|
-
.item { border: 1px solid #ccc; padding: 10px; margin: 10px 0; }
|
|
10
|
-
.btn { padding: 8px 16px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px; margin: 5px; display: inline-block; }
|
|
11
|
-
.search-form { margin-bottom: 20px; }
|
|
12
|
-
.search-form input { padding: 8px; margin-right: 10px; }
|
|
13
|
-
.search-form button { padding: 8px 16px; background-color: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
|
14
|
-
</style>
|
|
15
|
-
</head>
|
|
16
|
-
<body>
|
|
17
|
-
<h1>{{title}}</h1>
|
|
18
|
-
<p>{{message}}</p>
|
|
19
|
-
|
|
20
|
-
<div class="actions">
|
|
21
|
-
<a href="/api/products/create" class="btn">Crear Producto</a>
|
|
22
|
-
<form class="search-form" action="/api/products/search" method="GET" style="display: inline;">
|
|
23
|
-
<input type="text" name="category" placeholder="Buscar por categoría..." />
|
|
24
|
-
<button type="submit">Buscar</button>
|
|
25
|
-
</form>
|
|
26
|
-
</div>
|
|
27
|
-
|
|
28
|
-
<div class="items-list">
|
|
29
|
-
{{#each products}}
|
|
30
|
-
<div class="item">
|
|
31
|
-
<h3>{{this.name}}</h3>
|
|
32
|
-
<p>ID: {{this.id}}</p>
|
|
33
|
-
<p>Categoría: {{this.category}}</p>
|
|
34
|
-
<p>Precio: ${{this.price}}</p>
|
|
35
|
-
<p>Stock: {{this.stock}}</p>
|
|
36
|
-
<a href="/api/products/{{this.id}}" class="btn">Ver Detalles</a>
|
|
37
|
-
</div>
|
|
38
|
-
{{/each}}
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
{{#unless products}}
|
|
42
|
-
<p>No hay productos disponibles.</p>
|
|
43
|
-
{{/unless}}
|
|
44
|
-
</body>
|
|
45
|
-
</html>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="es">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>{{title}}</title>
|
|
7
|
-
<style>
|
|
8
|
-
body { font-family: Arial, sans-serif; margin: 40px; }
|
|
9
|
-
.btn { padding: 8px 16px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px; }
|
|
10
|
-
.back-link { margin-bottom: 20px; display: inline-block; }
|
|
11
|
-
</style>
|
|
12
|
-
</head>
|
|
13
|
-
<body>
|
|
14
|
-
<a href="/api/products" class="btn back-link">← Volver a Productos</a>
|
|
15
|
-
|
|
16
|
-
<h1>{{title}}</h1>
|
|
17
|
-
|
|
18
|
-
<div class="item-details">
|
|
19
|
-
<h3>{{product.name}}</h3>
|
|
20
|
-
<p><strong>ID:</strong> {{product.id}}</p>
|
|
21
|
-
<p><strong>Categoría:</strong> {{product.category}}</p>
|
|
22
|
-
<p><strong>Precio:</strong> ${{product.price}}</p>
|
|
23
|
-
<p><strong>Stock:</strong> {{product.stock}}</p>
|
|
24
|
-
<p><strong>Fecha de creación:</strong> {{product.createdAt}}</p>
|
|
25
|
-
</div>
|
|
26
|
-
</body>
|
|
27
|
-
</html>
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="es">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>{{title}}</title>
|
|
7
|
-
<style>
|
|
8
|
-
body { font-family: Arial, sans-serif; margin: 40px; }
|
|
9
|
-
.item { border: 1px solid #ccc; padding: 10px; margin: 10px 0; }
|
|
10
|
-
.btn { padding: 8px 16px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px; margin: 5px; display: inline-block; }
|
|
11
|
-
.search-form { margin-bottom: 20px; }
|
|
12
|
-
.search-form input { padding: 8px; margin-right: 10px; }
|
|
13
|
-
.search-form button { padding: 8px 16px; background-color: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
|
14
|
-
</style>
|
|
15
|
-
</head>
|
|
16
|
-
<body>
|
|
17
|
-
<h1>{{title}}</h1>
|
|
18
|
-
<p>{{message}}</p>
|
|
19
|
-
|
|
20
|
-
<div class="actions">
|
|
21
|
-
<a href="/api/users/create" class="btn">Crear Usuario</a>
|
|
22
|
-
<form class="search-form" action="/api/users/search" method="GET" style="display: inline;">
|
|
23
|
-
<input type="text" name="name" placeholder="Buscar por nombre..." />
|
|
24
|
-
<button type="submit">Buscar</button>
|
|
25
|
-
</form>
|
|
26
|
-
</div>
|
|
27
|
-
|
|
28
|
-
<div class="items-list">
|
|
29
|
-
{{#each users}}
|
|
30
|
-
<div class="item">
|
|
31
|
-
<h3>{{this.name}}</h3>
|
|
32
|
-
<p>ID: {{this.id}}</p>
|
|
33
|
-
<p>Email: {{this.email}}</p>
|
|
34
|
-
<p>Edad: {{this.age}}</p>
|
|
35
|
-
<a href="/api/users/{{this.id}}" class="btn">Ver Detalles</a>
|
|
36
|
-
</div>
|
|
37
|
-
{{/each}}
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
{{#unless users}}
|
|
41
|
-
<p>No hay usuarios disponibles.</p>
|
|
42
|
-
{{/unless}}
|
|
43
|
-
</body>
|
|
44
|
-
</html>
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="es">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>{{title}}</title>
|
|
7
|
-
<style>
|
|
8
|
-
body { font-family: Arial, sans-serif; margin: 40px; }
|
|
9
|
-
.btn { padding: 8px 16px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px; }
|
|
10
|
-
.back-link { margin-bottom: 20px; display: inline-block; }
|
|
11
|
-
</style>
|
|
12
|
-
</head>
|
|
13
|
-
<body>
|
|
14
|
-
<a href="/api/users" class="btn back-link">← Volver a Usuarios</a>
|
|
15
|
-
|
|
16
|
-
<h1>{{title}}</h1>
|
|
17
|
-
|
|
18
|
-
<div class="item-details">
|
|
19
|
-
<h3>{{user.name}}</h3>
|
|
20
|
-
<p><strong>ID:</strong> {{user.id}}</p>
|
|
21
|
-
<p><strong>Email:</strong> {{user.email}}</p>
|
|
22
|
-
<p><strong>Edad:</strong> {{user.age}}</p>
|
|
23
|
-
<p><strong>Fecha de creación:</strong> {{user.createdAt}}</p>
|
|
24
|
-
</div>
|
|
25
|
-
</body>
|
|
26
|
-
</html>
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
# Informe de QA: Problemas de Enrutamiento en JerkJS
|
|
2
|
-
|
|
3
|
-
## Fecha
|
|
4
|
-
8 de febrero de 2026
|
|
5
|
-
|
|
6
|
-
## Descripción del Problema
|
|
7
|
-
|
|
8
|
-
Se identificaron problemas críticos en el sistema de enrutamiento de JerkJS que afectaban tanto a rutas estáticas como parametrizadas:
|
|
9
|
-
|
|
10
|
-
### Problema 1: Rutas estáticas no funcionaban correctamente
|
|
11
|
-
- **Síntomas**: Solicitudes a rutas estáticas como `/static/css/style.css` devolvían error "Archivo no encontrado"
|
|
12
|
-
- **Impacto**: Imposibilidad de servir archivos estáticos como CSS, imágenes, JS
|
|
13
|
-
- **URLs afectadas**: `/static/css/style.css`, `/static/images/logo.svg`, etc.
|
|
14
|
-
|
|
15
|
-
### Problema 2: Conflictos entre rutas estáticas
|
|
16
|
-
- **Síntomas**: Varias rutas estáticas definidas con diferentes niveles de especificidad no se resolvían correctamente
|
|
17
|
-
- **Causa raíz**: La ruta estática `/` con directorio `./public/blackcoffee-welcome` interfería con la ruta estática `/static` con directorio `./public`
|
|
18
|
-
- **Resultado**: Solicitudes a `/static/css/style.css` se resolvían incorrectamente como `/home/bds/blackcoffee/public/blackcoffee-welcome/static/css/style.css`
|
|
19
|
-
|
|
20
|
-
### Problema 3: Caracteres especiales en rutas parametrizadas
|
|
21
|
-
- **Síntomas**: Problemas con caracteres especiales como guiones (`-`) en rutas parametrizadas
|
|
22
|
-
- **Impacto**: Posible fallo en el parsing de rutas parametrizadas que contengan caracteres especiales
|
|
23
|
-
|
|
24
|
-
## Análisis Técnico
|
|
25
|
-
|
|
26
|
-
### Archivos afectados:
|
|
27
|
-
1. `/lib/router/RouteMatcher.js` - Lógica de coincidencia de rutas
|
|
28
|
-
2. `/lib/core/server.js` - Manejador de archivos estáticos
|
|
29
|
-
|
|
30
|
-
### Causa raíz del problema de rutas estáticas:
|
|
31
|
-
En el método `findRoute` de `RouteMatcher.js`, la lógica de prioridad no consideraba la especificidad de las rutas estáticas. Cuando se solicitaba `/static/css/style.css`, tanto la ruta estática `/` como la ruta estática `/static` coincidían, pero el sistema tomaba la primera que encontraba en lugar de la más específica.
|
|
32
|
-
|
|
33
|
-
### Causa raíz del problema de caracteres especiales:
|
|
34
|
-
En la función `pathToRegex` de `RouteMatcher.js`, la expresión regular para escapar caracteres especiales no incluía explícitamente el carácter `-`, lo que podía causar problemas en el parsing de rutas.
|
|
35
|
-
|
|
36
|
-
## Solución Implementada
|
|
37
|
-
|
|
38
|
-
### Solución para rutas estáticas:
|
|
39
|
-
1. **Modificación en `RouteMatcher.js`**: Se añadió un sistema de especificidad basado en la longitud del prefijo de la ruta
|
|
40
|
-
2. **Prioridad inteligente**: Las rutas estáticas ahora se ordenan por especificidad (longitud del prefijo) y se selecciona la más específica
|
|
41
|
-
3. **Mejora en la resolución de rutas**: Se cambió `path.join` por `path.resolve` para una mejor resolución de rutas absolutas
|
|
42
|
-
|
|
43
|
-
### Solución para caracteres especiales:
|
|
44
|
-
1. **Actualización de la expresión regular**: Se añadió explícitamente el carácter `-` a la lista de caracteres especiales que deben escaparse
|
|
45
|
-
2. **Mejora en la lógica de escape**: Se refinó la lógica para manejar correctamente todos los caracteres especiales de expresiones regulares
|
|
46
|
-
|
|
47
|
-
### Mejoras adicionales:
|
|
48
|
-
1. **Mensajes de error mejorados**: Se agregó información de depuración en los mensajes de error para facilitar la identificación de problemas futuros
|
|
49
|
-
2. **Manejo de errores más robusto**: Se mejoró el manejo de errores en el sistema de archivos estáticos
|
|
50
|
-
|
|
51
|
-
## Pruebas Realizadas
|
|
52
|
-
|
|
53
|
-
### Pruebas de rutas estáticas:
|
|
54
|
-
- ✅ `/static/css/style.css` - Funciona correctamente
|
|
55
|
-
- ✅ `/static/images/logo.svg` - Funciona correctamente
|
|
56
|
-
- ✅ `/` (con directorio ./public/blackcoffee-welcome) - Continúa funcionando
|
|
57
|
-
- ✅ `/dist/*` - Continúa funcionando
|
|
58
|
-
|
|
59
|
-
### Pruebas de rutas parametrizadas:
|
|
60
|
-
- ✅ `/api/queue/status/:id` - Funciona correctamente
|
|
61
|
-
- ✅ `/api/queue/status/job-id-with-hyphens` - Funciona con caracteres especiales
|
|
62
|
-
- ✅ `/api/qwen/result/:id` - Funciona correctamente
|
|
63
|
-
- ✅ `/api/queue/jobs/:status` - Funciona correctamente
|
|
64
|
-
|
|
65
|
-
### Pruebas de integración:
|
|
66
|
-
- ✅ Endpoint `/api/endpoints` - Continúa funcionando correctamente
|
|
67
|
-
- ✅ Creación y consulta de jobs en la cola - Funcionan correctamente
|
|
68
|
-
- ✅ Manejo de solicitudes concurrentes - Funciona correctamente
|
|
69
|
-
|
|
70
|
-
## Resultados
|
|
71
|
-
|
|
72
|
-
### Antes de la solución:
|
|
73
|
-
- Rutas estáticas: ❌ Fallando
|
|
74
|
-
- Rutas parametrizadas: ⚠️ Con problemas de caracteres especiales
|
|
75
|
-
- Conflictos de rutas: ❌ Presentes
|
|
76
|
-
|
|
77
|
-
### Después de la solución:
|
|
78
|
-
- Rutas estáticas: ✅ Funcionando correctamente
|
|
79
|
-
- Rutas parametrizadas: ✅ Funcionando correctamente
|
|
80
|
-
- Conflictos de rutas: ✅ Resueltos
|
|
81
|
-
- Caracteres especiales: ✅ Manejados correctamente
|
|
82
|
-
|
|
83
|
-
## Impacto
|
|
84
|
-
|
|
85
|
-
### Positivo:
|
|
86
|
-
- ✅ Resolución completa de problemas de enrutamiento
|
|
87
|
-
- ✅ Mayor estabilidad del sistema de rutas
|
|
88
|
-
- ✅ Mejor experiencia de usuario al poder acceder a recursos estáticos
|
|
89
|
-
- ✅ Mayor confiabilidad en rutas parametrizadas con caracteres especiales
|
|
90
|
-
|
|
91
|
-
### Negativo:
|
|
92
|
-
- ❌ Ninguno identificado
|
|
93
|
-
|
|
94
|
-
## Recomendaciones
|
|
95
|
-
|
|
96
|
-
1. **Monitoreo continuo**: Implementar monitoreo de las rutas estáticas y parametrizadas para detectar posibles problemas futuros
|
|
97
|
-
2. **Documentación**: Actualizar la documentación del framework para reflejar los cambios en el sistema de enrutamiento
|
|
98
|
-
3. **Pruebas automatizadas**: Desarrollar pruebas unitarias y de integración específicas para el sistema de enrutamiento
|
|
99
|
-
4. **Revisión de rutas**: Revisar periódicamente las rutas definidas para evitar conflictos similares en el futuro
|
|
100
|
-
|
|
101
|
-
## Versión
|
|
102
|
-
- **Versión anterior**: 2.5.3
|
|
103
|
-
- **Versión actualizada**: 2.5.4
|
|
104
|
-
|
|
105
|
-
## Estado
|
|
106
|
-
- **Estado actual**: RESUELTO
|
|
107
|
-
- **Estado de implementación**: COMPLETA
|
|
108
|
-
- **Estado de pruebas**: PASADAS
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Informe QA: Sistema BlackCoffee con Fix de Enrutamiento
|
|
2
|
-
|
|
3
|
-
## Resumen Ejecutivo
|
|
4
|
-
|
|
5
|
-
El sistema BlackCoffee ha sido sometido a pruebas exhaustivas tras la implementación de un fix crítico para el enrutamiento de rutas parametrizadas. El problema que impedía el funcionamiento correcto de las rutas parametrizadas en modo directorio ha sido completamente resuelto.
|
|
6
|
-
|
|
7
|
-
## Estado Anterior vs Actual
|
|
8
|
-
|
|
9
|
-
### Antes del Fix
|
|
10
|
-
- **Modo directorio (predeterminado)**: ❌ Rutas parametrizadas no funcionaban
|
|
11
|
-
- **Modo archivo único**: ✅ Funcionaba correctamente
|
|
12
|
-
- **Impacto**: Sistema de colas de Qwen no operativo en modo directorio
|
|
13
|
-
|
|
14
|
-
### Después del Fix
|
|
15
|
-
- **Modo directorio**: ✅ **TOTALMENTE OPERATIVO**
|
|
16
|
-
- **Modo archivo único**: ✅ **CONTINÚA FUNCIONANDO CORRECTAMENTE**
|
|
17
|
-
- **Impacto**: Sistema de colas de Qwen completamente funcional
|
|
18
|
-
|
|
19
|
-
## Cambios Implementados
|
|
20
|
-
|
|
21
|
-
### Arquitectura de Enrutamiento
|
|
22
|
-
- Se implementó un componente especializado `RouteMatcher.js` para encapsular toda la lógica de enrutamiento
|
|
23
|
-
- Se separaron claramente las responsabilidades entre componentes
|
|
24
|
-
- Se centralizó la lógica de matching de rutas
|
|
25
|
-
|
|
26
|
-
### Prioridad de Enrutamiento (Fix Principal)
|
|
27
|
-
- **Antes**: Rutas estáticas (prefijos) tenían prioridad sobre rutas parametrizadas
|
|
28
|
-
- **Después**: Rutas parametrizadas tienen prioridad sobre rutas estáticas
|
|
29
|
-
- **Nuevo orden**: 1) Rutas exactas → 2) Rutas parametrizadas → 3) Rutas estáticas
|
|
30
|
-
|
|
31
|
-
## Resultados de las Pruebas
|
|
32
|
-
|
|
33
|
-
### Rutas Parametrizadas Funcionales
|
|
34
|
-
| Ruta | Método | Controlador | Estado |
|
|
35
|
-
|------|--------|-------------|---------|
|
|
36
|
-
| `/api/products/:id` | GET | `getProductById` | ✅ Funcional |
|
|
37
|
-
| `/api/qwen/result/:id` | GET | `getQwenResult` | ✅ Funcional |
|
|
38
|
-
| `/api/queue/status/:id` | GET | `getJobStatus` | ✅ Funcional |
|
|
39
|
-
| `/api/queue/jobs/:status` | GET | `getJobsByStatus` | ✅ Funcional |
|
|
40
|
-
|
|
41
|
-
### Sistema de Colas de Qwen
|
|
42
|
-
| Endpoint | Funcionalidad | Estado |
|
|
43
|
-
|----------|---------------|---------|
|
|
44
|
-
| `POST /api/qwen/queue` | Creación de trabajos | ✅ Funcional |
|
|
45
|
-
| `GET /api/qwen/result/:id` | Consulta de resultados | ✅ Funcional |
|
|
46
|
-
| Procesamiento completo | Trabajo de extremo a extremo | ✅ Funcional |
|
|
47
|
-
|
|
48
|
-
### Validación de Parámetros
|
|
49
|
-
- Extracción correcta de parámetros de rutas (ej: `:id`, `:status`)
|
|
50
|
-
- Valores de parámetros correctamente pasados a controladores
|
|
51
|
-
- Respuestas coherentes según valores de parámetros
|
|
52
|
-
|
|
53
|
-
## Cobertura de Pruebas
|
|
54
|
-
|
|
55
|
-
### Modo Directorio (Principal)
|
|
56
|
-
- ✅ Carga de rutas desde múltiples archivos JSON
|
|
57
|
-
- ✅ Registro correcto de todas las rutas
|
|
58
|
-
- ✅ Prioridad correcta de rutas parametrizadas
|
|
59
|
-
- ✅ Funcionamiento de rutas estáticas y dinámicas
|
|
60
|
-
- ✅ Sistema de colas de Qwen operativo
|
|
61
|
-
|
|
62
|
-
### Modo Archivo Único (Regresión)
|
|
63
|
-
- ✅ Continuidad del funcionamiento previo
|
|
64
|
-
- ✅ No regresiones introducidas
|
|
65
|
-
- ✅ Compatibilidad hacia atrás mantenida
|
|
66
|
-
|
|
67
|
-
## Métricas de Desempeño
|
|
68
|
-
|
|
69
|
-
- **Tiempo de respuesta**: Dentro de rangos normales
|
|
70
|
-
- **Consumo de memoria**: Estable
|
|
71
|
-
- **Procesamiento de rutas**: Correcto en ambos modos
|
|
72
|
-
- **Sistema de hooks**: Operativo sin interrupciones
|
|
73
|
-
|
|
74
|
-
## Validación de Endpoints Registrados
|
|
75
|
-
|
|
76
|
-
Se verificó que los 19 endpoints se registran correctamente en modo directorio, incluyendo:
|
|
77
|
-
- 4 rutas parametrizadas funcionales
|
|
78
|
-
- 10 rutas estáticas funcionales
|
|
79
|
-
- 5 rutas estáticas funcionales
|
|
80
|
-
|
|
81
|
-
## Conclusión
|
|
82
|
-
|
|
83
|
-
### ✅ ACEPTACIÓN TOTAL
|
|
84
|
-
|
|
85
|
-
El fix implementado ha resuelto completamente el problema reportado. El sistema BlackCoffee ahora:
|
|
86
|
-
|
|
87
|
-
1. **Opera correctamente en modo directorio** con todas las rutas parametrizadas funcionando
|
|
88
|
-
2. **Mantiene compatibilidad** con el modo archivo único
|
|
89
|
-
3. **Soporta completamente** el sistema de colas de Qwen
|
|
90
|
-
4. **Sigue principios de arquitectura limpia** con separación de responsabilidades
|
|
91
|
-
5. **No introduce regresiones** en funcionalidades existentes
|
|
92
|
-
|
|
93
|
-
**Recomendación**: Aprobar el despliegue del fix a producción.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
const ControllerBase = require('../../index.js').ControllerBase;
|
|
2
|
-
|
|
3
|
-
class HomeController extends ControllerBase {
|
|
4
|
-
index(req, res) {
|
|
5
|
-
res.render('index.html', { title: 'Inicio - JERK QA App', message: 'Bienvenido a la aplicación de prueba de JERK Framework' });
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
module.exports = new HomeController();
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
const ControllerBase = require('../../index.js').ControllerBase;
|
|
2
|
-
const { MemoryAdapter } = require('../../index.js');
|
|
3
|
-
|
|
4
|
-
// Crear instancia del modelo fuera del controlador
|
|
5
|
-
const memoryAdapter = new MemoryAdapter();
|
|
6
|
-
const UserModel = require('../models/UserModel.js');
|
|
7
|
-
const userModelInstance = new UserModel({ adapter: memoryAdapter });
|
|
8
|
-
|
|
9
|
-
class UserController extends ControllerBase {
|
|
10
|
-
constructor() {
|
|
11
|
-
super();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async indexView(req, res) {
|
|
15
|
-
try {
|
|
16
|
-
// Usar el modelo para obtener usuarios
|
|
17
|
-
const users = await userModelInstance.find({});
|
|
18
|
-
|
|
19
|
-
// Renderizar la vista con los usuarios
|
|
20
|
-
res.render('users.html', { users });
|
|
21
|
-
} catch (error) {
|
|
22
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
23
|
-
res.end(JSON.stringify({ success: false, error: error.message }));
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async getAllUsers(req, res) {
|
|
28
|
-
try {
|
|
29
|
-
// Usar el modelo para obtener usuarios
|
|
30
|
-
const users = await userModelInstance.find({});
|
|
31
|
-
|
|
32
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
33
|
-
res.end(JSON.stringify({ success: true, data: users }));
|
|
34
|
-
} catch (error) {
|
|
35
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
36
|
-
res.end(JSON.stringify({ success: false, error: error.message }));
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async getUserById(req, res) {
|
|
41
|
-
try {
|
|
42
|
-
const userId = req.params.id;
|
|
43
|
-
|
|
44
|
-
// Usar el modelo para encontrar un usuario específico
|
|
45
|
-
const user = await userModelInstance.findOne({ id: userId });
|
|
46
|
-
|
|
47
|
-
if (!user) {
|
|
48
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
49
|
-
res.end(JSON.stringify({ success: false, error: 'Usuario no encontrado' }));
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
54
|
-
res.end(JSON.stringify({ success: true, data: user }));
|
|
55
|
-
} catch (error) {
|
|
56
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
57
|
-
res.end(JSON.stringify({ success: false, error: error.message }));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async createUser(req, res) {
|
|
62
|
-
try {
|
|
63
|
-
// Usar el modelo para crear un nuevo usuario
|
|
64
|
-
const userData = req.body;
|
|
65
|
-
const newUser = await userModelInstance.createUser(userData);
|
|
66
|
-
|
|
67
|
-
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
68
|
-
res.end(JSON.stringify({ success: true, data: newUser }));
|
|
69
|
-
} catch (error) {
|
|
70
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
71
|
-
res.end(JSON.stringify({ success: false, error: error.message }));
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
module.exports = new UserController();
|
package/qa-app/hooks-config.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
const { hooks } = require('../index.js');
|
|
2
|
-
|
|
3
|
-
// Hook para registrar cada solicitud recibida
|
|
4
|
-
hooks.addAction('request_received', (req, res) => {
|
|
5
|
-
console.log(`[${new Date().toISOString()}] Nueva solicitud: ${req.method} ${req.url}`);
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
// Hook para registrar cada ruta encontrada
|
|
9
|
-
hooks.addAction('route_matched', (matchedRoute, req, res) => {
|
|
10
|
-
if (matchedRoute && typeof matchedRoute === 'object' && matchedRoute.route && matchedRoute.route.path) {
|
|
11
|
-
console.log(`[${new Date().toISOString()}] Ruta encontrada: ${req.method} ${req.url} -> ${matchedRoute.route.path}`);
|
|
12
|
-
} else {
|
|
13
|
-
console.log(`[${new Date().toISOString()}] Ruta encontrada: ${req.method} ${req.url} -> Información incompleta`);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
// Hook para registrar cada ruta no encontrada
|
|
18
|
-
hooks.addAction('route_not_found', (pathname, req, res) => {
|
|
19
|
-
console.log(`[${new Date().toISOString()}] Ruta no encontrada: ${pathname}`);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Hook para registrar cada solicitud procesada
|
|
23
|
-
hooks.addAction('request_processed', (req, res) => {
|
|
24
|
-
console.log(`[${new Date().toISOString()}] Solicitud procesada: ${req.method} ${req.url}`);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Filter para modificar el cuerpo de la solicitud antes de crear un usuario
|
|
28
|
-
hooks.addFilter('model_before_create', (data, modelName) => {
|
|
29
|
-
if (modelName === 'UserModel') {
|
|
30
|
-
// Añadir marca de tiempo de creación si no existe
|
|
31
|
-
if (!data.createdAt) {
|
|
32
|
-
data.createdAt = new Date().toISOString();
|
|
33
|
-
}
|
|
34
|
-
console.log(`[${new Date().toISOString()}] Preparando para crear usuario:`, data.username);
|
|
35
|
-
}
|
|
36
|
-
return data;
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
// Filter para modificar los datos después de encontrar un usuario
|
|
40
|
-
hooks.addFilter('model_after_find_one', (result, modelName) => {
|
|
41
|
-
if (modelName === 'UserModel' && result) {
|
|
42
|
-
console.log(`[${new Date().toISOString()}] Usuario encontrado:`, result.username);
|
|
43
|
-
}
|
|
44
|
-
return result;
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Hook para registrar cuando se crea un modelo
|
|
48
|
-
hooks.addAction('model_created', (modelName, modelInstance) => {
|
|
49
|
-
console.log(`[${new Date().toISOString()}] Modelo creado: ${modelName}`);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Hook para registrar cuando se registra un controlador con un modelo
|
|
53
|
-
hooks.addAction('controller_registered_with_model', (controllerName, modelName) => {
|
|
54
|
-
console.log(`[${new Date().toISOString()}] Controlador ${controllerName} registrado con modelo ${modelName}`);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// Filter para modificar los resultados antes de enviarlos al cliente
|
|
58
|
-
hooks.addFilter('pre_static_file_serve', (hookData) => {
|
|
59
|
-
console.log(`[${new Date().toISOString()}] Sirviendo archivo estático:`, hookData.req.url);
|
|
60
|
-
return hookData;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
module.exports = { setupHooks: () => {
|
|
64
|
-
console.log('Hooks y filters configurados correctamente');
|
|
65
|
-
}};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const { ModelBase } = require('../../index.js');
|
|
2
|
-
|
|
3
|
-
class UserModel extends ModelBase {
|
|
4
|
-
constructor(options = {}) {
|
|
5
|
-
super({
|
|
6
|
-
...options,
|
|
7
|
-
tableName: options.tableName || 'users'
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
// Definir campos del modelo
|
|
11
|
-
this.fields = {
|
|
12
|
-
id: { type: 'integer', primaryKey: true, autoIncrement: true },
|
|
13
|
-
username: { type: 'string', required: true },
|
|
14
|
-
email: { type: 'string', required: true },
|
|
15
|
-
createdAt: { type: 'datetime', default: 'CURRENT_TIMESTAMP' }
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Método personalizado para encontrar usuario por email
|
|
20
|
-
async findByEmail(email) {
|
|
21
|
-
return await this.findOne({ email });
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Método personalizado para crear usuario con validación
|
|
25
|
-
async createUser(userData) {
|
|
26
|
-
// Validar datos antes de crear
|
|
27
|
-
const validation = this.validate('create', userData);
|
|
28
|
-
if (!validation.isValid) {
|
|
29
|
-
throw new Error(`Validación fallida: ${validation.errors.join(', ')}`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return await this.create(userData);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
module.exports = UserModel;
|