24 KiB
24 KiB
자주 쓰는 스니펫 (import 후보)
현재 snippets.db 구조 그대로. 한 스니펫 = ## 섹션 하나.
| md | DB 컬럼 |
|---|---|
## 제목 |
name (PK, 대문자·공백→_) |
- desc: |
desc |
| 코드펜스 안 | body (원문 그대로) |
- category: |
category |
기존 219개와 이름 안 겹치게 골랐음. 언어 태그(```ts 등)는 읽기 편하라고 붙인 거고 DB 컬럼 아님 — import 할 땐 버리면 됨.
USEQUERY-REACT
- desc: react-query 조회 훅 기본형
- category: 코드
import { useQuery } from '@tanstack/react-query'
import { xxxxxApi } from '../api/xxxxx.api'
export const XXXXXS_KEY = ['xxxxxs'] as const
export function useXxxxxs() {
return useQuery({
queryKey: XXXXXS_KEY,
queryFn: xxxxxApi.list,
staleTime: 30_000,
})
}
USEMUTATION-REACT
- desc: react-query 변경 훅 — invalidate + toast + ApiError 분기
- category: 코드
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { ApiError } from '@/lib/api/errors'
import { xxxxxApi } from '../api/xxxxx.api'
import { XXXXXS_KEY } from './useXxxxxs'
export function useCreateXxxxx() {
const qc = useQueryClient()
return useMutation({
mutationFn: xxxxxApi.create,
onSuccess: () => {
qc.invalidateQueries({ queryKey: XXXXXS_KEY })
toast.success('저장했어요')
},
onError: (e) => {
toast.error(e instanceof ApiError ? e.message : '저장 실패')
},
})
}
API_MODULE-REACT
- desc: feature api 객체 패턴 (apiGet/apiPost 래퍼)
- category: 코드
import { apiGet, apiPost, apiPatch, apiDelete } from '@/lib/api/client'
import type { Xxxxx, XxxxxCreate } from '@/types/api'
const BASE = '/xxxxxs'
export const xxxxxApi = {
list: () => apiGet<Xxxxx[]>(BASE),
get: (id: string) => apiGet<Xxxxx>(`${BASE}/${id}`),
create: (body: XxxxxCreate) => apiPost<Xxxxx>(BASE, body),
update: (id: string, body: Partial<XxxxxCreate>) => apiPatch<Xxxxx>(`${BASE}/${id}`, body),
remove: (id: string) => apiDelete<void>(`${BASE}/${id}`),
}
AXIOS_MOCK_TEST
- desc: axios-mock-adapter 로 api 모듈 테스트
- category: 코드
import MockAdapter from 'axios-mock-adapter'
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { http } from '@/lib/api/client'
import { xxxxxApi } from './xxxxx.api'
let mock: MockAdapter
beforeEach(() => { mock = new MockAdapter(http) })
afterEach(() => { mock.restore() })
describe('xxxxxApi', () => {
it('목록을 가져온다', async () => {
mock.onGet('/xxxxxs').reply(200, [{ id: '1' }])
await expect(xxxxxApi.list()).resolves.toHaveLength(1)
})
it('실패하면 ApiError 를 던진다', async () => {
mock.onGet('/xxxxxs').reply(500)
await expect(xxxxxApi.list()).rejects.toThrow()
})
})
VITEST_RTL
- desc: vitest + testing-library 컴포넌트 테스트 뼈대
- category: 코드
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { describe, it, expect, vi } from 'vitest'
import { Xxxxx } from './Xxxxx'
describe('Xxxxx', () => {
it('클릭하면 콜백이 불린다', async () => {
const onPick = vi.fn()
render(<Xxxxx onPick={onPick} />)
await userEvent.click(screen.getByRole('button', { name: '선택' }))
expect(onPick).toHaveBeenCalledTimes(1)
})
})
ZUSTAND_STORE
- desc: zustand 스토어 기본형
- category: 코드
import { create } from 'zustand'
interface XxxxxState {
value: string
setValue: (v: string) => void
reset: () => void
}
export const useXxxxxStore = create<XxxxxState>((set) => ({
value: '',
setValue: (value) => set({ value }),
reset: () => set({ value: '' }),
}))
USEDEBOUNCE
- desc: 입력 디바운스 훅
- category: 코드
import { useEffect, useState } from 'react'
export function useDebounce<T>(value: T, delay = 200): T {
const [debounced, setDebounced] = useState(value)
useEffect(() => {
const t = setTimeout(() => setDebounced(value), delay)
return () => clearTimeout(t)
}, [value, delay])
return debounced
}
USE_HOTKEY
- desc: 전역 키보드 단축키 훅 (팔레트용)
- category: 코드
import { useEffect } from 'react'
export function useHotkey(key: string, handler: () => void) {
useEffect(() => {
const onKeyDown = (e: KeyboardEvent) => {
if (e.isComposing) return // IME 조합 중이면 무시
if (e.key !== key) return
e.preventDefault()
handler()
}
window.addEventListener('keydown', onKeyDown)
return () => window.removeEventListener('keydown', onKeyDown)
}, [key, handler])
}
CN_UTIL
- desc: clsx + tailwind-merge 클래스 합치기
- category: 코드
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
SHADCN_DIALOG
- desc: shadcn Dialog 열고 닫기
- category: 코드
import {
Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter,
} from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle>XXXXX</DialogTitle>
</DialogHeader>
{/* 본문 */}
<DialogFooter>
<Button variant="ghost" onClick={() => setOpen(false)}>취소</Button>
<Button onClick={onSave}>저장</Button>
</DialogFooter>
</DialogContent>
</Dialog>
SSE_STREAM
- desc: fetch 로 SSE 스트리밍 받아 한 줄씩 처리
- category: 코드
const res = await fetch(url, { method: 'POST', body: JSON.stringify(payload) })
const reader = res.body!.getReader()
const decoder = new TextDecoder()
let buf = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
buf += decoder.decode(value, { stream: true })
const lines = buf.split('\n')
buf = lines.pop() ?? ''
for (const line of lines) {
if (!line.startsWith('data:')) continue
const data = line.slice(5).trim()
if (data === '[DONE]') return
onChunk(JSON.parse(data))
}
}
ENV_VITE
- desc: vite 환경변수 읽기 + .env 예시
- category: 코드
// .env.development
// VITE_API_BASE_URL=http://localhost:8000
const baseUrl = import.meta.env.VITE_API_BASE_URL as string
const isDev = import.meta.env.DEV
FMAIN
- desc: FastAPI 앱 진입점 + CORS + 라우터 등록
- category: 코드
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from routers import xxxxx
@asynccontextmanager
async def lifespan(app: FastAPI):
# 시작 시
yield
# 종료 시
app = FastAPI(title="XXXXX", lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(xxxxx.router)
FROUTER
- desc: FastAPI APIRouter 뼈대 (CRUD 5종)
- category: 코드
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from database import get_db
router = APIRouter(prefix="/xxxxxs", tags=["xxxxx"])
@router.get("")
async def list_xxxxx(db: AsyncSession = Depends(get_db)):
pass
@router.get("/{xxxxx_id}")
async def get_xxxxx(xxxxx_id: int, db: AsyncSession = Depends(get_db)):
pass
@router.post("", status_code=201)
async def create_xxxxx(request: XxxxxPIN, db: AsyncSession = Depends(get_db)):
pass
@router.patch("/{xxxxx_id}")
async def update_xxxxx(xxxxx_id: int, request: XxxxxPIN, db: AsyncSession = Depends(get_db)):
pass
@router.delete("/{xxxxx_id}", status_code=204)
async def delete_xxxxx(xxxxx_id: int, db: AsyncSession = Depends(get_db)):
pass
FDB_SESSION
- desc: SQLAlchemy async 세션 + get_db 의존성
- category: 코드
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
DATABASE_URL = "postgresql+asyncpg://user:pass@localhost:5432/dbname"
engine = create_async_engine(DATABASE_URL, echo=False, pool_pre_ping=True)
SessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def get_db():
async with SessionLocal() as session:
yield session
FSELECT-ONE
- desc: FastAPI 한 건 조회 (없으면 404)
- category: 코드
from sqlalchemy import select
from fastapi import HTTPException
result = await db.execute(select(XXXXX).where(XXXXX.id == xxxxx_id))
ret = result.scalar_one_or_none()
if ret is None:
raise HTTPException(status_code=404, detail="XXXXX Not Found")
return ret
FINSERT
- desc: FastAPI insert (add → commit → refresh)
- category: 코드
from utils.error_handlers import handle_error
try:
row = XXXXX(**request.model_dump())
db.add(row)
await db.commit()
await db.refresh(row)
return row
except Exception as error:
await db.rollback()
handle_error(error, "XXXXX Create Fail")
FUPDATE
- desc: FastAPI 부분 수정 (exclude_unset)
- category: 코드
from sqlalchemy import select
result = await db.execute(select(XXXXX).where(XXXXX.id == xxxxx_id))
row = result.scalar_one_or_none()
if row is None:
raise HTTPException(status_code=404, detail="XXXXX Not Found")
for key, value in request.model_dump(exclude_unset=True).items():
setattr(row, key, value)
await db.commit()
await db.refresh(row)
return row
FDELETE
- desc: FastAPI 소프트 삭제
- category: 코드
from datetime import datetime
from sqlalchemy import update
await db.execute(
update(XXXXX)
.where(XXXXX.id == xxxxx_id)
.values(is_deleted=True, updated_at=datetime.now())
)
await db.commit()
FPAGING
- desc: FastAPI 페이징 (count + limit/offset)
- category: 코드
from sqlalchemy import func, select
base = select(XXXXX).where(XXXXX.is_deleted == False) # noqa: E712
total = await db.scalar(select(func.count()).select_from(base.subquery()))
result = await db.execute(base.order_by(XXXXX.created_at.desc()).limit(size).offset((page - 1) * size))
return {"total": total, "page": page, "size": size, "items": result.scalars().all()}
FMODEL_PIN_POUT
- desc: pydantic 요청/응답 모델 (PIN/POUT 규칙)
- category: 코드
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
class XxxxxPIN(BaseModel):
name: str = Field(..., max_length=50)
description: str | None = None
class XxxxxPOUT(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
name: str
description: str | None
created_at: datetime
FMODEL_ORM
- desc: SQLAlchemy 2.0 ORM 모델 (Mapped 스타일)
- category: 코드
from datetime import datetime
from sqlalchemy import DateTime, String, func
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class Xxxxx(Base):
__tablename__ = "xxxxx"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(50), nullable=False)
is_deleted: Mapped[bool] = mapped_column(default=False)
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
ALEMBIC_CMD
- desc: alembic 마이그레이션 명령 모음
- category: 코드
alembic init -t async alembic
alembic revision --autogenerate -m "XXXXX"
alembic upgrade head
alembic downgrade -1
alembic current
alembic history --verbose
PYTEST_ASYNC
- desc: pytest async 테스트 + httpx 클라이언트
- category: 코드
import pytest
from httpx import ASGITransport, AsyncClient
from main import app
@pytest.fixture
async def client():
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
yield ac
@pytest.mark.asyncio
async def test_list_xxxxx(client):
res = await client.get("/xxxxxs")
assert res.status_code == 200
LOGGING_PY
- desc: 파이썬 로깅 기본 설정
- category: 코드
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
datefmt="%H:%M:%S",
)
logger = logging.getLogger(__name__)
logger.info("XXXXX")
HTTPX_POST
- desc: httpx 비동기 POST 호출
- category: 코드
import httpx
async with httpx.AsyncClient(timeout=30.0) as client:
res = await client.post(url, json=payload, headers={"Authorization": f"Bearer {token}"})
res.raise_for_status()
data = res.json()
GIT_UNDO
- desc: git 되돌리기 모음 (커밋·스테이징·파일)
- category: 코드
git reset --soft HEAD~1 # 마지막 커밋만 취소, 변경은 남김
git reset HEAD <file> # 스테이징만 취소
git restore <file> # 파일 변경 버리기
git restore --staged <file> # 스테이징 취소(신형)
git revert <commit> # 되돌리는 새 커밋 생성(푸시된 커밋용)
git reflog # 날린 커밋 찾기
GIT_STASH
- desc: git stash 사용법
- category: 코드
git stash push -m "작업중"
git stash list
git stash show -p stash@{0}
git stash pop
git stash drop stash@{0}
GIT_AMEND
- desc: 마지막 커밋 메시지·내용 고치기
- category: 코드
git commit --amend -m "새 메시지"
git commit --amend --no-edit
git push --force-with-lease
GIT_LOG_PRETTY
- desc: 한 줄 그래프 로그
- category: 코드
git log --oneline --graph --decorate --all -20
git log --since="1 week ago" --author="XXXXX" --oneline
DOCKER_EXEC
- desc: 컨테이너 접속·상태 확인
- category: 코드
docker exec -it <container> /bin/bash
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker stats --no-stream
docker inspect <container> | grep -i ipaddress
PORT_KILL_WIN
- desc: 윈도우에서 포트 점유 프로세스 죽이기
- category: 코드
netstat -ano | findstr :8000
taskkill /PID <pid> /F
# 한 줄
Get-NetTCPConnection -LocalPort 8000 | Select-Object -ExpandProperty OwningProcess | ForEach-Object { Stop-Process -Id $_ -Force }
NPM_CLEAN_INSTALL
- desc: node_modules 완전 초기화 재설치
- category: 코드
rm -rf node_modules package-lock.json
npm cache clean --force
npm install
# 윈도우
Remove-Item -Recurse -Force node_modules, package-lock.json
CURL_POST
- desc: curl 로 JSON POST + 토큰
- category: 코드
curl -X POST http://localhost:8000/xxxxxs \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"name":"XXXXX"}' \
-w "\n%{http_code}\n"
APPEND_ITAB-ABAP
- desc: 인터널 테이블에 행 추가
- category: 코드
"★★APPEND, 인터널 테이블에 한 줄 추가
CLEAR GS_LIST.
GS_LIST-MATNR = LS_DATA-MATNR.
GS_LIST-MAKTX = LS_DATA-MAKTX.
APPEND GS_LIST TO GT_LIST.
CLEAR GS_LIST.
"740 이상
APPEND VALUE #( MATNR = LS_DATA-MATNR
MAKTX = LS_DATA-MAKTX ) TO GT_LIST.
TRY_CATCH-ABAP
- desc: ABAP 예외 처리 (CX_ROOT)
- category: 코드
DATA : LO_ERR TYPE REF TO CX_ROOT,
LV_MSG TYPE STRING.
TRY.
"★처리 구문
CATCH CX_SY_CONVERSION_NO_NUMBER INTO LO_ERR.
LV_MSG = LO_ERR->GET_TEXT( ).
MESSAGE LV_MSG TYPE 'S' DISPLAY LIKE 'E'.
CATCH CX_ROOT INTO LO_ERR.
LV_MSG = LO_ERR->GET_TEXT( ).
ENDTRY.
SELECT_JOIN-ABAP
- desc: INNER / LEFT OUTER JOIN 조회
- category: 코드
SELECT A~MATNR
A~MTART
B~MAKTX
INTO CORRESPONDING FIELDS OF TABLE GT_LIST
FROM MARA AS A
INNER JOIN MAKT AS B
ON B~MATNR = A~MATNR
AND B~SPRAS = SY-LANGU
WHERE A~MATNR IN S_MATNR
AND A~LVORM EQ SPACE.
IF SY-SUBRC NE 0.
MESSAGE '조회된 데이터가 없습니다.' TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
SELECT_UP_TO-ABAP
- desc: 건수 제한 조회 + 존재 여부 확인
- category: 코드
"★상위 N건만
SELECT MATNR MAKTX
INTO TABLE GT_LIST
FROM MAKT
UP TO 100 ROWS
WHERE SPRAS = SY-LANGU.
"★존재 여부만 확인 (성능)
SELECT SINGLE @ABAP_TRUE
FROM MARA
INTO @DATA(LV_EXISTS)
WHERE MATNR = @GS_LIST-MATNR.
ALV_FIELDCAT-ABAP
- desc: ALV 필드카탈로그 수동 구성
- category: 코드
DATA : GT_FCAT TYPE LVC_T_FCAT,
GS_FCAT TYPE LVC_S_FCAT.
DEFINE _FCAT.
CLEAR GS_FCAT.
GS_FCAT-FIELDNAME = &1.
GS_FCAT-COLTEXT = &2.
GS_FCAT-OUTPUTLEN = &3.
GS_FCAT-KEY = &4.
APPEND GS_FCAT TO GT_FCAT.
END-OF-DEFINITION.
_FCAT : 'MATNR' '자재코드' 18 'X',
'MAKTX' '자재내역' 40 '',
'MENGE' '수량' 13 ''.
ALV_LAYOUT-ABAP
- desc: ALV 레이아웃 기본 설정
- category: 코드
DATA : GS_LAYOUT TYPE LVC_S_LAYO.
CLEAR GS_LAYOUT.
GS_LAYOUT-ZEBRA = 'X'. "줄무늬
GS_LAYOUT-CWIDTH_OPT = 'X'. "컬럼폭 자동
GS_LAYOUT-SEL_MODE = 'A'. "선택 모드
GS_LAYOUT-NO_ROWMARK = SPACE.
GS_LAYOUT-STYLEFNAME = 'CELLSTYLE'.
GS_LAYOUT-CTAB_FNAME = 'CELLCOLOR'.
ALV_HOTSPOT-ABAP
- desc: ALV 핫스팟 클릭 이벤트 핸들러
- category: 코드
CLASS LCL_EVENT DEFINITION.
PUBLIC SECTION.
METHODS HANDLE_HOTSPOT
FOR EVENT HOTSPOT_CLICK OF CL_GUI_ALV_GRID
IMPORTING E_ROW_ID E_COLUMN_ID.
ENDCLASS.
CLASS LCL_EVENT IMPLEMENTATION.
METHOD HANDLE_HOTSPOT.
READ TABLE GT_LIST INTO GS_LIST INDEX E_ROW_ID-INDEX.
CHECK SY-SUBRC EQ 0.
CASE E_COLUMN_ID-FIELDNAME.
WHEN 'MATNR'.
SET PARAMETER ID 'MAT' FIELD GS_LIST-MATNR.
CALL TRANSACTION 'MM03' AND SKIP FIRST SCREEN.
ENDCASE.
ENDMETHOD.
ENDCLASS.
"등록
SET HANDLER GO_EVENT->HANDLE_HOTSPOT FOR GO_GRID.
CLASS_LOCAL-ABAP
- desc: 로컬 클래스 정의·구현 뼈대
- category: 코드
CLASS LCL_XXXXX DEFINITION.
PUBLIC SECTION.
METHODS : CONSTRUCTOR IMPORTING IV_WERKS TYPE WERKS_D,
GET_DATA RETURNING VALUE(RT_LIST) TYPE TT_LIST.
PRIVATE SECTION.
DATA : MV_WERKS TYPE WERKS_D,
MT_LIST TYPE TT_LIST.
ENDCLASS.
CLASS LCL_XXXXX IMPLEMENTATION.
METHOD CONSTRUCTOR.
MV_WERKS = IV_WERKS.
ENDMETHOD.
METHOD GET_DATA.
RT_LIST = MT_LIST.
ENDMETHOD.
ENDCLASS.
SUBMIT_PROGRAM-ABAP
- desc: 다른 프로그램 실행 후 결과 받기
- category: 코드
DATA : LT_LIST TYPE TABLE OF ABAPLIST.
SUBMIT ZXXXXX
WITH P_BUKRS EQ GS_LIST-BUKRS
WITH S_MATNR IN S_MATNR
EXPORTING LIST TO MEMORY
AND RETURN.
CALL FUNCTION 'LIST_FROM_MEMORY'
TABLES
LISTOBJECT = LT_LIST
EXCEPTIONS
NOT_FOUND = 1
OTHERS = 2.
RFC_CALL-ABAP
- desc: RFC 원격 호출 (DESTINATION)
- category: 코드
DATA : LV_MSG TYPE STRING.
CALL FUNCTION 'ZXXXXX'
DESTINATION 'XXXXXCLNT100'
EXPORTING
IV_WERKS = GS_LIST-WERKS
TABLES
ET_LIST = GT_LIST
EXCEPTIONS
COMMUNICATION_FAILURE = 1 MESSAGE LV_MSG
SYSTEM_FAILURE = 2 MESSAGE LV_MSG
OTHERS = 3.
IF SY-SUBRC NE 0.
MESSAGE LV_MSG TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
JSON_CONVERT-ABAP
- desc: 인터널 테이블 ↔ JSON 변환
- category: 코드
DATA : LV_JSON TYPE STRING.
"★ITAB → JSON (카멜케이스)
LV_JSON = /UI2/CL_JSON=>SERIALIZE(
DATA = GT_LIST
COMPRESS = ABAP_TRUE
PRETTY_NAME = /UI2/CL_JSON=>PRETTY_MODE-CAMEL_CASE ).
"★JSON → ITAB
/UI2/CL_JSON=>DESERIALIZE(
EXPORTING JSON = LV_JSON
PRETTY_NAME = /UI2/CL_JSON=>PRETTY_MODE-CAMEL_CASE
CHANGING DATA = GT_LIST ).
AUTHORITY_CHECK-ABAP
- desc: 권한 체크
- category: 코드
AUTHORITY-CHECK OBJECT 'M_MATE_WRK'
ID 'ACTVT' FIELD '03'
ID 'WERKS' FIELD GS_LIST-WERKS.
IF SY-SUBRC NE 0.
MESSAGE |플랜트 { GS_LIST-WERKS } 조회 권한이 없습니다.| TYPE 'S' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
COMMIT_ROLLBACK-ABAP
- desc: BAPI 호출 후 커밋/롤백 처리
- category: 코드
DATA : LT_RETURN TYPE TABLE OF BAPIRET2.
CALL FUNCTION 'BAPI_XXXXX_CREATE'
EXPORTING
XXXXX = GS_LIST-XXXXX
TABLES
RETURN = LT_RETURN.
READ TABLE LT_RETURN TRANSPORTING NO FIELDS WITH KEY TYPE = 'E'.
IF SY-SUBRC EQ 0.
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
MESSAGE '처리 실패' TYPE 'S' DISPLAY LIKE 'E'.
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING WAIT = 'X'.
MESSAGE '처리 완료' TYPE 'S'.
ENDIF.
PROMPT_CODE_REVIEW
- desc: 코드리뷰 요청 프롬프트
- category: 코드
아래 코드를 리뷰해줘.
[중점]
1) 버그·엣지케이스 (null, 빈 배열, 동시 요청, 예외 경로)
2) 기존 코드 컨벤션과 어긋나는 부분
3) 지울 수 있는 것 (중복, 안 쓰는 추상화)
[규칙]
- 문제 있는 부분만 지적. 잘한 점 나열 금지.
- 각 지적은 "파일:줄 - 뭐가 문제 - 어떻게 고침" 세 줄로.
- 확실하지 않으면 추측이라고 명시.
[코드]
여기에 붙여넣기
PROMPT_TDD
- desc: 실패하는 테스트부터 요청하는 프롬프트
- category: 코드
TDD로 진행한다.
1) 먼저 실패하는 테스트만 작성해줘. 구현 코드는 아직 쓰지 마.
2) 테스트를 실행해서 실패하는 걸 확인한 뒤 알려줘.
3) 그 다음 테스트를 통과하는 최소 코드만 작성한다.
[요구사항]
여기에 기술
[기존 테스트 스타일]
여기에 붙여넣기
PROMPT_ERROR_FIX
- desc: 에러 원인 분석 요청 프롬프트
- category: 코드
에러가 났어. 추측으로 고치지 말고 순서대로 해줘.
1) 에러 메시지를 그대로 읽고 무슨 뜻인지 설명
2) 재현되는 최소 조건을 찾아 확인
3) 근본 원인 한 줄로 정리 (증상 말고 원인)
4) 같은 함수를 부르는 다른 곳도 같은 문제인지 확인
5) 그 다음에 수정
[에러]
여기에 붙여넣기
[관련 코드]
여기에 붙여넣기
PROMPT_COMMIT
- desc: 커밋 메시지 작성 프롬프트
- category: 코드
아래 변경사항으로 커밋 메시지를 써줘.
[규칙]
- 형식: <type>(<scope>): <한글 요약 50자 이내>
- type: feat / fix / docs / refactor / test / chore
- 본문은 "왜 고쳤는지"만. "무엇을 바꿨는지"는 diff 보면 아니까 생략.
- 여러 관심사가 섞였으면 커밋을 나누라고 알려줘.
[diff]
여기에 붙여넣기
PROMPT_REFACTOR
- desc: 리팩터링 요청 프롬프트 (동작 불변)
- category: 코드
아래 코드를 리팩터링해줘.
[철칙]
- 동작은 한 글자도 바뀌면 안 됨. 기능 추가 금지.
- 테스트가 있으면 먼저 돌려보고, 리팩터 후 다시 돌려서 같은 결과인지 확인.
- 추상화를 새로 만들기 전에 이미 있는 걸 먼저 찾아 쓸 것.
- 변경은 작게 나눠서, 각 단계마다 뭘 왜 바꿨는지 한 줄.
[코드]
여기에 붙여넣기