들어가면서 — AI를 쓰는 사람이 많아졌지만

회사에서는 Cursor.ai, 사내에서 만든 Cline, Codex를 쓰고, 집에서는 Claude Code, Antigravity 같은 도구들을 사용한다. 모델도 다르고, UI도 다르고, 자동화 수준도 제각각이다.

 

AI를 쓰는 사람은 확실히 많아졌고, 개인적으로도 퍼포먼스가 올라갔다는 느낌은 분명하다.

 

그런데 어느 순간 이런 생각이 들었다.

왜 같은 코드베이스, 같은 문서를 두고
결과의 느낌이 이렇게 다를까?

 

어떤 날은 굉장히 매끄럽게 일이 풀리고, 어떤 날은 결과는 나왔지만 찜찜함이 남는다. 이걸 단순히 “모델 차이”나 “도구 숙련도”로만 설명하기는 어려웠다.

 

그러다 문득 질문이 바뀌었다.

이건 AI를 어떻게 쓰느냐의 문제가 아니라,
AI와 함께 _어떤 순서로 생각하고 있느냐_의 문제 아닐까?

내가 정리해본 AI와 일하는 기본 흐름

이 질문을 계기로, 내가 AI와 일할 때 암묵적으로 거치고 있던 단계를 한 번 정리해봤다.
표준도 아니고, 규칙도 아니다. 그냥 내 개인적인 경험을 구조로 적어본 것에 가깝다.

0. Context Setting 
1. Problem Space Definition 
2. Option / Proposal Generation 
3. Human Adjustment (HITL zone) 
4. Execution 
5. Review & Learning (optional but recommended)

0. Context Setting

AI에게 일을 시키기 전에,
이 대화에서 무엇을 기준으로 삼을지를 먼저 맞춘다.

  • 코드베이스
  • docs/specs
  • 개인적으로 정리해둔 notes
  • 툴에 따라 미리 설정하는 문서 (e.g. CLAUDE.md)

이 단계는 결과를 만들기 위한 준비라기보다, 대화의 전제를 맞추는 과정에 가깝다.
지금 생각해보면, 이건 거의 System Prompt에 해당한다.

1. Problem Space Definition

그다음은 문제 정의다. 여기에는 두 가지가 섞여 있다.

  • 무엇을 구현하려는가
  • 무엇을 고치려는가

PRD나 Feature Requirement Doc이 있는 경우도 있고, 단순한 개선이나 리팩토링일 때도 있다. 중요한 건 이번 작업에서 하지 않을 것(out of scope)까지 함께 정리하는 것이다.

2. Option / Proposal Generation

이 단계에서 일부러 바로 실행하지 않는다.

  • 가능한 선택지를 몇 개 만들어보고
  • 각 선택이 전제하고 있는 가정을 살펴본다

이건 속도를 늦추기 위한 단계라기보다는, 사고 공간을 넓히기 위한 단계에 가깝다.

3. Human Adjustment (HITL zone)

여기가 사람이 가장 적극적으로 개입하는 구간이다.

  • 조건을 바꿔보거나
  • 관점을 바꿔보거나
  • 중요도를 재정렬해본다

여기서의 인간은 승인자가 아니라, 사고를 조정하는 존재에 가깝다.

4. Execution

조건과 방향이 어느 정도 정리된 뒤에 실행한다. 이때는 오히려 속도가 빨라진다. 무엇을 왜 하는지가 비교적 명확해져 있기 때문이다.

5. Review & Learning

항상 하지는 않지만, 가끔은 이렇게 돌아본다.

  • 이 단계는 다음에 기계에게 넘겨도 될까?
  • 어디까지는 자동화해도 괜찮을까?

이건 결과 평가라기보다, 다음 루프를 위한 정리에 가깝다.

HITL을 돌아보며 — 우리는 어디에 서 있는가

이 흐름을 정리하다 보니, Human-in-the-loop(HITL)를 이분법으로 보는 시선이 조금 불편해졌다. 현실은 훨씬 연속적이다.

Human-out-of-the-loop
         ↓ 
Machine-in-the-loop
         ↓ 
Human-on-the-loop
         ↓ 
Human-in-the-loop

 

중요한 건 우리가 이 중 하나를 선택해야 한다는 게 아니라, 지금 어떤 위치에서 일하고 있는지를 자각하는 것이었다. 그리고 그 위치는, 작업마다 달라질 수 있다. 즉, 같은 사람도 같은 날 안에서도 이 스펙트럼을 계속 오간다.

  • 반복적이고 되돌릴 수 있는 작업은 MITL이 더 건강할 때도 있고
  • 불확실성이 큰 순간에는 HITL이 필요하다

HITL이 늘어날수록, 사람은 더 많이 생각하게 된다. 이건 분명 비용이다.

하지만 동시에, 그 비용이 성장으로 이어질 수 있는 지점이기도 하다.

어떻게 팀과 공유할까 — 규칙이 아니라 참여로

이 생각을 팀과 나눌 때, 가장 조심했던 건 규칙을 만들지 않는 것이었다.

사실 이건 진짜다. 나는 규칙을 만들지 않았다. 그저 내 개인적인 경험을 정리해서 제안했을 뿐이다.

이 걸 공유하려고 정리하는 지점에서 애자일 도입 경험이 떠올랐다.

  • 프랙티스를 그대로 따라 하는 건 어렵지 않았다
  • 하지만 진짜 어려웠던 건,
    팀이 직접 해석하고, 조정하고, 참여하게 만드는 과정이었다
  • 이렇게 해야 유지가 된다.
    팀은 결국 직접 참여하고, 반복적으로 되짚을 때 변화가 남는다.

AI 협업도 비슷하다고 느꼈다. 그래서 이렇게 접근했다.

  • “이렇게 써야 한다”가 아니라
  • “나는 이렇게 쓰고 있다”를 공유했다
  • 그리고 같이 해볼 동료를 찾기로 했다

작게, 하지만 임팩트가 있는 실험을 하려는 것이다. 그 실험이 어떻게 자랄지는 아직 모른다. 다만 씨앗을 심어보는 건 의미가 있다고 생각했다.

마무리 — 속도가 아니라 질문의 밀도

AI는 일을 빠르게 만들어준다. 이건 부정하기 어렵다.

하지만 내가 느끼기에, 더 큰 변화는 다른 곳에 있었다.

AI와 함께 일하면서,
사람은 다시 질문하게 된다.

 

무엇을 기준으로 삼고 있는지, 어디에서 개입하고 있는지, 무엇을 기계에게 맡기고 있는지.

어쩌면 AI가 늘린 것은 속도가 아니라, 질문의 밀도였는지도 모른다.

 

그리고 그 질문은, 여전히 사람 쪽에 남아 있다.

들어가며: 왜 같은 프로젝트를 두 번 만들었나?

Vibe Coding으로 복잡한 요구 사항을 다루어 보려고, GPTers와 유사한 학습 플랫폼을 만들기로 했다. 많은 사람들이 접근하는 방법에 따라서 요구 사항(PRD)를 만들고 단계적 접근 방법 (Iterative Approach)를 따라서 접근했다. 기능을 하나씩 완성해가며 쌓아올리는 방법이다.

 

그런데, 의문이 생겼다. 이 방법이 정말 좋은 것인가?

 

이 때 떠오른 방법이 Christopher Alexander의 Nature Of Order에서 설명하는 생성적인 접근법(Generative Sequence)을 써보고 비교해보고 싶었다. 즉, 구조적 개선을 중심으로 점진적으로 진화시키는 방법이다.

 

결론부터 말하자면, 둘 다 만들어봤다.

 

그리고 그 과정에서 깨달았다. 개발 철학의 차이가 코드 몇 줄보다 훨씬 큰 영향을 미친다는 것을.


Part 1: 두 프로젝트의 탄생

StudyBlog: "완성된 기능을 쌓아가는 방식"

핵심 철학: "작동하는 것부터 만들자"

Phase 1 (MVP)
├── Iteration 1: 프로젝트 초기 설정
├── Iteration 2: 인증 시스템 ✅
├── Iteration 3: 게시물 CRUD ✅
├── Iteration 4: 카테고리 시스템 ✅
└── Iteration 5: UI 개선 ✅

Phase 2
└── Iteration 6: 코드 품질 개선 🔄

결과:

  •  기본 블로그 기능 완벽 작동
  •  Supabase + Drizzle ORM으로 안정적인 DB
  •  다크모드, 반응형 디자인

하지만:

  • 일반적인 블로그와 차별화 포인트 부족
  • AI 기능은 "미래 계획"으로만 존재

StudyBlogGenSeq: "구조를 진화시키는 방식"

핵심 철학: "이 변경이 사용자 경험을 어떻게 개선하는가?"

이 방식은 Christopher Alexander가 건축에서 설명한 원리와 놀랍도록 유사하다.

Alexander는 이렇게 말한다:

 

"만약 당신이 정말로 땅, 부지, 그리고 형성되어가는 건물의 전체성(wholeness)을 따르고, 그 전체성이 자연스럽게 전개되도록 허용한다면—처음의 (그리고 임의적인) 이미지는 점차적으로 상식, 즉 현실과 자리하고 있는 것의 전체성에 자리를 내주게 될 것이다."

 

소프트웨어 개발에서도 마찬가지다. "AI 학습 플랫폼"이라는 초기 이미지에서 출발했지만, 실제로 사용자가 글을 쓰는 과정을 관찰하고, 그들이 겪는 어려움을 이해하면서, 현실이 말해주는 바에 따라 구조가 진화했다.

 

Phase 1: Foundation ✅
Phase 2: AI Editor Core ✅
├── 실시간 문장 개선 (GPT-4o-mini)
├── 자동 태그 생성 (16개 키워드 감지)
├── 템플릿 시스템 (학습경험/프로젝트후기/튜토리얼)
└── Multi-provider AI 아키텍처 (OpenAI/Claude)

Phase 3: Database & Community 🔄
└── LocalStorage → Supabase 전환 예정

결과:

  • 실제로 작동하는 AI 글쓰기 어시스턴트
  •  템플릿으로 초보자도 구조화된 글 작성
  •  2초 후 자동 태그, 8초 후 문장 개선 제안
  • 완전한 Write → Publish → Explore 워크플로우
  •  LocalStorage로 즉시 발행 가능

트레이드오프:

  • AI 비용 지속 발생 ($100-200/월 예상)

Part 2: 철학의 차이가 만든 결과들

1. "무엇을 먼저 만드는가?"

Alexander의 건축 비유를 계속해보자. 그는 원통형 집의 이미지에서 출발한 건축가를 예로 든다.

Iteration 방식 (StudyBlog)은 이렇게 말한다:

  • "원통형 집을 짓기로 했어. 먼저 기초를 완성하고, 그 다음 벽을 세우고, 지붕을 올리고, 마지막에 창문을 내자."
  • 각 단계는 완벽하게 끝나야 다음으로 진행할 수 있다.
  • 이미지가 주도권을 갖는다.

Transformation 방식 (StudyBlogGenSeq)은 이렇게 말한다:

  • "원통형이라는 이미지로 시작했지만, 이 땅의 경사를 보니 다른 형태가 더 자연스럽겠어."
  • "나무의 위치를 보니 창문은 여기에 있어야 해."
  • "전망을 고려하면 현관의 방향이 바뀌어야 해."
  • 현실이 주도권을 갖는다.

Alexander의 말대로:

"점진적으로, 천천히, 단계적으로, 당신의 선행 이미지 속 모든 요소들은 녹아 사라지게 되며, 현실과 상식은 전혀 다른 것을 만들어내게 된다."

 

StudyBlog의 우선순위

1. 인증 → 2. CRUD → 3. 카테고리 → 4. UI → 5. AI(?)

논리: "기본 기능이 완성되어야 AI를 얹을 수 있다"

StudyBlogGenSeq의 우선순위

1. AI 에디터 → 2. 템플릿 → 3. 워크플로우 → 4. DB

논리: "AI가 핵심 차별화 요소다. 먼저 증명하자"

결과의 차이

  • StudyBlog: 안정적이지만 평범한 블로그
  • StudyBlogGenSeq: AI 기능을 완성하고 불확실한 이 부분에 집중이 가능하다.

Part 3: CLAUDE.md - AI 페어 프로그래밍 가이드의 차이

두 프로젝트는 Claude AI와 협업하는 방식도 완전히 달랐다. 그 차이가 CLAUDE.md 파일에 고스란히 담겨있다.

StudyBlog의 CLAUDE.md: "실용적 가이드"

파일명: CLAUDE.md (37줄)

핵심 내용:

# Context Awareness & Code Preservation
- 사용자 정의 코드 구조와 네이밍 보존
- 명시적 지시가 없으면 리팩토링 금지

# Clarity and Traceability
- 생성/수정된 모든 코드에 명확한 설명과 TODO 마커

# Modular Thinking
- 모듈화되고 테스트 가능한 구현
- 유틸 함수, 재사용 가능한 컴포넌트

# Iterative Development
- 작은 테스트 가능한 단계로 분할
- 다음 단계로 진행 전 사용자 확인

# Documentation & Library Integration
- context7 MCP로 최신 문서 검색
- 공식 문서 패턴 우선 사용

특징:

  •  실용적이고 간결함
  •  전통적인 개발 Best Practice
  •  "어떻게 코드를 짜야 하는가"에 집중
  •  라이브러리 통합과 문서화 강조

철학: "Claude는 코딩 도우미"


StudyBlogGenSeq의 CLAUDE.md: "Transformation Agent"

파일명: CLAUDE.md (96줄, StudyBlog의 2.6배)

핵심 내용:

##  목적: Transformation 중심 AI Pair Programming

- **구조적 생명력(Structural Life) 향상**
- **살아있는 구조(Living PRD)**로 진화
- **Transformation 단위 진행** (Iteration이 아님)
- **맥락 보존(Context-preserving)** 개발

##  운영 원칙

### Generative Sequence 기반 개발 루프
1. 맥락 로드: PRD, 기존 코드, Transformation Log 확인
2. Transformation 정의: '작은 구조적 변화 한 가지'
3. 설계 옵션 제안: 2~3개 대안과 트레이드오프
4. 코드 생성/수정: 작은 PR(diff) 단위
5. 맥락 보존 검증: 구조 퀄리티 메트릭 체크
6. 문서 업데이트: Living PRD, Backlog, Transformation Log
7. 후속 Transformation 제안: 다음 단계 후보 제시

##  Transformation 템플릿
- Intent: 구조 개선 목표 (문제-맥락-해결책)
- Change: 변경 내용
- Constraints: 제약 조건
- Design Options: A/B/C - 트레이드오프 포함
- Chosen & Rationale: 선택과 근거
- Acceptance: 테스트/데모 기준
- Impact: API/데이터/UX/문서 영향
- Structural Quality Metric Change: 응집도/결합도 변화
- Follow-ups: 후속 작업

특징:

  •  Christopher Alexander의 철학 반영
  •  "구조적 생명력" 향상이 목표
  •  Iteration이 아닌 Transformation 단위
  •  Living PRD - 문서가 살아 진화함
  •  고객을 "공동 설계자"로 간주

철학: "Claude는 Transformation Agent"


CLAUDE.md 비교표

항목 StudyBlog StudyBlogGenSeq
분량 37줄 96줄 (2.6배)
개발 단위 Iteration Transformation
문서 철학 정적 가이드 Living Document
Claude의 역할 코딩 도우미 Transformation Agent
핵심 개념 Best Practice Structural Life (구조적 생명력)
의사결정 사용자 확인 후 진행 2-3개 옵션 + 트레이드오프 제시
문서화 코드 설명 중심 PRD/TRANSFORMATIONS/BACKLOG 진화
검증 방식 테스트 케이스 구조 퀄리티 메트릭
고객 관점 피드백 제공자 공동 설계자

실제 개발 과정의 차이

StudyBlog 방식 (Iteration)

개발자: "인증 시스템 만들어줘"
Claude: "Supabase Auth 사용하시겠습니까?"
개발자: "응"
Claude: [코드 생성]
개발자: "좋아, 다음은 게시물 CRUD 만들어줘"

특징: 명확하고 빠름, 한 번에 한 가지 완성


StudyBlogGenSeq 방식 (Transformation)

개발자: "사용자가 글을 잘 쓸 수 있게 도와주고 싶어"

Claude (Transformation Agent):
"T-20251003-001: AI 글쓰기 어시스턴트 추가

Intent:
- 초보자도 구조화된 글을 쓸 수 있게 AI 제안 제공
- 사용자 경험의 핵심 차별화 요소

Design Options:
A) OpenAI만 사용 (빠름, 비용 $0.15/1M tokens)
B) Claude만 사용 (고품질 한국어, $3.00/1M tokens)
C) Multi-provider (유연성, Factory Pattern)

트레이드오프:
- A: 빠르지만 한국어 품질 낮음
- B: 품질 좋지만 비용 20배
- C: 복잡하지만 상황별 선택 가능

Chosen: C (Multi-provider)
Rationale:
- 개발 시 Mock 사용 (비용 $0)
- 프로덕션 시 OpenAI/Claude 선택 가능
- 한 Provider 장애 시 Fallback

Impact:
- 사용자: 8초 대기 후 개선안 확인
- 비용: $50/월 (1000 요청)
- 코드: Factory Pattern 추가

Structural Quality Metric:
- 응집도: AI 서비스 레이어 분리 → 향상
- 결합도: Interface로 Provider 격리 → 감소
- 테스트 용이성: Mock으로 API 없이 테스트 가능

Follow-ups:
- T-20251003-002: 요청 캐싱으로 비용 50% 절감
- T-20251003-003: 사용자 피드백 수집 시스템

특징: 느리지만 깊이 있음, 구조적 사고 강제됨


어느 것이 더 나은가?

StudyBlog 방식의 장점

 

  • 빠른 진행: 질문-답변-구현으로 즉시 완성
  •  명확한 목표: 한 번에 한 가지만
  •  낮은 진입 장벽: 전통적인 개발 방식
  •  실용성: Best Practice 즉시 적용

StudyBlogGenSeq 방식의 장점

  • 구조적 사고: 왜, 어떻게, 다음은?
  •  의사결정 기록: Transformation Log로 근거 추적
  •  진화하는 문서: Living PRD가 계속 업데이트
  •  트레이드오프 인식: A vs B vs C를 항상 고려

 


깨달은 것

1. CLAUDE.md는 "개발 철학의 선언문"

  • StudyBlog: "Claude야, 내가 시키는 대로 코드 짜줘"
  • StudyBlogGenSeq: "Claude야, 나와 함께 구조를 진화시켜줘"

2. 같은 AI, 다른 역할

  • 코딩 도우미 Claude: 빠르지만 얕은 협업
  • Transformation Agent Claude: 느리지만 깊은 협업

3. 문서는 "과거 기록" vs "미래 설계도"

StudyBlog:

## Iteration 3
- [x] 게시물 CRUD 완료
- [x] 카테고리 추가

→ "무엇을 했는가"

StudyBlogGenSeq:

## T-20251003-001
Intent: 초보자도 전문가처럼
Options: A/B/C
Chosen: C
Follow-ups: 캐싱, 피드백

→ "왜 이렇게 했는가, 다음은?"

4. 속도 vs 품질의 트레이드오프

  • Iteration 방식: 빠르게 완성 → 나중에 리팩토링 (언제?)
  • Transformation 방식: 천천히 진화 → 구조는 항상 깔끔 (하지만 느림)

결론: 당신의 CLAUDE.md는 어떤가?

이 글을 읽는 당신에게 질문하고 싶다.

당신의 CLAUDE.md는 어떤 철학을 담고 있는가?

  • Claude를 "코딩 도구"로 쓰는가?
  • Claude를 "공동 설계자"로 쓰는가?

빠른 완성이 목표라면 → StudyBlog 방식

  • 37줄의 간결한 가이드
  • Iteration 단위
  • Best Practice 즉시 적용

구조적 진화가 목표라면 → StudyBlogGenSeq 방식

  • 96줄의 Transformation 철학
  • Living PRD
  • 트레이드오프 기반 의사결정

정답은 없다. 하지만 선택은 해야 한다.

그리고 그 선택이 CLAUDE.md에 담겨야 한다.

왜냐하면, CLAUDE.md는 단순한 설정 파일이 아니라, 당신의 개발 철학이 담긴 선언문이기 때문이다.

참고 문서

StudyBlog: https://github.com/blcktgr73/StudyBlog
StudyBlogGenSeq: https://github.com/blcktgr73/StudyBlogGenSeq

Claude Code를 활용해 반복적인 작업을 자동화하려면 실행 환경 구성자동화 설정(Task Scheduler 연동) 이 필요하다. 여기서는 Windows 환경과 OneDrive + Obsidian 기반 워크플로우를 예시로 정리했다.

1. 실행 환경 구성

1.1 Claude CLI 설치

Claude Code는 CLI(Command Line Interface)로 실행된다. 설치 후에는 전역 실행이 가능해야 하지만, Windows에서는 경로 문제로 claude 명령어가 바로 동작하지 않을 수 있습니다.

  • 기본 실행 경로 예시:
  • C:\Users\<사용자>\AppData\Roaming\npm\claude.cmd
  • 이 경로를 환경 변수 PATH에 추가해야 claude 명령만으로 실행 가능하다.

👉 설치 후 반드시 claude -h로 동작 여부를 확인하자.

1.2 실행 폴더 지정

자동화 실행 시 기준 폴더를 정해두면 관리가 편하다. 예를 들어:

C:\Users\<사용자>\OneDrive\문서\Obsidian\Repository

이 폴더 안에서 자동화 스크립트나 결과 파일이 관리되도록 구성할 수 있습니다. 저 폴더를 기준으로 OneDrive를 통해 동기화를 수행하면서, PC 및 스마트폰에서도 Obsidian으로 접근해서 사용하고 있다.

2. 자동화 실행 예시

Claude CLI는 -p 옵션과 함께 실행할 수 있습니다. 예를 들어 특정 collector를 자동 실행하도록 설정하면:

claude -p --permission-mode bypassPermissions /economic-tracker
claude -p --permission-mode bypassPermissions /claude-collector
claude -p --permission-mode bypassPermissions /codex-collector
  • --permission-mode bypassPermissions : 자동화 실행 시 권한 확인을 건너뜀
  • /economic-tracker, /claude-collector 등 : 실행할 작업 단위(collector). custom command이다.

이렇게 여러 collector를 순차 실행하도록 배치파일(.bat)로 만들어 둘 수 있다. 물론 보라 cli command로 넣을 수 있다.

3. Task Scheduler 연동

Windows Task Scheduler를 이용하면 특정 시간/주기에 자동으로 Claude Code를 실행할 수 있다.

  1. 작업 생성
    • 작업 스케줄러 실행 → 새 작업 만들기
    • 이름 예: Claude Automation
  2. 트리거 설정
    • 매일/매주/부팅 시 등 원하는 조건으로 설정
  3. 동작 설정
    • 프로그램/스크립트: C:\Users\<사용자>\AppData\Roaming\npm\claude.cmd
    • 인수 추가: -p --permission-mode bypassPermissions /economic-tracker
    • 시작 위치: C:\Users\<사용자>\OneDrive\문서\Obsidian\Repository
  4. 테스트
    • 우클릭 → 실행
    • 로그를 확인해 collector들이 정상적으로 실행되는지 확인

4. 실행 환경 선택: 로컬 PC vs 클라우드

자동화를 위한 실행 환경은 크게 두 가지 방식이 있다:

항목 로컬 Mini PC (Intel N100/N150) Google Cloud Windows VM (On-Demand)
초기 비용 약 20만 원 (구매비) 없음
월 유지비 약 2천 원 (전기료) 약 2만 원 (60시간 기준)
관리 직접 패치/백업 필요 GCP가 자동 관리
확장성 로컬 한정 무제한, API/스케줄러 연동
장점 저렴, 오프라인 사용 가능 유지보수 불필요, 확장성 높음

👉 단순 개인용(Obsidian + OneDrive 동기화 중심 자동화) → N100 미니PC가 전기료 대비 매력적
👉 LLM API 트리거, 대규모 자동화가 필요 → Google Cloud Windows VM이 적합


5. 마무리

이 과정을 통해 얻을 수 있는 효과는:

  • 반복 작업의 완전 자동화 (수동 실행 불필요)
  • Obsidian + OneDrive를 통한 데이터 자동 동기화
  • 로컬/클라우드 선택에 따른 비용·편의성 최적화

개요

Firebase Auth만 사용하는 이유

Firebase Authentication만 사용한다면 정적 페이지로 충분합니다!

  • 정적 페이지로 가능한 것: 로그인/로그아웃, 사용자 기본 정보 (이메일, 이름, 프로필 사진)
  • 동적 페이지가 필요한 경우: 사용자 추가 정보 저장, 복잡한 비즈니스 로직, 서버사이드 검증

언제 동적 페이지를 고려해야 할까요?

동적 페이지 (서버 필요) 고려 시점:

  • 📊 Firestore/Database: 사용자의 추가 정보, 앱 데이터 저장
  • 🔐 서버사이드 검증: 민감한 데이터 처리, 관리자 권한 확인
  • 🤖 복잡한 로직: 결제 처리, 외부 API 연동, 데이터 분석
  • 📧 백그라운드 작업: 이메일 발송, 배치 처리, 스케줄링

현재 가이드 범위: Firebase Auth만 사용하는 정적 페이지 구현


1단계: Firebase 프로젝트 생성 및 기본 설정

1.1 Firebase 프로젝트 생성

  1. Firebase Console 접속
  2. "프로젝트 추가" 클릭
  3. 프로젝트 정보 입력:
프로젝트 이름: bookplay-production
프로젝트 ID: bookplay-production-[자동생성번호]
프로젝트 이름: bookplay-production
프로젝트 ID: bookplay-production
프로젝트 번호: 902982228800
웹 API 키: 이 프로젝트에 웹 API 키가 없습니다.
  1. Google Analytics 설정: 필요에 따라 선택 (Auth만 사용시 불필요)

1.2 프로젝트 정보 확인

생성 완료 후 기록할 정보:

프로젝트 ID: bookplay-production-xxxxx
웹 API 키: AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXX
Auth 도메인: bookplay-production-xxxxx.firebaseapp.com

1.3 필요한 API 활성화 (GCP Console)

  1. Google Cloud Console 접속
  2. 프로젝트 선택: 생성한 Firebase 프로젝트
  3. APIs & Services라이브러리에서 다음 API 활성화:
✅ Firebase Authentication API
✅ Identity and Access Management (IAM) API
API 활성화느 

2단계: Firebase Authentication 설정

2.1 Authentication 서비스 활성화

  1. Authentication시작하기
  2. Sign-in method 탭으로 이동
  3. Google 제공업체 설정:
  4. ✅ 사용 설정 프로젝트 지원 이메일: your-email@gmail.com 프로젝트 공개용 이름: BookPlay Production
  5. 저장 클릭

2.2 웹 앱 등록

  1. 프로젝트 개요앱 추가
  2. 앱 정보 입력:
  3. 앱 닉네임: BookPlay Web App ✅ 이 앱의 Firebase Hosting도 설정합니다 (체크)
  4. 앱 등록 후 설정 정보 복사 및 저장

2.3 승인된 도메인 설정

  1. Authentication설정승인된 도메인
  2. 기본 설정 확인:
✅ localhost (로컬 개발용)
✅ bookplay-production-xxxxx.firebaseapp.com (Firebase Hosting)
✅ bookplay-production-xxxxx.web.app (Firebase Hosting)

3단계: 로컬 테스트를 위한 정적 구성

3.1 프로젝트 구조 생성

# 프로젝트 폴더 생성
mkdir my-auth-app
cd my-auth-app

# 폴더 구조 생성
mkdir public
mkdir public/js
mkdir public/css
mkdir public/assets

최종 구조:

my-auth-app/
├── public/
│   ├── index.html
│   ├── login.html
│   ├── dashboard.html
│   ├── js/
│   │   ├── firebase-config.js
│   │   ├── auth.js
│   │   └── app.js
│   ├── css/
│   │   └── style.css
│   └── assets/
└── firebase.json (나중에 생성)

3.2 Firebase 설정 파일

// public/js/firebase-config.js
import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.0.0/firebase-app.js';
import { getAuth } from 'https://www.gstatic.com/firebasejs/10.0.0/firebase-auth.js';

const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "your-project.firebaseapp.com", 
  projectId: "your-project-id",
  storageBucket: "your-project.appspot.com",
  messagingSenderId: "123456789",
  appId: "your-app-id"
};

export const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);

3.3 인증 로직 구현

// public/js/auth.js
import { auth } from './firebase-config.js';
import { 
  GoogleAuthProvider, 
  signInWithPopup, 
  signOut, 
  onAuthStateChanged 
} from 'https://www.gstatic.com/firebasejs/10.0.0/firebase-auth.js';

const googleProvider = new GoogleAuthProvider();

// Google 로그인
export const signInWithGoogle = async () => {
  try {
    const result = await signInWithPopup(auth, googleProvider);
    console.log('로그인 성공:', result.user);
    return result.user;
  } catch (error) {
    console.error('로그인 실패:', error);
    throw error;
  }
};

// 로그아웃
export const logout = async () => {
  try {
    await signOut(auth);
    console.log('로그아웃 성공');
  } catch (error) {
    console.error('로그아웃 실패:', error);
    throw error;
  }
};

// 인증 상태 변화 감지
export const onAuthChange = (callback) => {
  return onAuthStateChanged(auth, callback);
};

// 현재 사용자 정보 가져오기
export const getCurrentUser = () => {
  return auth.currentUser;
};

3.4 메인 앱 로직

// public/js/app.js
import { signInWithGoogle, logout, onAuthChange, getCurrentUser } from './auth.js';

// DOM 요소
const loginBtn = document.getElementById('login-btn');
const logoutBtn = document.getElementById('logout-btn');
const userInfo = document.getElementById('user-info');
const loginSection = document.getElementById('login-section');
const userSection = document.getElementById('user-section');

// 페이지 로드 시 초기화
document.addEventListener('DOMContentLoaded', () => {
  initApp();
});

function initApp() {
  // 이벤트 리스너 등록
  loginBtn?.addEventListener('click', handleLogin);
  logoutBtn?.addEventListener('click', handleLogout);

  // 인증 상태 변화 감지
  onAuthChange((user) => {
    if (user) {
      showUserSection(user);
    } else {
      showLoginSection();
    }
  });
}

// 로그인 처리
async function handleLogin() {
  try {
    loginBtn.disabled = true;
    loginBtn.textContent = '로그인 중...';

    const user = await signInWithGoogle();
    console.log('로그인 성공:', user);
  } catch (error) {
    alert('로그인에 실패했습니다: ' + error.message);
    console.error('로그인 에러:', error);
  } finally {
    loginBtn.disabled = false;
    loginBtn.textContent = 'Google로 로그인';
  }
}

// 로그아웃 처리
async function handleLogout() {
  try {
    logoutBtn.disabled = true;
    logoutBtn.textContent = '로그아웃 중...';

    await logout();
    console.log('로그아웃 성공');
  } catch (error) {
    alert('로그아웃에 실패했습니다: ' + error.message);
    console.error('로그아웃 에러:', error);
  } finally {
    logoutBtn.disabled = false;
    logoutBtn.textContent = '로그아웃';
  }
}

// 사용자 섹션 표시
function showUserSection(user) {
  if (loginSection) loginSection.style.display = 'none';
  if (userSection) userSection.style.display = 'block';

  if (userInfo) {
    userInfo.innerHTML = `
      <div class="user-profile">
        <img src="${user.photoURL || '/assets/default-avatar.png'}" 
             alt="프로필" class="profile-img">
        <div class="user-details">
          <h2>환영합니다, ${user.displayName || '사용자'}님!</h2>
          <p class="user-email">${user.email}</p>
          <p class="user-id">UID: ${user.uid}</p>
        </div>
      </div>
    `;
  }
}

// 로그인 섹션 표시
function showLoginSection() {
  if (loginSection) loginSection.style.display = 'block';
  if (userSection) userSection.style.display = 'none';
}

3.5 HTML 파일

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Firebase Auth Test</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="container">
        <header>
            <h1>🔥 Firebase Auth 테스트</h1>
        </header>

        <div id="login-section" class="auth-section">
            <h2>로그인이 필요합니다</h2>
            <p>Google 계정으로 로그인해주세요.</p>
            <button id="login-btn" class="btn btn-google">
                <span>🔑 Google로 로그인</span>
            </button>
        </div>

        <div id="user-section" class="auth-section" style="display: none;">
            <div id="user-info"></div>
            <div class="actions">
                <button id="logout-btn" class="btn btn-secondary">로그아웃</button>
            </div>
        </div>
    </div>

    <script type="module" src="js/app.js"></script>
</body>
</html>

3.6 스타일 파일

/* public/css/style.css */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
}

.container {
    background: white;
    border-radius: 20px;
    padding: 40px;
    box-shadow: 0 20px 40px rgba(0,0,0,0.1);
    max-width: 500px;
    width: 90%;
    text-align: center;
}

header h1 {
    color: #333;
    margin-bottom: 30px;
    font-size: 2rem;
}

.auth-section {
    padding: 20px 0;
}

.auth-section h2 {
    color: #555;
    margin-bottom: 15px;
}

.auth-section p {
    color: #666;
    margin-bottom: 25px;
    line-height: 1.6;
}

.btn {
    padding: 15px 30px;
    border: none;
    border-radius: 50px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.3s ease;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 200px;
}

.btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.btn-google {
    background: #4285f4;
    color: white;
}

.btn-google:hover:not(:disabled) {
    background: #3367d6;
    transform: translateY(-2px);
    box-shadow: 0 5px 15px rgba(66, 133, 244, 0.3);
}

.btn-secondary {
    background: #6c757d;
    color: white;
    margin-top: 20px;
}

.btn-secondary:hover:not(:disabled) {
    background: #545b62;
    transform: translateY(-2px);
}

.user-profile {
    display: flex;
    align-items: center;
    text-align: left;
    background: #f8f9fa;
    padding: 20px;
    border-radius: 15px;
    margin-bottom: 20px;
}

.profile-img {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    margin-right: 20px;
    border: 3px solid #4285f4;
}

.user-details h2 {
    color: #333;
    margin-bottom: 5px;
    font-size: 1.4rem;
}

.user-email {
    color: #666;
    font-size: 1rem;
    margin-bottom: 5px;
}

.user-id {
    color: #999;
    font-size: 0.8rem;
    font-family: monospace;
}

.actions {
    text-align: center;
}

@media (max-width: 600px) {
    .container {
        padding: 30px 20px;
    }

    .user-profile {
        flex-direction: column;
        text-align: center;
    }

    .profile-img {
        margin-right: 0;
        margin-bottom: 15px;
    }
}

3.7 로컬 테스트 실행

# 간단한 HTTP 서버 실행 (여러 방법 중 선택)

# 방법 1: Python (가장 간단)
cd public
python -m http.server 8000
# 브라우저에서 http://localhost:8000 접속

# 방법 2: Node.js (npx 사용)
cd public  
npx serve -s . -p 8000

# 방법 3: Live Server (VS Code 확장)
# VS Code에서 index.html 우클릭 → "Open with Live Server"

테스트 체크리스트:

  • 페이지가 정상 로드되는지
  • Google 로그인 버튼 클릭 시 팝업이 뜨는지
  • 로그인 성공 후 사용자 정보가 표시되는지
  • 로그아웃이 정상 작동하는지
  • 브라우저 개발자 도구에서 에러가 없는지

4단계: GCP에 정적 배포

4.1 Firebase CLI 설치 및 로그인

# Firebase CLI 설치
npm install -g firebase-tools

# Firebase 로그인
firebase login

# 로그인 확인
firebase projects:list

4.2 Firebase 프로젝트 초기화

# 프로젝트 루트 폴더에서 실행
firebase init hosting

# 설정 선택
? Select a default Firebase project: [생성한 프로젝트 선택]
? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? Set up automatic builds and deploys with GitHub? No
? File public/index.html already exists. Overwrite? No

4.3 Firebase 설정 파일

{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [ {
      "source": "**",
      "destination": "/index.html"
    } ],
    "headers": [ {
      "source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
      "headers": [ {
        "key": "Access-Control-Allow-Origin",
        "value": "*"
      } ]
    }, {
      "source": "**/*.@(js|css)",
      "headers": [ {
        "key": "Cache-Control",
        "value": "max-age=604800"
      } ]
    } ]
  }
}

4.4 배포 실행

# 배포 전 로컬 프리뷰 (선택사항)
firebase serve --only hosting

# 실제 배포
firebase deploy --only hosting

# 배포 완료 후 표시되는 URL들:
# ✔ Deploy complete!
# Project Console: https://console.firebase.google.com/project/your-project/overview
# Hosting URL: https://your-project.web.app

4.5 배포 테스트

배포된 URL에서 다음 사항 확인:

  • HTTPS로 정상 접속되는지
  • Google 로그인이 작동하는지
  • 모바일에서도 정상 작동하는지
  • 새로고침 후에도 로그인 상태가 유지되는지

4.6 배포 URL 관리

# 현재 배포된 사이트 정보 확인
firebase hosting:sites:list

# 커스텀 도메인 추가 (선택사항)
firebase hosting:sites:create your-custom-domain

# 배포 히스토리 확인
firebase hosting:clone your-project:source your-project:dest

Cursor와 같은 도구는 IDE에 잘 연결되어 있어서 세세한 기능이 Claude Code 보다 좋다 느낄 때가 있다. 그 중 한가지는 시간이 오래 걸리는 작업을 하고 있을 때 완료되면 작업이 완료되었다고 알려주는 기능이다.

Claude Code의 새로운 hooks 기능이 개발자들 사이에서 화제가 되고 있는데, 이 기능을 사용하면 작업 세션이 완료될 때마다 자동으로 알림을 받을 수 있어, 다른 작업을 하면서도 Claude의 작업 진행 상황을 놓치지 않을 수 있다.

Claude Code Hooks란?

Claude Code hooks는 Claude의 작업 생명주기에서 특정 시점에 사용자 정의 스크립트를 실행할 수 있게 해주는 기능입니다. 다음과 같은 시점에서 작동합니다:

  • UserPromptSubmit: 사용자가 프롬프트를 제출하기 직전
  • PreToolUse: Claude가 도구를 사용하기 직전
  • PostToolUse: Claude가 도구 사용을 완료한 직후
  • Notification: 사용자에게 알림이 필요한 시점
  • Stop: 세션이 완료된 시점

이 중에서 Stop 이벤트를 활용하면 작업 완료 시 자동으로 알림을 받을 수 있습니다.

Windows 데스크톱 알림 구현하기

1단계: PowerShell 알림 스크립트 생성

먼저 Windows 토스트 알림을 생성하는 PowerShell 스크립트를 만들어보자.

파일 위치: C:\Users\[사용자명]\bin\auto-notification.ps1

# Auto-disappearing notification
param(
    [string]$Title = "Claude Code",
    [string]$Message = "Task completed",
    [int]$Duration = 2
)

Add-Type -AssemblyName System.Windows.Forms

# Create a form that will auto-close
$form = New-Object System.Windows.Forms.Form
$form.Text = $Title
$form.Size = New-Object System.Drawing.Size(400, 150)
$form.StartPosition = "CenterScreen"
$form.FormBorderStyle = "FixedDialog"
$form.MaximizeBox = $false
$form.MinimizeBox = $false
$form.TopMost = $true
$form.BackColor = [System.Drawing.Color]::LightBlue

# Add label for message
$label = New-Object System.Windows.Forms.Label
$label.Text = $Message
$label.Size = New-Object System.Drawing.Size(380, 80)
$label.Location = New-Object System.Drawing.Point(10, 30)
$label.TextAlign = "MiddleCenter"
$label.Font = New-Object System.Drawing.Font("Arial", 10)
$form.Controls.Add($label)

# Timer to auto-close
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = $Duration * 1000
$timer.Add_Tick({
    $form.Close()
    $timer.Stop()
})

# Show form and start timer
$timer.Start()
$form.ShowDialog() | Out-Null

Write-Host "Notification displayed for $Duration seconds"

2단계: Claude Code 설정 파일 생성

Claude Code가 알림 스크립트를 실행하도록 설정한한다.

파일 위치: C:\Users\[사용자명]\.claude\settings.json

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "powershell -ExecutionPolicy Bypass -File \"C:\\Users\\[사용자명]\\bin\\auto-notification.ps1\" -Title \"✅ Claude 작업 완료\" -Message \"AI 코딩 세션이 완료되었습니다!\" -Sound \"Notification.SMS\""
          }
        ]
      }
    ]
  }
}

3단계: PowerShell 실행 정책 설정

보안을 위해 PowerShell 스크립트 실행 정책을 설정해야 한다. VS Code와 Claude Code를 연동하고 있다면 이 동작을 미리 했을 수 있다. 관리자 권한으로 PowerShell을 열고 다음 명령어를 실행하자:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

4단계: 디렉토리 생성 및 파일 설정

필요한 디렉토리를 생성하고 파일을 배치한다:

mkdir C:\Users\[사용자명]\bin
mkdir C:\Users\[사용자명]\.claude

중요: [사용자명] 부분을 실제 Windows 사용자명으로 교체해야 한다.

실제 사용 경험

이 설정을 완료한 후 Claude Code를 사용하면:

  1. 명령어 실행: claude 명령어로 AI 코딩 세션 시작
  2. 작업 진행: Claude와 대화하며 코딩 작업 수행
  3. 세션 종료: 작업 완료 후 자동으로 Windows 토스트 알림 표시
  4. 멀티태스킹: 다른 앱을 사용하다가도 알림으로 작업 완료를 즉시 확인 가능

사용 사례 및 활용 팁

프로젝트별 맞춤 알림

특정 프로젝트에서만 작동하는 알림을 설정하려면 프로젝트 폴더에 .claude/settings.local.json 파일을 생성하자:

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "powershell -ExecutionPolicy Bypass -File \"C:\\Users\\[사용자명]\\bin\\auto-notification.ps1\" -Title \"🚀 [프로젝트명] 완료\" -Message \"프로젝트 작업이 완료되었습니다!\" -Sound \"Notification.Default\""
          }
        ]
      }
    ]
  }
}

확장 가능성

이 기본 설정을 바탕으로 다음과 같은 고급 기능들도 구현할 수 있다:

  • 이메일 알림: 중요한 작업 완료 시 이메일 발송
  • 슬랙 메시지: 팀 채널에 작업 완료 알림
  • 파일 백업: 작업 완료 시 자동으로 파일 백업
  • 로그 기록: 모든 세션 기록을 자동으로 저장
  • Git 연동: 작업 완료 시 자동 커밋

문제 해결

토스트 알림이 표시되지 않는 경우

  1. Windows 알림 설정 확인: 설정 > 시스템 > 알림에서 알림이 활성화되어 있는지 확인
  2. 포커스 어시스트 설정: 집중 지원 모드에서도 알림이 표시되도록 설정
  3. 권한 문제: 스크립트 실행 권한이 올바르게 설정되었는지 확인

PowerShell 실행 오류

실행 정책 오류가 발생하면 다음 명령어로 해결할 수 있습니다:

Unblock-File "C:\Users\[사용자명]\bin\claude-notification.ps1"

결론

Claude Code hooks를 활용하면 개발 혹은 업무 자동화에 용이하다. 단순한 알림부터 시작해서 복잡한 워크플로우 자동화까지 확장할 수 있다. 특히 긴 분석 작업이나 복잡한 코드 생성 작업을 수행할 때, 다른 업무를 처리하면서도 Claude의 작업 완료를 놓치지 않을 수 있다.

AI로 내 문제 풀기"는 "비개발자도 자신의 현실적인 문제를 LLM과 함께 해결할 수 있을까?"라는 질문에서 출발했다. 바이브 코딩을 배우는 것이 목표가 아니라, 각자의 문제를 AI와 함께 탐구하며 협업적으로 풀어보는 경험을 만드는 데 초점을 두었다.

3명의 운영자가 최대 3명의 참여자와 함께 오리엔테이션에서 다루고 싶은 문제와 AI 활용의 어려움을 공유했다. 이후 두 번의 오프라인 세션(각 3시간)에서 문제를 작게 쪼개고, 페어 작업과 라운드 기반 협업을 통해 실제 문제 해결을 시도했다.

실험의 목적

비개발자들에게는 혼자 해소하기 어려운 기술적 허들이 있다. 또한 AI를 개발에 활용하는 멘탈 모델이나, 비개발자가 AI로 문제를 해결하는 전략도 필요하다. 이 두 가지가 어떻게 시너지를 내는지 살펴보고자 했다. 이를 위해 페어워크 모델을 활용했고, 개발자와 비개발자가 짝으로 작업하도록 실험을 설계했다.

이 활동을 하면서 느낀 점 중 하나는, LLM의 능력이나 기능 자체도 중요하지만, 그것을 활용하는 전략이 실질적인 도움이 된다는 것이었다.

효과적인 전략들

1. Seeing is Believing — 빠른 피드백으로 확신 얻기

"어떻게 할 수 있을까?"라는 고민이 생길 때, 페어워크에서는 LLM에게 "만들어서 보여줘"라고 바로 요청했다.

유튜브 콘텐츠를 제작하는 기은님의 사례가 대표적이다. 기은님은 고객이나 동료와 피드백을 주고받는 효과적인 방법을 찾고 있었다. 자막을 보면서 메모로 피드백하는 시스템을 Chrome 브라우저 플러그인으로 만들려고 개발자인 동생과 시도했지만 어려움을 겪고 있었다.

GPT를 사용하던 중 프로토타이핑이 가능하다는 것을 알게 되었고, "계속 수정이 필요하지만, 영상 URL과 자막 업로드가 되었고 시간에 맞게 실행된다"며 원하던 핵심 경험을 만들어냈다. 단순한 시각화만으로도 인지 부하가 줄어들었고, 다른 것들을 고민하며 나아가려는 힘이 생겼다.

2. Small Step — 문제를 작게 쪼개기

요구사항이 복잡해지고 커지면서 이 전략이 유용하게 작동했다. 요구사항이 커지면 PRD 형태가 되어가고, LLM은 사용자가 원하는 것의 맥락을 놓치기 쉽다. 이때 작게 접근하는 것이 효과적이다.

PM 업무를 하는 기림님은 Slack으로 업무를 많이 하는데, 올해를 돌아보기 위해 Slack 채널의 대화들을 분석하는 것이 목표였다. 문제를 작게 만들기 위해 먼저 자신의 Workspace에서 동작을 확인한 뒤, 회사 Workspace로 이동해서 테스트했다.

이 과정에서 채널 중에 2023년 것도 있었고, 가져오려는 채널 수도 2000개가 넘어 시간이 오래 걸리는 것을 확인했다. 문제를 더 작게 만들기로 하고, 빠른 피드백을 얻으려고 두세 번 시도했다. 많은 채널의 아주 오래된 메시지까지 확인하는 것을 보고, 다루려는 채널 수와 시간 범위를 줄였다. 추가로 데이터를 가져오는 진행 상황을 사용자에게 계속 피드백하도록 만들었다.

3. Holding Hands — 익숙한 사람과 함께 걷기

마지막에 이야기한다고 해서 가장 덜 중요한 전략은 아니다. 단순히 자신이 가져온 문제를 "함께" 해결하는 것만이 다가 아니었다. 주로 사용하지 않는 도구나 익숙하지 않은 환경을 내 문제에 적용하는 것도 어려웠다. 조금 더 익숙한 사람의 걸음을 따라 적용해보니 난이도가 낮아졌다. 또한 자신의 문제에 바로 도구를 적용해보니 만족감이 더 높다는 것을 알게 되었다.

기림님의 사례가 떠오른다. GPT의 가이드만으로 접근할 때 Python 환경 설정이 잘 되지 않는 부분이 있었고, 나도 Mac 환경 설정이 쉽지 않았다. Cursor의 Agent 기능이 이런 문제를 잘 다루는 것을 기억하고 Cursor를 제안했다. 기림님에게는 익숙하지 않은 도구였지만, 해결되지 않던 Python 환경 설정 문제를 쉽게 해결했고, 기존에 쓰던 GPT와도 병행해서 잘 사용하는 것을 볼 수 있었다.

실험을 통해 배운 것

이번 실험을 통해 비개발자와 개발자가 한 팀을 이루어 LLM을 실제 문제 해결에 적용할 때, 학습·도구·사고방식이 서로를 북돋우며 빠르게 확장된다는 사실을 직접 체감했다.

위에서 설명한 몇 가지 전략은 단순한 기법이 아니라, AI와 함께 문제를 풀어가는 새로운 협업 모델의 기반이 되었다. 특히 비개발자들이 '할 수 있다'는 감각을 얻게 만드는 강력한 촉매제였다.

반면 LLM이 놓치는 맥락, 추상화 전환의 어려움, 범위가 커질 때의 한계 등은 페어워크 구조가 있어야만 효과적으로 보완된다는 점도 확인했다.

결국 이번 실험은 AI를 잘 쓰는 법을 가르치는 과정이 아니라, 각자가 가진 문제·도메인·경험·역량을 연결해 새로운 방식의 협업을 만들어내는 실험이었다. 이 작은 시도로부터 "AI 시대의 문제 해결은 혼자 하는 공부가 아니라, 함께 문제를 탐구하는 일"임을 확인했다.

앞으로도 이 경험을 기반으로, 더 다양한 문제 영역과 더 다양한 사람들과 함께 실험을 확장해 보고자 한다.

소개

Claude Code의 기본 기능들을 학습한 후, 개인 지식 관리 툴인 Obsidian에 적용해 보았습니다.
Obsidian은 평소에도 PARA 구조로 정리하면서 사용하고 있었지만, 점점 구조가 엉키면서 자동화의 필요성을 느끼고 있던 참이었어요. Claude와의 연동을 통해, 반복 작업을 줄이고 더욱 정돈된 시스템을 만드는 것이 목표였습니다.

진행 방법

🔧 Vault 구조 정리

  • 기존에는 MOC(Map of Contents) 개념을 활용하긴 했지만, 별도 폴더로 분리하지 않았습니다.
  • Claude Code를 통해 MOC를 구조적으로 분리한 뒤, PARA 기반의 폴더 구성을 명확하게 만들었습니다.

🤖 Subagent 기능 활용

  • Claude에게 병렬 작업을 시키는 Subagent 기능이 인상 깊었어요.
  • 다음과 같은 프롬프트로 테스트:
I want you to spin up three sub-agents for a new research task.
We are going to create a new note that is called "AI model pricing".
I want you to look up the pricing of OpenAI models, Cloud Code models, and Google models.
And I want you to put those in a table inside of that note.
And I want to price everything per million tokens.
  • 마치 3명의 조수를 동시에 불러 정리시키는 듯한 느낌이 들었습니다 😄

📥 YouTube Transcript 정리 Command

  • 학습 자료로 YouTube 영상을 주로 활용하고 있었기에, 해당 영상의 자막을 받아 정리하는 커맨드를 만들어봤습니다.
  • Claude Code에서 커맨드를 아래와 같이 만들고, 자동으로 .md 파일로 정리되도록 설정:
.claude/commands/youtube-transcript.js
  • 결과적으로 학습한 내용을 Obsidian에서 관리하기 훨씬 쉬워졌습니다.

결과와 배운 점

  • 자동화 가능성: Claude Code를 통해 Obsidian 관리의 많은 부분이 자동화 가능하다는 걸 확인했어요.
  • Subagent의 유용함: 복잡한 리서치 작업에 특히 유용했습니다. 단일 에이전트보다 효율적인 정보 수집이 가능해졌어요.
  • Vault 구조화의 필요성 재확인: MOC를 명확히 분리하고 태그 규칙을 설정하니 문서 흐름이 눈에 띄게 개선되었습니다.
  • 다음 목표: 파일 내용 요약이나 리마인드 기능까지 Claude와 연결해보는 것이 다음 단계입니다.

도움 받은 글

- YouTube 예제 영상: https://www.youtube.com/watch?v=d7Pb73dbcIM

- gpters 글 링크: https://www.gpters.org/llm-service/post/claude-code-obsidian-private-7Q0tBGQ5kg3hCs2

최근 gpters에서 진행한 Claude Code Study에 참여했다. ChatGPT, Cursor, Lovable 등을 경험해봤지만, 이번 스터디는 조금 달랐다. 단순히 "코드를 잘 짜는 AI"를 배우는 게 아니라, 내 개발 루틴과 지식 관리에 Claude Code를 녹여내는 방법을 탐구했기 때문이다.

4일간의 학습 여정

링크에 소개된 것 같이 8/10~8/31 4주, 4일 간의 과정이었다.

1일차: 기본기 다지기

첫날은 Claude Code의 기본 개념을 파악하는 시간이었다. 단순한 명령어부터 시작해서 나만의 자동화 도구를 만드는 첫걸음을 떼었다.

  • 파일 생성과 이동
  • Custom Command 만들기
  • Agent 활용법 익히기

 

2일차: Obsidian 연동으로 지식 관리 혁신

둘 째날 부터 참여자들이 스스로 진행한 것들을 공유하는 날이었다. 나는 Obsidian을 활용하는 것이 나에게 가장 효과적일 것 같았다. Obsidian과 연결하여 YouTube 영상을 자동으로 요약하고, 내 지식 체계에 맞게 정리하는 과정을 체험했다. 정보 수집부터 정리까지 하나의 플로우로 연결되는 경험이 새로웠다.

 

3일차: MCP 서버로 데이터 수집 자동화

MCP 서버를 통해 실시간 투자 지표를 수집하고 분석하는 과정을 경험했다. Custom Command와는 다른 차원의 자동화 가능성을 확인할 수 있었다.

 

4일차: 복잡한 Vibe Coding 실전

가장 고도화된 활용법이었다. 단순한 코드 생성이 아니라, 기획 문서부터 기술 명세, 실제 구현까지 일관된 맥락을 유지하며 진행하는 방법을 배웠다.

 

핵심 깨달음: Claude Code는 Agent 기반 자동화 도구다

느낀 점은 명확하다. Claude Code는 단순한 코딩 도우미가 아니라, agent 기반의 자동화 도구라는 것이다. ChatGPT를 포함한 다른 LLM이 agent 모드를 도입하고 있지만, Claude Code는 Obsidian, Github, n8n 같은 툴과 연결되며 컴퓨터를 이용한 작업 자체를 바꾸는 모습을 보여준다.

앞으로의 계획

이제 나만의 루틴에 맞춰 Claude Code를 더 깊게 적용해볼 생각이다:

  1. 지속적 활용: Obsidian의 데이터 정리와 글쓰기, Vibe Coding 에 활용.
  2. Hook 기반 자동화: 일상 개발 루틴 자동화 시도.

 

마치며

Claude Code는 단순히 "코드를 잘 짜주는 AI"가 아니었다. 내 작업 환경과 깊이 통합되어 사고의 확장을 도와주는 디지털 파트너에 가까웠다. 앞으로 Context7, CLAUDE.md 시스템 정리, Hook 자동화까지 더 깊이 파고들 계획이다. Claude Code가 단순한 도구를 넘어 새로운 작업 방식 자체가 될 수 있을 것 같다.

 Voice Cloning + TTS API 시스템 PRD

목표:
사용자가 제공한 음성으로 개인화된 TTS 서비스를 제공하는 오픈소스 기반 API 시스템을 Google Cloud 위에 구축한다.

 

 핵심 기능 요약

기능 설명
음성 클로닝 사용자가 업로드한 음성(3~5초)을 기반으로 음색 임베딩 생성
텍스트 → 음성 합성 사용자가 입력한 텍스트와 임베딩을 사용하여 음성 생성
REST API 음성 업로드, 합성 요청, 결과 조회 API 제공
저장 Cloud Storage에 사용자 음성 및 합성 결과 저장
GPU 기반 추론 Vertex AI Custom Job을 활용한 TTS 처리 (필요 시 GCE로 확장)

 

 구성 요소 및 기술 스택

구성 요소 기술 설명
음성 클로닝 모델 xtts-v2, YourTTS, SV2TTS 음성 임베딩 생성 및 다국어 음성 합성 지원
TTS 엔진 xtts-v2 (by Coqui) 텍스트 + 임베딩 → 오디오 생성
API 서버 FastAPI + Docker + Cloud Run /upload, /synthesize REST API 제공
음성 저장소 Cloud Storage 원본 및 합성 음성 저장 (gs://.../voices/, .../results/)
TTS 실행 환경 Vertex AI Custom Job (GPU) 비용 효율적 배치 처리용
향후 확장 가능 환경 GCE GPU 인스턴스 + FastAPI 실시간 추론 서비스 필요 시 확장
임베딩 관리 Firestore 또는 Redis (옵션) user_id별 speaker embedding 저장
배포 자동화 Cloud Build + Artifact Registry + YAML CI/CD 구성
인증 및 보안 Firebase Auth / Cloud IAM / API Key 사용자 인증, 호출 제한
모니터링 Cloud Logging, Error Reporting 상태 추적 및 장애 감지

 

 아키텍처

graph TD
  A[사용자] -->|음성 업로드| B[Cloud Run API 서버]
  B --> C[Cloud Storage (원본 음성 저장)]
  B --> D[Vertex AI Custom Job (XTTS 추론)]
  D --> E[Cloud Storage (합성 결과 저장)]
  B -->|합성 음성 URL 반환| A

 

 폴더 및 Docker 구조

voice-clone-backend/
├── cloudrun-api/                        # Cloud Run용 경량 API 서버
│   ├── app/
│   │   ├── main.py                      # /synthesize 요청 수신
│   │   ├── trigger_job.py              # Vertex Job 실행용 wrapper
│   │   ├── voice_encoder.py            # 사용자 음성 임베딩
│   │   ├── storage.py                  # GCS 입출력
│   │   └── config.py                   # 환경 설정
│   ├── requirements.txt                # ⚠️ TTS 제거
│   ├── Dockerfile                      # Cloud Run용
│   └── deploy/
│       └── cloudrun.yaml               # 배포 스크립트
└── vertex-job/                         # Vertex AI Custom Job 실행 코드
    ├── job/
    │   ├── run_batch.py                # text + voice_id → 음성 생성
    │   ├── tts_engine.py              # XTTS 호출 wrapper
    │   ├── voice_encoder.py           # 동일하지만 Vertex 버전
    │   ├── storage.py
    │   └── config.py
    ├── requirements.txt                # ⚠️ TTS 포함 (TTS, torch 등)
    ├── Dockerfile                      # Vertex Job용
    └── deploy/
        └── xtts-job.yaml              # Custom Job 정의 YAML

 

처리 흐름

1. 사용자 음성 업로드

  • 클라이언트 → /upload-voice 호출 (파일 포함)
  • Cloud Run → GCS /voices/{user_id}/sample.wav 저장
  • (선택) speaker embedding 생성 후 Firestore/캐시에 저장

2. 텍스트 → 음성 합성

  • 클라이언트 → /synthesize 호출 (text, user_id)
  • Cloud Run → Vertex AI Custom Job 실행 요청
  • XTTS 모델 실행: sample.wav + text.wav 결과 생성
  • 결과 파일 gs://.../results/{user_id}/{uuid}.wav 저장
  • Cloud Run → 결과 URL 반환

 

 비용 전략

실행 방식 장점 월 예상 비용 (T4 기준)
Vertex AI Custom Job 사용한 시간만큼만 과금 (비용 효율) $30$50/월 (1일 12시간 기준)
GCE GPU 인스턴스 실시간 API 서버 운영 가능 $390~400/월 (상시 실행 기준)

 

 

구현 내용

https://github.com/blcktgr73/VoiceCloning

Claude Code의 확장 메커니즘들을 비교 분석해봅시다.

Agents, Custom Command(Workflow라고 부르는 분도 있습니다.) 그리고 이것들을 묶어 주는 Plugin이 있습니다. 이 때, Skill도 추가되었는데요. Plugin과 따로 쓸 수도 있다고 합니다.

1. Agents (Sub-agents)

개념

특정 전문 분야에 특화된 AI 페르소나로, Claude Code가 작업을 위임할 수 있는 전문가들입니다.

구조

---
name: bug-analyst
description: Issue triage and classification expert
tools: []
---

# Agent Definition
You are a specialized bug analyst expert...

특징

  • 위치: ~/.claude/agents/ 또는 프로젝트 내 .claude/agents/
  • 자동 감지: Claude Code가 자동으로 로드
  • 동적 호출:
    • 자동: Claude가 컨텍스트 분석 후 적절한 agent 선택
    • 수동: "Use the bug-analyst agent to..."
  • 병렬 실행: 여러 agent를 동시에 실행 가능
  • 토큰 사용: 각 agent가 독립적인 컨텍스트를 가지므로 토큰 사용량 증가

사용 예시

# 자동 선택
"Analyze this bug and suggest a fix"
→ Claude가 bug-analyst 선택

# 명시적 호출
"Have the backend-architect review this API design"

장점

  • ✅ 전문성 분리 (separation of concerns)
  • ✅ 컨텍스트 격리로 명확한 역할 구분
  • ✅ 재사용성 높음
  • ✅ 팀 간 공유 가능

단점

  • ❌ 높은 토큰 소비
  • ❌ 각 agent마다 컨텍스트 로딩 필요
  • ❌ Agent 간 통신 오버헤드

2. Custom Commands (Workflows)

개념

미리 정의된 작업 시퀀스를 슬래시 명령어로 실행하는 워크플로우 자동화 도구입니다.

구조

---
name: bug-fix-workflow
description: Systematic bug investigation and resolution
---

# Bug Fix Workflow

When this command is invoked with /bug-fix-workflow [description]:

1. **Bug Analysis Phase**
   - Use QA Test Engineer to reproduce the bug
   - Document the reproduction steps

2. **Implementation Phase**
   - Use Implementation Engineer to fix the bug

3. **Validation Phase**
   - Use QA Test Engineer to validate the fix

특징

  • 위치: ~/.claude/commands/ 또는 .claude/commands/
  • 호출 방식: /command-name [arguments]
  • 순차 실행: 정해진 순서대로 agent들을 오케스트레이션
  • 워크플로우 정의: 복잡한 다단계 프로세스 자동화
  • 품질 게이트: 각 단계별 검증 포인트 설정 가능

사용 예시

/bug-fix-workflow "User login fails with 500 error"

/feature-workflow "Create user authentication with JWT"

/code-review-workflow src/components/

장점

  • ✅ 복잡한 워크플로우 자동화
  • ✅ 일관된 프로세스 보장
  • ✅ 여러 agent를 조율하는 오케스트레이션
  • ✅ 재현 가능한 작업 흐름

단점

  • ❌ 유연성 부족 (미리 정의된 순서)
  • ❌ 수정하려면 파일 편집 필요
  • ❌ 조건부 분기 구현이 복잡

3. Claude Code Plugins (최신 추가)

개념

모듈식 패키지 시스템으로, agents + commands + skills를 하나의 논리적 단위로 묶어 관리합니다.

구조

plugin-name/
├── agents/           # 관련 agents
│   ├── agent1.md
│   └── agent2.md
├── commands/         # 관련 commands
│   └── workflow.md
├── skills/           # 지식 패키지
│   ├── skill1.md
│   └── skill2.md
└── plugin.json       # 메타데이터

특징

  • 위치: ~/.claude/plugins/ 또는 프로젝트 내
  • 설치 방식:
  • /plugin install python-development/plugin install kubernetes-operations
  • 점진적 로딩: 필요할 때만 활성화 (progressive disclosure)
  • 스킬 시스템: 자동 활성화되는 전문 지식 패키지
  • 의존성 관리: 플러그인 간 의존성 정의 가능
  • 마켓플레이스: 중앙화된 플러그인 저장소

Skills의 개념

---
name: kubernetes-deployment
type: skill
activates_on: ["kubernetes", "k8s", "deployment"]
---

# Kubernetes Deployment Skill
This skill provides specialized knowledge about...
  • 특정 키워드나 컨텍스트에서 자동 활성화
  • Agent에게 전문 지식을 "주입"
  • 토큰 효율적 (필요할 때만 로드)

사용 예시

# 플러그인 설치
/plugin install python-development

# 자동 활성화
"Create a FastAPI microservice"
→ python-development 플러그인의 agents, skills 활성화
→ 관련 commands 사용 가능

# 플러그인 전용 명령어
/python-development:python-scaffold fastapi-microservice

장점

  • 모듈화: 관련 기능을 논리적으로 그룹화
  • 토큰 효율성: 필요한 것만 로드 (최소 토큰 사용)
  • 버전 관리: 플러그인 단위로 업데이트
  • 의존성 해결: 자동으로 필요한 플러그인 설치
  • 컴포저빌리티: 여러 플러그인 조합 가능
  • 배포 용이성: 팀 전체에 표준화된 도구 배포

단점

  • ❌ 최신 기능 (일부 도구만 지원)
  • ❌ 설정 복잡도 증가
  • ❌ 플러그인 간 충돌 가능성

비교표

특성 Agents Commands Plugins
추상화 수준 낮음 (개별 전문가) 중간 (워크플로우) 높음 (모듈 패키지)
재사용성 ⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐⭐
토큰 효율성 ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
유연성 ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐
설정 난이도 쉬움 중간 복잡
활성화 방식 자동/수동 수동 (/cmd) 자동/설치
배포 편의성 파일 복사 파일 복사 패키지 관리
버전 관리
의존성 관리

실제 사용 시나리오

Scenario 1: 단순 전문가 자문

"Review this code for security issues"

최적: Agent (security-auditor)

  • 단일 전문가의 의견만 필요
  • 빠르고 직접적

Scenario 2: 복잡한 다단계 프로세스

/feature-workflow "User authentication system"

최적: Command (workflow)

  • 여러 단계를 거쳐야 함
  • 품질 게이트 필요
  • 일관된 프로세스 보장

Scenario 3: 특정 기술 스택 작업

/plugin install python-development
"Create a FastAPI app with SQLAlchemy"

최적: Plugin

  • 관련된 모든 도구 한번에 활성화
  • 자동으로 적절한 skills 로드
  • 토큰 효율적

아키텍처 관점

Layer 구조

┌─────────────────────────────────────┐
│         Plugins (최상위)             │
│  - python-development                │
│  - kubernetes-operations             │
└────────────┬────────────────────────┘
             │ contains
    ┌────────┴─────────┐
    │                  │
┌───▼──────────┐  ┌───▼──────────┐
│   Agents     │  │  Commands    │
│  (전문가)     │  │ (워크플로우)  │
└──────────────┘  └──────────────┘
         │              │
         └──────┬───────┘
                │ uses
         ┌──────▼──────┐
         │   Skills    │
         │ (지식 패키지) │
         └─────────────┘

권장 사항

언제 Agent를 사용할까?

  • ✅ 단일 전문가의 의견이 필요할 때
  • ✅ 유연한 대화형 상호작용이 필요할 때
  • ✅ 빠른 프로토타이핑

언제 Command를 사용할까?

  • ✅ 반복적인 다단계 프로세스
  • ✅ 팀 전체가 따라야 하는 표준 워크플로우
  • ✅ 품질 게이트가 필요한 프로세스

언제 Plugin을 사용할까?

  • ✅ 관련 기능을 패키지로 배포
  • ✅ 토큰 효율성이 중요할 때
  • ✅ 버전 관리와 의존성 해결이 필요할 때
  • ✅ 대규모 팀에서 표준화된 도구 배포

진화 경로

2024 초반: Agents만 존재
    ↓
2024 중반: Commands 추가 (워크플로우 오케스트레이션)
    ↓
2024 후반/2025: Plugins 도입 (모듈화 + 토큰 효율성)

Plugins는 Agents와 Commands의 장점을 결합하면서 토큰 효율성과 배포 편의성을 크게 개선한 최신 접근 방식입니다.

첨부하신 bug-analyst.mdAgent 형식이므로, Plugin 시스템으로 마이그레이션하면 다음과 같은 구조가 될 것입니다:

bug-analysis-plugin/
├── agents/
│   ├── bug-analyst.md
│   ├── error-detective.md
│   ├── code-diagnostician.md
│   └── fix-architect.md
├── commands/
│   └── bug-fix-workflow.md
├── skills/
│   ├── python-debugging.md
│   └── react-debugging.md
└── plugin.json

이렇게 구조화하면 /plugin install bug-analysis로 한번에 모든 버그 분석 도구를 활성화할 수 있습니다! 아참, Plugin은 Maketplace로 만들어야 됩니다. 다른 plugin 참고하세요.

+ Recent posts