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:
- Prisma Client desactualizado — El modelo
FeatureFlagexiste en el schema pero el cliente generado no lo incluía - Sin seguridad — Comandos administrativos accesibles desde cualquier guild
- 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íficosgradual→ Incremento progresivo en X días
📁 Archivos Modificados/Creados
Modificados
-
src/core/services/FeatureFlagService.ts- Añadidas referencias locales a delegados
- Validaciones defensivas mejoradas
- Logs estructurados con Pino
-
src/commands/splashcmd/net/featureflags.ts- Importado
requireTestGuildAndAdmin - Guard de seguridad al inicio del
run()
- Importado
Creados
-
src/core/lib/security.ts⭐- Sistema completo de permisos y guards
- 5 funciones principales + 4 auxiliares
- Logs de seguridad automáticos
-
scripts/testDiscordCommandFlow.ts- Simula flujo completo de comando Discord
- Útil para debugging
-
README/SECURITY_SYSTEM.md📖- Documentación completa del sistema
- Ejemplos de uso
- Checklist de implementación
-
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
/featureflagsprotegido conrequireTestGuildAndAdmin - Variable
guildTestconfigurada 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
-
Reiniciar el bot:
pm2 restart amayo -
Probar
/featureflagsen Discord:- Guild de testing + admin → ✅ Debería funcionar
- Otro guild → ❌ Debería bloquearse
-
Crear tu primer flag:
/featureflags create name:test_flag status:disabled target:global -
Aplicar seguridad a otros comandos sensibles:
- Identificar comandos admin
- Añadir
requireTestGuildAndAdminal inicio delrun()
📞 Troubleshooting
"featureFlag delegate missing"
npx prisma generate
pm2 restart amayo
"Este comando solo está disponible en el servidor de testing"
- Verifica que
guildTesten.envcoincida con tu guild ID - Usa
/featureflagsen el guild correcto
"Este comando requiere permisos de administrador"
- Necesitas rol de administrador en el servidor
- O añade tu user ID en
OWNER_IDen.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)