rss2/bugs.md

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-19
  • backend/internal/handlers/news.go:14-28
  • frontend/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 usa titulo
  • Modelo usa Summary, BD usa resumen
  • Modelo usa ImageURL, BD usa imagen
  • Modelo usa PublishedAt, BD usa fecha

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:

  1. db.Connect() en backend/internal/db/postgres.go:13
  2. workers.Connect() en backend/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

  1. Unificar JWT Secret: Usar un único package para manejar el secret
  2. Implementar Rate Limiting: Usar una librería como golang.org/x/time/rate
  3. Configurar CORS correctamente: Usar variable de entorno para orígenes permitidos
  4. Forzar Secret Key: Hacer requerida la variable SECRET_KEY

Media Prioridad

  1. Traducir idioma configurable: Pasar idioma como parámetro o configuración
  2. Usar migraciones: Implementar golang-migrate
  3. Añadir tests: Crear tests unitarios para handlers críticos
  4. Corregir mapeo de campos: Estandarizar snake_case en toda la aplicación

Baja Prioridad

  1. Implementar LoggerMiddleware: Añadir logging real
  2. Implementar findFeedLinksInHTML: Usar goquery para parsing HTML
  3. 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 - usa titulo, resumen
  • backend/internal/models/models.go - usa Title, 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 de db.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 usa config.Load().DockerComposeDir
  • server/main.go:113 - Ahora usa cfg.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)

  1. Unificar JWT Secret
  2. Implementar Rate Limiting
  3. Configurar CORS correctamente: Usar variable de entorno
  4. Corregir manejo de errores: No ignorar silenciosamente
  5. Eliminar rutas hardcodeadas

Media Prioridad

  1. Idioma traducciones configurable
  2. Usar migraciones
  3. Añadir tests
  4. Corregir mapeo de campos

Baja Prioridad

  1. Implementar LoggerMiddleware
  2. Implementar findFeedLinksInHTML
  3. Consolidar DB
  4. Estandarizar respuestas API
  5. Añadir health checks