관리자 NFC 카드 운영 API

관리자가 NFC 재고를 등록하고, 회원에게 발급하고, 명함에 연결하거나 삭제하는 API 명세입니다.

공통 규칙

  • Base path: /v1/admin
  • 인증: Authorization: Bearer {accessToken}
  • 권한: ROLE_ADMIN
  • 일반 사용자는 403 DB0004를 반환합니다.
  • 시간은 기존 API와 동일한 LocalDateTime ISO-8601 문자열입니다.
  • NFC 카드는 발급 회원과 연결 명함을 별도로 기록합니다.
Member 1 ── N NfcCard N ── 0..1 BusinessCard

NFC 카드 식별 필드는 uuid가 아니라 기존 백엔드 용어인 cardUid를 사용합니다. 신규 발급 시 값은 서버가 UUID v4로 생성합니다.

상태와 삭제

상태설명
IN_STOCK시스템에 등록됐지만 회원에게 발급되지 않은 재고 카드
UNCONNECTED회원에게 발급됐지만 명함에 연결되지 않은 카드
CONNECTED명함에 연결되어 사용 가능한 카드
INACTIVE일시적으로 사용하지 않는 카드
LOST분실 신고된 카드
REVOKED폐기된 카드

관리자 삭제는 상태 변경과 별개인 논리 삭제입니다. 삭제된 카드는 DB에 남지만 기본 조회·집계·태그 resolve에서 제외됩니다.

1. 운영 요약 조회

GET /v1/admin/card-operations/summary

Response 200

{
  "totalUsers": 5,
  "totalNfcCards": 7,
  "connectedNfcCards": 2,
  "unconnectedNfcCards": 2,
  "attentionNfcCards": 5
}
  • totalUsers: ACTIVE 상태인 일반·관리자 회원 수
  • totalNfcCards: 논리 삭제되지 않은 카드 수
  • attentionNfcCards: CONNECTED가 아닌 카드 수

2. 사용자 카드 레지스트리 조회

GET /v1/admin/users?query={검색어}&nfcCardStatus={상태}

검색 대상은 이름, 이메일, 명함 slug, 카드 이름, cardUid입니다.

카드 상태와 보유 수량은 businessCardId가 아니라 assignedMemberId를 기준으로 집계합니다. 따라서 명함이 없는 회원에게 발급한 UNCONNECTED 카드도 결과에 포함됩니다.

Response 200

{
  "users": [
    {
      "memberId": "member_01",
      "displayName": "김민서",
      "email": "minseo.kim@taple.team",
      "role": "USER",
      "joinedAt": "2026-07-02T03:12:00",
      "businessCard": {
        "id": "business_card_01",
        "slug": "minseo-kim",
        "published": true
      },
      "cardStatus": "CONNECTED",
      "cardStatuses": ["CONNECTED", "INACTIVE"],
      "lastTaggedAt": "2026-07-15T14:32:00",
      "nfcCardCount": 2
    }
  ]
}

대표 cardStatus 우선순위는 다음과 같습니다.

CONNECTED > LOST > INACTIVE > UNCONNECTED > REVOKED > NONE

3. 회원별 NFC 카드 조회

GET /v1/admin/members/{memberId}/nfc-cards

회원에게 발급된 모든 카드를 assignedMemberId 기준으로 반환합니다. businessCardId가 없는 UNCONNECTED 카드도 포함합니다.

Response 200

{
  "nfcCards": [
    {
      "id": "nfc_01",
      "cardUid": "d3357c7d-190c-4e64-9d8e-434e7aa8231e",
      "label": "메인 비즈니스 카드",
      "status": "CONNECTED",
      "assignedMemberId": "member_01",
      "assignedAt": "2026-07-03T02:10:00",
      "businessCardId": "business_card_01",
      "businessCardSlug": "minseo-kim",
      "activatedAt": "2026-07-03T02:10:00",
      "lastTaggedAt": "2026-07-15T14:32:00"
    }
  ]
}

기존 GET /v1/admin/business-cards/{businessCardId}/nfc-cards는 명함에 연결된 카드만 조회하는 호환용 계약으로 유지합니다.

4. NFC 카드 목록 조회

GET /v1/admin/nfc-cards?status=UNCONNECTED&query={검색어}&unassignedOnly=true
파라미터필수설명
status아니요NFC 카드 상태
query아니요카드 이름 또는 cardUid 부분 검색
unassignedOnly아니요truebusinessCardId가 없는 카드만 조회

응답 형식은 명함별 NFC 카드 조회와 동일합니다.

5. NFC 카드 발급

POST /v1/admin/nfc-cards
Content-Type: application/json

미발급 재고 등록

{
  "label": "미발급 재고 카드",
  "businessCardId": null
}

명함에 즉시 연결하여 발급

{
  "label": "메인 비즈니스 카드",
  "businessCardId": "business_card_01"
}

검증 규칙:

  • label: 공백 제거 후 필수, 최대 30자
  • businessCardId: 선택값. 지정하면 존재하는 명함이어야 함
  • cardUid: 요청으로 받지 않고 서버가 UUID v4 생성
  • businessCardId가 없으면 IN_STOCK, 지정하면 명함 소유자에게 발급 후 CONNECTED

Response 201

{
  "id": "nfc_01",
  "cardUid": "e7f08a26-929f-4a23-a685-e0d356ad938a",
  "label": "메인 비즈니스 카드",
  "status": "CONNECTED",
  "assignedMemberId": "member_01",
  "assignedAt": "2026-07-15T15:40:00",
  "businessCardId": "business_card_01",
  "businessCardSlug": null,
  "activatedAt": "2026-07-15T15:40:00",
  "lastTaggedAt": null
}

6. 재고 NFC 카드를 회원에게 발급

POST /v1/admin/nfc-cards/{cardId}/assign
Content-Type: application/json
{
  "memberId": "member_01"
}
  • 대상 회원 행을 비관적 잠금으로 조회하고 ACTIVE 상태인지 확인합니다.
  • 카드 행을 비관적 잠금으로 조회합니다.
  • IN_STOCK만 발급할 수 있습니다.
  • 성공하면 UNCONNECTED로 변경하고 assignedMemberId, assignedAt을 기록합니다.
  • 대상 회원이 없거나 탈퇴했으면 404 US0001을 반환합니다.
  • 발급할 수 없는 카드 상태면 409 NF0003을 반환합니다.

Response 200

발급된 NFC 카드 단건 응답을 반환합니다.

7. 미연결 NFC 카드 연결

POST /v1/admin/nfc-cards/{cardId}/connect
Content-Type: application/json
{
  "businessCardId": "business_card_01"
}
  • 카드 행을 비관적 잠금으로 조회합니다.
  • IN_STOCK이면 명함 소유자에게 발급하고 즉시 연결합니다.
  • UNCONNECTED이면 발급 회원과 명함 소유자가 같아야 합니다.
  • 성공하면 CONNECTED로 변경하고 activatedAt을 기록합니다.
  • 이미 연결됐거나 연결할 수 없는 상태면 409 NF0002를 반환합니다.

Response 200

NFC 카드 단건 응답을 반환합니다.

8. NFC 카드 삭제

DELETE /v1/admin/nfc-cards/{cardId}

Response 204

본문은 없습니다. 같은 카드를 다시 삭제해도 204를 반환합니다. 존재하지 않는 카드 ID는 404 NF0001입니다.

오류 응답

기존 공통 형식을 사용합니다.

{
  "code": "NF0002",
  "message": "NFC card is not in a connectable state",
  "data": null
}
코드HTTP설명
DB0003400파라미터·본문 검증 실패
DB0004403관리자 권한 없음
US0001404발급할 회원이 없거나 탈퇴함
BC0001404명함을 찾을 수 없음
NF0001404NFC 카드를 찾을 수 없음
NF0002409NFC 카드를 연결할 수 없는 상태
NF0003409NFC 카드를 발급할 수 없는 상태
VALIDATION_FAILED422필수 입력값이 없거나 잘못됨

프론트 URL 조립

백엔드는 프론트 도메인이 포함된 URL을 반환하지 않습니다.

NFC 주소  = {frontendOrigin}/nfc/{cardUid}
공개 주소 = {frontendOrigin}/card/{businessCardSlug}

현재 구현 범위

  • 목록 API는 현재 전체 목록을 반환하며 페이지네이션은 적용하지 않았습니다.
  • 카드 등록·회원 발급·연결·삭제에 대한 별도 관리자 감사 로그는 기록하지 않습니다.
  • 요청 재시도를 위한 idempotency key는 지원하지 않습니다.
  • 카드 상태를 임의로 변경하는 관리자 API는 이번 범위에 포함하지 않았습니다.