Web·iOS·Android 화면을 WCAG 2.2에 맞춰 설계하고 점검합니다. 화면 읽기와 키보드 조작, 레이블, 대비, 조작 대상 크기를 확인합니다.
- 아이콘 버튼에 설명 추가
- 키보드 조작과 모달 초점 점검
- 대비와 조작 대상 크기 확인
공통 기준으로 코드의 명명, 가독성, 원본 데이터를 바꾸지 않는 갱신 방식과 오류 처리를 검토합니다. 중복과 복잡한 구조를 찾아 유지보수하기 쉽게 정리합니다.
Baseline cross-project coding conventions for naming, readability, immutability, and code-quality review. Use detailed frontend or backend skills for framework-specific patterns. Use when reviewing code quality or naming with no framework-specific skill that applies.
프로젝트 공통 기준으로 코드를 검토하고 읽기 쉽고 유지보수하기 편한 형태로 정리합니다. 의미가 분명한 변수와 함수 이름, 일관된 서식, 원본 데이터를 직접 바꾸지 않는 갱신 방식, 오류 처리를 다룹니다. 중복 처리, 지나치게 긴 함수, 깊게 중첩된 조건 분기, 의미가 설명되지 않은 수치를 찾고 불필요하게 복잡한 설계를 피하는 지침을 제공합니다.
새 프로젝트나 모듈의 규칙을 통일하거나 기존 코드의 품질을 검토할 때 유용합니다. 참여자에게 공통 작성 방식을 안내하거나 명명과 구조의 차이를 정리할 때도 사용합니다. TypeScript와 JavaScript 예시로 타입 지정, 비동기 처리, 주석 작성 방법도 확인합니다.
공통 코딩 규칙이 중심입니다. React 구성과 렌더링에는 frontend-patterns, 서버 설계와 API 세부 사항에는 backend-patterns나 api-design 등 대상에 맞는 전문 스킬을 사용하도록 안내합니다.
이 소개문은 공개된 SKILL.md를 바탕으로 AI(OpenAI Codex)가 작성했습니다. 정확한 사양은 아래 원문을 확인하세요.
AI가 SKILL.md의 내용만을 근거로 4가지 관점에서 판정했습니다. 스타 수나 인기도는 판정에 넣지 않았습니다.
총점은 각 항목을 A=25점, B=15점, C=5점으로 더한 값입니다. 2026년 10월 19일 기준으로 AI(OpenAI Codex)가 판정했습니다. 참고용이므로 설치 전에 원문도 확인해 주세요.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Baseline coding conventions applicable across projects.
This skill is the shared floor, not the detailed framework playbook.
frontend-patterns for React, state, forms, rendering, and UI architecture.backend-patterns or api-design for repository/service layers, endpoint design, validation, and server-specific concerns.rules/common/coding-style.md when you need the shortest reusable rule layer instead of a full skill walkthrough.Activate this skill for:
Do not use this skill as the primary source for:
// PASS: GOOD: Descriptive names
const marketSearchQuery = 'election'
const isUserAuthenticated = true
const totalRevenue = 1000
// FAIL: BAD: Unclear names
const q = 'election'
const flag = true
const x = 1000
// PASS: GOOD: Verb-noun pattern
async function fetchMarketData(marketId: string) { }
function calculateSimilarity(a: number[], b: number[]) { }
function isValidEmail(email: string): boolean { }
// FAIL: BAD: Unclear or noun-only
async function market(id: string) { }
function similarity(a, b) { }
function email(e) { }
// PASS: ALWAYS use spread operator
const updatedUser = {
...user,
name: 'New Name'
}
const updatedArray = [...items, newItem]
// FAIL: NEVER mutate directly
user.name = 'New Name' // BAD
items.push(newItem) // BAD
// PASS: GOOD: Comprehensive error handling
async function fetchData(url: string) {
try {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
return await response.json()
} catch (error) {
console.error('Fetch failed:', error)
throw new Error('Failed to fetch data')
}
}
// FAIL: BAD: No error handling
async function fetchData(url) {
const response = await fetch(url)
return response.json()
}
// PASS: GOOD: Parallel execution when possible
const [users, markets, stats] = await Promise.all([
fetchUsers(),
fetchMarkets(),
fetchStats()
])
// FAIL: BAD: Sequential when unnecessary
const users = await fetchUsers()
const markets = await fetchMarkets()
const stats = await fetchStats()
// PASS: GOOD: Proper types
interface Market {
id: string
name: string
status: 'active' | 'resolved' | 'closed'
created_at: Date
}
function getMarket(id: string): Promise<Market> {
// Implementation
}
// FAIL: BAD: Using 'any'
function getMarket(id: any): Promise<any> {
// Implementation
}
// PASS: GOOD: Functional component with types
interface ButtonProps {
children: React.ReactNode
onClick: () => void
disabled?: boolean
variant?: 'primary' | 'secondary'
}
export function Button({
children,
onClick,
disabled = false,
variant = 'primary'
}: ButtonProps) {
return (
<button
onClick={onClick}
disabled={disabled}
className={`btn btn-${variant}`}
>
{children}
</button>
)
}
// FAIL: BAD: No types, unclear structure
export function Button(props) {
return <button onClick={props.onClick}>{props.children}</button>
}
// PASS: GOOD: Reusable custom hook
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value)
}, delay)
return () => clearTimeout(handler)
}, [value, delay])
return debouncedValue
}
// Usage
const debouncedQuery = useDebounce(searchQuery, 500)
// PASS: GOOD: Proper state updates
const [count, setCount] = useState(0)
// Functional update for state based on previous state
setCount(prev => prev + 1)
// FAIL: BAD: Direct state reference
setCount(count + 1) // Can be stale in async scenarios
// PASS: GOOD: Clear conditional rendering
{isLoading && <Spinner />}
{error && <ErrorMessage error={error} />}
{data && <DataDisplay data={data} />}
// FAIL: BAD: Ternary hell
{isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}
GET /api/markets # List all markets
GET /api/markets/:id # Get specific market
POST /api/markets # Create new market
PUT /api/markets/:id # Update market (full)
PATCH /api/markets/:id # Update market (partial)
DELETE /api/markets/:id # Delete market
# Query parameters for filtering
GET /api/markets?status=active&limit=10&offset=0
// PASS: GOOD: Consistent response structure
interface ApiResponse<T> {
success: boolean
data?: T
error?: string
meta?: {
total: number
page: number
limit: number
}
}
// Success response
return NextResponse.json({
success: true,
data: markets,
meta: { total: 100, page: 1, limit: 10 }
})
// Error response
return NextResponse.json({
success: false,
error: 'Invalid request'
}, { status: 400 })
import { z } from 'zod'
// PASS: GOOD: Schema validation
const CreateMarketSchema = z.object({
name: z.string().min(1).max(200),
description: z.string().min(1).max(2000),
endDate: z.string().datetime(),
categories: z.array(z.string()).min(1)
})
export async function POST(request: Request) {
const body = await request.json()
try {
const validated = CreateMarketSchema.parse(body)
// Proceed with validated data
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json({
success: false,
error: 'Validation failed',
details: error.issues
}, { status: 400 })
}
}
}
src/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ ├── markets/ # Market pages
│ └── (auth)/ # Auth pages (route groups)
├── components/ # React components
│ ├── ui/ # Generic UI components
│ ├── forms/ # Form components
│ └── layouts/ # Layout components
├── hooks/ # Custom React hooks
├── lib/ # Utilities and configs
│ ├── api/ # API clients
│ ├── utils/ # Helper functions
│ └── constants/ # Constants
├── types/ # TypeScript types
└── styles/ # Global styles
components/Button.tsx # PascalCase for components
hooks/useAuth.ts # camelCase with 'use' prefix
lib/formatDate.ts # camelCase for utilities
types/market.types.ts # camelCase with .types suffix
// PASS: GOOD: Explain WHY, not WHAT
// Use exponential backoff to avoid overwhelming the API during outages
const delay = Math.min(1000 * Math.pow(2, retryCount), 30000)
// Deliberately using mutation here for performance with large arrays
items.push(newItem)
// FAIL: BAD: Stating the obvious
// Increment counter by 1
count++
// Set name to user's name
name = user.name
/**
* Searches markets using semantic similarity.
*
* @param query - Natural language search query
* @param limit - Maximum number of results (default: 10)
* @returns Array of markets sorted by similarity score
* @throws {Error} If OpenAI API fails or Redis unavailable
*
* @example
* ```typescript
* const results = await searchMarkets('election', 5)
* console.log(results[0].name) // "Trump vs Biden"
* ```
*/
export async function searchMarkets(
query: string,
limit: number = 10
): Promise<Market[]> {
// Implementation
}
import { useMemo, useCallback } from 'react'
// PASS: GOOD: Memoize expensive computations
// Copy before sorting - Array.prototype.sort mutates in place
const sortedMarkets = useMemo(() => {
return [...markets].sort((a, b) => b.volume - a.volume)
}, [markets])
// PASS: GOOD: Memoize callbacks
const handleSearch = useCallback((query: string) => {
setSearchQuery(query)
}, [])
import { lazy, Suspense } from 'react'
// PASS: GOOD: Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'))
export function Dashboard() {
return (
<Suspense fallback={<Spinner />}>
<HeavyChart />
</Suspense>
)
}
// PASS: GOOD: Select only needed columns
const { data } = await supabase
.from('markets')
.select('id, name, status')
.limit(10)
// FAIL: BAD: Select everything
const { data } = await supabase
.from('markets')
.select('*')
test('calculates similarity correctly', () => {
// Arrange
const vector1 = [1, 0, 0]
const vector2 = [0, 1, 0]
// Act
const similarity = calculateCosineSimilarity(vector1, vector2)
// Assert
expect(similarity).toBe(0)
})
// PASS: GOOD: Descriptive test names
test('returns empty array when no markets match query', () => { })
test('throws error when OpenAI API key is missing', () => { })
test('falls back to substring search when Redis unavailable', () => { })
// FAIL: BAD: Vague test names
test('works', () => { })
test('test search', () => { })
Watch for these anti-patterns:
// FAIL: BAD: Function > 50 lines
function processMarketData() {
// 100 lines of code
}
// PASS: GOOD: Split into smaller functions
function processMarketData() {
const validated = validateData()
const transformed = transformData(validated)
return saveData(transformed)
}
// FAIL: BAD: 5+ levels of nesting
if (user) {
if (user.isAdmin) {
if (market) {
if (market.isActive) {
if (hasPermission) {
// Do something
}
}
}
}
}
// PASS: GOOD: Early returns
if (!user) return
if (!user.isAdmin) return
if (!market) return
if (!market.isActive) return
if (!hasPermission) return
// Do something
// FAIL: BAD: Unexplained numbers
if (retryCount > 3) { }
setTimeout(callback, 500)
// PASS: GOOD: Named constants
const MAX_RETRIES = 3
const DEBOUNCE_DELAY_MS = 500
if (retryCount > MAX_RETRIES) { }
setTimeout(callback, DEBOUNCE_DELAY_MS)
Remember: Code quality is not negotiable. Clear, maintainable code enables rapid development and confident refactoring.
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Web·iOS·Android 화면을 WCAG 2.2에 맞춰 설계하고 점검합니다. 화면 읽기와 키보드 조작, 레이블, 대비, 조작 대상 크기를 확인합니다.
인공지능 에이전트의 문제를 지시, 기억, 도구 실행, 화면 표시 등 12개 계층에서 조사합니다. 코드와 로그를 근거로 원인을 정리하고 심각도에 따른 지적 사항과 수정안을 제시합니다.
실제 개발 과제로 여러 코딩 에이전트를 비교합니다. 성공률, 확인 가능한 API 비용, 소요 시간과 반복 실행의 안정성을 측정해 도입 결정과 업데이트 후 평가에 활용합니다.
AI 에이전트의 도구 구성, 입력과 출력 형식, 오류 복구 절차를 설계합니다. 문맥 정보량을 관리하고 완료율, 재시도 횟수, 성공한 작업당 비용으로 개선을 평가합니다.
오류와 실행 환경을 바탕으로 AI 에이전트가 실패하거나 같은 작업을 반복하는 원인을 조사합니다. 작은 복구 작업을 시험하고 결과와 근거를 인계용 보고서로 정리합니다.
AI 에이전트의 반복 실패와 도구 사용을 기록하고 원인을 좁힙니다. 영향이 제한된 복구 작업과 결과 보고를 통해 근거 있는 재시도를 돕습니다.