테마
Story: 크레딧 관리 API
메타
| 항목 | 값 |
|---|---|
| Story ID | E-02-S-04 |
| Epic | E-02 어드민 강화 |
| 상태 | draft |
| 우선순위 | P1 |
| 규모 | S |
| 담당 개발자 | BE (하록님) |
사용자 스토리
As a CS팀/운영팀 관리자, I want 사용자 크레딧 잔액을 조회하고 직접 지급/차감, So that CS 보상을 즉시 처리하고 오지급 시 회수할 수 있다.
수락 기준 (Acceptance Criteria)
AC-01: 크레딧 잔액 조회
| 항목 | 내용 |
|---|---|
| Given | 특정 사업장 ID (bizId) |
| When | 잔액 조회 요청 |
| Then | 해당 사업장의 크레딧 잔액 + 통계 반환 |
응답 필드:
{
bizId: number,
bizName: string, // Biz 테이블 조인
balance: number, // 현재 잔액
totalEarned: number, // 총 적립액
totalUsed: number, // 총 사용액
totalExpired: number, // 총 만료액
updatedAt: string
}AC-02: 크레딧 지급
| 항목 | 내용 |
|---|---|
| Given | bizId, 금액, 사유 |
| When | 크레딧 지급 요청 |
| Then | 크레딧이 지급되고 원장에 기록됨 |
요청 필드:
{
bizId: number, // 필수
amount: number, // 필수, 양수
reason: string, // 필수 (지급 사유)
expireAt?: string // 선택 (만료일, 기본 90일 후)
}처리 로직:
- CreditBalance 생성 또는 업데이트 (balance += amount)
- CreditLedger에 EARN 타입 기록
- 지급 내역 반환
AC-03: 크레딧 거래 이력 조회
| 항목 | 내용 |
|---|---|
| Given | 특정 사업장 ID |
| When | 거래 이력 조회 |
| Then | 해당 사업장의 전체 크레딧 이력 반환 |
응답 필드:
{
items: [{
id, bizId,
type, // EARN, USE, EXPIRE, REFUND, HOLD, CANCEL
amount, // 금액 (EARN: +, USE/EXPIRE: -)
balanceAfter, // 거래 후 잔액
reason, // 지급/사용 사유
expireAt, // 만료 예정일
createdAt
}],
pagination: { page, size, total, totalPages }
}필터:
- type (전체/적립/사용/만료)
AC-04: 존재하지 않는 사업장
| 항목 | 내용 |
|---|---|
| Given | 존재하지 않는 bizId |
| When | 잔액 조회/지급 요청 |
| Then | 404 Not Found |
AC-05: 잘못된 금액
| 항목 | 내용 |
|---|---|
| Given | amount ≤ 0 |
| When | 크레딧 지급 요청 |
| Then | 400 Bad Request + "지급 금액은 0보다 커야 합니다" |
AC-06: 크레딧 차감/취소
| 항목 | 내용 |
|---|---|
| Given | bizId, 차감 금액, 사유 |
| When | 크레딧 차감 요청 |
| Then | 크레딧이 차감되고 원장에 기록됨 |
요청 필드:
{
bizId: number, // 필수
amount: number, // 필수, 양수
reason: string, // 필수 (차감 사유)
type: string // DEDUCT | CANCEL (차감 유형)
}처리 로직:
- 잔액 부족 검증 (balance >= amount)
- CreditBalance 업데이트 (balance -= amount)
- CreditLedger에 USE 또는 CANCEL 타입 기록
- 잔액 부족 시 400 + "잔액이 부족합니다"
사용 시나리오:
- DEDUCT: 오지급된 크레딧 회수
- CANCEL: 지급 취소 (사유: "오지급 취소" 등)
태스크 분해
Task 1: 잔액 조회 API AC-01, AC-04
- [ ] 1.1:
GET /admin/credits/balance/:bizId엔드포인트 생성 - [ ] 1.2: CreditBalance + Biz 조인 쿼리
- [ ] 1.3: 잔액이 없는 경우 기본값 반환 (0)
- [ ] 1.4: 사업장 존재 여부 검증
Task 2: 크레딧 지급 API AC-02, AC-04, AC-05
- [ ] 2.1:
POST /admin/credits/grant엔드포인트 생성 - [ ] 2.2: 요청 DTO 정의 + 유효성 검증
- [ ] 2.3: 사업장 존재 여부 검증
- [ ] 2.4: CreditBalance upsert 로직
- [ ] 2.5: CreditLedger EARN 기록
- [ ] 2.6: 트랜잭션 처리
Task 3: 거래 이력 API AC-03
- [ ] 3.1:
GET /admin/credits/ledger/:bizId엔드포인트 생성 - [ ] 3.2: CreditLedger 조회 + 페이지네이션
- [ ] 3.3: type 필터 구현
- [ ] 3.4: 정렬 (최신순)
Task 4: 크레딧 차감/취소 API AC-06
- [ ] 4.1:
POST /admin/credits/deduct엔드포인트 생성 - [ ] 4.2: 요청 DTO 정의 + 유효성 검증
- [ ] 4.3: 잔액 부족 검증 로직
- [ ] 4.4: CreditBalance 차감 업데이트
- [ ] 4.5: CreditLedger USE/CANCEL 기록
- [ ] 4.6: 트랜잭션 처리
Task 5: 테스트 작성
- [ ] 5.1: 잔액 조회 테스트
- [ ] 5.2: 크레딧 지급 테스트 (정상/에러)
- [ ] 5.3: 크레딧 차감/취소 테스트 (정상/잔액부족)
- [ ] 5.4: 이력 조회 테스트
- [ ] 5.5: 트랜잭션 롤백 테스트
Task 6: 마무리
- [ ] 6.1: API 문서화
- [ ] 6.2: PR 생성
Dev Notes (AI Agent 최적화)
아키텍처 패턴
| 항목 | 내용 |
|---|---|
| 사용할 패턴 | Repository Pattern + Service Layer |
| 참고 구현 | 기존 CreditService (S52 E-07) |
| 피해야 할 것 | 잔액 업데이트 시 트랜잭션 누락 |
영향 받는 소스 트리
src/
├── admin/
│ └── credit/
│ ├── credit.admin.controller.ts # 🆕 신규 생성
│ ├── credit.admin.service.ts # 🆕 신규 생성
│ └── dto/
│ └── grant-credit.dto.ts # 🆕 신규 생성
└── tests/
└── admin/
└── credit.admin.spec.ts # 🆕 신규 생성비즈니스 로직 상세
크레딧 지급 트랜잭션
typescript
// 유사 코드
await prisma.$transaction(async (tx) => {
// 1. CreditBalance upsert
const balance = await tx.creditBalance.upsert({
where: { bizId },
create: { bizId, balance: amount, totalEarned: amount },
update: {
balance: { increment: amount },
totalEarned: { increment: amount }
}
});
// 2. CreditLedger 기록
await tx.creditLedger.create({
data: {
bizId,
type: 'EARN',
amount,
balanceAfter: balance.balance,
reason,
expireAt: expireAt || addDays(new Date(), 90)
}
});
});충돌 감지
| 항목 | 상태 | 설명 |
|---|---|---|
| 기존 코드 충돌 | ⚠️ 주의 | 기존 CreditService와 역할 분리 확인 |
| API 계약 변경 | ✅ 없음 | 신규 어드민 엔드포인트 |
| DB 스키마 변경 | ✅ 없음 | 기존 테이블 사용 |
References
| 출처 | 경로/링크 | 참조 섹션 |
|---|---|---|
| Epic Spec | .context/sprints/s53/epic-specs/E-02.md | 크레딧 API 설계 |
| 테이블 스키마 | S52 E-07 DDL | CreditBalance, CreditLedger |
| 기존 서비스 | src/credit/credit.service.ts | 로직 참고 |
Dev Agent Record
| 항목 | 값 |
|---|---|
| 생성 Agent | Claude Opus 4.5 |
| 생성일 | 2026-01-27 |
| 마지막 수정 | 2026-01-27 |
| 검증자 | - |
검증 결과: 🔄 PENDING (PO 승인 대기) 검증일: -
생성일: 2026-01-27마지막 수정: 2026-01-27
