From ebd2704e682bd482fe92ddef4867c374b27ff5a3 Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Sun, 17 Aug 2025 22:06:13 +0900
Subject: [PATCH 1/9] feat: add none to enforcement entries
---
 pages/addbot.tsx         | 32 +++++++++++++++++++++-----------
 pages/bots/[id]/edit.tsx | 32 +++++++++++++++++++++-----------
 utils/Constants.ts       |  4 ++++
 utils/Query.ts           |  4 ++--
 4 files changed, 48 insertions(+), 24 deletions(-)
diff --git a/pages/addbot.tsx b/pages/addbot.tsx
index beb642df95..efe2b01659 100644
--- a/pages/addbot.tsx
+++ b/pages/addbot.tsx
@@ -367,20 +367,30 @@ const AddBot: NextPage = ({ logged, user, csrfToken, theme }) => {
 							}
 						>
 							 ({
-									label: v.label,
-									value: k,
-								}))}
-								handleChange={(value) => {
-									setFieldValue(
-										'enforcements',
-										value.map((v) => v.value)
-									)
+								options={Object.entries(botEnforcements)
+									.filter(([k, v]) => k === 'NONE' || !values.enforcements.includes('NONE'))
+									.map(([k, v]) => ({
+										label: v.label,
+										value: k,
+									}))}
+								handleChange={(values) => {
+									if (values.some((i) => i.value === 'NONE')) {
+										setFieldValue('enforcements', ['NONE'])
+									} else {
+										setFieldValue(
+											'enforcements',
+											values.map((v) => v.value)
+										)
+									}
 								}}
 								handleTouch={() => setFieldTouched('enforcements', true)}
 								values={values.enforcements ?? ([] as string[])}
-								setValues={(value) => {
-									setFieldValue('enforcements', value)
+								setValues={(values) => {
+									if (values.includes('NONE')) {
+										setFieldValue('enforcements', ['NONE'])
+									} else {
+										setFieldValue('enforcements', values)
+									}
 								}}
 							/>
 						
diff --git a/pages/bots/[id]/edit.tsx b/pages/bots/[id]/edit.tsx
index 4dbf03bc04..57360743ad 100644
--- a/pages/bots/[id]/edit.tsx
+++ b/pages/bots/[id]/edit.tsx
@@ -339,20 +339,30 @@ const ManageBotPage: NextPage = ({ bot, user, csrfToken, theme }
 							}
 						>
 							 ({
-									label: v.label,
-									value: k,
-								}))}
-								handleChange={(value) => {
-									setFieldValue(
-										'enforcements',
-										value.map((v) => v.value)
-									)
+								options={Object.entries(botEnforcements)
+									.filter(([k, v]) => k === 'NONE' || !values.enforcements.includes('NONE'))
+									.map(([k, v]) => ({
+										label: v.label,
+										value: k,
+									}))}
+								handleChange={(values) => {
+									if (values.some((i) => i.value === 'NONE')) {
+										setFieldValue('enforcements', ['NONE'])
+									} else {
+										setFieldValue(
+											'enforcements',
+											values.map((v) => v.value)
+										)
+									}
 								}}
 								handleTouch={() => setFieldTouched('enforcements', true)}
 								values={values.enforcements ?? ([] as string[])}
-								setValues={(value) => {
-									setFieldValue('enforcements', value)
+								setValues={(values) => {
+									if (values.includes('NONE')) {
+										setFieldValue('enforcements', ['NONE'])
+									} else {
+										setFieldValue('enforcements', values)
+									}
 								}}
 							/>
 						
diff --git a/utils/Constants.ts b/utils/Constants.ts
index fbda29880b..ac7db24838 100644
--- a/utils/Constants.ts
+++ b/utils/Constants.ts
@@ -121,6 +121,10 @@ export const botCategoryDescription = {
 }
 
 export const botEnforcements = {
+	NONE: {
+		label: '해당사항이 없습니다.',
+		description: '',
+	},
 	JOIN_PARTIALLY_ENFORCED: {
 		label: '서버 참여가 필요한 기능이 있습니다',
 		description: '봇의 일부 명령어는 봇의 디스코드 서버에 참여해야 사용할 수 있습니다.',
diff --git a/utils/Query.ts b/utils/Query.ts
index ce26ab4e6c..09f82f2e4d 100644
--- a/utils/Query.ts
+++ b/utils/Query.ts
@@ -641,7 +641,7 @@ async function submitBot(
 		git: data.git,
 		url: data.url,
 		category: JSON.stringify(data.category),
-		enforcements: JSON.stringify(data.enforcements),
+		enforcements: JSON.stringify(data.enforcements.filter((el) => el !== 'NONE')),
 		discord: data.discord,
 		state: 0,
 	})
@@ -751,7 +751,7 @@ async function updateBot(id: string, data: ManageBot): Promise {
 			intro: data.intro,
 			desc: data.desc,
 			vanity: data.vanity,
-			enforcements: JSON.stringify(data.enforcements),
+			enforcements: JSON.stringify(data.enforcements.filter((el) => el !== 'NONE')),
 			banner: data.banner,
 			bg: data.bg,
 		})
From ac68917a74fac7431a576d503ac9dbadd2375ea1 Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Sun, 17 Aug 2025 22:07:31 +0900
Subject: [PATCH 2/9] chore: clarify join enforced description
---
 utils/Constants.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/utils/Constants.ts b/utils/Constants.ts
index ac7db24838..526bdc4fdf 100644
--- a/utils/Constants.ts
+++ b/utils/Constants.ts
@@ -127,11 +127,11 @@ export const botEnforcements = {
 	},
 	JOIN_PARTIALLY_ENFORCED: {
 		label: '서버 참여가 필요한 기능이 있습니다',
-		description: '봇의 일부 명령어는 봇의 디스코드 서버에 참여해야 사용할 수 있습니다.',
+		description: '봇의 일부 명령어는 특정한 디스코드 서버에 참여해야 사용할 수 있습니다.',
 	},
 	JOIN_ENFORCED: {
 		label: '서버 참여 없이는 봇의 핵심 기능을 사용할 수 없습니다',
-		description: '봇의 핵심 기능은 봇의 디스코드 서버에 참여해야 사용할 수 있습니다.',
+		description: '봇의 핵심 기능은 특정한 디스코드 서버에 참여해야 사용할 수 있습니다.',
 	},
 	LICENSE_PARTIALLY_ENFORCED: {
 		label: '유료 구매가 필요한 기능이 있습니다',
From 0d65b22bc67446715056d7279fcc8dd4ec324e72 Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Sun, 17 Aug 2025 22:19:25 +0900
Subject: [PATCH 3/9] feat: add constant for enforcements
---
 utils/Yup.ts | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/utils/Yup.ts b/utils/Yup.ts
index 7f73e87cff..b1ede4197b 100644
--- a/utils/Yup.ts
+++ b/utils/Yup.ts
@@ -175,7 +175,10 @@ export const AddBotSubmitSchema: Yup.SchemaOf = Yup.object({
 		.min(100, '봇 설명은 최소 100자여야합니다.')
 		.max(1500, '봇 설명은 최대 1500자여야합니다.')
 		.required('봇 설명은 필수 항목입니다.'),
-	enforcements: Yup.array(Yup.string().oneOf(Object.keys(botEnforcements))),
+	enforcements: Yup.array(Yup.string().oneOf(Object.keys(botEnforcements)))
+		.min(1, '최소 한 개의 선택지를 선택해주세요.')
+		.unique('선택지는 중복될 수 없습니다.')
+		.required('강제사항 명시는 필수 선택사항입니다.'),
 	_csrf: Yup.string().required(),
 	_captcha: Yup.string().required(),
 })
@@ -306,7 +309,10 @@ export function getManageBotSchema(perkAvailable = false) {
 			.min(100, '봇 설명은 최소 100자여야합니다.')
 			.max(1500, '봇 설명은 최대 1500자여야합니다.')
 			.required('봇 설명은 필수 항목입니다.'),
-		enforcements: Yup.array(Yup.string().oneOf(Object.keys(botEnforcements))),
+		enforcements: Yup.array(Yup.string().oneOf(Object.keys(botEnforcements)))
+			.min(1, '최소 한 개의 선택지를 선택해주세요.')
+			.unique('선택지는 중복될 수 없습니다.')
+			.required('강제사항 명시는 필수 선택사항입니다.'),
 		_csrf: Yup.string().required(),
 	}
 
From d1703b669db189b3f43508635d00fc04bb4dbb20 Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Tue, 19 Aug 2025 00:26:23 +0900
Subject: [PATCH 4/9] fix: do not filter none
---
 utils/Query.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/utils/Query.ts b/utils/Query.ts
index 09f82f2e4d..ce26ab4e6c 100644
--- a/utils/Query.ts
+++ b/utils/Query.ts
@@ -641,7 +641,7 @@ async function submitBot(
 		git: data.git,
 		url: data.url,
 		category: JSON.stringify(data.category),
-		enforcements: JSON.stringify(data.enforcements.filter((el) => el !== 'NONE')),
+		enforcements: JSON.stringify(data.enforcements),
 		discord: data.discord,
 		state: 0,
 	})
@@ -751,7 +751,7 @@ async function updateBot(id: string, data: ManageBot): Promise {
 			intro: data.intro,
 			desc: data.desc,
 			vanity: data.vanity,
-			enforcements: JSON.stringify(data.enforcements.filter((el) => el !== 'NONE')),
+			enforcements: JSON.stringify(data.enforcements),
 			banner: data.banner,
 			bg: data.bg,
 		})
From 8ab66a32852481354c798f4c5860ec9ef9ea0558 Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Tue, 19 Aug 2025 00:43:44 +0900
Subject: [PATCH 5/9] fix: do not show message when none is set
---
 pages/bots/[id]/index.tsx | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/pages/bots/[id]/index.tsx b/pages/bots/[id]/index.tsx
index b342930a08..5450d02d2d 100644
--- a/pages/bots/[id]/index.tsx
+++ b/pages/bots/[id]/index.tsx
@@ -116,13 +116,15 @@ const Bots: NextPage = ({ data, desc, date, user, theme, csrfToken })
 										로 문의해주세요.
 									
 								
-							) : data.enforcements.length > 0 ? (
+							) : data.enforcements.filter((i) => i !== 'NONE').length > 0 ? (
 								
 									이 봇은 기능에 제한을 두고 있습니다.
 									
-										{data.enforcements.map((i) => (
-											
{botEnforcements[i].description}
-										))}
+										{data.enforcements
+											.filter((i) => i !== 'NONE')
+											.map((i) => (
+												{botEnforcements[i].description}
+											))}
 									
 								
 							) : (
From a9ee83acbc5e67e99820c9b9a5fc8fad9e47fef1 Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Tue, 19 Aug 2025 17:43:26 +0900
Subject: [PATCH 6/9] style: fix lint
---
 pages/addbot.tsx         | 2 +-
 pages/bots/[id]/edit.tsx | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pages/addbot.tsx b/pages/addbot.tsx
index efe2b01659..4e2cc72f43 100644
--- a/pages/addbot.tsx
+++ b/pages/addbot.tsx
@@ -368,7 +368,7 @@ const AddBot: NextPage = ({ logged, user, csrfToken, theme }) => {
 						>
 							 k === 'NONE' || !values.enforcements.includes('NONE'))
+									.filter(([k]) => k === 'NONE' || !values.enforcements.includes('NONE'))
 									.map(([k, v]) => ({
 										label: v.label,
 										value: k,
diff --git a/pages/bots/[id]/edit.tsx b/pages/bots/[id]/edit.tsx
index 57360743ad..5dddab5a84 100644
--- a/pages/bots/[id]/edit.tsx
+++ b/pages/bots/[id]/edit.tsx
@@ -340,7 +340,7 @@ const ManageBotPage: NextPage = ({ bot, user, csrfToken, theme }
 						>
 							 k === 'NONE' || !values.enforcements.includes('NONE'))
+									.filter(([k]) => k === 'NONE' || !values.enforcements.includes('NONE'))
 									.map(([k, v]) => ({
 										label: v.label,
 										value: k,
From 40c6c0fd89eb0ebc78467dd940ccef7f488494e3 Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Wed, 20 Aug 2025 17:09:18 +0900
Subject: [PATCH 7/9] chore: explicit next of dd-trace
---
 instrumentation.ts | 1 +
 1 file changed, 1 insertion(+)
diff --git a/instrumentation.ts b/instrumentation.ts
index ff193d2bfe..e9b461b0e3 100644
--- a/instrumentation.ts
+++ b/instrumentation.ts
@@ -7,5 +7,6 @@ export async function register() {
 			version: packageJson.version,
 			env: process.env.DD_ENV,
 		})
+		tracer.use('next')
 	}
 }
From 9f91729969d0a2c50583778aab9b5dd8554ef65e Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Wed, 20 Aug 2025 17:11:19 +0900
Subject: [PATCH 8/9] chore: improve wordings for join enforcements
---
 utils/Constants.ts | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/utils/Constants.ts b/utils/Constants.ts
index 526bdc4fdf..1c9f001364 100644
--- a/utils/Constants.ts
+++ b/utils/Constants.ts
@@ -127,11 +127,12 @@ export const botEnforcements = {
 	},
 	JOIN_PARTIALLY_ENFORCED: {
 		label: '서버 참여가 필요한 기능이 있습니다',
-		description: '봇의 일부 명령어는 특정한 디스코드 서버에 참여해야 사용할 수 있습니다.',
+		description:
+			'봇의 일부 명령어는 봇이 제공하는 특정 디스코드 서버에 참여해야 사용할 수 있습니다.',
 	},
 	JOIN_ENFORCED: {
 		label: '서버 참여 없이는 봇의 핵심 기능을 사용할 수 없습니다',
-		description: '봇의 핵심 기능은 특정한 디스코드 서버에 참여해야 사용할 수 있습니다.',
+		description: '봇의 핵심 기능은 봇이 제공하는 특정 디스코드 서버에 참여해야 사용할 수 있습니다.',
 	},
 	LICENSE_PARTIALLY_ENFORCED: {
 		label: '유료 구매가 필요한 기능이 있습니다',
From 79cda5c62ccba5ccf81b61844088ea3a6b218762 Mon Sep 17 00:00:00 2001
From: skinmaker1345 
Date: Wed, 20 Aug 2025 21:42:08 +0900
Subject: [PATCH 9/9] chore: clarify join enforced
---
 utils/Constants.ts | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/utils/Constants.ts b/utils/Constants.ts
index 1c9f001364..18d7209bf2 100644
--- a/utils/Constants.ts
+++ b/utils/Constants.ts
@@ -126,13 +126,12 @@ export const botEnforcements = {
 		description: '',
 	},
 	JOIN_PARTIALLY_ENFORCED: {
-		label: '서버 참여가 필요한 기능이 있습니다',
-		description:
-			'봇의 일부 명령어는 봇이 제공하는 특정 디스코드 서버에 참여해야 사용할 수 있습니다.',
+		label: '지정된 서버에 참여해야만 사용이 가능한 기능이 있습니다',
+		description: '봇의 일부 명령어는 봇이 지정한 특정 디스코드 서버에 참여해야 사용할 수 있습니다.',
 	},
 	JOIN_ENFORCED: {
-		label: '서버 참여 없이는 봇의 핵심 기능을 사용할 수 없습니다',
-		description: '봇의 핵심 기능은 봇이 제공하는 특정 디스코드 서버에 참여해야 사용할 수 있습니다.',
+		label: '지정된 서버에 참여하지 않으면 봇의 핵심 기능을 사용할 수 없습니다',
+		description: '봇의 핵심 기능은 봇이 지정한 특정 디스코드 서버에 참여해야 사용할 수 있습니다.',
 	},
 	LICENSE_PARTIALLY_ENFORCED: {
 		label: '유료 구매가 필요한 기능이 있습니다',