Build in Public Ep.6: "안 된다"는 세일즈포스 답변을 받고, 클로드와 함께 직접 만들었습니다.
1. 고객사별 슬랙 커넥트 채널, 왔다갔다 하는 게 너무 불편
B2B 영업을 하다 보면 고객사마다 소통 채널이 따로 있거든요. 저는 고객사별로 Slack Connect라는 외부 협업 채널을 운영하고 있는데, 문제는 이게 Salesforce(CRM)와 연결이 안 되어 있다는 점이었습니다.
Salesforce에서 'A사' 고객 정보를 보고 있다가 "지난주에 이 고객사와 슬랙에서 뭘 논의했더라?" 싶으면, 슬랙 앱으로 넘어가서 채널을 검색해야 합니다. 고객이 3곳이면 괜찮은데, 10곳, 20곳이 되면 이 왔다갔다 하는 시간이 은근히 쌓이더라고요.
"Salesforce 고객 페이지에서 바로 Slack 채널로 이동할 수 있으면 좋겠다." 그냥 단순한 바람이었습니다.
2. Salesforce에 물어봤더니 "안 됩니다"
Salesforce에는 이미 Slack Channel이라는 내장 컴포넌트가 있습니다. 고객(Account) 페이지에 슬랙 채널을 보여주는 기능이죠. 그런데 이건 Salesforce가 직접 관리하는 내부 채널 전용이라서, 외부 고객과의 Slack Connect 채널도 지원하는지는 불분명했습니다.
그래서 Salesforce 고객지원팀에 케이스(Case)를 하나 열었습니다. 해결 방법이 있는지 알고 싶었습니다.
며칠 뒤 담당자가 배정되었고, 담당자 Hari로부터 답변이 왔습니다. 기술 리더와 내부 프로덕트 팀까지 확인한 뒤 보내준, 꽤 상세한 답변이었어요. 핵심은 이랬습니다.
"Slack Channel 컴포넌트는 Salesforce Channel 전용입니다. Slack Connect 채널은 지원하지 않습니다."
안 되는 이유도 3가지로 설명해줬는데, 요약하면 이렇습니다:
보안/권한 체계가 다르다: Salesforce Channel은 CRM의 레코드 권한과 슬랙 채널 접근 권한이 딱 맞물리게 설계되어 있는데, 외부 사용자가 참여하는 Slack Connect는 이 구조에 맞지 않는다는 거예요.
1:1 매핑 구조다: 하나의 Salesforce 레코드(예: A사)에 하나의 채널이 직접 연결되는 구조인데, Slack Connect는 이 매핑 밖에 있다는 겁니다.
외부 사용자를 지원하지 않는다: 애초에 Salesforce Channel은 외부 사용자(고객사 담당자 등)가 참여하는 채널을 다루도록 설계되지 않았다는 거죠.
설정을 바꿔서 되는 문제가 아니라, 제품 설계 자체가 그렇게 되어 있는 거였어요.
Hari가 제안한 대안은 두 가지였습니다.
첫 번째는 "커스텀 Lightning Web Component를 직접 개발하세요." 그리고 두 번째는 "Salesforce IdeaExchange에 기능 요청을 올리세요."
IdeaExchange라는 건 Salesforce의 기능 건의 게시판 같은 건데, 거기에 올리면 다른 고객들이 투표하고, 투표 많이 받은 기능을 프로덕트 팀이 검토한다는 거예요. 물론 검토한다는 거지, 만들어준다는 건 아니죠.
이 두 번째 제안을 읽는 순간 느낀 건... "아, 이건 기다리면 안 되겠구나"였습니다. 기능 건의 올리고 투표 받고 프로덕트 팀이 검토하고 개발 로드맵에 들어가고... 그러면 대체 언제 되는 건지. 고객사가 계속 늘어나는 지금 당장 필요한 건데 말이에요.
그래서 첫 번째 제안에 집중하기로 했습니다. "직접 개발하세요"라는 그 제안에요. 문제는 저한테 개발 능력이 없다는 거였지만요.
3. "이거 내가 직접 할 수 있어?"
오전에 "안 된다"는 답변을 받고, 일단 Claude한테 물어봤습니다.
"Salesforce에서 Slack Connect 채널 링크를 Account 페이지에 보여주는 커스텀 컴포넌트를 만들고 싶은데, 코드를 한 번도 써본 적 없는 내가 할 수 있어?"
저는 코드를 작성해본 적 없는 영업 담당자입니다. 다만 Salesforce를 약 1년간 써왔고, 이전 회사에서 Salesforce와 다른 제품을 연동하면서 "어떤 오브젝트에 어떤 필드가 있고, 데이터가 어떻게 흐르는지" 정도는 이해하고 있었거든요.
그래서 생각했습니다. "내가 Salesforce 구조를 설명하고, Claude가 코드를 작성하면 되지 않을까?"
4. 아무것도 모르는 상태로 일단 해보기
이 과정을 공유하려는 이유 중 하나는, 시작할 때 제가 정말 아무것도 몰랐다는 걸 솔직하게 보여주고 싶어서입니다. 매 단계마다 막히고, 물어보고, 겨우 넘어가는 과정의 연속이었거든요.
"Homebrew가 뭐야? sudo는 뭐야?"
개발의 첫 단계는 코드 작성이 아니라 개발 환경 세팅이었습니다. Claude가 "먼저 Homebrew를 설치하세요"라고 했을 때, 저는 Homebrew가 뭔지 몰랐습니다. 맥에서 개발 도구를 설치해주는 패키지 관리자라는 것도 처음 알았고, sudo가 뭔지도 몰라서 물어봤어요.
심지어 터미널 글자 크기가 너무 작아서 "이거 크기 조절은 어떻게 해?" 같은 질문도 했습니다. 정말 그 수준에서 시작한 겁니다.
"설치했는데 왜 command not found가 뜨지?"
Homebrew 설치 완료하고 다음 명령어를 실행했더니 zsh: command not found 라는 에러가 떴습니다. 분명히 설치했는데 왜 못 찾는 걸까? 이건 PATH라는 개념 때문이었는데, 프로그램이 설치된 위치를 컴퓨터에게 알려주는 환경 설정이더라고요. 이런 게 있다는 것 자체를 몰랐습니다. Claude가 알려주는 대로 한 줄 추가하고 나서야 해결됐어요.
"인증 로그인이 안 되네..."
Salesforce에 연결하는 단계에서도 막혔습니다. sf org login web이라는 명령어를 실행하면 브라우저 인증 화면이 뜨는데, 거기서 로그인이 안 되는 거예요. 알고 보니 저는 사용자 정의 도메인(Custom Domain)을 사용하고 있었고, 기본 로그인 URL로는 접속이 안 되는 거였습니다. Claude가 --instance-url 옵션을 알려줘서 이렇게 실행했더니 성공했어요.
Salesforce를 써왔지만, 이 도메인 설정이 터미널 인증에도 영향을 준다는 건 처음 알았어요. 그리고 모르면 일단 스크린샷 찍어서 상황 설명하고 도움 요청하면 찰떡같이 알아듣고 답을 주니 계속 멈추지 않고 진행할 수 있었습니다.
"SFDX 는 뭐지, 계속 모르는 것 투성이지만 일단 진행"
로그인 성공하고 나니 Claude가 "SFDX 프로젝트를 생성하세요"라고 했습니다. 또 모르는 단어가 나왔죠.
계속 물어보면서 진행했습니다. 모른다고 멈추면 할 수 있는게 아무것도 없을 게 뻔해서 계속 물어봤습니다. 그런데 이 과정에서 좋았던 점이 새로운 용어와 개념을 그냥 책 보면서 습득하는 것보다 속도면에서도 그렇게 저의 머리속에 쏙쏙 박히는 느낌을 받았습니다. 실전에서 제품에 직접 적용하는 과정에서 하니까 이게 너무 다르더라구요. 새로운 것을 배우는 관점에서는 이 방식을 계속 적용해야겠다는 생각이 강하게 들었습니다.
SFDX(Salesforce DX)는 세일즈포스 개발을 로컬 컴퓨터에서 할 수 있게 해주는 개발 환경이더라고요. 지금까지는 브라우저에서 Setup 들어가서 클릭으로 설정했는데, 이건 내 컴퓨터에서 코드를 작성하고 → 세일즈포스에 업로드(배포)하는 방식인 거였습니다.
sf project generate --name slack-channel-link
cd slack-channel-link이 명령어 두 줄이 세일즈포스에 올릴 코드를 담을 폴더 구조를 자동으로 만들어주는 거였어요. 그리고 나중에 sf project deploy start가 "이 코드를 내 세일즈포스에 올려줘"라는 뜻이고요. 알고 나면 간단한데, 처음에는 각 명령어가 뭘 하는 건지 하나하나 물어봐야 했습니다.
"4개 파일을 어디에 넣으라고?"
Claude가 만들어준 컴포넌트는 4개의 파일로 구성되어 있었습니다:
slack-channel-link/
└── force-app/
└── main/
└── default/
└── lwc/
└── slackChannelLink/
├── slackChannelLink.html ← 화면 구조
├── slackChannelLink.js ← 동작 로직
├── slackChannelLink.css ← 디자인
└── slackChannelLink.js-meta.xml ← 설정 파일처음에 Claude가 파일을 다운로드받아서 복사하라고 했는데, 다운로드가 제대로 안 됐더라고요. ls ~/Downloads/slack*으로 확인해보니 파일이 아예 없었습니다. 그래서 방법을 바꿔서 터미널에서 직접 파일을 생성했습니다. cat이라는 명령어로 코드를 통째로 붙여넣는 방식이었어요.
cat > force-app/main/default/lwc/slackChannelLink/slackChannelLink.html << 'EOF'
<template>
<lightning-card title="Slack Connect Channel" icon-name="custom:custom53">
...
</lightning-card>
</template>
EOF이런 식으로 HTML, JS, CSS, XML 파일 4개를 하나씩 만들었습니다. 코드의 내용을 100% 이해한 건 아니었지만, Claude가 설명해준 구조는 이해할 수 있었어요. HTML은 화면에 뭘 보여줄지, JS는 Salesforce 데이터를 어떻게 읽어올지, CSS는 어떻게 꾸밀지, XML은 이 컴포넌트를 어디에서 사용할 수 있는지를 정의하는 파일이라는 거였습니다. 구조를 깨닫는 것 역시 해보는 도중에 자연스레 알 수 있게 되었습니다.
"이건 레이블로 적으라는 거야, API 이름이야?"
배포 전에 먼저 Salesforce Setup에서 커스텀 필드를 만들어야 했습니다. 코드가 읽어올 데이터 저장소를 만드는 거죠. Claude가 Slack_Channel_URL__c라는 필드를 Account와 Opportunity 오브젝트에 각각 만들라고 했는데, 이게 사용자가 보는 레이블 이름인지 시스템이 사용하는 API 이름인지 순간 헷갈렸습니다.
결론은 API Name이 Slack_Channel_URL__c가 되어야 한다는 거였고, Field Label에 Slack Channel URL이라고 입력하면 Salesforce가 알아서 API Name을 Slack_Channel_URL__c로 만들어줍니다. 알고 나면 간단한데 처음엔 헷갈리는 부분이었어요.
"성공했는데... URL을 어디서 입력하지?"
커스텀 필드 4개 만들고, 배포 명령어 실행하고, Account 레코드 페이지에서 Edit Page 들어가서 컴포넌트를 드래그앤드롭으로 배치하는 것까지 성공했을 때, 진짜 뿌듯했습니다. 그런데 바로 다음 질문이 "그래서 Slack 채널 URL을 어디서 입력하지?"였어요. 컴포넌트는 만들었는데 데이터를 어떻게 넣는 건지 바로 이해가 안 됐던 거죠.
레코드 상세 페이지에서 Edit 버튼 눌러서 해당 필드에 직접 입력하면 된다는 걸 확인하고 나서야 전체 그림이 그려졌습니다. 필드에 데이터 넣기 → 컴포넌트가 그 데이터를 읽어서 → 화면에 보여주는 흐름이었던 거죠.
5. 개발: 2시간, 3번의 반복
1차: 기본 기능 (V1)
첫 번째 목표는 단순했습니다. Account(고객사)와 Opportunity(영업기회) 페이지에서 Slack 채널 링크를 보여주고, 클릭하면 Slack으로 이동하는 것.
Claude한테 요구사항을 설명하니까, 4개의 파일로 구성된 코드를 만들어줬습니다. 핵심 설계가 꽤 똑똑했는데, 하나의 컴포넌트가 objectApiName을 자동 감지해서 Account 페이지에서는 Account 필드를, Opportunity 페이지에서는 Opportunity 필드를 읽어요. 별도 컴포넌트를 만들 필요가 없는 구조였습니다.
터미널에서 cat 명령어로 4개 파일을 생성하고, 배포 명령어를 실행했습니다:
sf project deploy start --source-dir force-app --target-org my-org이 한 줄이 떴을 때의 기분이란... ㅎㅎ
바로 Account 레코드 페이지에서 Edit Page 들어가서 좌측 Components 패널에서 "Slack Channel Link"를 검색하고, 우측 사이드바에 드래그앤드롭으로 배치했습니다. Save → Activate 누르니까 첫 번째 버전이 바로 동작했어요.
URL이 등록된 고객 페이지에서는 Slack 퍼플 컬러(#611f69)의 "Open in Slack" 버튼이 나타나고, 클릭하면 바로 Slack 채널로 이동합니다. URL이 없는 고객은 "No Slack Connect channel linked yet"이라는 안내 메시지가 표시됐고요.
그런데 한 가지 불편한 점이 있었습니다. Slack 채널 URL과 이름을 입력하려면 레코드의 Edit 화면에서 별도 필드를 찾아 입력해야 했거든요. 컴포넌트는 "보여주기만" 하고, 데이터 입력은 다른 곳에서 해야 하는 분리된 구조였죠.
2차: 사용 경험 개선 (V2)
"입력도 컴포넌트 안에서 할 수 있으면 안 될까?" Claude한테 물어보니 "가능합니다"라고 하더라고요.
이번에는 JavaScript 파일에 인라인 편집 기능이 추가되었습니다. updateRecord라는 Salesforce API를 사용해서, 컴포넌트 안에서 바로 데이터를 저장할 수 있게 된 거예요. HTML 파일에도 입력 폼과 버튼 코드가 추가됐고, CSS에도 편집 모드용 스타일이 들어갔습니다. 업데이트된 3개 파일을 터미널에서 cat 명령어로 덮어쓰고 다시 배포했습니다.
그런데 여기서 또 에러가 났어요. cat 명령어로 3개 파일을 덮어쓰는 과정에서 js-meta.xml 파일이 사라져버린 겁니다. 배포했더니 실패. ls로 확인해보니 역시나 파일이 3개밖에 없었어요.
누락된 xml 파일을 다시 cat으로 추가하고 재배포:
이번엔 성공. 채널이 아직 등록 안 된 고객 페이지에서는 "Add Channel" 버튼이 보이고, 버튼 누르면 컴포넌트 안에서 바로 URL과 이름을 입력할 수 있게 되었습니다. 이미 등록된 경우에는 연필 아이콘으로 수정도 가능해졌고요. 하나의 컴포넌트가 조회, 입력, 수정을 모두 처리하는 깔끔한 구조가 됐어요.
이제 컴포넌트 안에서 입력과 수정이 다 되니까, 페이지 레이아웃에 따로 노출되어 있던 Slack Channel Name과 Slack Channel URL 입력 필드는 더 이상 필요 없어졌습니다. 세일즈포스의 Setup → Object Manager → Account → Page Layouts에 들어가서 해당 필드 두 개를 레이아웃에서 제거했어요. 같은 데이터를 두 곳에서 입력할 수 있으면 오히려 혼란만 생기니까요.
이렇게 정리하고 나니 페이지가 훨씬 깔끔해졌습니다.
3차: 디자인 맞추기 (V3)
기능은 됐는데, Salesforce에 원래 내장된 Slack Channel 컴포넌트와 나란히 놓고 보니 디자인 차이가 눈에 띄더라고요. 로고 크기, 글자 크기, 볼드 처리가 달랐습니다.
여기서 좀 욕심이 생겼어요. "기존 네이티브 컴포넌트와 구분이 안 되는 수준으로 만들 수 있을까?" 싶어서 스크린샷을 Claude한테 보여주며 물어봤습니다.
"이 두 컴포넌트의 차이점을 파악할 수 있어?"
Claude가 스크린샷을 분석해서 차이점을 짚어냈습니다:
Slack 로고 크기가 네이티브보다 약간 크다
타이틀 폰트 사이즈와 웨이트가 다르다
버튼 패딩이 과하다
몇 번 수정하고 나니 나중에 글자 크기 수정에서는 CSS 파일만 수정해주더라구요. 그래서 또 배웠습니다. 아 다른 3가지 건드리지 않는 걸 보니 웹프론트엔드 화면에서 수정할 때는 CSS 만 수정하면 되는구나. 구조가 어떻게 되어있는지 해보면서 그 과정속에서 자연스레 체득하게 되는거죠.
수정된 CSS를 받아서 CSS 파일만 업데이트하고 다시 배포했습니다. 이번에는 파일 하나만 수정하면 됐기 때문에 5분도 안 걸렸어요. 하지만 여전히 폰트 크기는 달라서 이 부분은 어느 정도 사람 손이 들어가야 되는구나도 또 알게 되었습니다. 모든 게 다 되는 건 아닌거죠.
타임라인 요약
단계 | 소요 시간 | 내용 |
|---|---|---|
환경 세팅 | 30분 | 개발 도구 설치, Salesforce 연결 |
기본 기능 (V1) | 30분 | 채널 링크 표시 + Open in Slack 버튼 |
사용성 개선 (V2) | 40분 | 컴포넌트 내 인라인 입력/수정 |
디자인 맞춤 (V3) | 20분 | 네이티브 컴포넌트와 동일한 UI |
합계 | 약 2시간 |
6. "이미 만들었습니다" — Salesforce에 보낸 답장
오전에 "안 된다"는 답변을 받고, 오후에 Hari에게 답장을 보냈습니다.
"Good news — 이미 해결했습니다. 말씀하신 대로 Custom Lightning Web Component를 직접 만들었어요. Claude를 사용해서 약 2시간 만에 개발하고 배포했습니다."
스크린샷도 첨부했습니다. Salesforce 기본 Slack Channel 컴포넌트(내부 협업용)와 제가 만든 Slack Connect Channel 컴포넌트(외부 고객 소통용)가 나란히 놓인 화면이었죠. 오히려 둘 다 있으니까 내부 협업과 외부 소통을 한 페이지에서 볼 수 있게 되어서, 원래 원했던 것보다 더 나은 결과가 나온 거였습니다.
Hari의 답장이 왔어요.
"That's absolutely fantastic news — congratulations on resolving this so quickly! I'm genuinely impressed that you were able to develop and deploy a Custom Lightning Web Component in just 2 hours using Claude Code."
기술 리더까지 상의해서 "안 됩니다"라는 답변을 준 지 몇 시간 만에, 코드 한 줄 작성해 본 적 없는 사람이 직접 만들어서 보여줬으니 그럴 만도 하다 싶었어요.
오전에 "안 된다"는 답변을 받고, 오후에 "이미 만들었습니다"라고 답장을 보낸 하루. 케이스 접수부터 종료까지 딱 하루였습니다.
7. 배운 점들
"안 된다"가 끝이 아니더라
Salesforce의 공식 답변은 "지원하지 않습니다"였습니다. 심지어 대안으로 "기능 건의 게시판에 올려주세요"라는 안내까지 받았어요. 예전이었으면 거기서 멈추거나, 개발 외주 비용부터 알아봤을 겁니다. 그런데 이번에는 "안 된다"는 답변 앞에서 멈추지 않고, 클로드에게 "이거 내가 할 수 있어?"라고 물어보는 걸로 시작했습니다. 그리고 진짜로 할 수 있었어요.
도메인 지식이 진짜 중요하다
코드를 한 줄도 작성할 줄 몰라도, "무엇을 만들어야 하는지"를 정확히 아는 게 핵심이었습니다. 어떤 오브젝트에 어떤 필드가 필요한지, 컴포넌트가 어디에 배치되어야 하는지를 설명할 수 있었기 때문에 Claude가 정확한 코드를 만들 수 있었거든요. "어떻게"는 AI가, "무엇을"은 사람이 담당하는 구조가 가장 잘 맞았습니다.
모르는 건 더 이상 장벽이 아니다
Ep.2에서 DNS 설정 때문에 3시간 헤맸고, Ep.4에서 리버스프록시를 모르는 채로 설정했던 것처럼, 이번에도 Homebrew가 뭔지 모르는 상태에서 시작했습니다. "터미널 글자 크기 조절법"부터 물어본 사람이 2시간 후에는 프로덕션 환경에 컴포넌트를 배포하고 있었어요. 모르는 것 자체는 문제가 아니고, 물어보지 않는 게 문제입니다.
Salesforce Apex를 몰라도 가능했다
이건 저도 좀 놀랐는데, Salesforce의 개발 언어인 Apex를 전혀 몰라도 실제로 작동하는 컴포넌트를 만들 수 있었습니다. 물론 Salesforce CLI 같은 개발 인프라가 이미 잘 갖춰져 있어서 가능했던 부분도 있어요. 프로젝트 뼈대를 자동으로 만들어주고, 한 줄로 배포되고, 드래그앤드롭으로 페이지에 배치하는 구조가 아니었으면 2시간은 불가능했을 겁니다. 사람 + AI + 플랫폼, 이 세 가지가 맞물렸을 때 가능한 일이었습니다.
오전에 "안 된다"는 답변을 받고, 오후에 "이미 만들었습니다"라고 답장을 보낸 하루. 이번에 만든 건 Slack Connect 채널 링크 하나를 보여주는 작은 컴포넌트에 불과하지만, "안 된다"는 답변 앞에서 멈추지 않고 직접 만들어볼 수 있다는 경험 자체가 앞으로 더 큰 문제를 풀 수 있겠다는 자신감을 줬습니다.