Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,7 @@ tsconfig.tsbuildinfo
tsconfig.tsbuildinfo
# Sentry Config File
.env.sentry-build-plugin

# next-sitemap 생성 파일 (postbuild)
public/sitemap*.xml
public/robots.txt
44 changes: 44 additions & 0 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Binary file not shown.
Binary file not shown.
64 changes: 64 additions & 0 deletions next-sitemap.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* next-sitemap 설정
* 빌드 후 postbuild 스크립트로 실행되어 public/sitemap*.xml 과 public/robots.txt 를 생성한다.
* stage/prod 환경 분기는 NEXT_PUBLIC_API_PATH 에 'stage' 포함 여부로 판단 (src/static/url.ts 와 동일 규칙).
*/

const IS_STAGE = process.env.NEXT_PUBLIC_API_PATH?.includes('stage');
const SITE_URL = IS_STAGE ? 'https://stage.koreatech.in' : 'https://koreatech.in';

const PRIVATE_PATHS = [
'/auth',
'/auth/*',
'/webview/*',
'/report/*',
'/callvan/add',
'/callvan/chat/*',
'/callvan/notifications',
'/callvan/*/participants',
'/callvan/*/report/*',
'/timetable/modify',
'/clubs/new',
'/clubs/edit/*',
'/clubs/recruitment/edit/*',
'/clubs/*/event/edit/*',
'/lost-item/edit/*',
'/lost-item/report/*',
'/lost-item/chat',
'/store/review/*',
'/store/review/edit/**',
];

/** @type {import('next-sitemap').IConfig} */
export default {
siteUrl: SITE_URL,
generateRobotsTxt: true,
sitemapSize: 5000,
changefreq: 'daily',
priority: 0.7,
exclude: ['/404', '/_error', '/_app', '/_document', ...PRIVATE_PATHS],
robotsTxtOptions: {
policies: [
{
userAgent: '*',
allow: '/',
disallow: [
'/auth',
'/webview',
'/report',
'/callvan/add',
'/callvan/chat',
'/callvan/notifications',
'/timetable/modify',
'/clubs/new',
'/clubs/edit',
'/clubs/recruitment/edit',
'/lost-item/edit',
'/lost-item/report',
'/lost-item/chat',
'/store/review',
],
Comment on lines +39 to +60
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find . -name "next-sitemap.config.js" -o -name "*sitemap*" -type f | head -20

Repository: BCSDLab/KOIN_WEB_RECODE

Length of output: 1409


🏁 Script executed:

fd -e js -e ts -e json | grep -i "sitemap\|next.config" | head -20

Repository: BCSDLab/KOIN_WEB_RECODE

Length of output: 90


🏁 Script executed:

git ls-files | grep -i sitemap

Repository: BCSDLab/KOIN_WEB_RECODE

Length of output: 151


🌐 Web query:

next-sitemap exclude robotsTxtOptions disallow behavior configuration

💡 Result:

In next-sitemap, the 'exclude' configuration and 'robotsTxtOptions' (specifically its 'policies' with 'disallow') serve distinct purposes with no direct interaction between them. The 'exclude' option is an array of relative paths (supporting wildcards like '/private/') that prevents specific paths from being included in the generated sitemap XML files (sitemap.xml, sitemap-.xml). It does not affect robots.txt generation.[1][2][3] Separately, 'robotsTxtOptions.policies' defines crawl policies for the generated robots.txt file. Each policy has a 'userAgent', optional 'allow' (string | string[]), and optional 'disallow' (string | string[]) directives. These follow standard robots.txt syntax to instruct crawlers on allowed/disallowed paths. For example: robotsTxtOptions: { policies: [ { userAgent: '', allow: '/', disallow: ['/admin/', '/private/'] // Crawlers should not crawl these paths }, { userAgent: 'bad-bot', disallow: '/' } ] } This generates robots.txt entries like: User-agent: * Allow: / Disallow: /admin/* Disallow: /private/ # bad-bot User-agent: bad-bot Disallow: /[3][2] 'robotsTxtOptions.additionalSitemaps' adds extra sitemap URLs to robots.txt (e.g., custom server-side sitemaps), but these may inadvertently appear in the main sitemap index despite 'exclude', due to known issues (e.g., #823, #481). Workarounds include custom 'transform' functions or disabling index sitemaps.[4][5][3] Disallowing paths in robots.txt does not exclude them from sitemaps; crawlers use sitemaps to discover URLs but respect robots.txt for crawling/indexing. Conversely, excluding from sitemaps hides from discovery but does not prevent crawling if linked elsewhere.[1][6]

Citations:


🌐 Web query:

robots.txt trailing slash pattern matching /auth vs /auth/

💡 Result:

In robots.txt path patterns, rules are matched by “path prefix” semantics: a crawler checks whether the URL path starts with the pattern from an Allow/Disallow rule, and the “most specific” (longest matching) rule wins. That means /auth and /auth/ are not equivalent patterns; they differ in what they match around the immediate next character after auth. What matches with Disallow: /auth - It matches any URL path that starts with /auth, including /auth itself and any path that continues with anything after auth (for example /auth/anything and /authfoo). This follows from prefix matching of the path value in Allow/Disallow rules [1]. What matches with Disallow: /auth/ - It matches only URL paths that start with /auth/ (note the trailing slash), i.e., it matches /auth/ and subpaths like /auth/login, but it does NOT match /auth (the version without the slash), because that path does not start with /auth/. This is consistent with the example prefix matching behavior and the “longest specific match” rule in RFC 9309 [2]. Practical guidance - If you intend to block a directory and its contents, the standard approach is to include the trailing slash in the directory path pattern (e.g., Disallow: /auth/) [3]. - If you instead use Disallow: /auth, you may accidentally block URLs you didn’t mean to (e.g., /auth.html-like paths or other paths that merely begin with /auth but aren’t under /auth/). This risk is explicitly noted for prefix-style matching behavior in explanations of robots.txt path matching [4]. Answer to your specific comparison - Disallow: /auth blocks both /auth and /auth/… (and also anything else that has prefix /auth). - Disallow: /auth/ blocks /auth/… but does not block /auth (no trailing slash).

Citations:


🏁 Script executed:

cat -n ./next-sitemap.config.js

Repository: BCSDLab/KOIN_WEB_RECODE

Length of output: 2207


🏁 Script executed:

wc -l ./next-sitemap.config.js

Repository: BCSDLab/KOIN_WEB_RECODE

Length of output: 95


robots.txt disallow 설정이 누락되어 크롤러가 비공개 경로에 접근할 수 있습니다.

robots.txt의 disallow 목록(49-65줄)에서 다음 경로들이 누락되었습니다:

  • /store/review/edit/* (PRIVATE_PATHS에는 있음)
  • /monitoring/* (PRIVATE_PATHS에는 있음)

또한 /auth/, /webview/, /report/는 trailing slash 규칙으로만 설정되어 /auth, /webview, /report 정확 경로는 차단되지 않습니다. 크롤러가 이 경로들에 접근할 수 있게 됩니다.

🔧 제안 수정안
         disallow: [
-          '/auth/',
-          '/webview/',
-          '/report/',
+          '/auth',
+          '/webview',
+          '/report',
           '/callvan/add',
-          '/callvan/chat/',
+          '/callvan/chat',
           '/callvan/notifications',
           '/timetable/modify',
           '/clubs/new',
-          '/clubs/edit/',
+          '/clubs/edit',
-          '/clubs/recruitment/edit/',
+          '/clubs/recruitment/edit',
-          '/lost-item/edit/',
-          '/lost-item/report/',
+          '/lost-item/edit',
+          '/lost-item/report',
           '/lost-item/chat',
-          '/store/review/',
+          '/store/review',
+          '/store/review/edit',
+          '/monitoring',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@next-sitemap.config.js` around lines 43 - 65, The
robotsTxtOptions.policies[0].disallow array is missing specific patterns and
non-trailing-slash variants so crawlers can still reach private routes; update
the disallow list used by robotsTxtOptions in next-sitemap.config.js (and ensure
PRIVATE_PATHS is honored) to add the wildcard patterns '/store/review/edit/*'
and '/monitoring/*' and include both trailing and non-trailing variants for the
listed prefixes (e.g., add '/auth' in addition to '/auth/', '/webview' in
addition to '/webview/', and '/report' in addition to '/report/') so all exact
and nested paths are disallowed by the policy.

},
],
},
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"scripts": {
"start": "next dev",
"start:serve": "next start",
"build": "tsc && next build",
"build": "tsc && next build && next-sitemap",
"test": "test --coverage",
"sourcemap:clean": "find ./build -name '*.map' -type f -delete",
"lint": "yarn lint:eslint && yarn lint:stylelint",
Expand Down Expand Up @@ -81,6 +81,7 @@
"eslint-plugin-react-hooks": "^7.0.1",
"globals": "^16.4.0",
"jest": "^29.7.0",
"next-sitemap": "^4.2.3",
"postcss": "^8.5.11",
"prettier": "^3.6.2",
"sass": "^1.53.0",
Expand Down
3 changes: 0 additions & 3 deletions public/robots.txt

This file was deleted.

34 changes: 33 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2176,6 +2176,13 @@ __metadata:
languageName: node
linkType: hard

"@corex/deepmerge@npm:^4.0.43":
version: 4.0.43
resolution: "@corex/deepmerge@npm:4.0.43"
checksum: 10/c9ac6163e982e81e3216a9fc7c68cd60b9788ad3b23d7387c9e9741b0274b42dfc332ae74b993e550c95e4256be5ce68045fc55d363aa083344392dc95b50d8b
languageName: node
linkType: hard

"@csstools/css-parser-algorithms@npm:^2.5.0":
version: 2.5.0
resolution: "@csstools/css-parser-algorithms@npm:2.5.0"
Expand Down Expand Up @@ -3162,6 +3169,13 @@ __metadata:
languageName: node
linkType: hard

"@next/env@npm:^13.4.3":
version: 13.5.11
resolution: "@next/env@npm:13.5.11"
checksum: 10/2d34ec742e28b4da54b7bfe62eb27c1c90f927f0dfe387a0af8c1a535faf75d80475e58a33472bdf722bab02349be074935e2bdf512b5fd0a46dab364700dd3d
languageName: node
linkType: hard

"@next/eslint-plugin-next@npm:^16.0.0":
version: 16.0.0
resolution: "@next/eslint-plugin-next@npm:16.0.0"
Expand Down Expand Up @@ -10048,6 +10062,7 @@ __metadata:
jest: "npm:^29.7.0"
lottie-react: "npm:^2.4.1"
next: "npm:15.5.18"
next-sitemap: "npm:^4.2.3"
postcss: "npm:^8.5.11"
prettier: "npm:^3.6.2"
react: "npm:^19.2.6"
Expand Down Expand Up @@ -10473,7 +10488,7 @@ __metadata:
languageName: node
linkType: hard

"minimist@npm:^1.2.0, minimist@npm:^1.2.6":
"minimist@npm:^1.2.0, minimist@npm:^1.2.6, minimist@npm:^1.2.8":
version: 1.2.8
resolution: "minimist@npm:1.2.8"
checksum: 10/908491b6cc15a6c440ba5b22780a0ba89b9810e1aea684e253e43c4e3b8d56ec1dcdd7ea96dde119c29df59c936cde16062159eae4225c691e19c70b432b6e6f
Expand Down Expand Up @@ -10658,6 +10673,23 @@ __metadata:
languageName: node
linkType: hard

"next-sitemap@npm:^4.2.3":
version: 4.2.3
resolution: "next-sitemap@npm:4.2.3"
dependencies:
"@corex/deepmerge": "npm:^4.0.43"
"@next/env": "npm:^13.4.3"
fast-glob: "npm:^3.2.12"
minimist: "npm:^1.2.8"
peerDependencies:
next: "*"
bin:
next-sitemap: bin/next-sitemap.mjs
next-sitemap-cjs: bin/next-sitemap.cjs
checksum: 10/8e88c941b5e487584abaa21a31a94d888c8d37e95892cd6b5bdbc121f49435f75c279e97508a7a99d3de0010e833f3769d0c2d0888d9228be4dbd48e031b831c
languageName: node
linkType: hard

"next@npm:15.5.18":
version: 15.5.18
resolution: "next@npm:15.5.18"
Expand Down
Loading