포스트

AI 코딩 에이전트와 함께한 DevLog 개발 여정 (가상 시나리오)

AI 코딩 에이전트와 함께한 DevLog 개발 여정 (가상 시나리오)

풀스택 애플리케이션을 4가지 AI 도구로 구축하는 실전 이야기

들어가며: 새로운 시대의 개발자

2026년 1월, 저는 개인 프로젝트 하나를 시작하기로 결심했습니다. DevLog라는 이름의 개발자 일일 로그 시스템이었죠. Spring Boot 백엔드에 React 프론트엔드, PostgreSQL 데이터베이스, 그리고 Docker로 배포까지. 혼자서 이 모든 걸 구축하려면 최소 2-3개월은 걸릴 것 같았습니다.

하지만 저에게는 특별한 팀원들이 있었습니다. Cursor, Claude Code, Google Antigravity, 그리고 GPT-5.2 Codex. 이 네 가지 AI 코딩 에이전트와 함께라면 얼마나 걸릴까요? 그리고 더 중요한 질문은, 각자 언제 투입해야 최고의 효율을 낼 수 있을까요?

이것은 제가 그들과 함께 DevLog를 만들어가며 배운 것들에 대한 이야기입니다.


Chapter 1: 팀을 구성하다

네 명의 팀원, 각자의 역할

프로젝트를 시작하기 전, 저는 먼저 제 팀원들의 성격을 파악해야 했습니다. 사람으로 치면 대리, 과장, PM, 그리고 상무급에 해당하는 네 명이었죠.

Cursor는 팀의 막내 대리 같았습니다. 무엇보다 빠릅니다. “이 버튼 색상 바꿔줘”라고 하면 1초 만에 결과를 보여줍니다. Tab 키만 누르면 제가 생각하는 코드를 자동으로 완성해주고, Cmd+K를 누르고 지시하면 선택한 코드를 즉시 수정합니다. VS Code를 기반으로 만들어져서 제가 이미 익숙한 환경 그대로였고, 심지어 Auto-run 모드로 설정하면 테스트를 자동으로 돌리고, 실패하면 스스로 고쳐서 다시 실행합니다. 하지만 복잡한 아키텍처 결정을 맡기기엔 아직 경험이 부족했습니다. 장시간 작업하다 보면 가끔 처음에 한 이야기를 잊어버리기도 했죠.

Claude Code는 베테랑 과장급이었습니다. 프로젝트를 시작할 때 가장 먼저 찾는 사람입니다. “이 프로젝트 어떻게 설계할까?”라고 물으면, Plan Mode로 전환하여 체계적인 계획을 세워줍니다. 200,000 토큰이라는 방대한 컨텍스트 윈도우로 전체 코드베이스를 한눈에 파악하고, 복잡한 작업은 자동으로 Explore, Plan, Task 같은 subagent들에게 위임합니다. 특히 opusplan 모드는 인상적이었습니다. Opus 4.5라는 똑똑한 모델로 계획을 세우고, Sonnet 4.5라는 효율적인 모델로 실행하는 방식이죠. 비용은 절약하면서도 품질은 유지하는 영리함이 있었습니다. 다만 터미널 기반이라 시각적 작업에는 약간 불편했고, Cursor보다는 속도가 느렸습니다.

Google Antigravity는 2025년 11월에 막 입사한 젊은 PM 같았습니다. 구글이 Windsurf 팀을 인수하면서 만든 최신 도구였죠. 이 친구의 특별함은 Manager View에 있었습니다. 한 번에 여러 개의 에이전트를 띄워서 각자 다른 일을 시킬 수 있었습니다. “Workspace 1에서는 백엔드 API 만들고, Workspace 2에서는 프론트엔드 페이지 만들고, Workspace 3에서는 Docker 설정해”라고 하면, 세 명의 에이전트가 동시에 작업을 시작합니다. 더 놀라운 건 Browser Subagent였습니다. 실제 브라우저를 띄워서 제가 만든 웹페이지를 자동으로 클릭하고, 입력하고, 테스트합니다. 그리고 결과를 스크린샷과 영상으로 남겨줍니다. 이런 Artifacts 덕분에 PM이나 디자이너에게 진행 상황을 코드 없이도 쉽게 공유할 수 있었죠. 하지만 출시한 지 얼마 안 된 만큼, 가끔 오류가 있었고 속도도 느린 편이었습니다.

GPT-5.2 Codex는 팀의 상무님이었습니다. 모든 코드가 완성되면 이분께 최종 검토를 맡깁니다. 느립니다. 하지만 그만큼 깊이 있게 봅니다. effort를 ‘xhigh’로 설정하면 정말 오래 생각합니다. 그리고는 제가 미처 발견하지 못한 보안 취약점, 미묘한 race condition, 숨어있는 메모리 누수를 찾아냅니다. SWE-Bench Pro에서 56.4%라는 최고 점수를 기록한 디버깅 전문가답게, “이 코드는 지금은 잘 돌아가지만 동시 접속자 100명 넘으면 문제가 생길 겁니다”라고 미리 경고해줍니다. 새로운 기능을 만들기보다는 이미 만들어진 것을 검증하고 개선하는 데 특화되어 있었습니다.

예산에 맞춰 팀 구성하기

이상적으로는 네 명 모두와 함께 일하면 좋겠지만, 현실은 예산이 있습니다. 저는 세 가지 시나리오를 생각해봤습니다.

가장 저렴한 옵션은 월 20달러로 Cursor만 쓰는 것입니다. 혼자 모든 걸 해야 하지만, 상세한 .cursorrules 파일과 CLAUDE.md를 잘 작성하면 수동 개발 대비 2.5배 정도 빨라집니다. 4-5주면 DevLog를 완성할 수 있을 것 같았습니다.

제가 선택한 건 월 60달러 옵션이었습니다. Cursor 20달러, Claude Code 20달러, 그리고 Antigravity는 무료 프리뷰였으니까요. 이 조합이라면 2-3주면 충분할 것 같았고, 생산성은 4배 정도 될 거라 예상했습니다. 60달러 투자로 개발 시간을 절반 이상 줄인다면, 제 시급을 생각하면 수천 달러를 절약하는 셈이니까요.

만약 프로덕션 품질의 완벽한 시스템이 필요하다면 월 140달러를 쓸 수도 있습니다. Claude Code Max가 100달러로 무제한 사용, Codex는 ChatGPT Plus 구독으로 20달러. 이렇게 하면 1-2주 만에 프로덕션 레벨로 완성할 수 있고, 생산성은 6배까지 올라갑니다.


Chapter 2: 프로젝트의 시작 - 설계의 중요성

첫날, Claude Code와의 대화

월요일 아침, 저는 Claude Code를 실행했습니다. 터미널에 claude --model opusplan을 입력하고, 제 구상을 이야기하기 시작했습니다.

“DevLog라는 개발자 일일 로그 시스템을 만들려고 해. Spring Boot로 백엔드를 만들고, React로 프론트엔드를 만들 거야. 데이터베이스는 PostgreSQL을 쓰고, Docker로 배포할 계획이야. 필요한 기능은 37개 정도의 REST API 엔드포인트와 5개 주요 페이지야.”

Claude Code는 잠시 생각하더니 자동으로 Plan Mode로 전환했습니다. “복잡한 프로젝트네요. 체계적으로 접근하겠습니다”라는 메시지와 함께 상세한 계획서를 작성하기 시작했습니다.

먼저 프로젝트 구조를 제안했습니다. 루트 디렉토리 아래 backend, frontend, database, docs 폴더를 만들고, 각각의 역할을 명확히 정의했습니다. 그다음 데이터베이스 설계로 넘어갔습니다. DevLog, Project, TechTag, LogTags라는 네 개의 테이블과 그들 간의 관계를 ERD로 그려 보여줬습니다. 특히 PostgreSQL은 컬럼명을 소문자로 반환한다는 점을 강조하며, 모든 컬럼을 snake_case로 명명해야 한다고 조언했습니다. “이거 안 지키면 나중에 프론트엔드에서 데이터가 안 보이는 버그로 고생할 겁니다”라는 경고와 함께요.

기본 설정 단계에서는 application.yml 구조, CORS 설정, 환경 변수 관리 방법까지 제시했습니다. “계속 진행할까요?”라고 묻길래, 저는 승인했습니다.

그러자 Claude Code는 실제로 파일을 만들기 시작했습니다. backend 폴더에 Spring Boot 프로젝트 스켈레톤을, frontend 폴더에 React 프로젝트를 생성했습니다. schema.sql 파일에는 제가 이야기한 모든 테이블 정의와 제약조건, 인덱스까지 들어있었습니다. 심지어 시드 데이터까지 준비해뒀더군요.

3시간 정도 걸릴 줄 알았던 초기 설정이 30분 만에 끝났습니다.

CLAUDE.md - 우리 팀의 헌법

프로젝트 구조가 잡히자, Claude Code는 한 가지를 더 제안했습니다. “CLAUDE.md 파일을 만들어두시는 게 좋겠습니다. 이건 모든 AI 에이전트가 읽는 일종의 프로젝트 헌법 같은 거예요.”

저는 루트 디렉토리에 CLAUDE.md를 만들고, 프로젝트의 핵심 규칙들을 적기 시작했습니다. “PostgreSQL 컬럼명은 절대 camelCase 쓰지 마라. 무조건 snake_case다.” “프론트엔드 API 호출은 반드시 axios interceptor를 거쳐야 한다.” “UI 색상은 WCAG AA 기준을 만족해야 한다.” “절대 git push -f 하지 마라.”

이 파일의 멋진 점은, Cursor든 Claude Code든 Antigravity든, 어떤 도구를 써도 세션 시작할 때 자동으로 읽는다는 겁니다. 매번 똑같은 설명을 반복할 필요가 없어졌습니다. 더 중요한 건, 팀원이 생기면 그들도 이 파일만 읽으면 프로젝트의 모든 규칙을 알 수 있다는 점이었습니다.

그날 저녁, 저는 CLAUDE.md를 Git에 커밋했습니다. 이 파일은 앞으로 프로젝트가 진행되면서 계속 업데이트될 것입니다. AI가 실수할 때마다, 그 실수를 방지하는 규칙을 추가하면서요.


Chapter 3: 백엔드 개발 - 역할 분담의 예술

데이터베이스 스키마, Claude Code의 독무대

이틀째 되던 날, 본격적인 개발에 들어갔습니다. 먼저 데이터베이스 스키마를 완성해야 했습니다. 이건 Claude Code에게 맡기기로 했습니다. 복잡한 관계형 데이터베이스 설계는 이 친구가 가장 잘하니까요.

“DevLog, Project, TechTag, LogTags 테이블의 완전한 스키마를 만들어줘. 모든 제약조건과 인덱스도 포함해서.”

Claude Code는 Plan Mode에서 먼저 각 테이블의 역할을 분석했습니다. DevLog는 실제 로그 데이터를 저장하고, Project는 프로젝트 정보를, TechTag는 기술 스택 태그를, LogTags는 DevLog와 TechTag의 다대다 관계를 연결합니다. 그리고는 각 필드의 타입, 길이 제약, NULL 허용 여부를 하나하나 정의했습니다.

특히 인상적이었던 건 인덱스 설계였습니다. “log_date는 자주 검색될 거니까 인덱스 추가”, “project_id와 log_date의 복합 인덱스는 통계 쿼리를 빠르게 할 겁니다”, “tech_tag의 name은 UNIQUE 제약조건이 필요합니다” 같은 설명과 함께 최적화된 스키마를 만들었습니다.

완성된 schema.sql은 200줄이 넘었지만, 주석이 잘 달려있어서 이해하기 쉬웠습니다. CREATE TABLE 문마다 “이 테이블의 목적”, “주의사항” 같은 설명이 붙어있었습니다.

MyBatis 매퍼, Cursor의 시간

스키마가 완성되자, 이제 MyBatis XML 매퍼를 만들 차례였습니다. 각 테이블마다 CRUD 쿼리가 필요하고, 통계용 복잡한 쿼리도 몇 개 추가해야 했습니다. 이건 반복 작업이 많으니까 Cursor에게 맡겼습니다.

Cursor를 열고, Agent Mode로 전환한 뒤 간단히 지시했습니다. “schema.sql을 보고 모든 MyBatis 매퍼를 생성해줘. DevLogMapper.xml, ProjectMapper.xml, TechTagMapper.xml. 각각 CRUD와 통계 쿼리 포함.”

Cursor는 즉시 패턴을 파악했습니다. DevLog 테이블을 보고는 selectAll, selectById, insert, update, delete 쿼리를 자동 생성했습니다. 그리고 SELECT 문에서는 “반드시 AS 별칭을 써서 camelCase로 변환하라”는 CLAUDE.md의 규칙을 지켰습니다.

1
2
3
4
5
6
SELECT 
    id AS "id",
    project_id AS "projectId",
    created_at AS "createdAt",
    updated_at AS "updatedAt"
FROM dev_logs

15분 만에 네 개의 매퍼 파일이 완성됐습니다. 각 파일은 200줄 정도였는데, 제가 수동으로 작성했다면 몇 시간은 걸렸을 겁니다.

Service 계층, 복잡도에 따른 선택

Service 계층을 만들 때는 작업의 복잡도에 따라 도구를 나눠 썼습니다. 단순한 CRUD 메서드는 Cursor로 빠르게 작성했습니다. create(), update(), delete(), findById() 같은 메서드들은 패턴이 거의 동일하니까요.

하지만 통계 로직은 달랐습니다. getWeeklyStatistics()라는 메서드는 이번 주의 일별 작업 시간을 집계하고, 활동 일수를 계산하고, 평균을 내야 했습니다. 이건 Claude Code에게 맡겼습니다.

“DevLogService의 getWeeklyStatistics() 메서드 로직을 계획해줘.”

Claude Code는 단계별로 접근했습니다. 먼저 이번 주의 시작일과 종료일을 LocalDate로 계산하는 방법을 제시했습니다. 그다음 Mapper를 통해 해당 기간의 데이터를 조회하고, Java Stream API로 집계하는 방법을 설명했습니다. 마지막으로 결과를 DTO로 변환하여 반환하는 전체 플로우를 보여줬습니다.

계획을 확인하고 승인하자, Claude Code는 실제 코드를 작성했습니다. 각 단계마다 주석이 달려있어서, 나중에 제가 봐도 무슨 일을 하는지 한눈에 알 수 있었습니다.

Codex의 날카로운 눈

백엔드의 모든 Service가 완성되자, 저는 Codex를 불렀습니다. “이제 상무님께 검토받을 시간이야.”

터미널에 codex --effort xhigh를 입력하고, Service 디렉토리 전체를 리뷰 요청했습니다. 특히 트랜잭션 관리, 예외 처리, SQL Injection 방지, 동시성 문제를 중점적으로 봐달라고 했습니다.

Codex는 느렸습니다. 5분 정도 아무 반응이 없더니, 갑자기 상세한 리포트를 쏟아냈습니다.

“Critical Issues Found: 3개”로 시작하는 보고서였습니다.

첫 번째 이슈는 DevLogService의 create() 메서드에서 RuntimeException을 던지고 있다는 점이었습니다. “너무 일반적입니다. Custom ResourceCreationException을 만들어 쓰세요. 그래야 나중에 전역 예외 핸들러에서 적절한 HTTP 상태 코드를 반환할 수 있습니다.”

두 번째는 StatisticsService의 getMonthlyStats()에서 N+1 쿼리 문제가 있다는 지적이었습니다. “루프 안에서 데이터베이스를 호출하고 있습니다. JOIN 쿼리 하나로 한 번에 조회하세요.”

세 번째는 가장 심각했습니다. ProjectService의 delete()가 프로젝트만 삭제하고, 연관된 DevLog는 그대로 남겨둔다는 겁니다. “고아 레코드가 생깁니다. @Transactional 안에서 연관 레코드를 먼저 삭제하세요.”

Codex의 리뷰는 단순히 문제를 지적하는 데 그치지 않았습니다. 각 이슈마다 “현재 코드”, “문제점”, “해결 방법”, “예상 결과”를 모두 제시했습니다. 그대로 따라 하기만 하면 될 정도로 친절했습니다.

저는 Cursor를 열고, Codex가 지적한 세 가지를 모두 수정했습니다. Custom Exception 클래스를 만들고, N+1 쿼리를 JOIN으로 바꾸고, cascade delete 로직을 추가했습니다. 다시 테스트를 돌리니, 모두 통과했습니다.


Chapter 4: 프론트엔드 개발 - Antigravity의 진가

Manager View, 세 개의 에이전트를 동시에

프론트엔드 개발을 시작할 때, 저는 새로운 실험을 해보기로 했습니다. Antigravity의 Manager View를 써보는 겁니다.

Antigravity를 열고 Manager View로 전환하자, 화면이 세 개의 영역으로 나뉘었습니다. 저는 각 Workspace에 하나씩 에이전트를 배정했습니다.

Workspace 1에는 Dashboard 페이지를 맡겼습니다. “통계 카드 4개, 주간 바 차트, 최근 로그 5개를 보여주는 대시보드를 만들어줘. Glassmorphism 스타일로.”

Workspace 2에는 Logs 페이지를 맡겼습니다. “로그 목록을 무한 스크롤로 보여주고, 필터링과 검색 기능도 추가해줘.”

Workspace 3에는 Statistics 페이지를 맡겼습니다. “주간/월간 차트, 프로젝트 분포 파이 차트, 기술 스택 통계를 시각화해줘.”

“Start All”을 누르자, 세 개의 에이전트가 동시에 작업을 시작했습니다. 각 Workspace에서는 에이전트가 무슨 일을 하는지 실시간으로 볼 수 있었습니다.

Workspace 1의 에이전트는 먼저 Plan Mode로 들어가서 계획을 세웠습니다. “StatCard, WeeklyChart, RecentLogs 컴포넌트를 만들고, Dashboard.jsx에서 조합하겠습니다. API는 /api/statistics/dashboard를 호출합니다.” 계획을 보여주고 승인을 기다렸습니다.

저는 세 Workspace를 빠르게 훑어보며 각각 승인했습니다. 그러자 에이전트들은 Fast Mode로 전환해서 실제 코드를 작성하기 시작했습니다.

놀라운 건 Browser Subagent였습니다. 각 에이전트가 컴포넌트를 완성할 때마다, 자동으로 브라우저를 띄워서 테스트했습니다. 실제로 페이지가 제대로 렌더링되는지, 버튼을 클릭하면 동작하는지, 모바일 화면에서도 괜찮은지 확인했습니다. 그리고 스크린샷을 찍어서 Artifacts로 남겼습니다.

20분 후, 세 페이지가 모두 완성됐습니다. 평소라면 하루는 걸렸을 작업이었습니다. Manager View의 왼쪽에는 각 Workspace의 Artifacts가 쌓여있었습니다. 스크린샷 18장, 동작 영상 3개, 테스트 리포트 3개. 이걸 PM이나 디자이너에게 보여주면, 코드를 보지 않고도 제가 뭘 만들었는지 정확히 알 수 있을 겁니다.

Cursor로 다듬기

Antigravity가 만든 기본 구조는 훌륭했지만, 세부적인 스타일은 제 취향에 맞게 조정하고 싶었습니다. 이럴 땐 Cursor가 최고입니다.

Dashboard 컴포넌트를 Cursor에서 열고, StatCard 부분을 선택했습니다. Cmd+K를 누르고 간단히 지시했습니다.

“이 카드에 호버 효과 추가해줘. 마우스 올리면 살짝 떠오르는 느낌으로, 트랜지션은 0.3초.”

1초 만에 코드가 수정됐습니다. className에 hover:scale-105 hover:shadow-2xl transition-all duration-300이 추가됐습니다. 브라우저를 새로고침하니 즉시 적용됐습니다. 마우스를 카드에 올리자 부드럽게 떠오르는 효과가 보였습니다.

이런 식으로 20여 군데를 빠르게 조정했습니다. 색상, 간격, 애니메이션, 폰트 크기. 각 수정마다 1-2초씩밖에 안 걸렸습니다. Cursor의 인라인 편집은 이런 미세 조정에 완벽했습니다.

Recharts와의 씨름, Claude Code의 도움

Statistics 페이지의 차트는 생각보다 복잡했습니다. Recharts 라이브러리를 써야 했는데, 설정 옵션이 너무 많았습니다. 툴팁 포맷, 색상 그라데이션, 레전드 위치, 반응형 크기 조정 등등.

저는 Claude Code에게 먼저 전체 구조를 계획해달라고 했습니다.

“Statistics 페이지에 세 개 차트가 필요해. 월간 작업 시간 라인 차트, 프로젝트별 파이 차트, 기술 스택 바 차트. 각각 어떻게 설정해야 할지 계획 세워줘.”

Claude Code는 각 차트의 데이터 구조부터 정의했습니다. 월간 라인 차트는 [{ date: "2026-01-01", minutes: 120 }, ...] 형태로, 파이 차트는 [{ name: "DevLog", value: 45, color: "#8B5CF6" }, ...] 형태로 데이터가 와야 한다고 설명했습니다.

그다음 Recharts 컴포넌트별 설정을 제시했습니다. BarChart는 layout을 “vertical”로 해야 가로 바가 되고, XAxis와 YAxis의 역할이 바뀐다는 것, Tooltip은 custom 함수로 포맷을 바꿀 수 있다는 것, 색상은 fill 속성에 직접 넣거나 gradient를 쓸 수 있다는 것.

계획을 보고는 Antigravity에게 구현을 맡겼습니다. “위 계획대로 세 개 차트를 만들고, 브라우저에서 실제 데이터로 테스트해줘.”

Antigravity는 계획을 읽고, 세 개의 차트 컴포넌트를 만들었습니다. 그리고 Browser Subagent를 띄워서 실제로 차트가 제대로 그려지는지 확인했습니다. 툴팁에 마우스를 올려보고, 반응형으로 화면 크기를 바꿔보고, 데이터가 없을 때도 테스트했습니다. 모든 시나리오를 영상으로 녹화해서 보여줬습니다.

Codex의 UX 리뷰

프론트엔드가 거의 완성되자, 저는 다시 Codex를 불렀습니다. 이번에는 코드 품질이 아니라 UX 관점에서 봐달라고 했습니다.

“frontend/src/pages 디렉토리의 모든 페이지를 UX 관점에서 리뷰해줘. 접근성, 키보드 네비게이션, 로딩 상태, 에러 메시지를 중점적으로.”

Codex는 꼼꼼했습니다. LogForm에서 로딩 중에도 버튼을 클릭할 수 있다는 걸 지적했습니다. “disabled={isLoading} 속성을 추가하세요.” Dashboard에서 차트가 로딩될 때 빈 공간이 그대로 있어서 Cumulative Layout Shift 문제가 생긴다고 했습니다. “Skeleton loader를 추가하세요.”

가장 중요한 지적은 접근성이었습니다. 모든 폼 필드에 ARIA 라벨이 빠져있었습니다. 시각 장애인이 스크린 리더를 쓰면 어떤 입력창인지 알 수 없다는 겁니다. “aria-label 또는 aria-labelledby를 추가하세요.”

Cursor로 이 지적사항들을 모두 고쳤습니다. 10분 정도 걸렸습니다. 다시 접근성 테스트를 돌리니, WCAG AA 기준을 만족했습니다.


Chapter 5: 통합과 테스트 - 완벽함을 향해

E2E 테스트, Antigravity의 마법

프론트엔드와 백엔드가 모두 완성되자, 이제 전체 시스템이 제대로 돌아가는지 확인할 차례였습니다. 저는 Antigravity에게 완전한 사용자 시나리오를 테스트해달라고 했습니다.

“새로운 개발자가 처음 사용하는 시나리오를 E2E로 테스트해줘. 대시보드 접속부터 시작해서, 로그 작성하고, 목록에서 확인하고, 편집하고, 다시 대시보드에서 통계가 업데이트됐는지 확인하는 전체 플로우.”

Antigravity는 먼저 계획을 세웠습니다. 데이터베이스를 깨끗한 상태로 리셋하고, 테스트용 프로젝트를 하나 만들고, 개발 서버들을 띄웁니다. 그다음 브라우저를 열어서 실제 사용자처럼 클릭하고 입력합니다.

실행을 승인하자, Browser Subagent가 Chrome을 띄웠습니다. 그리고 정말로 사람처럼 행동하기 시작했습니다.

먼저 http://localhost:3000으로 접속했습니다. 페이지가 로드되길 기다렸습니다. “아직 로그가 없습니다”라는 메시지가 보이는지 확인했습니다. 스크린샷을 찍었습니다.

“새 로그 작성” 버튼을 찾아서 클릭했습니다. 로그 작성 폼으로 이동했는지 확인했습니다.

폼을 채우기 시작했습니다. 프로젝트 드롭다운을 클릭해서 “My First Project”를 선택했습니다. 제목 입력창에 “Setup development environment”를 타이핑했습니다. 시작 시간 “09:00”, 종료 시간 “11:30”을 입력했습니다. 작업 시간이 자동으로 “150분”으로 계산되는지 확인했습니다. 기분은 “GOOD” 이모지를 선택했습니다. 기술 태그는 “React”, “Node.js”, “Docker” 세 개를 추가했습니다.

저장 버튼을 클릭했습니다. API 호출이 성공했는지, 응답이 201 Created인지 확인했습니다. 로그 목록 페이지로 리다이렉트됐는지 확인했습니다.

방금 만든 로그가 목록에 보이는지 찾았습니다. 제목이 정확한지, 작업 시간이 “2h 30m”으로 표시되는지 확인했습니다. 로그 카드를 클릭해서 상세 페이지로 들어갔습니다.

편집 버튼을 클릭했습니다. 폼이 기존 데이터로 미리 채워져있는지 확인했습니다. 제목을 “Setup development environment - Complete”로 수정했습니다. 저장했습니다.

대시보드로 돌아왔습니다. 통계가 업데이트됐는지 확인했습니다. “이번 주: 2h 30m”, “로그: 1개”, “활성 프로젝트: 1개”가 표시되는지 확인했습니다. 주간 차트에 월요일 바가 150분으로 표시되는지 확인했습니다.

전 과정이 18초 걸렸습니다. Antigravity는 모든 단계를 영상으로 녹화했고, 각 중요 지점마다 스크린샷을 찍었습니다. 그리고 “All steps passed!”라는 메시지와 함께 상세한 테스트 리포트를 생성했습니다.

만약 어딘가에서 실패했다면, Antigravity는 자동으로 문제를 분석했을 겁니다. 네트워크 탭을 확인하고, 콘솔 로그를 읽고, 어디서 잘못됐는지 찾아냈을 겁니다. 실제로 한 번 실패가 있었습니다. 프론트엔드가 camelCase로 데이터를 보냈는데, 백엔드는 snake_case를 기대하고 있었던 겁니다. Antigravity는 즉시 이 불일치를 발견하고, axios interceptor를 추가하라고 제안했습니다.

Claude Code의 버그 수정

Antigravity가 발견한 버그를 Claude Code에게 맡겼습니다. “프론트엔드와 백엔드 간 필드명 불일치를 axios interceptor로 해결해줘.”

Claude Code는 utils 폴더에 apiTransform.js 파일을 만들었습니다. camelCase를 snake_case로 변환하는 함수와 그 반대 함수를 만들고, axios의 request와 response interceptor에 연결했습니다. 이제 프론트엔드는 계속 camelCase로 작성해도, 백엔드로 보낼 때 자동으로 snake_case로 변환됩니다. 백엔드 응답도 자동으로 camelCase로 변환되어 돌아옵니다.

단 10줄의 코드로 전체 애플리케이션의 데이터 일관성 문제가 해결됐습니다.

Codex의 최종 감사

모든 기능이 완성되고 테스트도 통과하자, 마지막으로 Codex를 불렀습니다. “전체 시스템을 최종 검토해줘. 특히 프론트엔드와 백엔드 간 데이터 일관성, 에러 핸들링, 성능 병목, 보안 취약점을 봐줘.”

Codex는 이번에도 effort를 xhigh로 설정했습니다. 5분간의 침묵 후, 방대한 리포트가 나왔습니다.

Critical Issues가 한 개 있었습니다. DELETE /api/projects/{id} 엔드포인트가 프로젝트를 삭제하면서 연관된 로그는 그대로 남겨둔다는 겁니다. 고아 레코드가 생길 수 있었습니다. “@Transactional 안에서 연관 레코드를 먼저 삭제하세요”라는 해결책과 함께요.

Medium Priority 이슈가 10개 있었습니다. Statistics 페이지의 차트 렌더링이 비효율적이라는 지적, CORS 설정이 너무 관대하다는 지적, Rate Limiting이 없어서 API 남용이 가능하다는 지적.

Low Priority 이슈가 15개 있었습니다. 주로 코드 중복, 불필요한 재렌더링, 더 나은 에러 메시지 같은 것들이었습니다.

저는 Cursor로 Critical과 Medium 이슈들을 모두 고쳤습니다. Cascade delete 로직을 추가하고, React.memo와 useMemo로 차트를 최적화하고, CORS 허용 도메인을 환경 변수로 제한하고, Rate Limiter를 추가했습니다.


Chapter 6: 배포 - 프로덕션으로

Docker 최적화, Claude Code의 마법

배포를 준비하면서, 저는 Docker 이미지 크기가 걱정됐습니다. 현재 백엔드 이미지가 650MB, 프론트엔드가 280MB나 됐습니다. 이건 너무 컸습니다.

Claude Code에게 multi-stage build로 최적화해달라고 했습니다. “백엔드는 200MB 이하, 프론트엔드는 50MB 이하로 줄여줘.”

Claude Code는 Plan Mode에서 전략을 세웠습니다. 백엔드는 두 단계로 나눕니다. 첫 번째 단계에서 Maven으로 빌드하고, 두 번째 단계에서는 빌드된 JAR 파일만 가져와서 JRE만 있는 Alpine 이미지에 넣습니다. 프론트엔드도 마찬가지로 NPM으로 빌드한 후, Nginx Alpine 이미지에 빌드 결과물만 복사합니다.

구현된 Dockerfile을 보니 정말 깔끔했습니다. 불필요한 의존성은 모두 첫 번째 단계에만 남아있고, 최종 이미지에는 실행에 필요한 최소한만 들어갔습니다. .dockerignore 파일로 node_modules, target 같은 큰 폴더들은 빌드 컨텍스트에서 제외했습니다.

이미지를 다시 빌드하니, 백엔드가 148MB, 프론트엔드가 24MB로 줄었습니다. 78%와 91%의 크기 감소였습니다.

Antigravity의 배포 테스트

Docker 이미지가 준비되자, docker-compose.yml로 전체 스택을 통합했습니다. PostgreSQL, Backend, Frontend 세 개의 서비스를 하나의 네트워크로 연결하고, 헬스 체크와 재시작 정책을 설정했습니다.

Antigravity에게 배포 테스트를 맡겼습니다. “docker-compose up으로 전체 스택을 띄우고, E2E 테스트를 실행해줘.”

Antigravity는 먼저 이미지를 빌드했습니다. 3분 42초가 걸렸습니다. 컨테이너들을 시작했습니다. PostgreSQL이 준비될 때까지 8초 기다렸습니다. 백엔드 헬스 체크가 통과될 때까지 기다렸습니다. 프론트엔드가 접속 가능한지 확인했습니다.

그리고는 아까 했던 E2E 테스트를 다시 실행했습니다. 이번에는 배포된 환경에서요. 모든 테스트가 통과했습니다.

마지막으로 성능 테스트를 돌렸습니다. Apache Bench로 1000개 요청을 동시 접속 10으로 보냈습니다. 평균 응답 시간 45ms, 99th percentile 120ms, 에러 0개. 만족스러운 결과였습니다.

Codex의 보안 감사

배포 직전, Codex에게 보안 점검을 의뢰했습니다. “프로덕션 배포 전 보안 감사해줘.”

Codex는 여러 문제를 발견했습니다.

가장 Critical한 건 application.yml에 데이터베이스 비밀번호가 평문으로 들어있다는 점이었습니다. “환경 변수로 바꾸세요. ${DB_PASSWORD}로.”

두 번째는 CORS 설정이 모든 도메인을 허용하고 있다는 점이었습니다. “@CrossOrigin(origins = "*")를 ${ALLOWED_ORIGINS}로 바꾸고, .env 파일에서 관리하세요.”

세 번째는 Rate Limiting이 없어서 API 남용이 가능하다는 점이었습니다. “RateLimiter Bean을 추가하세요. 분당 100 요청으로 제한하세요.”

네 번째는 HTTPS가 없다는 점이었습니다. “nginx.conf에 SSL 설정을 추가하세요.”

저는 이 네 가지를 모두 고쳤습니다. 환경 변수 파일을 만들고, CORS 도메인을 제한하고, Rate Limiter를 추가하고, Let’s Encrypt로 SSL 인증서를 발급받았습니다.

Codex에게 다시 감사를 받으니, 보안 점수가 7/10에서 9/10으로 올라갔습니다.


Chapter 7: 실전에서 배운 교훈

긴급 상황 - 버그의 발견

프로덕션 배포 후 첫날, 사용자로부터 버그 리포트가 왔습니다. “대시보드의 통계가 모두 0으로 나와요.”

당황한 저는 즉시 Antigravity를 켰습니다. “로컬에서 이 버그를 재현하고 원인을 찾아줘.”

Antigravity는 개발 환경을 띄우고 대시보드를 열었습니다. 정말로 모든 통계가 0이었습니다. 하지만 네트워크 탭을 보니 API 응답은 정상이었습니다. { weeklyMinutes: 150, logCount: 3 }가 정확히 왔습니다.

문제는 프론트엔드였습니다. Antigravity는 Dashboard.jsx를 분석했습니다. 그리고 45번 라인에서 문제를 발견했습니다.

1
2
const stats = response.data;
setStatsData(stats.weeklyMinutes);  // 전체가 아니라 한 필드만!

전체 객체를 저장해야 하는데, weeklyMinutes 하나만 저장하고 있었습니다. 나머지 필드들은 undefined가 돼서 0으로 표시된 겁니다.

저는 Cursor로 즉시 수정했습니다. setStatsData(stats); 한 줄로. 2분 만에 버그가 고쳐졌습니다.

빌드하고, 배포하고, 확인하는 데 5분 더 걸렸습니다. 총 7분 만에 프로덕션 버그가 해결됐습니다.

새 기능 추가 - 주간 리포트

한 달 후, 새로운 기능 요청이 들어왔습니다. “매주 월요일 아침마다 지난 주 활동 요약을 이메일로 받고 싶어요.”

이건 복잡한 기능이었습니다. 데이터 수집, 리포트 생성, PDF 변환, 이메일 발송, 스케줄링까지 여러 단계가 필요했습니다.

저는 Claude Code에게 전체 계획을 맡겼습니다. Plan Mode에서 5개 단계로 나눴습니다. Phase 1은 데이터 수집, Phase 2는 리포트 생성, Phase 3은 이메일 발송, Phase 4는 스케줄링, Phase 5는 사용자 설정 UI.

그리고는 Antigravity Manager View로 세 개의 에이전트를 띄웠습니다. 하나는 백엔드 데이터 수집과 리포트 생성을, 하나는 이메일 서비스와 스케줄러를, 하나는 프론트엔드 설정 UI를 만들었습니다.

세 에이전트가 병렬로 작업했습니다. WeeklyReportService, Thymeleaf 템플릿, Flying Saucer PDF 라이브러리, Spring Mail 설정, @Scheduled annotation, 그리고 Settings 페이지의 이메일 설정 섹션. 20분 만에 모두 완성됐습니다.

Antigravity로 E2E 테스트를 돌렸습니다. 설정 페이지에서 이메일을 활성화하고, 테스트 메일을 발송하고, 실제로 이메일이 도착하는지 확인했습니다. PDF 첨부 파일도 제대로 생성됐습니다.

1시간 만에 완전히 새로운 기능이 프로덕션에 배포됐습니다.


에필로그: 혼자가 아닌 개발

DevLog 프로젝트는 3주 만에 완성됐습니다. 혼자 했다면 2-3개월 걸렸을 겁니다. 하지만 저는 혼자가 아니었습니다. 네 명의 뛰어난 팀원과 함께였습니다.

Cursor는 제가 생각하는 속도로 코드를 작성했습니다. Claude Code는 복잡한 문제를 체계적으로 접근하는 법을 알려줬습니다. Antigravity는 지루한 반복 작업을 맡아서 저를 창의적인 일에 집중하게 해줬습니다. Codex는 제가 놓친 실수들을 찾아내서 품질을 보장했습니다.

하지만 가장 중요한 건, 이들이 도구일 뿐이라는 사실입니다. 진짜 가치는 제가 CLAUDE.md에 얼마나 명확하게 프로젝트의 규칙을 적었는지, 각 도구를 언제 어떻게 사용할지 전략적으로 판단했는지에서 나왔습니다.

AI 시대의 개발자는 코드를 직접 타이핑하는 사람이 아닙니다. 올바른 질문을 던지고, 적절한 도구를 선택하고, 결과를 검증하는 오케스트라 지휘자입니다.

그리고 저는, 이제 막 지휘봉을 잡는 법을 배우기 시작했습니다.


부록: 실용적인 조언들

어떤 도구부터 배워야 할까?

초보자라면 Cursor부터 시작하세요. 가장 친숙하고, 즉각적인 피드백을 주기 때문입니다. Tab 완성으로 코딩하는 재미를 느끼고, Cmd+K로 빠른 수정의 편리함을 경험하세요. 익숙해지면 Agent Mode를 써보세요.

1-2개월 후 Claude Code를 추가하세요. 터미널이 익숙하지 않다면 조금 어렵게 느껴질 수 있지만, Plan Mode의 가치는 곧 알게 될 겁니다. 복잡한 작업을 시작하기 전에 계획을 세우는 습관이 생길 겁니다.

Antigravity는 멀티 에이전트 개념을 이해한 후에 시도하세요. 여러 작업을 동시에 진행하고, Browser Subagent로 자동 테스트를 경험하면, 다시는 수동 테스트로 돌아가고 싶지 않을 겁니다.

Codex는 프로젝트가 어느 정도 완성된 후에 추가하세요. 코드 리뷰와 품질 보증 단계에서 진가를 발휘합니다.

예산이 제한적이라면?

월 20달러만 있다면 Cursor 하나로 충분히 시작할 수 있습니다. .cursorrules를 잘 작성하고, CLAUDE.md를 체계적으로 관리하면, 혼자서도 2.5배 생산성을 낼 수 있습니다.

월 60달러를 쓸 수 있다면, Cursor에 Claude Code를 추가하세요. 그리고 Antigravity는 무료 프리뷰니까 함께 쓰세요. 이 조합이 가성비가 가장 좋습니다. 4배 생산성에 도달할 수 있습니다.

월 140달러를 투자할 수 있다면, 모든 도구를 쓰세요. Claude Code Max로 무제한 코딩을 하고, Codex로 품질을 보장받으세요. 프로덕션 레벨의 애플리케이션을 짧은 시간에 만들 수 있습니다.

언제 어떤 도구를 써야 할까?

간단한 법칙이 있습니다.

빠른 작업이 필요하면 Cursor를 쓰세요. 버튼 색상 바꾸기, CSS 조정, 간단한 버그 수정 같은 것들이요.

복잡한 계획이 필요하면 Claude Code를 쓰세요. 새로운 기능 설계, 데이터베이스 스키마 작성, 아키텍처 결정 같은 것들이요.

병렬 작업이 가능하면 Antigravity를 쓰세요. 여러 페이지 동시 개발, 자동 테스트, UI 검증 같은 것들이요.

최종 검증이 필요하면 Codex를 쓰세요. 배포 전 코드 리뷰, 보안 감사, 복잡한 버그 디버깅 같은 것들이요.

CLAUDE.md는 정말 중요할까?

매우 중요합니다. CLAUDE.md는 팀의 헌법 같은 겁니다. 여기에 프로젝트의 규칙, 컨벤션, 주의사항을 적어두면, 어떤 AI 도구를 써도 일관된 결과를 얻을 수 있습니다.

처음엔 짧게 시작하세요. 기술 스택, 절대 하지 말아야 할 것들, 자주 쓰는 명령어 정도만 적으세요. 그리고 프로젝트가 진행되면서 AI가 실수할 때마다 규칙을 추가하세요.

AI가 “PostgreSQL 컬럼은 camelCase로”라고 잘못 만들었나요? CLAUDE.md에 “NEVER use camelCase for PostgreSQL columns. ALWAYS use snake_case.”를 추가하세요. 다시는 같은 실수가 반복되지 않습니다.

6개월 후, 당신의 CLAUDE.md는 수백 줄이 될 겁니다. 그리고 그게 바로 당신 프로젝트의 지식 베이스입니다. 새로운 팀원이 합류하면, 이 파일만 읽으면 됩니다. 새로운 AI 도구를 시도하면, 이 파일만 읽히면 됩니다.

도구를 바꿔도 될까?

네, 언제든 바꿔도 됩니다. 아침에 Claude Code로 설계하고, 오후에 Cursor로 구현하고, 저녁에 Antigravity로 테스트하는 게 자연스러운 워크플로우입니다.

다만 작업을 전환할 때는 각 도구에게 컨텍스트를 명확히 주세요. Claude Code에서 /clear로 컨텍스트를 리셋하거나, Cursor에서 새 세션을 시작하세요. 그리고 가장 최근 변경사항을 간단히 설명해주세요.

“방금 Claude Code로 DevLogService를 만들었어. 이제 Cursor로 테스트 코드를 작성하고 싶어.”라고 하면 충분합니다.

실패했을 때는?

AI가 같은 실수를 두 번 반복하면, 다른 도구로 바꾸세요. Cursor가 계속 같은 버그를 만든다면, Claude Code에게 맡기세요. Claude Code가 계획만 세우고 구현을 못 한다면, Antigravity에게 맡기세요.

같은 접근법으로 세 번 실패하면, 접근법 자체를 바꿔야 합니다. 문제를 더 작게 쪼개거나, 다른 각도로 접근하거나, 직접 검색해서 해결책을 찾으세요.

AI는 만능이 아닙니다. 때로는 공식 문서가 더 정확하고, 때로는 Stack Overflow가 더 빠릅니다. AI를 맹신하지 말고, 검증하는 습관을 가지세요.


이 이야기가 당신의 개발 여정에 도움이 되길 바랍니다.

작성일: 2026-01-03
저자: AI 코딩 에이전트와 함께 배우고 있는 한 개발자

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.