Files
2026-09-16 17:22:14 +09:00

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: 코드
아래 코드를 리팩터링해줘.

[철칙]
- 동작은 한 글자도 바뀌면 안 됨. 기능 추가 금지.
- 테스트가 있으면 먼저 돌려보고, 리팩터 후 다시 돌려서 같은 결과인지 확인.
- 추상화를 새로 만들기 전에 이미 있는 걸 먼저 찾아 쓸 것.
- 변경은 작게 나눠서, 각 단계마다 뭘 왜 바꿨는지 한 줄.

[코드]
여기에 붙여넣기