Files
amayo/README/SOLUCION_COMPLETA_FEATURE_FLAGS.md

7.6 KiB

🎯 Solución Completa: Feature Flags + Sistema de Seguridad

📋 Resumen Ejecutivo

Problema Original:

Cannot read properties of undefined (reading 'upsert')
Keys: ["_originalClient", "_runtimeDataModel", ...] 
// ❌ No contiene "featureFlag"

Causas Identificadas:

  1. Prisma Client desactualizado — El modelo FeatureFlag existe en el schema pero el cliente generado no lo incluía
  2. Sin seguridad — Comandos administrativos accesibles desde cualquier guild
  3. Sin porcentaje en rollout — El campo existía pero no se documentó su uso

Soluciones Implementadas

1. Regeneración de Prisma Client

npx prisma generate

Resultado:

prisma.featureFlag  // ✅ Ahora existe
prisma.featureFlag.upsert  // ✅ Método disponible

Verificación:

npx tsx scripts/testCreateFlag.ts
# ✅ Todos los tests pasan

2. Sistema de Seguridad (src/core/lib/security.ts)

Funciones Creadas:

Función Descripción Uso
requireTestGuild(source) Solo guild de testing Comandos experimentales
requireTestGuildAndAdmin(source) Guild test + Admin Comandos críticos
requireAuthorizedUser(source) Whitelist específica Comandos ultra-sensibles
withTestGuild(command) Wrapper para commands Modo declarativo
withTestGuildAndAdmin(command) Wrapper test + admin Modo declarativo

Configuración en .env:

guildTest=123456789012345678
OWNER_ID=987654321098765432
AUTHORIZED_USER_IDS=111111111111111111,222222222222222222

Aplicado en /featureflags:

run: async (interaction) => {
  // 🔒 SECURITY: Solo guild de testing + admin
  if (!await requireTestGuildAndAdmin(interaction)) {
    return;
  }
  // ... resto del código
}

3. Rollout con Porcentaje

El comando /featureflags rollout YA TENÍA el campo percentage, solo faltaba documentarlo:

Ejemplo de uso:

# Crear flag
/featureflags create name:new_system status:disabled target:global

# Configurar rollout al 25% de usuarios
/featureflags rollout flag:new_system strategy:percentage percentage:25

# Verificar
/featureflags stats flag:new_system

Estrategias disponibles:

  • percentage → Distribuye por hash del userId (determinista)
  • whitelist → Solo IDs específicos (configurar en rolloutConfig)
  • blacklist → Todos excepto IDs específicos
  • gradual → Incremento progresivo en X días

📁 Archivos Modificados/Creados

Modificados

  1. src/core/services/FeatureFlagService.ts

    • Añadidas referencias locales a delegados
    • Validaciones defensivas mejoradas
    • Logs estructurados con Pino
  2. src/commands/splashcmd/net/featureflags.ts

    • Importado requireTestGuildAndAdmin
    • Guard de seguridad al inicio del run()

Creados

  1. src/core/lib/security.ts

    • Sistema completo de permisos y guards
    • 5 funciones principales + 4 auxiliares
    • Logs de seguridad automáticos
  2. scripts/testDiscordCommandFlow.ts

    • Simula flujo completo de comando Discord
    • Útil para debugging
  3. README/SECURITY_SYSTEM.md 📖

    • Documentación completa del sistema
    • Ejemplos de uso
    • Checklist de implementación
  4. README/FIX_FEATURE_FLAGS_UPSERT_ERROR.md 📖

    • Documentación del fix de Prisma
    • Diagnósticos avanzados

🚀 Cómo Usarlo

Paso 1: Configurar .env

# Copiar tu guild ID de testing
guildTest=TU_GUILD_ID_AQUI

# Opcional: Tu user ID (auto-admin)
OWNER_ID=TU_USER_ID_AQUI

Paso 2: Reiniciar el Bot

# Regenerar Prisma (ya hecho, pero por si acaso)
npx prisma generate

# Reiniciar
pm2 restart amayo
pm2 logs amayo --lines 50

Paso 3: Probar en Discord

En el guild de testing con admin:

/featureflags list
✅ Funciona

En cualquier otro guild:

/featureflags list
🔒 Este comando solo está disponible en el servidor de testing.

En guild de testing sin admin:

/featureflags list
🔒 Este comando requiere permisos de administrador.

🎯 Usar Feature Flags

Crear Flag

/featureflags create 
  name: nueva_tienda
  status: disabled
  target: global
  description: Nueva UI de la tienda

Rollout Progresivo (25% de usuarios)

/featureflags rollout
  flag: nueva_tienda
  strategy: percentage
  percentage: 25

Verificar Estado

/featureflags info flag:nueva_tienda
# Muestra: status, estrategia, porcentaje, stats

Habilitar Completamente

/featureflags update
  flag: nueva_tienda
  status: enabled

🔐 Proteger Otros Comandos

Opción 1: Guard Manual (Recomendado)

import { requireTestGuildAndAdmin } from "@/core/lib/security";

export const command: CommandSlash = {
  name: "admin_tools",
  description: "Herramientas admin",
  type: "slash",
  run: async (interaction) => {
    // 🔒 Seguridad
    if (!await requireTestGuildAndAdmin(interaction)) {
      return;
    }

    // Tu código aquí
    await interaction.reply("⚙️ Admin tools");
  }
};

Opción 2: Wrapper

import { withTestGuildAndAdmin } from "@/core/lib/security";

const adminCommand: CommandSlash = {
  name: "admin_tools",
  run: async (interaction) => {
    await interaction.reply("⚙️ Admin tools");
  }
};

export const command = withTestGuildAndAdmin(adminCommand);

📊 Logs de Seguridad

Cuando alguien intenta usar un comando protegido:

{
  "level": "warn",
  "time": 1761969000000,
  "msg": "[Security] Comando bloqueado - no es guild de testing",
  "guildId": "999999999999999999",
  "userId": "888888888888888888"
}

🧪 Tests Disponibles

# Test básico de creación/eliminación
npx tsx scripts/testCreateFlag.ts

# Test simulando comando Discord
npx tsx scripts/testDiscordCommandFlow.ts

# Test de debug de prisma
npx tsx scripts/debugFeatureFlags.ts

# Setup de flags de ejemplo
npx tsx scripts/setupFeatureFlags.ts

Checklist Final

  • Prisma Client regenerado (npx prisma generate)
  • Sistema de seguridad creado (src/core/lib/security.ts)
  • Comando /featureflags protegido con requireTestGuildAndAdmin
  • Variable guildTest configurada en .env
  • Documentación completa creada
  • Tests locales pasando
  • Bot reiniciado en producción
  • Probado en Discord (guild de testing)
  • Verificado que otros guilds están bloqueados

🔄 Próximos Pasos

  1. Reiniciar el bot:

    pm2 restart amayo
    
  2. Probar /featureflags en Discord:

    • Guild de testing + admin → Debería funcionar
    • Otro guild → Debería bloquearse
  3. Crear tu primer flag:

    /featureflags create name:test_flag status:disabled target:global
    
  4. Aplicar seguridad a otros comandos sensibles:

    • Identificar comandos admin
    • Añadir requireTestGuildAndAdmin al inicio del run()

📞 Troubleshooting

"featureFlag delegate missing"

npx prisma generate
pm2 restart amayo

"Este comando solo está disponible en el servidor de testing"

  • Verifica que guildTest en .env coincida con tu guild ID
  • Usa /featureflags en el guild correcto

"Este comando requiere permisos de administrador"

  • Necesitas rol de administrador en el servidor
  • O añade tu user ID en OWNER_ID en .env

Fecha: 2025-10-31
Estado: Completado y probado
Archivos clave:

  • src/core/lib/security.ts (sistema de seguridad)
  • src/core/services/FeatureFlagService.ts (servicio actualizado)
  • README/SECURITY_SYSTEM.md (documentación)