옵션
집 Skill 개발자 도구 systematic-debugging

systematic-debugging

obra/superpowers obra/superpowers

수정안을 제안하기 전에 버그, 테스트 실패 또는 예상치 못한 동작의 근본 원인을 파악하십시오.

...모든 것을 확장하십시오
21
업데이트 된 시간 2026년 9월 3일

체계적인 디버깅

개요

무작위적인 수정 작업은 시간을 낭비할 뿐만 아니라 새로운 버그를 유발합니다. 임시방편적인 수정(퀵 패치)은 근본적인 문제를 가릴 뿐입니다.

핵심 원칙: 수정 작업을 시도하기 전에 반드시 근본 원인을 찾아야 합니다. 증상만 해결하는 것은 실패입니다.

이 프로세스의 문언을 위반하는 것은 디버깅의 정신을 위반하는 것입니다.

철칙

근본 원인 조사 없이는 수정 금지

1단계를 완료하지 않았다면 수정안을 제안할 수 없습니다.

사용 시점

모든 기술적 문제에 적용:

  • 테스트 실패
  • 운영 환경의 버그
  • 예상치 못한 동작
  • 성능 문제
  • 빌드 실패
  • 통합 문제

특히 다음과 같은 경우에 이 방법을 사용하십시오:

  • 시간적 압박을 받을 때 (긴급 상황에서는 추측에 의존하고 싶어지기 마련입니다)
  • "단순히 한 번만 빠르게 고치면 된다"는 생각이 들 때
  • 이미 여러 가지 해결책을 시도해 본 경우
  • 이전 해결책이 효과가 없었을 때
  • 문제를 완전히 이해하지 못하는 경우

다음과 같은 경우에는 건너뛰지 마세요:

  • 문제가 단순해 보일 때 (단순한 버그에도 근본 원인이 있습니다)
  • 시간이 촉박할 때 (서두르면 재작업이 불가피합니다)
  • 관리자가 ‘지금 당장’ 해결을 원할 때 (체계적인 접근이 무작정 시도하는 것보다 빠릅니다)

4단계

다음 단계로 넘어가기 전에 각 단계를 반드시 완료해야 합니다.

1단계: 근본 원인 조사

어떤 수정 작업도 시도하기 전에:

  1. 오류 메시지를 주의 깊게 읽으십시오

    • 오류나 경고 메시지를 그냥 넘기지 마십시오
    • 오류나 경고 메시지에는 대개 정확한 해결책이 포함되어 있습니다
    • 스택 트레이스를 끝까지 읽어보세요
    • 줄 번호, 파일 경로, 오류 코드를 기록하십시오
  2. 일관되게 재현하십시오

    • 이 현상을 확실하게 재현할 수 있습니까?
    • 정확한 단계는 무엇입니까?
    • 매번 발생하나요?
    • 재현할 수 없는 경우 → 더 많은 데이터를 수집하고, 추측하지 마세요
  3. 최근 변경 사항 확인

    • 이 현상을 유발할 만한 변경 사항은 무엇입니까?
    • Git diff, 최근 커밋
    • 새로운 의존성, 설정 변경
    • 환경 차이
  4. 다중 구성 요소 시스템에서 증거 수집

    시스템에 여러 구성 요소가 있는 경우(CI → 빌드 → 서명, API → 서비스 → 데이터베이스):

    수정안을 제안하기 전에 진단 도구를 추가하십시오:

    각 구성 요소 경계마다:
      - 구성 요소로 들어오는 데이터를 기록
      - 구성 요소에서 나가는 데이터를 기록
      - 환경/구성 정보의 전파 확인
      - 각 계층의 상태 확인
    
    한 번 실행하여 오류가 발생하는 위치를 보여주는 증거를 수집
    그런 다음 증거를 분석하여 오류가 발생한 구성 요소를 식별
    그런 다음 해당 특정 구성 요소를 조사
    

    예시 (다층 시스템):

    # 레이어 1: 워크플로우
    echo "=== 워크플로우에서 사용 가능한 시크릿: ==="
    echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}"
    
    # 레이어 2: 빌드 스크립트
    echo "=== 빌드 스크립트의 환경 변수: ==="
    env | grep IDENTITY || echo "환경에 IDENTITY가 없음"
    
    # 레이어 3: 서명 스크립트
    echo "=== 키체인 상태: ==="
    security list-keychains
    security find-identity -v
    
    # 레이어 4: 실제 서명
    codesign --sign "$IDENTITY" --verbose=4 "$APP"
    

    이를 통해 다음이 드러납니다: 어떤 레이어에서 오류가 발생하는지 (시크릿 → 워크플로우 ✓, 워크플로우 → 빌드 ✗)

  5. 데이터 흐름 추적

    오류가 호출 스택 깊숙한 곳에 있는 경우:

    전체 역추적 기법에 대해서는 이 디렉터리의 root-cause-tracing.md 파일을 참조하십시오.

    간단한 설명:

    • 잘못된 값은 어디에서 비롯되었는가?
    • 어떤 함수가 잘못된 값을 전달하며 이 함수를 호출했는가?
    • 원인을 찾을 때까지 위쪽으로 계속 추적하세요
    • 증상이 나타나는 곳이 아니라 근원지에서 해결하십시오

2단계: 패턴 분석

수정하기 전에 패턴을 찾아보세요:

  1. 정상 작동하는 예제 찾기

    • 동일한 코드베이스에서 유사한 정상 작동 코드를 찾아보세요
    • 오류가 발생한 코드와 유사하면서도 정상적으로 작동하는 코드는 무엇인가?
  2. 참조 코드와 비교하기

    • 패턴을 구현할 경우, 참조 구현을 철저히 읽어보세요
    • 대충 훑어보지 말고, 모든 줄을 꼼꼼히 읽으세요
    • 적용하기 전에 패턴을 완전히 이해하십시오
  3. 차이점 파악하기

    • 정상 작동하는 경우와 오류가 발생하는 경우의 차이점은 무엇인가?
    • 아무리 사소한 차이라도 모두 나열하십시오
    • “그건 중요하지 않을 거야”라고 가정하지 마세요
  4. 의존성을 파악하세요

    • 이것에 필요한 다른 구성 요소는 무엇인가요?
    • 어떤 설정, 구성, 환경이 필요한가?
    • 어떤 가정을 전제로 하고 있나요?

3단계: 가설 수립 및 검증

과학적 방법:

  1. 단일 가설 수립

    • 명확히 기술하기: “Y이기 때문에 X가 근본 원인이라고 생각한다”
    • 적어 두기
    • 모호하지 말고 구체적으로 작성하기
  2. 최소한의 실험으로 검증하기

    • 가설을 검증하기 위해 가능한 한 최소한의 변화만 주십시오
    • 한 번에 하나의 변수만 변경하세요
    • 한 번에 여러 가지를 수정하지 마세요
  3. 계속 진행하기 전에 검증하세요

    • 효과가 있었나요? 예 → 4단계
    • 효과가 없었나요? 새로운 가설을 세우세요
    • 그 위에 수정 사항을 더 추가하지 마세요
  4. 모르겠을 때

    • “X를 이해하지 못하겠습니다”라고 말하세요
    • 아는 척하지 마세요
    • 도움을 요청하세요
    • 더 자세히 조사하세요

4단계: 실행

증상이 아니라 근본 원인을 해결하세요:

  1. 실패하는 테스트 케이스 작성

    • 가능한 한 간단한 재현 방법
    • 가능하면 자동화된 테스트
    • 프레임워크가 없다면 일회용 테스트 스크립트 작성
    • 수정 전에 반드시 확인해야 할 사항
    • 올바른 실패 테스트를 작성하려면 '테스트 주도 개발(TDD)' 기술을 활용하세요
  2. 단일 수정 사항 구현

    • 확인된 근본 원인을 해결하십시오
    • 한 번에 한 가지 변경만 수행
    • "이왕 하는 김에"라는 식의 개선은 하지 마세요
    • 리팩토링을 한꺼번에 묶어 처리하지 마세요
  3. 수정 사항 검증

    • 테스트가 이제 통과되나요?
    • 다른 테스트는 깨지지 않았나요?
    • 문제가 실제로 해결되었나요?
  4. 수정 사항이 효과가 없다면

    • 중지
    • 횟수: 몇 번이나 수정해 보셨나요?
    • 3개 미만인 경우: 1단계로 돌아가 새로운 정보를 바탕으로 재분석하십시오
    • 3개 이상인 경우: 중지하고 아키텍처에 대해 재검토하십시오(아래 5단계 참조)
    • 아키텍처에 대한 논의 없이는 수정안 #4를 시도하지 마십시오
  5. 3개 이상의 수정 방법이 실패한 경우: 아키텍처에 의문을 제기하십시오

    아키텍처 문제를 나타내는 패턴:

    • 각 수정 시마다 서로 다른 위치에서 새로운 공유 상태/결합/문제가 드러남
    • 수정 사항을 구현하려면 “대규모 리팩토링”이 필요합니다
    • 각 수정 조치마다 다른 곳에서 새로운 증상이 발생합니다

    잠시 멈추고 기본 원칙을 재검토하십시오:

    • 이 패턴은 근본적으로 타당한가?
    • 우리가 “단순한 관성 때문에” 이 방식을 고수하고 있는 것은 아닐까?
    • 증상을 계속 수정할 것인가, 아니면 아키텍처를 리팩토링해야 할 것인가?

    더 많은 수정 작업을 시도하기 전에 동료와 논의하십시오

    이것은 실패한 가설이 아닙니다. 잘못된 아키텍처입니다.

경고 신호 - 중단하고 프로세스를 따르세요

다음과 같은 생각이 든다면:

  • "일단 임시로 고치고 나중에 조사하자"
  • "그냥 X를 바꿔 보고 작동하는지 확인해 보자"
  • "여러 가지 변경 사항을 추가하고 테스트를 실행해 보자"
  • "테스트는 건너뛰고, 수동으로 확인해 볼게"
  • "아마 X 때문일 거야, 그거 고쳐볼게"
  • "완전히 이해하진 못했지만 이 방법이 통할 수도 있어"
  • "패턴상으로는 X라고 되어 있지만, 저는 다르게 적용해 볼게요"
  • "주요 문제는 다음과 같습니다: [조사 없이 수정 사항 나열]"
  • 데이터 흐름을 추적하기 전에 해결책을 제안함
  • "한 번 더 수정해 볼게요" (이미 2회 이상 시도한 경우)
  • 수정할 때마다 다른 곳에서 새로운 문제가 드러남

이 모든 것은 ‘중단’을 의미합니다. 1단계로 되돌아가세요.

3회 이상의 수정 시도가 실패했다면: 아키텍처에 의문을 제기하세요 (4.5단계 참조)

동료의 ‘그건 잘못된 방법이다’라는 신호

다음과 같은 화제 전환에 주의하세요:

  • "그게 일어나지 않나요?" — 확인도 없이 가정해 버렸습니다
  • "그게 우리에게 보여줄까요...?" - 증거 수집 단계를 추가했어야 했습니다
  • "추측은 그만해" - 상황을 제대로 이해하지 못한 채 해결책을 제안하고 있다
  • "이 문제를 깊이 있게 생각해 봐" - 단순한 증상이 아니라 근본 원인을 따져보라는 뜻
  • "막혔나요?" (좌절감) - 당신의 접근 방식이 통하지 않습니다

이런 표현을 보게 되면: 멈추세요. 1단계로 돌아가세요.

흔히 하는 합리화

변명 현실
"문제는 간단하니 절차 따위는 필요 없어" 단순한 문제에도 근본 원인은 있습니다. 간단한 버그의 경우 절차에 따라 처리하는 것이 더 빠릅니다.
"긴급한 상황이라 절차를 따를 시간이 없다" 체계적인 디버깅은 막무가내로 추측하고 확인하는 방식보다 더 빠릅니다.
"일단 이걸 먼저 시도해 보고, 그다음에 조사하자" 첫 번째 수정 방식이 향후 패턴을 정합니다. 처음부터 제대로 하세요.
"수정 사항이 작동하는지 확인한 뒤에 테스트를 작성할게요" 테스트되지 않은 수정 사항은 오래가지 못합니다. 먼저 테스트해야 그 효과가 입증됩니다.
"한 번에 여러 가지를 수정하면 시간을 절약할 수 있다" 무엇이 효과가 있었는지 파악할 수 없습니다. 새로운 버그를 유발합니다.
"참조 문장이 너무 길어. 패턴을 좀 바꿔 볼게" 부분적인 이해는 버그를 보장합니다. 전체를 꼼꼼히 읽어보세요.
"문제를 파악했으니, 제가 고쳐볼게요" 증상을 파악하는 것과 근본 원인을 이해하는 것은 다릅니다.
"한 번 더 수정해 볼게요" (2회 이상 실패 후) 3회 이상 실패 = 아키텍처 문제. 패턴을 재검토하고, 다시 수정하지 마세요.

빠른 참조

단계 주요 활동 성공 기준
1. 근본 원인 오류 확인, 재현, 변경 사항 점검, 증거 수집 '무엇'과 '왜'를 파악
2. 패턴 정상 작동하는 사례 찾기, 비교 차이점 파악
3. 가설 이론을 세우고, 최소한의 테스트를 수행한다 가설 확인 또는 새로운 가설 도출
4. 구현 테스트 생성, 수정, 검증 버그 해결, 테스트 통과

프로세스 조사 결과 “근본 원인 없음”으로 판명될 때

체계적인 조사 결과 문제가 실제로 환경적, 타이밍에 따른, 또는 외부적인 요인에 기인한 것으로 밝혀진 경우:

  1. 프로세스를 완료한 것입니다
  2. 조사한 내용을 문서화하십시오
  3. 적절한 처리 방식(재시도, 타임아웃, 오류 메시지)을 구현하십시오
  4. 향후 조사를 위해 모니터링 및 로깅 기능을 추가하십시오

하지만: “근본 원인 미확인” 사례의 95%는 조사가 불완전하기 때문입니다.

지원 기법

이러한 기법들은 체계적인 디버깅의 일부이며 다음 디렉터리에 포함되어 있습니다:

  • root-cause-tracing.md - 호출 스택을 거슬러 올라가 버그의 근본 원인을 추적하여 최초의 유발 요인을 찾습니다
  • defense-in-depth.md - 근본 원인을 파악한 후 여러 계층에서 유효성 검사를 추가합니다
  • condition-based-waiting.md - 임의의 타임아웃을 조건 기반 폴링으로 대체

관련 기술:

  • superpowers:test-driven-development - 실패하는 테스트 케이스 생성용 (4단계, 1단계)
  • superpowers:verification-before-completion - 성공을 선언하기 전에 수정 사항이 제대로 작동하는지 검증하기

실제 영향

디버깅 세션에서:

  • 체계적인 접근 방식: 수정하는 데 15~30분 소요
  • 무작위 수정 방식: 2~3시간 동안의 고군분투
  • 첫 번째 시도 성공률: 95% 대 40%
  • 새로운 버그 발생: 거의 없음 vs 빈번함
GitHub에서 보기
---
name: systematic-debugging
description: Find root causes of bugs, test failures, or unexpected behavior before proposing any fixes.
---

# Systematic Debugging

## Overview

Random fixes waste time and create new bugs. Quick patches mask underlying issues.

**Core principle:** ALWAYS find root cause before attempting fixes. Symptom fixes are failure.

**Violating the letter of this process is violating the spirit of debugging.**

## The Iron Law

```
NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
```

If you haven't completed Phase 1, you cannot propose fixes.

## When to Use

Use for ANY technical issue:
- Test failures
- Bugs in production
- Unexpected behavior
- Performance problems
- Build failures
- Integration issues

**Use this ESPECIALLY when:**
- Under time pressure (emergencies make guessing tempting)
- "Just one quick fix" seems obvious
- You've already tried multiple fixes
- Previous fix didn't work
- You don't fully understand the issue

**Don't skip when:**
- Issue seems simple (simple bugs have root causes too)
- You're in a hurry (rushing guarantees rework)
- Manager wants it fixed NOW (systematic is faster than thrashing)

## The Four Phases

You MUST complete each phase before proceeding to the next.

### Phase 1: Root Cause Investigation

**BEFORE attempting ANY fix:**

1. **Read Error Messages Carefully**
   - Don't skip past errors or warnings
   - They often contain the exact solution
   - Read stack traces completely
   - Note line numbers, file paths, error codes

2. **Reproduce Consistently**
   - Can you trigger it reliably?
   - What are the exact steps?
   - Does it happen every time?
   - If not reproducible → gather more data, don't guess

3. **Check Recent Changes**
   - What changed that could cause this?
   - Git diff, recent commits
   - New dependencies, config changes
   - Environmental differences

4. **Gather Evidence in Multi-Component Systems**

   **WHEN system has multiple components (CI → build → signing, API → service → database):**

   **BEFORE proposing fixes, add diagnostic instrumentation:**
   ```
   For EACH component boundary:
     - Log what data enters component
     - Log what data exits component
     - Verify environment/config propagation
     - Check state at each layer

   Run once to gather evidence showing WHERE it breaks
   THEN analyze evidence to identify failing component
   THEN investigate that specific component
   ```

   **Example (multi-layer system):**
   ```bash
   # Layer 1: Workflow
   echo "=== Secrets available in workflow: ==="
   echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}"

   # Layer 2: Build script
   echo "=== Env vars in build script: ==="
   env | grep IDENTITY || echo "IDENTITY not in environment"

   # Layer 3: Signing script
   echo "=== Keychain state: ==="
   security list-keychains
   security find-identity -v

   # Layer 4: Actual signing
   codesign --sign "$IDENTITY" --verbose=4 "$APP"
   ```

   **This reveals:** Which layer fails (secrets → workflow ✓, workflow → build ✗)

5. **Trace Data Flow**

   **WHEN error is deep in call stack:**

   See `root-cause-tracing.md` in this directory for the complete backward tracing technique.

   **Quick version:**
   - Where does bad value originate?
   - What called this with bad value?
   - Keep tracing up until you find the source
   - Fix at source, not at symptom

### Phase 2: Pattern Analysis

**Find the pattern before fixing:**

1. **Find Working Examples**
   - Locate similar working code in same codebase
   - What works that's similar to what's broken?

2. **Compare Against References**
   - If implementing pattern, read reference implementation COMPLETELY
   - Don't skim - read every line
   - Understand the pattern fully before applying

3. **Identify Differences**
   - What's different between working and broken?
   - List every difference, however small
   - Don't assume "that can't matter"

4. **Understand Dependencies**
   - What other components does this need?
   - What settings, config, environment?
   - What assumptions does it make?

### Phase 3: Hypothesis and Testing

**Scientific method:**

1. **Form Single Hypothesis**
   - State clearly: "I think X is the root cause because Y"
   - Write it down
   - Be specific, not vague

2. **Test Minimally**
   - Make the SMALLEST possible change to test hypothesis
   - One variable at a time
   - Don't fix multiple things at once

3. **Verify Before Continuing**
   - Did it work? Yes → Phase 4
   - Didn't work? Form NEW hypothesis
   - DON'T add more fixes on top

4. **When You Don't Know**
   - Say "I don't understand X"
   - Don't pretend to know
   - Ask for help
   - Research more

### Phase 4: Implementation

**Fix the root cause, not the symptom:**

1. **Create Failing Test Case**
   - Simplest possible reproduction
   - Automated test if possible
   - One-off test script if no framework
   - MUST have before fixing
   - Use the `superpowers:test-driven-development` skill for writing proper failing tests

2. **Implement Single Fix**
   - Address the root cause identified
   - ONE change at a time
   - No "while I'm here" improvements
   - No bundled refactoring

3. **Verify Fix**
   - Test passes now?
   - No other tests broken?
   - Issue actually resolved?

4. **If Fix Doesn't Work**
   - STOP
   - Count: How many fixes have you tried?
   - If < 3: Return to Phase 1, re-analyze with new information
   - **If ≥ 3: STOP and question the architecture (step 5 below)**
   - DON'T attempt Fix #4 without architectural discussion

5. **If 3+ Fixes Failed: Question Architecture**

   **Pattern indicating architectural problem:**
   - Each fix reveals new shared state/coupling/problem in different place
   - Fixes require "massive refactoring" to implement
   - Each fix creates new symptoms elsewhere

   **STOP and question fundamentals:**
   - Is this pattern fundamentally sound?
   - Are we "sticking with it through sheer inertia"?
   - Should we refactor architecture vs. continue fixing symptoms?

   **Discuss with your human partner before attempting more fixes**

   This is NOT a failed hypothesis - this is a wrong architecture.

## Red Flags - STOP and Follow Process

If you catch yourself thinking:
- "Quick fix for now, investigate later"
- "Just try changing X and see if it works"
- "Add multiple changes, run tests"
- "Skip the test, I'll manually verify"
- "It's probably X, let me fix that"
- "I don't fully understand but this might work"
- "Pattern says X but I'll adapt it differently"
- "Here are the main problems: [lists fixes without investigation]"
- Proposing solutions before tracing data flow
- **"One more fix attempt" (when already tried 2+)**
- **Each fix reveals new problem in different place**

**ALL of these mean: STOP. Return to Phase 1.**

**If 3+ fixes failed:** Question the architecture (see Phase 4.5)

## your human partner's Signals You're Doing It Wrong

**Watch for these redirections:**
- "Is that not happening?" - You assumed without verifying
- "Will it show us...?" - You should have added evidence gathering
- "Stop guessing" - You're proposing fixes without understanding
- "Ultra-think this" - Question fundamentals, not just symptoms
- "We're stuck?" (frustrated) - Your approach isn't working

**When you see these:** STOP. Return to Phase 1.

## Common Rationalizations

| Excuse | Reality |
|--------|---------|
| "Issue is simple, don't need process" | Simple issues have root causes too. Process is fast for simple bugs. |
| "Emergency, no time for process" | Systematic debugging is FASTER than guess-and-check thrashing. |
| "Just try this first, then investigate" | First fix sets the pattern. Do it right from the start. |
| "I'll write test after confirming fix works" | Untested fixes don't stick. Test first proves it. |
| "Multiple fixes at once saves time" | Can't isolate what worked. Causes new bugs. |
| "Reference too long, I'll adapt the pattern" | Partial understanding guarantees bugs. Read it completely. |
| "I see the problem, let me fix it" | Seeing symptoms ≠ understanding root cause. |
| "One more fix attempt" (after 2+ failures) | 3+ failures = architectural problem. Question pattern, don't fix again. |

## Quick Reference

| Phase | Key Activities | Success Criteria |
|-------|---------------|------------------|
| **1. Root Cause** | Read errors, reproduce, check changes, gather evidence | Understand WHAT and WHY |
| **2. Pattern** | Find working examples, compare | Identify differences |
| **3. Hypothesis** | Form theory, test minimally | Confirmed or new hypothesis |
| **4. Implementation** | Create test, fix, verify | Bug resolved, tests pass |

## When Process Reveals "No Root Cause"

If systematic investigation reveals issue is truly environmental, timing-dependent, or external:

1. You've completed the process
2. Document what you investigated
3. Implement appropriate handling (retry, timeout, error message)
4. Add monitoring/logging for future investigation

**But:** 95% of "no root cause" cases are incomplete investigation.

## Supporting Techniques

These techniques are part of systematic debugging and available in this directory:

- **`root-cause-tracing.md`** - Trace bugs backward through call stack to find original trigger
- **`defense-in-depth.md`** - Add validation at multiple layers after finding root cause
- **`condition-based-waiting.md`** - Replace arbitrary timeouts with condition polling

**Related skills:**
- **superpowers:test-driven-development** - For creating failing test case (Phase 4, Step 1)
- **superpowers:verification-before-completion** - Verify fix worked before claiming success

## Real-World Impact

From debugging sessions:
- Systematic approach: 15-30 minutes to fix
- Random fixes approach: 2-3 hours of thrashing
- First-time fix rate: 95% vs 40%
- New bugs introduced: Near zero vs common

모든 파일

0개 파일

systematic-debugging 설치

스킬 파일을 다운로드하여 .claude/skills/ 디렉터리에 압축을 풀어 주세요.

ZIP 다운로드

저장소를 클론하고 스킬 파일을 프로젝트에 복사하세요.

git clone https://github.com/obra/superpowers/tree/main/skills/systematic-debugging # Copy SKILL.md to your .claude/skills/ directory

복사 복사
빠른 설정: 스킬 폴더를 .claude/skills/로 복사하세요. Claude가 해당 스킬을 자동으로 감지하여 사용합니다.
저장소 obra/superpowers

관련 스킬

algorithmic-art
업데이트 된 시간 2026년 8월 27일
receiving-code-review
업데이트 된 시간 2026년 9월 3일
tech-debt-tracker
업데이트 된 시간 2026년 8월 29일
senior-backend
업데이트 된 시간 2026년 8월 30일
OR