Bir discord moderasyon botu, büyüyen bir sunucuyu yönetilebilir tutmanın en pratik yoludur: kural ihlallerine saniyeler içinde yanıt verir, her işlemi kayıt altına alır ve yetkiyi yalnızca doğru kişilere bırakır. Bu yazıda discord.js v14 ile ban, kick ve mute (timeout) komutlarını sıfırdan kuruyoruz. Odağımız yalnızca komutların çalışması değil; yetki kontrolü, rol hiyerarşisi ve audit log nedenleri gibi gerçek sunucularda fark yaratan ayrıntılar.
Gerekli izinler ve intent'ler
Moderasyon komutları, botun üyeleri yönetebilmesini gerektirir. Discord Developer Portal'da botunuza Ban Members, Kick Members ve Moderate Members izinlerini verin. Moderate Members, timeout (mute) için zorunludur. Ayrıca üye verisine erişebilmek için kodda GuildMembers intent'ini açmanız ve portalda bu privileged intent'i etkinleştirmeniz gerekir.
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
],
});
Botun rolü, sunucu ayarlarında moderasyon yapacağı üyelerin rollerinden daha yukarıda olmalı. Discord, kendinden üst sıradaki bir üyeyi banlamasına izin vermez; bu kuralı kod tarafında da kontrol edeceğiz.
Komut tanımı ve varsayılan yetki
Slash komutlarını tanımlarken setDefaultMemberPermissions ile komutun varsayılan görünürlüğünü sınırlayabilirsiniz. Bu, izni olmayan üyelerin komutu menüde görmemesini sağlar; ancak bu yalnızca bir UI filtresidir, gerçek güvenlik kontrolünü çalışma anında yine kendiniz yapmalısınız.
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
const banCommand = new SlashCommandBuilder()
.setName('ban')
.setDescription('Bir üyeyi sunucudan yasaklar')
.addUserOption(o =>
o.setName('uye').setDescription('Yasaklanacak üye').setRequired(true))
.addStringOption(o =>
o.setName('sebep').setDescription('Yasaklama sebebi'))
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers);
Yetki ve hiyerarşi kontrolü
Her moderasyon komutunda iki şeyi doğrulamalısınız: komutu çalıştıran kişinin yetkisi ve rol hiyerarşisi. discord.js, bu kontrolü kolaylaştıran hazır getter'lar sunar: member.bannable, member.kickable ve member.moderatable. Bunlar hem botun yetkisini hem de rol sırasını dikkate alır. Yine de komutu çalıştıran moderatörün hedef üyeden üstte olduğunu da ayrıca denetlemek iyi bir alışkanlıktır.
function canModerate(interaction, target) {
const actor = interaction.member;
// Sunucu sahibi her şeyi yapabilir
if (actor.id === interaction.guild.ownerId) return true;
// Moderatör hedeften üstte mi?
return actor.roles.highest.comparePositionTo(target.roles.highest) > 0;
}
comparePositionTo pozitif dönerse actor daha üst sıradadır. Bu kontrolü atlamak, bir moderatörün kendinden yetkili birini banlamasına yol açabilir.
Ban, kick ve timeout uygulaması
Komutları tek bir handler altında topluyoruz. Dikkat edilecek nokta: audit log nedeni, ilgili metoda reason alanıyla geçirildiğinde Discord'un denetim kaydında görünür. Böylece "kim, kimi, neden" sorusu sonradan yanıtsız kalmaz.
client.on('interactionCreate', async (interaction) => {
if (!interaction.isChatInputCommand()) return;
const target = interaction.options.getMember('uye');
const sebep = interaction.options.getString('sebep') ?? 'Belirtilmedi';
if (!target) {
return interaction.reply({ content: 'Üye bulunamadı.', ephemeral: true });
}
if (!canModerate(interaction, target)) {
return interaction.reply({ content: 'Bu üyeyi moderate edemezsin.', ephemeral: true });
}
if (interaction.commandName === 'ban') {
if (!target.bannable) {
return interaction.reply({ content: 'Bu üyeyi banlayamıyorum.', ephemeral: true });
}
await target.ban({ reason: sebep, deleteMessageSeconds: 60 * 60 * 24 });
await interaction.reply(`🔨 ${target.user.tag} yasaklandı. Sebep: ${sebep}`);
}
if (interaction.commandName === 'kick') {
if (!target.kickable) {
return interaction.reply({ content: 'Bu üyeyi atamıyorum.', ephemeral: true });
}
await target.kick(sebep);
await interaction.reply(`👢 ${target.user.tag} sunucudan atıldı. Sebep: ${sebep}`);
}
if (interaction.commandName === 'mute') {
if (!target.moderatable) {
return interaction.reply({ content: 'Bu üyeyi susturamıyorum.', ephemeral: true });
}
const dakika = interaction.options.getInteger('dakika') ?? 10;
await target.timeout(dakika * 60 * 1000, sebep);
await interaction.reply(`🔇 ${target.user.tag} ${dakika} dakika susturuldu.`);
}
});
Burada mute için ayrı bir rol oluşturmuyoruz; Discord'un yerleşik timeout özelliğini kullanıyoruz. member.timeout() milisaniye cinsinden süre alır ve üst sınır 28 gündür. Süreyi null geçerek timeout'u kaldırabilirsiniz. Yerleşik timeout, ayrı "muted" rolü kurmaktan daha güvenilirdir çünkü kullanıcı yeni kanallara katılsa bile susturma geçerli kalır.
Hataları yutmayın
Ağ hatası, eksik izin veya zaten ayrılmış bir üye gibi durumlar gerçek hayatta sık görülür. Komutları bir try/catch içine alın ve kullanıcıya anlamlı bir mesaj dönün; konsola sessizce düşen hata, "bot çalışmıyor" şikâyetlerinin en yaygın sebebidir.
try {
await target.ban({ reason: sebep });
await interaction.reply(`🔨 ${target.user.tag} yasaklandı.`);
} catch (err) {
console.error(err);
await interaction.reply({ content: 'İşlem başarısız oldu.', ephemeral: true });
}
İyi uygulama notları
- Ephemeral yanıt: Hata ve yetki mesajlarını
ephemeral: trueile yalnızca komutu kullanan kişiye gösterin; kanalı kirletmez. - Sebep zorunluluğu: Ciddi işlemlerde sebebi
setRequired(true)yaparak moderatörü açıklama yazmaya zorlayın. - Ayrı log kanalı: Her moderasyon işlemini bir embed olarak özel bir log kanalına da gönderin; audit log'a ek olarak kalıcı bir kayıt olur.
- Kendini ve botu koru: Hedef, komutu çalıştıran kişiyle veya botun kendisiyle aynıysa işlemi reddedin.
Sık Sorulan Sorular
Mute için ayrı bir rol mü kurmalıyım?
Hayır. discord.js v14 ile Discord'un yerleşik timeout özelliğini (member.timeout()) kullanmak çok daha sağlamdır. Ayrı "muted" rolü kurmak, her kanalda izin ayarı gerektirir ve kullanıcı yeni kanallara katıldığında boşluk bırakabilir; timeout ise sunucu genelinde otomatik uygulanır.
Botum üst rütbeli üyeleri neden banlayamıyor?
Discord, bir botun veya üyenin yalnızca kendi en yüksek rolünün altında kalan üyeleri yönetmesine izin verir. Botun rolünü Sunucu Ayarları → Roller bölümünden ilgili üyelerin üzerine taşıyın. member.bannable getter'ı false dönüyorsa neredeyse her zaman sebep hiyerarşidir.
Audit log'a sebep nasıl yazdırılır?
İlgili metoda reason alanını geçmeniz yeterli: target.ban({ reason: 'Spam' }) ya da target.timeout(ms, 'Reklam'). Discord bu metni sunucunun denetim kaydında işlemin yanına ekler.
Sunucunuz için güvenli, yetki kontrollü bir moderasyon botu mu istiyorsunuz? Ban/kick/timeout, otomatik log kanalı ve anti-raid önlemleriyle birlikte kurulumunu birlikte planlayalım — benimle iletişime geçin.