11 KiB
Análisis de Errores e Inconsistencias - RSS2
Fecha de análisis: 2026-04-01
Resumen Ejecutivo
Se han identificado 13 problemas clasificados en:
- 3 Errores Críticos
- 7 Inconsistencias
- 3 Warnings de Arquitectura
1. Errores Críticos
1.1 Rate Limiting No Implementado
Ubicación: backend/internal/middleware/auth.go:104-108
Descripción: La función existe pero no hace nada:
func RateLimitMiddleware(requestsPerMinute int) gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
}
}
Problema: No implementa ningún tipo de limitación de rate. Vulnerable a ataques de fuerza bruta y DoS.
Impacto: Alto - Seguridad comprometida.
1.2 CORS Demasiado Permisivo
Ubicación: backend/internal/middleware/auth.go:77-90
Descripción:
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
Problema: Permite cualquier origen, lo cual es inseguro para APIs de producción. Permite ataques CSRF y expone datos a orígenes maliciosos.
Impacto: Alto - Seguridad comprometida.
1.3 Secret Key Por Defecto Hardcodeada
Ubicación: backend/internal/config/config.go:32
Descripción:
SecretKey: getEnv("SECRET_KEY", "change-this-secret-key"),
Problema: Si no se proporciona la variable de entorno, la aplicación usa una clave por defecto conocida. Cualquier despliegue sin configurar esta variable es vulnerable.
Impacto: Crítico - Compromiso total de autenticación.
2. Inconsistencias
2.1 Mapeo de Campos Inconsistente (Snake Case vs Camel Case)
Descripción: La aplicación usa convenciones de nomenclatura diferentes en distintas capas:
| Capa | Estructura | Ejemplo |
|---|---|---|
| Models | Snake case | Title, Summary, ImageURL |
| Handlers | Pascal case | Titulo, Resumen, ImagenURL |
| Frontend TS | camelCase | titulo, resumen, imagen_url |
Archivos afectados:
backend/internal/models/models.go:7-19backend/internal/handlers/news.go:14-28frontend/src/services/api.ts:20-34
Problema: Dificulta el mantenimiento y genera potenciales errores de serialización.
2.2 Idioma de Traducción Hardcodeado
Descripción:
El idioma destino de traducción (es) está hardcodeado en múltiples lugares:
news.go:67:
where += " AND t.status = 'done' AND t.titulo_trad IS NOT NULL"
news.go:96:
LEFT JOIN traducciones t ON t.noticia_id = n.id AND t.lang_to = 'es'
search.go:34-37:
if lang == "" {
lang = "es"
}
Problema: No es configurable. Si se quiere traducir a otros idiomas, requiere cambios en múltiples archivos.
2.3 Columna role en Users Sin映射 en Modelo
Descripción:
Se añade una columna role a la tabla users:
cmd/server/main.go:41-48:
_, err = db.GetPool().Exec(ctx, `
ALTER TABLE users ADD COLUMN IF NOT EXISTS role VARCHAR(20) DEFAULT 'user'
`)
Pero el modelo User no tiene este campo:
models/models.go:86-94:
type User struct {
ID int64 `json:"id"`
Email string `json:"email"`
Username string `json:"username"`
PasswordHash string `json:"-"`
IsAdmin bool `json:"is_admin"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Problema:
La columna role nunca se usa realmente. Hay dos campos (role y is_admin) que pueden causar confusión.
2.4 Feature No Implementada en Discovery
Ubicación: backend/cmd/discovery/main.go:129-133
Descripción:
func findFeedLinksInHTML(baseURL string) ([]string, error) {
// Simple feed link finder - returns empty for now
// In production, use goquery to parse HTML and find RSS/Atom links
return []string{}, nil
}
Problema: El worker de discovery no puede encontrar feeds RSS embebidos en páginas HTML. Solo detecta feeds directos.
Impacto: Medio - Reduce la efectividad del descubrimiento de feeds.
2.5 LoggerMiddleware No Funcional
Ubicación: backend/internal/middleware/auth.go:93-101
Descripción:
func LoggerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
status := c.Writer.Status()
if status >= 400 {
// Log error responses - pero no hace nada!
}
}
}
Problema: El logging de errores está commented out. No se registra nada.
2.6 Columnas de BD Diferentes a Modelos
Descripción:
El handler search.go referencia columnas que no existen en los modelos:
search.go:91-92:
SELECT n.id, n.titulo, n.resumen, n.contenido, n.url, n.imagen,
n.feed_id, n.lang, n.categoria_id, n.pais_id, n.created_at, n.updated_at,
Pero en models.go:7-19:
type News struct {
ID int64 `json:"id"`
Title string `json:"title"`
Summary string `json:"summary"`
Content string `json:"content"`
URL string `json:"url"`
ImageURL *string `json:"image_url"`
PublishedAt *time.Time `json:"published_at"`
Lang string `json:"lang"`
FeedID int64 `json:"feed_id"`
...
}
Problema:
- Modelo usa
Title, BD usatitulo - Modelo usa
Summary, BD usaresumen - Modelo usa
ImageURL, BD usaimagen - Modelo usa
PublishedAt, BD usafecha
Esto causa errores de serialización potenciales.
2.7 Inicialización de Base de Datos Duplicada
Descripción: Existen dos formas de conectar a la base de datos:
db.Connect()enbackend/internal/db/postgres.go:13workers.Connect()enbackend/internal/workers/db.go
Problema: Códigos duplicados que mantienen conexiones separadas. Puede causar problemas de pool de conexiones.
3. Warnings de Arquitectura
3.1 Creación de Tablas en Runtime
Ubicación: backend/cmd/server/main.go:20-77
Descripción: En lugar de usar migraciones formales, el servidor crea tablas al iniciar:
func initDB() {
_, err := db.GetPool().Exec(ctx, `
CREATE TABLE IF NOT EXISTS entity_aliases (...)
`)
// más tablas...
}
Problema:
- No hay control de versiones
- No hay rollback
- Difícil de mantener en producción
Recomendación: Usar golang-migrate o similar.
3.2 No Hay Tests Unitarios
Descripción:
No se encontraron archivos *_test.go en el código backend.
Problema: Sin tests, cualquier cambio puede romper funcionalidad existente sin detección.
3.3 Pool de Conexiones Sin Validación Periódica
Ubicación: backend/internal/db/postgres.go
Descripción: El pool se crea pero no hay health check periódico.
Problema: Las conexiones zombie pueden acumularse sin detección.
4. Recomendaciones de Corrección
Alta Prioridad
- Unificar JWT Secret: Usar un único package para manejar el secret
- Implementar Rate Limiting: Usar una librería como
golang.org/x/time/rate - Configurar CORS correctamente: Usar variable de entorno para orígenes permitidos
- Forzar Secret Key: Hacer requerida la variable
SECRET_KEY
Media Prioridad
- Traducir idioma configurable: Pasar idioma como parámetro o configuración
- Usar migraciones: Implementar golang-migrate
- Añadir tests: Crear tests unitarios para handlers críticos
- Corregir mapeo de campos: Estandarizar snake_case en toda la aplicación
Baja Prioridad
- Implementar LoggerMiddleware: Añadir logging real
- Implementar findFeedLinksInHTML: Usar goquery para parsing HTML
- Consolidar DB: Unificar inicialización de base de datos
5. Estadísticas
| Tipo | Cantidad |
|---|---|
| Errores Críticos | 3 |
| Inconsistencias | 7 |
| Warnings | 3 |
| Total | 13 |
6. Problemas Adicionales Detectados
6.1 Mapeo de Campos Inconsistente (Frontend)
Descripción: El frontend usa snake_case pero los modelos Go usan PascalCase.
Archivos:
frontend/src/services/api.ts- usatitulo,resumenbackend/internal/models/models.go- usaTitle,Summary
6.2 Structs Duplicados para Mismo Recurso
Descripción: handlers/news.go define NewsResponse diferente a models/models.go:News.
6.3 Query Params Inconsistentes
Descripción: Algunos handlers usan category_id (inglés) y otros categoria_id (español).
6.4 Duplicación Config DB
Descripción: API usa DATABASE_URL, workers usan DB_HOST, DB_PORT, etc.
6.5 Sin Health Checks en Workers
Descripción: Workers no implementan endpoint /health.
6.6 Manejo de Errores Inconsistente
Descripción: Mezcla de gin.H{"error": ...} y models.ErrorResponse.
7. Errores y Problemas Críticos Detectados
7.1 Errores Ignorados Silenciosamente (RESUELTO)
Descripción: Múltiples lugares donde errores eran ignorados sin logging.
Ejemplos corregidos:
admin.go:488-492- Ahora verifica errores dedb.GetPool().Exec()admin.go:522- Verifica error al actualizar estado
Impacto: Fallos silenciosos que pasan desapercibidos.
7.2 Rutas Hardcodeadas (RESUELTO)
Descripción: Rutas de archivos hardcodeadas en el código.
Correcciones:
admin.go:469,474,509- Ahora usaconfig.Load().DockerComposeDirserver/main.go:113- Ahora usacfg.WikiImagesPath- Añadidos nuevos campos en config:
DockerComposeDir,WikiImagesPath
7.3 Secret Key Por Defecto
Descripción: config.go:32 usa clave por defecto known.
SecretKey: getEnv("SECRET_KEY", "change-this-secret-key")
Impacto: Medio - Si no se configura, usar clave insegura.
7.4 Rate Limiting No Implementado
Descripción: middleware/auth.go:104-108 tiene función vacía.
Impacto: Alto - Vulnerable a ataques de fuerza bruta.
7.5 CORS Demasiado Permisivo
Descripción: middleware/auth.go:79 permite cualquier origen.
Impacto: Alto - Expuesto a ataques CSRF.
8. Recomendaciones de Corrección (Actualizado)
Alta Prioridad (CRÍTICO)
Unificar JWT Secret✅- Implementar Rate Limiting
Configurar CORS correctamente: Usar variable de entorno✅Corregir manejo de errores: No ignorar silenciosamente✅Eliminar rutas hardcodeadas✅
Media Prioridad
- Idioma traducciones configurable
- Usar migraciones
- Añadir tests
- Corregir mapeo de campos
Baja Prioridad
- Implementar LoggerMiddleware
- Implementar findFeedLinksInHTML
- Consolidar DB
- Estandarizar respuestas API
- Añadir health checks