# 자주 쓰는 스니펫 (import 후보) 현재 `snippets.db` 구조 그대로. 한 스니펫 = `##` 섹션 하나. | md | DB 컬럼 | |---|---| | `## 제목` | `name` (PK, 대문자·공백→`_`) | | `- desc:` | `desc` | | 코드펜스 안 | `body` (원문 그대로) | | `- category:` | `category` | 기존 219개와 이름 안 겹치게 골랐음. 언어 태그(```ts 등)는 읽기 편하라고 붙인 거고 DB 컬럼 아님 — import 할 땐 버리면 됨. --- ## USEQUERY-REACT - desc: react-query 조회 훅 기본형 - category: 코드 ```ts 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: 코드 ```ts 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: 코드 ```ts import { apiGet, apiPost, apiPatch, apiDelete } from '@/lib/api/client' import type { Xxxxx, XxxxxCreate } from '@/types/api' const BASE = '/xxxxxs' export const xxxxxApi = { list: () => apiGet(BASE), get: (id: string) => apiGet(`${BASE}/${id}`), create: (body: XxxxxCreate) => apiPost(BASE, body), update: (id: string, body: Partial) => apiPatch(`${BASE}/${id}`, body), remove: (id: string) => apiDelete(`${BASE}/${id}`), } ``` --- ## AXIOS_MOCK_TEST - desc: axios-mock-adapter 로 api 모듈 테스트 - category: 코드 ```ts 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: 코드 ```tsx 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() await userEvent.click(screen.getByRole('button', { name: '선택' })) expect(onPick).toHaveBeenCalledTimes(1) }) }) ``` --- ## ZUSTAND_STORE - desc: zustand 스토어 기본형 - category: 코드 ```ts import { create } from 'zustand' interface XxxxxState { value: string setValue: (v: string) => void reset: () => void } export const useXxxxxStore = create((set) => ({ value: '', setValue: (value) => set({ value }), reset: () => set({ value: '' }), })) ``` --- ## USEDEBOUNCE - desc: 입력 디바운스 훅 - category: 코드 ```ts import { useEffect, useState } from 'react' export function useDebounce(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: 코드 ```ts 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: 코드 ```ts 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: 코드 ```tsx import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' XXXXX {/* 본문 */} ``` --- ## SSE_STREAM - desc: fetch 로 SSE 스트리밍 받아 한 줄씩 처리 - category: 코드 ```ts 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: 코드 ```ts // .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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```bash 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: 코드 ```python 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: 코드 ```python 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: 코드 ```python 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: 코드 ```bash git reset --soft HEAD~1 # 마지막 커밋만 취소, 변경은 남김 git reset HEAD # 스테이징만 취소 git restore # 파일 변경 버리기 git restore --staged # 스테이징 취소(신형) git revert # 되돌리는 새 커밋 생성(푸시된 커밋용) git reflog # 날린 커밋 찾기 ``` --- ## GIT_STASH - desc: git stash 사용법 - category: 코드 ```bash 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: 코드 ```bash git commit --amend -m "새 메시지" git commit --amend --no-edit git push --force-with-lease ``` --- ## GIT_LOG_PRETTY - desc: 한 줄 그래프 로그 - category: 코드 ```bash git log --oneline --graph --decorate --all -20 git log --since="1 week ago" --author="XXXXX" --oneline ``` --- ## DOCKER_EXEC - desc: 컨테이너 접속·상태 확인 - category: 코드 ```bash docker exec -it /bin/bash docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" docker stats --no-stream docker inspect | grep -i ipaddress ``` --- ## PORT_KILL_WIN - desc: 윈도우에서 포트 점유 프로세스 죽이기 - category: 코드 ```powershell netstat -ano | findstr :8000 taskkill /PID /F # 한 줄 Get-NetTCPConnection -LocalPort 8000 | Select-Object -ExpandProperty OwningProcess | ForEach-Object { Stop-Process -Id $_ -Force } ``` --- ## NPM_CLEAN_INSTALL - desc: node_modules 완전 초기화 재설치 - category: 코드 ```bash 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: 코드 ```bash 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: 코드 ```abap "★★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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```abap "★상위 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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```abap 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: 코드 ```text 아래 코드를 리뷰해줘. [중점] 1) 버그·엣지케이스 (null, 빈 배열, 동시 요청, 예외 경로) 2) 기존 코드 컨벤션과 어긋나는 부분 3) 지울 수 있는 것 (중복, 안 쓰는 추상화) [규칙] - 문제 있는 부분만 지적. 잘한 점 나열 금지. - 각 지적은 "파일:줄 - 뭐가 문제 - 어떻게 고침" 세 줄로. - 확실하지 않으면 추측이라고 명시. [코드] 여기에 붙여넣기 ``` --- ## PROMPT_TDD - desc: 실패하는 테스트부터 요청하는 프롬프트 - category: 코드 ```text TDD로 진행한다. 1) 먼저 실패하는 테스트만 작성해줘. 구현 코드는 아직 쓰지 마. 2) 테스트를 실행해서 실패하는 걸 확인한 뒤 알려줘. 3) 그 다음 테스트를 통과하는 최소 코드만 작성한다. [요구사항] 여기에 기술 [기존 테스트 스타일] 여기에 붙여넣기 ``` --- ## PROMPT_ERROR_FIX - desc: 에러 원인 분석 요청 프롬프트 - category: 코드 ```text 에러가 났어. 추측으로 고치지 말고 순서대로 해줘. 1) 에러 메시지를 그대로 읽고 무슨 뜻인지 설명 2) 재현되는 최소 조건을 찾아 확인 3) 근본 원인 한 줄로 정리 (증상 말고 원인) 4) 같은 함수를 부르는 다른 곳도 같은 문제인지 확인 5) 그 다음에 수정 [에러] 여기에 붙여넣기 [관련 코드] 여기에 붙여넣기 ``` --- ## PROMPT_COMMIT - desc: 커밋 메시지 작성 프롬프트 - category: 코드 ```text 아래 변경사항으로 커밋 메시지를 써줘. [규칙] - 형식: (): <한글 요약 50자 이내> - type: feat / fix / docs / refactor / test / chore - 본문은 "왜 고쳤는지"만. "무엇을 바꿨는지"는 diff 보면 아니까 생략. - 여러 관심사가 섞였으면 커밋을 나누라고 알려줘. [diff] 여기에 붙여넣기 ``` --- ## PROMPT_REFACTOR - desc: 리팩터링 요청 프롬프트 (동작 불변) - category: 코드 ```text 아래 코드를 리팩터링해줘. [철칙] - 동작은 한 글자도 바뀌면 안 됨. 기능 추가 금지. - 테스트가 있으면 먼저 돌려보고, 리팩터 후 다시 돌려서 같은 결과인지 확인. - 추상화를 새로 만들기 전에 이미 있는 걸 먼저 찾아 쓸 것. - 변경은 작게 나눠서, 각 단계마다 뭘 왜 바꿨는지 한 줄. [코드] 여기에 붙여넣기 ```