| name | no-hardcoding |
| description | Forbid hardcoded values in code. Use this when reviewing code, writing new features, or when magic numbers/strings are detected. Enforces constants, env variables, and config files. |
| allowed-tools | Read, Glob, Grep, Edit, Write, Bash |
| license | MIT |
| metadata | {"author":"antigravity-team","version":"1.0"} |
No Hardcoding Policy
์ฝ๋์ ํ๋์ฝ๋ฉ๋ ๊ฐ์ ๊ธ์งํ๊ณ ์์/ํ๊ฒฝ๋ณ์/์ค์ ํ์ผ์ ์ฌ์ฉํ๋๋ก ๊ฐ์ ํ๋ ์คํฌ์
๋๋ค.
Core Principle
"์ฝ๋์ ์ง์ ๊ฐ์ ์ฐ๋ ์๊ฐ, ๋ณ๊ฒฝ์ด ๋ฐฐํฌ๊ฐ ๋๋ค."
Rules
| ์ ํ | ์ํ | ๋์ |
|---|
| Magic Number | ๐ด ๊ธ์ง | ์์/enum |
| Magic String | ๐ด ๊ธ์ง | ์์/enum |
| URL/๊ฒฝ๋ก | ๐ด ๊ธ์ง | ํ๊ฒฝ๋ณ์/config |
| ํฌ๋ฆฌ๋ด์
| ๐ด ์ ๋ ๊ธ์ง | .env + secrets |
| ํ์์์/๋๋ ์ด | ๐ด ๊ธ์ง | ์์/config |
| ํฌํธ ๋ฒํธ | ๐ด ๊ธ์ง | ํ๊ฒฝ๋ณ์ |
| API ํค | ๐ด ์ ๋ ๊ธ์ง | ํ๊ฒฝ๋ณ์ + secrets |
Detection Patterns
Magic Numbers
if (users.length > 100) { ... }
setTimeout(callback, 3000);
const tax = price * 0.1;
const MAX_USERS = 100;
const DEBOUNCE_MS = 3000;
const TAX_RATE = 0.1;
if (users.length > MAX_USERS) { ... }
setTimeout(callback, DEBOUNCE_MS);
const tax = price * TAX_RATE;
Magic Strings
if (status === 'pending') { ... }
if (status === 'pending') { ... }
enum Status {
PENDING = 'pending',
APPROVED = 'approved',
REJECTED = 'rejected',
}
if (status === Status.PENDING) { ... }
URLs/Endpoints
const response = await fetch('https://api.example.com/users');
const API_URL = process.env.NEXT_PUBLIC_API_URL;
const response = await fetch(`${API_URL}/users`);
Credentials (์ ๋ ๊ธ์ง)
const apiKey = 'sk-1234567890abcdef';
const password = 'admin123';
const dbConnection = 'mongodb://user:pass@host:27017';
const apiKey = process.env.API_KEY;
const password = process.env.DB_PASSWORD;
const dbConnection = process.env.DATABASE_URL;
Timeouts/Delays
await page.waitForTimeout(5000);
time.sleep(3);
const ANIMATION_DURATION = 300;
await page.waitForSelector('#content');
await delay(ANIMATION_DURATION);
File Organization
src/
โโโ constants/
โ โโโ index.ts # Re-exports
โ โโโ api.ts # API ๊ด๋ จ ์์
โ โโโ ui.ts # UI ๊ด๋ จ ์์
โ โโโ business.ts # ๋น์ฆ๋์ค ๋ก์ง ์์
โโโ config/
โ โโโ index.ts
โ โโโ env.ts # ํ๊ฒฝ๋ณ์ ๊ฒ์ฆ ๋ฐ ํ์
โโโ types/
โโโ enums.ts # Enum ์ ์
constants ์์
export const API = {
TIMEOUT_MS: 30000,
RETRY_COUNT: 3,
ENDPOINTS: {
USERS: '/api/users',
POSTS: '/api/posts',
},
} as const;
export const UI = {
DEBOUNCE_MS: 300,
ANIMATION_DURATION_MS: 200,
MAX_ITEMS_PER_PAGE: 20,
BREAKPOINTS: {
MOBILE: 768,
TABLET: 1024,
DESKTOP: 1280,
},
} as const;
ํ๊ฒฝ๋ณ์ ๊ฒ์ฆ
const requiredEnvVars = [
'DATABASE_URL',
'API_KEY',
'NEXT_PUBLIC_API_URL',
] as const;
export function validateEnv() {
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
throw new Error(`Missing required env var: ${envVar}`);
}
}
}
export const env = {
DATABASE_URL: process.env.DATABASE_URL!,
API_KEY: process.env.API_KEY!,
API_URL: process.env.NEXT_PUBLIC_API_URL!,
} as const;
Detection Commands
grep -rn "[^a-zA-Z][0-9]\{3,\}[^a-zA-Z0-9]" --include="*.ts" --include="*.tsx" src/
grep -rn "https\?://" --include="*.ts" --include="*.tsx" src/ | grep -v "node_modules"
grep -rn "password\|apiKey\|secret\|token" --include="*.ts" --include="*.tsx" src/ | grep -v "\.d\.ts"
Workflow
1. ์ฝ๋ ๋ฆฌ๋ทฐ ์
ํ๋์ฝ๋ฉ ๊ฐ์ง:
1. Magic Number/String ๊ฒ์
2. URL/๊ฒฝ๋ก ํ๋์ฝ๋ฉ ํ์ธ
3. ํฌ๋ฆฌ๋ด์
ํ๋์ฝ๋ฉ ํ์ธ (์ต์ฐ์ )
์๋ฐ ๋ฐ๊ฒฌ ์:
โ ์์ ์ถ์ถ ๊ถ์ฅ
โ ํ๊ฒฝ๋ณ์ ์ฌ์ฉ ์๋ด
โ .env.example ์
๋ฐ์ดํธ ํ์ธ
2. ์ ๊ธฐ๋ฅ ์์ฑ ์
๊ฐ ์ฌ์ฉ ์ ์ฒดํฌ:
- ์ด ๊ฐ์ด ๋ณ๊ฒฝ๋ ์ ์๋๊ฐ? โ ํ๊ฒฝ๋ณ์/config
- ์ด ๊ฐ์ด ์ฌ๋ฌ ๊ณณ์์ ์ฌ์ฉ๋๋๊ฐ? โ ์์
- ์ด ๊ฐ์ด ๋ฏผ๊ฐํ๊ฐ? โ ํ๊ฒฝ๋ณ์ + secrets
- ์ด ๊ฐ์ด ์๋ฏธ๋ฅผ ๊ฐ์ง๋๊ฐ? โ ์์ (์ด๋ฆ์ผ๋ก ์๋ฏธ ๋ถ์ฌ)
Exceptions
ํ์ฉ๋๋ ๊ฒฝ์ฐ
const index = array.indexOf(item);
if (index === -1) { ... }
const first = array[0];
const last = array[array.length - 1];
const half = total / 2;
const percentage = (part / whole) * 100;
Checklist