8월, 2026의 게시물 표시

Claude Code 플러그인, 통째로 깔지 않고 알맹이만 빼왔다

지난 편 → 6편 — 챗GPT랑 클로드, 왜 서로 대화는 못 시킬까 Claude Code로 한동안 일하다 보면, 남이 만들어 둔 도구를 가져다 쓰고 싶어지는 순간이 옵니다. 마켓플레이스에 올라온 플러그인 중 하나가 눈에 들어왔습니다. 코드를 필요 이상으로 부풀리지 않게, "게으른 시니어 개발자"처럼 최소로만 짜도록 붙잡아 주는 도구였습니다. 마음에 들었습니다. 그런데 막상 설치하려니 손이 멈췄습니다. 제가 원한 건 그 안에 담긴 원칙 하나 였는데, 플러그인은 그것 말고도 이런저런 것들을 통째로 데려옵니다. 안 쓸 기능까지 제 환경에 얹히는 게 영 내키지 않았습니다. 그래서 깔지 않고, 열어서 필요한 알맹이만 빼내기로 했습니다. 그러려면 먼저 "플러그인"과 "스킬"이 뭐가 다른지부터 알아야 했습니다. 스킬과 플러그인은 뭐가 다른가 한 줄로 하면 이렇습니다. 스킬은 부품 하나, 플러그인은 부품을 담은 상자. 스킬(Skill) 은 최소 단위입니다. SKILL.md 라는 마크다운 파일 하나가 전부고, 필요하면 옆에 보조 파일(스크립트·데이터)을 둘 수 있습니다. 두는 곳도 단순합니다. 개인용: ~/.claude/skills/<이름>/SKILL.md 프로젝트용: .claude/skills/<이름>/SKILL.md 파일 맨 위 frontmatter에 "이 스킬을 언제 써야 하는지"를 적어두면, Claude가 상황을 보고 알아서 불러 씁니다. 아니면 /스킬이름 으로 직접 부를 수도 있습니다. 말하자면 "이 일은 이렇게 처리해라"라고 적어둔 지침 한 장 입니다. 플러그인(Plugin) 은 그 부품들을 담아 배포하는 상자입니다. .claude-plugin/plugin.json 이라는 매니페스트를 중심으로, 여러 종류의 구성요소를 한 번에 묶습니다. skills/ — 스킬들 agents/ — 커스텀 에이전트(서브에이전트...

챗GPT랑 클로드, 왜 서로 대화는 못 시킬까

지난 편 → 5편 — 이틀 만에 만들었는데, 방문자가 0이었습니다 요즘 AI를 하나만 쓰는 사람은 드뭅니다. 챗GPT도 쓰고 클로드도 쓰고, 어떤 건 이게 낫고 어떤 건 저게 낫다 보니 두세 개를 오가며 쓰게 되죠. 그런데 그렇게 쓰다 보면 꼭 이런 순간이 옵니다. A에게 한참 설명해서 만든 내용을, B는 하나도 모릅니다. 그래서 B한테 처음부터 다시 설명합니다. A가 내놓은 결과를 B에게 넘기려고 매번 복사해서 붙여넣습니다. 심지어 "이거 어느 쪽한테 시켰더라?" 하고 내 머릿속에서도 섞입니다. 그러다 문득 이런 생각이 들어요. "얘네끼리 좀 알아서 주고받으면 안 되나?" 내가 매번 중간에서 우체부 노릇을 하지 않아도, 큰 결정만 내가 확인하고 자잘한 건 AI끼리 직접 넘기게 하면 편할 텐데. 오늘은 이 이야기입니다 — 왜 아직 그게 매끄럽게 안 되는지 , 그리고 그게 정말 못 할 일인지. 이 답답함, 당신만 느끼는 게 아닙니다 먼저 짚고 싶은 건, 이게 꽤 많은 사람이 원하는 것 이라는 점입니다. 완전 자동은 아니어도 돼요. 사람이 아예 손을 떼면 오히려 불안하니까요. 대부분이 원하는 건 이런 모습입니다 — 큰 건 내가 확인하되, 자잘한 전달은 AI끼리 알아서. 우체부 역할에서 벗어나고 싶은 거죠. 그런데 막상 이걸 하려고 하면 세 개의 벽 에 부딪힙니다. 하나씩 볼게요. 벽 ① 요금 — "그냥 연결하면" 돈이 눈덩이가 됩니다 AI끼리 연결하려면 보통 API 라는 걸 씁니다. 쉽게 말하면 프로그램끼리 AI를 불러 쓰는 통로예요. 그런데 API는 쓴 만큼 돈을 내는 종량제 입니다. 가볍게 쓰면 싸요. 문제는 AI 여러 개가 서로 계속 말을 주고받을 때 입니다. 대화가 오갈수록 그동안의 기록을 매번 다시 실어 보내야 해서, 요금이 곱으로 불어납니다. 실제로 "여러 AI를 엮는 사람이 가장 큰 요금 폭탄을 맞는다"는 게 업계의 공통된 경...

앱 하나 내려고 개인사업자가 된 개발자의 A to Z — 등록·간이과세·부가세, 실제로 겪은 것

결론부터 : 앱 하나(찰칵분리수거)를 Google Play에 내려던 게 시작이었습니다. 개인 계정으로 출시하려니 테스터 12명이 14일간 매일 테스트 해야 하는 요건이 걸렸고, 그걸 피하려 사업자(조직) 계정 을 택했어요. 그러려면 사업자 등록이 필요했고 — 그때부터 사업장 주소·부가세·간이과세까지 세무의 세계에 발을 들였습니다. (앱 출시·계정 선택 이야기 자체는 찰칵분리수거 개발기 1편 에 있어요.) 이 글은 앱을 내려다 개인사업자가 된 개발자의 전 과정 지도 입니다. 각 단계는 실제로 겪으며 따로 쓴 글로 연결해뒀습니다. 1. 개인사업자 등록 — 앱 출시가 계기였다 앱을 Google Play에 출시하려면 개발자 계정이 필요한데, 개인 계정은 테스터 12명 요건 이 붙습니다. 이 요건이 면제되는 사업자(조직) 계정 을 택하면서 사업자 등록을 하게 됐어요. 언제·어떻게 등록했는지, 업종(응용소프트웨어 개발 및 공급업)은 어떻게 정했는지 정리했습니다. 자세히 → 1인 사업자 실무 (1편) — 개인사업자 등록, 앱 개발자가 겪은 것들 2. 사업장 주소 — 집 주소 대신 공유오피스 사업자를 내려면 사업장 주소 가 필요한데, 집 주소를 올리기는 부담스러웠습니다. 그래서 공유오피스(비상주)를 연 264,000원에 계약했어요. 계약 전 물어봐야 할 것들까지 담았습니다. 자세히 → 2편 — 집 주소 대신 공유오피스, 계약 전 물어본 것들 3. 사업용 신용카드 — 홈택스에 미리 등록 사업용 카드를 홈택스에 등록해두면 부가세 신고 때 매입이 자동으로 모입니다. 등록 안 하면 하나씩 손으로 넣는 지옥을 겪어요(제가 그랬습니다). 자세히 → 3편 — 사업용 신용카드, 홈택스에 미리 등록하세요 4. 부가세 첫 신고 — 매출 0인데 8만 원을 환급받았다 첫 부가세 확정신고에서 매출은 0원 이었는데 87,308원을 환급 받았습니다. 개발 장비(GPU) 매입세액 덕분이었어요. 매출이 없어도 매입이 있으면 환급이 나오는 구조를 실제 신고서 숫자로 풀었습니다. ...

1인 사업자 실무 (번외 2) — 1인 개발자의 사업 경비, 뭐가 되고 뭐가 안 되나

결론부터 : 사업자를 내고 첫 신고를 하며 "이건 경비가 되나?"를 수도 없이 검색했습니다. 잘 넣은 것도 있고, 넣을 수 있었는데 놓친 것 도 있었고, 특히 "부가세는 공제가 안 되는데 소득세 경비는 되는" 헷갈리는 경우도 있었어요. 실제로 겪은 것들을, 실수까지 포함해 정리합니다. 이 글은 1인 사업자 실무 시리즈 의 실무 확장편입니다. 경비의 대원칙 — 4가지를 다 만족해야 합니다 세법상 어떤 지출이든 경비로 인정받으려면 네 가지를 모두 넘어야 합니다. 사업 관련성 — 사업과 직접 연결된 지출인가 실제 지출 — 돈이 실제로 나갔는가 해당 연도(1~12월)에 발생 했는가 객관적 증빙 이 있는가 그리고 "이건 사업용이다"를 증명할 책임은 나에게 있습니다. 증명 못 하면 경비가 아니에요. 잘 넣은 것 1인 개발자가 실제로 쓰는 것들은 대부분 경비가 됩니다. 사업용 장비 — GPU를 849,000원에 샀는데, 이건 그 해에 전액 즉시 비용 으로 처리됐고 부가세 매입세액도 공제받았습니다. (왜 즉시인지는 아래 "100만원 갈림길"에서) 도메인·호스팅 — 사업 운영에 쓰는 것이라 인정됩니다. (소프트웨어 구독료 같은 것도 사업용이면 같은 원리로 경비가 됩니다.) ★놓친 것도 있었습니다 — 공유오피스, 그리고 되찾는 법 여기가 이 글에서 제일 솔직하고, 또 제일 유용한 부분입니다. 저는 사업자를 내려고 공유오피스를 계약 했는데( 2편 참조), 이걸 개인 신용카드로 결제 했습니다. 그런데 첫 부가세 신고 때는 아직 사업용 카드를 홈택스에 등록하기 전이라( 3편 참조), 토스뱅크 앱의 카드 사용 내역을 보고 매입을 하나씩 수동으로 입력 했어요. 그런데 공유오피스는 개인 카드로 결제 해서 그 내역에 잡히지 않았고, 세금계산서로 따로 넣었어야 했는데 그 24,000원(세액)을 놓쳤습니다. 세금계산서는 멀쩡히 받아뒀는데도요. 그래서 "이건...

AI로 만들어본 것들 (5편) — 이틀 만에 만들었는데, 방문자가 0이었습니다

결론부터 : 4편에서 만든 간이과세 확인 도구를 배포했습니다. 이틀 만에 기획부터 배포까지 갔어요. 그런데 아무 일도 일어나지 않았습니다. 방문자 0이요. 뒤늦게 검색량을 재봤더니 더 뼈아픈 사실이 나왔습니다 — 제가 "경쟁이 세니 접자"고 판단했던 쪽의 수요가 8배였습니다. 만드는 것과 도달하는 것은 완전히 다른 일이더군요. 지난 편 → 4편 — 간이과세 확인 도구, 판정의 69%를 포기했습니다 배포하고 나서 아무 일도 없었습니다 도구를 GitHub Pages에 올렸습니다. 주소가 생겼고, 열면 잘 돌아갔어요. 거기까지였습니다. 당연한 결과였는데 그땐 몰랐습니다. 생각해보면 이렇습니다. 방금 만든 페이지라 검색 엔진에 색인조차 안 됐습니다 meta description 도, og: 태그도, sitemap도 없었어요 도메인 신뢰도는 당연히 0. "간이과세"로 검색하면 국세청·세무사 블로그·뉴스가 상위를 다 잡고 있습니다 만드는 데 이틀을 썼는데, 알리는 데는 0분을 썼습니다. 그래놓고 "왜 아무도 안 오지" 하고 있었던 거죠. 뒤늦게 검색량을 재봤습니다 네이버 검색광고 키워드도구로 관련 검색어의 월간 검색량을 조회했습니다. 진작 했어야 할 일인데, 만들고 나서야 했어요. 키워드 PC 모바일 합계 간이과세 300 510 810 간이과세 기준 300 390 690 간이과세 배제지역 260 170 430 업종코드 조회 4,730 1,900 6,630 제 도구가 겨냥한 "간이과세 배제지역"은 월 430 이었습니다. 세 키워드를 다 합쳐도 1,900이고, 서로 겹치는 검색을 감안하면 실질 1,000~1,500 수준이에요. 작은 시장인 게 맞았습니다. 진짜 뼈아픈 건 마지막 줄이었습니다 업종코드 조회가 6,630입니다. 간이과세 계열의 4~8배예요. 특히 PC가 4,730인 게 눈에 띕니다 — 사무실에서 서류 작성하다 막혀 검색하는...

AI로 만들어본 것들 (4편) — 간이과세 확인 도구, 판정의 69%를 포기했습니다

결론부터 : 사업자등록 때 겪은 불편으로 간이과세 배제 확인 도구 를 만들었습니다. AI에게 시켜 이틀 만에 배포까지 갔어요. 그런데 만들면서 내린 가장 중요한 결정은 기능을 더한 게 아니라 빼는 쪽 이었습니다 — 데이터 647행 중 448행(69%)은 자동 판정을 하지 않기로 했거든요. 왜 그랬는지, 그리고 그 판단을 하게 만든 아찔한 사건 하나를 풀어봅니다. 지난 편 → 3편 — 문서 민감정보 자동 마스킹 도구 만들기 왜 만들었나 사업자등록을 하면서 내가 간이과세 대상인지 확인하는 게 꽤 번거로웠습니다. 국세청이 매년 고시로 배제 기준을 정하는데, 그게 한글 문서로 나오거든요. (이 이야기는 1인 사업자 실무 5편 에 자세히 썼습니다.) "이거 검색으로 바꾸면 되겠는데" 싶었습니다. 데이터는 공개돼 있고, 상업적 이용도 제한이 없었어요. 전형적인 정적 데이터 + 판정 로직 문제로 보였습니다. 첫 관문 — 데이터가 한글 문서였습니다 국세청 고시는 HWPX 파일로 공개됩니다. 처음엔 막막했는데, 열어보니 의외로 다룰 만했어요. HWPX는 사실 ZIP 압축 파일이고, 풀면 안에 XML이 들어 있습니다. 표는 XML 태그로 구조가 잡혀 있어서 추출이 됩니다. 여기서 하나 배웠습니다. 별표 번호를 믿으면 안 됩니다. 2024년 고시에서는 별표 1이 종목기준이었는데, 2026년 고시에서는 별표 1이 과세유흥장소기준으로 바뀌어 있었어요. 번호로 찾도록 짰다면 다음 개정에서 조용히 엉뚱한 표를 읽었을 겁니다. 그래서 번호 대신 제목 텍스트로 찾도록 바꿨습니다. 이런 건 AI가 알아서 해주지 않습니다. 두 판본을 다 넣고 돌려보라고 시켜야 드러나요. 진짜 함정 — 의미가 정반대로 나갔습니다 여기가 이 편에서 제일 아찔했던 부분입니다. 고시의 "적용범위" 칸은 사람이 읽으라고 쓴 문장입니다. 그런데 한 칸 안에 정반대 의미가 섞여 있었어요. 전사업자(다만, 다음 사업자는 제외) ...

1인 사업자 실무 (번외) — 간이과세가 안 됐는데, 오히려 이득이었습니다

결론부터 : 사업자등록을 하면서 간이과세가 안 된다 는 걸 알았습니다. 처음엔 손해라고 생각했어요. 그런데 4편에서 말씀드린 부가세 환급 87,308원 이 바로 그 덕분이었습니다. 간이과세자였다면 그 돈을 못 돌려받았거든요. 이 편은 왜 간이과세가 안 됐는지 , 그리고 대부분이 모르는 세 번째 이유(사업장 주소) 에 대한 이야기입니다. 마지막에 제가 직접 만든 확인 도구도 공개합니다. 지난 편 → 4편 — 매출 0인데 부가세를 환급받았습니다 4편의 환급, 사실은 일반과세자여서 가능했습니다 지난 편에서 매출 0원인데 부가세를 환급받은 이야기를 했습니다. 매입세액을 돌려받는 구조였죠. GPU 849,000원에 붙은 부가세 약 77,182원이 그 대부분이었고요. 그런데 여기엔 전제가 하나 있습니다. 이 환급은 일반과세자만 받을 수 있습니다. 간이과세자는 매입세액 공제 방식이 달라서 이런 환급이 나오지 않아요. 즉 제가 환급을 받은 건 간이과세가 안 되는 사업자였기 때문 입니다. 등록할 때는 "간이과세가 안 되네, 세금 더 내겠구나" 하고 아쉬워했는데, 첫 신고에서 정반대 결과를 봤습니다. 간이과세가 안 되는 경우는 크게 셋입니다 제가 알아보면서 정리한 건 이렇습니다. 매출 기준 — 직전연도 매출(공급대가)이 기준액 이상이면 간이과세가 안 됩니다. 신규 사업자는 해당 없고요. 업종 기준 — 국세청이 고시로 정한 배제업종 에 해당하면 안 됩니다. 지역 기준 — 사업장 주소가 배제지역에 있으면 매출이나 업종과 무관하게 안 됩니다. ← 이게 대부분 모르는 부분입니다. 저는 2번 에 걸렸습니다. 제 경우 — 소프트웨어 개발업 제 업종은 응용소프트웨어 개발 및 공급업 입니다(2편에서 공유오피스 계약할 때 언급했던 그 업종이에요). 이 업종이 국세청 고시의 배제업종 목록에 들어 있습니다. 다만 여기엔 단서가 붙어요 — 배제업종이라고 전국 어디서나 적용되는 게 아니라, 서울특별시와 광역시, 그리고 수도...

1인 사업자 실무 (4편·완결) — 매출 0인데 부가세를 환급받았습니다

결론부터 : 첫 부가세 확정신고에서 매출은 0원 이었는데 87,308원을 환급 받게 됐습니다. 매출이 없는데 세금을 돌려받는다니 이상하죠? 부가세의 구조를 알면 당연한 결과입니다. 이 편은 그 원리와, 제가 실제 신고서에서 확인한 숫자, 그리고 해외결제(구글)에서 제가 했던 착각 까지 정리합니다. (이 시리즈 완결편입니다.) 지난 편 → 3편 — 사업용 신용카드, 홈택스에 미리 등록하세요 매출 0인데 왜 환급? — 부가세의 구조 부가세는 아주 단순한 뺄셈입니다. 낼 세금 = 매출세액 − 매입세액 매출세액 : 내가 판 것에 붙은 부가세 (매출의 10%) 매입세액 : 내가 산 것에 붙은 부가세 (매입의 10%) 저는 아직 입금된 매출이 없어서 매출세액이 0 이었습니다. 그런데 사업을 준비하며 산 것에는 부가세를 이미 냈어요. 그러니 0 − (낸 매입세액) = 마이너스, 즉 그 차액을 돌려받는(환급) 겁니다. 매출이 없어도 매입이 있으면 환급이 나오는 이유가 이거예요. 제 실제 신고서 숫자 말로만 하면 안 믿기니, 제가 실제로 낸 신고서 숫자를 공개합니다. 매출세액: 0원 (입금된 매출 없음) 매입세액: 82,308원 이 중 대부분이 GPU 구입 입니다. 849,000원에 산 GPU의 부가세가 약 77,182원 . 나머지는 도메인 등록 등 소액 매입의 부가세 약 5,126원. 전자신고 세액공제: 5,000원 (홈택스로 직접 전자신고하면 붙는 공제) 최종 환급: 82,308 + 5,000 = 87,308원 매출이 0인데 8만 원 넘게 돌려받는 거죠. GPU 하나 산 게 환급의 대부분을 만들었습니다. ★해외결제(구글)는 공제가 안 됩니다 — 제 착각 정정 여기가 이 편에서 제일 중요한 부분입니다. 저는 처음에 구글 개발자 등록비도 당연히 공제되는 줄 알았어요. 그런데 아니었습니다. 구글 개발자 등록비는 해외 사업자(외국법인)에게 낸 돈이라, 애초에 한국 부가세가 붙지 않습니다...

1인 사업자 실무 (3편) — 사업용 신용카드, 홈택스에 미리 등록하세요

결론부터 : 사업용 신용카드를 홈택스에 등록하면, 카드로 쓴 사업 지출을 부가세 신고 때 자동으로 불러옵니다. 안 해두면 신고할 때 매입을 하나씩 손으로 입력 해야 해요. 저는 첫 부가세 신고 때 이걸 안 해둬서 수동 입력의 고통을 겪고, 그 길로 등록했습니다. 이 편은 "왜, 언제, 어떻게 등록하는가"입니다. 지난 편 → 2편 — 공유오피스로 사업장 주소 확보하기 왜 등록해야 하나 — "자동" vs "수동"의 차이 사업을 하면 카드로 이것저것 결제합니다(장비, 소프트웨어 구독, 각종 수수료 등). 이 지출들은 부가세 신고 때 매입 으로 잡아 세금을 줄일 수 있어요. 문제는 그걸 어떻게 신고서에 올리느냐 입니다. 사업용 카드를 홈택스에 등록해 뒀다면 → 카드 사용 내역을 홈택스가 자동으로 모아서 보여줍니다. 신고 때 거의 클릭 몇 번이면 끝나요. 등록을 안 했다면 → 그 내역이 자동으로 안 들어옵니다. 결국 매입 건을 하나씩 손으로 입력 해야 해요. 항목이 몇 개면 몰라도, 쌓이면 이게 진짜 지옥 입니다. 저는 첫 신고 때 등록이 안 된 상태라 하나씩 넣었는데, "다음에도 이러면 못 하겠다" 싶어서 신고를 끝내자마자 등록했어요. 저는 이렇게 했습니다 (사업자 명의 카드 등록) 저는 사업자 명의로 발급받은 카드(토스 사업자 카드) 가 홈택스에 등록돼 있지 않아서, 그걸 등록했습니다. 등록 절차 자체는 어렵지 않았어요. 홈택스에서 이 경로로 들어갑니다(메뉴명은 개편으로 바뀔 수 있으니 "사업용 신용카드"로 검색하시는 게 안전합니다): 홈택스 → [계산서·영수증·카드] → [신용카드 매입] → [사업용 신용카드 등록 및 조회] 들어가서 카드사·카드번호·휴대폰번호 를 입력하고 개인정보 제공에 동의한 뒤 등록 접수하면 끝입니다. 한 가지 주의 — 가족카드·기프트카드·직불카드는 등록이 안 됩니다. 사업용으로 쓸 카드가 등록 가능한 종...

1인 사업자 실무 (2편) — 공유오피스로 사업장 주소 확보하기

결론부터 : 사업자등록에는 사업장 주소가 필요한데, 집 주소를 앱스토어에 노출하고 싶지 않았습니다. 그래서 비상주 공유오피스(주소만 빌리는 것)로 사업장 주소를 마련했어요. 방문 없이 계약하는 거라 불안해서, 계약 전에 8가지를 미리 물어봤습니다. 그 8가지가 이 글의 핵심입니다 — 비상주 계약을 앞두셨다면 그대로 복사해 쓰셔도 됩니다. 지난 편 → 1편 — 개인사업자 등록, 앱 개발자가 겪은 것들 왜 공유오피스였나 1편에서 개인사업자를 냈다고 했는데, 사업자등록에는 사업장 주소 가 들어갑니다. 그런데 이 주소가 문제였어요. 집 주소를 쓰기 싫었습니다. 앱스토어 개발자 정보 등 여러 곳에 사업장 주소가 노출되는데, 거기에 제 집 주소가 뜨는 게 꺼려졌어요. 개인 집 주소는 신빙성이 떨어질 수 있다 는 조언도 참고했습니다(이 부분은 LLM에게 물어보고 판단했어요). 사업자 주소가 아파트면 아무래도 사업체로서의 인상이 약하죠. 그래서 비상주 공유오피스 — 실제로 자리를 쓰는 게 아니라 주소만 빌리는 서비스 를 택했습니다. 1인 개발자에겐 실제 사무 공간보다 "번듯한 사업장 주소" 자체가 필요했으니까요. 유튜브로 찾은 이유 비상주는 특성상 직접 방문하기가 어렵습니다 (어차피 안 갈 공간이니까요). 그러니 "이 업체 믿을 만한가"를 확인할 방법이 마땅치 않았어요. 그래서 유튜브 영상 을 통해 찾았습니다. 실제 이용 후기나 업체 소개 영상을 보면서 최소한의 신빙성을 확보하려 한 거죠. 홈페이지 광고 문구만 보는 것보다는 나았습니다. ★계약 전에 반드시 확인한 8가지 여기가 핵심입니다. 방문도 안 하고 1년을 계약하는 거라, 계약 전에 업체에 이메일로 8가지를 물어봤습니다. 비상주 공유오피스를 고민 중이시라면 이 목록을 그대로 물어보세요. 지점별 가격 차이 — 같은 업체라도 지점마다 가격이 다를 수 있습니다. 여러 지점 가격을 한꺼번에 물어 비교했어요. 우편물 전달 방식 — 비상주...

1인 사업자 실무 (1편) — 개인사업자 등록, 앱 개발자가 겪은 것들

결론부터 : 앱 하나 배포하려다 개인사업자까지 냈습니다. 홈택스로 온라인 등록했는데, 업종 코드에서 한 번, 과세 유형에서 또 한 번 막혔어요. 특히 소프트웨어 개발업은 간이과세가 안 됩니다 — 저는 그걸 등록하다가 알았습니다. 처음 사업자 내는 1인 개발자가 똑같이 헤맬 지점들을 정리합니다. 앱 하나 내려다 사업자를 냈습니다 분리수거 앱을 만들어 구글 플레이에 올리려는데, 개인 계정으로는 제약이 많았습니다. (계정 관련 자세한 얘기는 분리수거 앱 개발기에서 다뤘으니 여기선 넘어갑니다.) 결국 "사업자를 내자"는 결론에 도달했어요. 앱 하나 만들었을 뿐인데 사업자 등록까지 오게 된 거죠. 1인 개발자로 뭔가를 세상에 내놓으면, 생각보다 빨리 이 단계를 마주합니다. 홈택스로 온라인 등록 세무서에 갈 필요 없이 홈택스에서 온라인으로 다 됩니다. 공동인증서로 로그인하고, 사업자등록 신청 메뉴를 따라가면 됩니다. 절차 자체는 생각보다 간단했어요. 문제는 절차가 아니라 중간중간 골라야 하는 것들 이었습니다. 첫 번째 삽질 — 업종 코드 사업자등록에는 업종·업태 를 골라야 합니다. 저는 이렇게 잡았어요: 정보통신업 — 응용소프트웨어 개발 및 공급업 광고 대행업 (앱 광고 수익을 고려) 그런데 여기서 막혔습니다. LLM에게 물어서 안내받은 업종 코드가, 실제 홈택스의 코드와 달랐던 겁니다. AI가 알려준 코드를 그대로 넣으려다 안 맞아서, 결국 직접 찾아봤어요. 이건 AI를 탓할 게 아니라 — 업종 코드는 개정되거나 세분화되기 때문에 , AI가 학습한 시점과 현재가 다를 수 있습니다. 그래서 최종 코드는 홈택스에서 직접 확인 하는 게 맞습니다. AI로 방향을 잡되, 확정은 공식 사이트에서. 이건 세금 정보 전반에 적용되는 원칙이에요. 두 번째 삽질 — 간이과세로 하려다 막혔습니다 여기가 이 편에서 제일 중요한 부분입니다. 저는 처음에 간이과세 로 하려 했어요. 매출이 적을 땐 간이가 세부담이 적다고 들었거...

AI가 만든 소프트웨어, 어떻게 믿을까 (3편) — 못 잡은 것, 그리고 만든 AI의 증언

결론부터 : 2편까지가 "검증이 잡아낸 것"이었다면, 이번엔 "못 잡은 것" 입니다. 검증 체계가 놓친 실제 사례 하나와, 개발을 수행한 AI 본인의 증언 을 공개합니다. 그리고 마지막에 — 회사가 아니라 혼자 일하는 당신이 이 방식을 축소판으로 시작하는 법 까지 담았습니다. 지난 편 → 2편 — 검증이 실제로 잡아낸 것들 "잡은 게 60건이면, 못 잡은 건 몇 건입니까?" 가장 정직하게 답해야 하는 질문입니다. 먼저 인정부터 하겠습니다 — 못 잡은 결함의 총수는 아무도 모릅니다. 이 프로젝트만이 아니라 세상 모든 소프트웨어가 마찬가지예요. "버그가 없다"는 증명은 원리적으로 불가능하고, 그렇게 주장하는 쪽을 오히려 의심해야 합니다. 할 수 있는 건 간접 증거를 보이는 일입니다. 먼저 잡은 쪽의 숫자 — 기록상 13개 작업 묶음에 걸쳐 약 60여 건 의 약점이 완료 선언 이전에 잡혔습니다(건수가 명시된 기록만 보수적으로 합산한 하한값). 전부 수정·재검증 통과·사실 정정·사유를 명시한 보류 중 하나로 종결됐고, 무응답 방치는 0건 입니다. 더 중요한 간접 증거는 이겁니다 — 내부 검증을 통과한 뒤, 만든 쪽을 모르는 독립 검증에서 추가로 나오는 코드 결함이 라운드를 거듭할수록 줄었습니다. 초기엔 실제 코드 결함이 여럿 나왔지만, 후반으로 갈수록 발견물이 "코드가 틀렸다"에서 "문서를 더 쉽게 써 달라"로 옮겨 갔고, 마지막 라운드들에서는 새 코드 결함이 0건 이었어요. 총수를 셀 방법은 없으니 이건 경향에 대한 서술입니다. 다만 "그물을 통과해 하류에서 잡히는 물고기가 갈수록 줄어 마침내 0이 됐다"는 건, 그물이 촘촘해지고 있다는 합리적 증거입니다. 정직 코너 — 검증이 놓친 한 건 이 검증 체계가 놓친 실제 사례 를 공개합니다. 파일의 기본 보존 기간을 정하는 기능이 있었는데, 그 계산 로직 자체는 완벽히...

AI가 만든 소프트웨어, 어떻게 믿을까 (2편) — 검증이 실제로 잡아낸 것들

결론부터 : 1편에서 "AI를 안 믿는 3겹 구조"를 이야기했습니다. 이번엔 그 구조가 실제로 무엇을 잡아냈는지 입니다. 검증 과정에서 걸린 문제는 기록상 60건이 넘는데, 그중 조용히 자물쇠를 바꿔치기하던 코드, 철거 중인 방에 들어간 청소부 같은 버그 세 편을 비유로 풀어봅니다. 셋 다 실제 기록에 남은 사건입니다. 지난 편 → 1편 — 우리는 AI를 믿지 않기로 했습니다 사례 1 — 조용한 자물쇠 바꿔치기 이런 시공업자를 상상해 보세요. "국산 자물쇠로 채워 주세요"라고 주문했는데, 마침 재고가 없자 말없이 다른 자물쇠를 채워 놓는 겁니다. 문은 잠기니까 겉보기엔 아무 문제가 없습니다. 주문한 사람은 국산 자물쇠라고 믿고 살죠. 파일 암호화 기능에서 정확히 이런 동작이 발견됐습니다. 설정 파일에 암호화 방식을 잘못 적으면(오타 등), 프로그램이 에러를 내는 대신 조용히 기본 방식(AES)으로 바꿔서 암호화 했어요. 암호화 자체는 되고 있으니 어떤 정상 동작 테스트도 실패하지 않습니다. 이걸 검사역 AI가 잡았습니다. 수정 방향이 핵심입니다. "몰래 다른 걸로 해주는 친절"을 금지하고, 주문과 다르면 프로그램이 아예 기동을 거부하고 즉시 알리도록 바꿨습니다. 시작 시점에 시끄럽게 실패하는 것이, 몇 달을 조용히 틀리게 도는 것보다 백배 낫기 때문이에요. 막은 사고 : 규정상 특정 암호 방식이 필수인 엄격한 환경에서, 담당자는 그 방식을 쓴다고 믿는데 실제로는 다른 방식으로 저장되는 규정 위반 상태가 장기간 지속 될 뻔했습니다. 파일이 쌓인 뒤에 발견되면 전량을 다시 암호화해야 하는 유형의 사고예요. 사례 2 — 딛고 선 사다리를 치워버리다 높은 곳에서 사다리를 딛고 일하는 사람이 있는데, 다른 사람이 "이제 정리하자"며 그 사다리를 치워버리면 어떻게 될까요. 딛고 있던 발판이 사라져 그대로 추락합니다. 프로그램에도 똑같은 상황이 있어요. 프로그램을...

AI가 만든 소프트웨어, 어떻게 믿을까 (1편) — 우리는 AI를 믿지 않기로 했습니다

결론부터 : AI한테 개발을 맡겼는데 그 결과를 믿을 수 있었던 이유는, 역설적으로 아무도 AI 말을 그냥 믿지 않았기 때문 입니다. AI가 "다 됐다"고 해도 곧이듣지 않고 세 겹의 그물 로 걸렀어요 — ① 사람 판단이 아니라 기계가 자동으로 통과·실패를 매기고 , ② 흠 잡는 것만 전담하는 별도의 검사 AI 를 두고, ③ 만든 과정을 전혀 모르는 제3자 가 결과물만 받아 다시 확인합니다. 이 편은 그 세 겹 이야기예요. "AI가 만들었습니다"라는 말이 불안한 이유 "이 소프트웨어, AI가 만들었습니다." 이 말을 듣고 마음이 편해지는 사람은 별로 없을 겁니다. 오히려 이런 질문이 떠오르는 게 정상이에요. "AI는 그럴듯한 거짓말을 잘한다던데, 그게 만든 물건을 어떻게 믿지?" 그 불신은 정당합니다. 실제로 AI 언어모델(LLM)은 하지 않은 일을 "완료했습니다"라고 보고하는 경향이 있습니다. 이건 소문이 아니라 제가 개발을 진행하며 출발점으로 삼은 전제 였어요. 개발의 상당 부분을 AI가 수행하는 프로젝트였고, 그래서 첫날부터 규칙이 하나 있었습니다. "AI의 '완료했다'는 말은 믿지 않는다. 실제로 실행해서 확인된 것만 완료다." "검증하는 것도 AI라면서요? 그게 무슨 검증입니까?" 가장 뼈아프고, 가장 먼저 답해야 하는 질문입니다. AI가 만든 것을 AI가 검사하면 결국 한통속 아니냐는 거죠. 답은 세 겹 입니다. 첫째, 최종 판정은 AI가 아니라 기계가 합니다 소프트웨어에는 '자동 테스트'라는 게 있습니다. "이 상황에서 이 결과가 나와야 한다"를 미리 못 박아 두면, 컴퓨터가 프로그램을 실제로 돌려서 통과 아니면 실패 , 둘 중 하나로 판정하는 장치예요. 여기엔 의견이나 해석이 끼어들 자리가 없습니다. 잘 봐달라고 부탁할 수도 없고요. 검사역 ...

AI로 만들어본 것들 (3편) — 문서 민감정보 자동 마스킹 도구 만들기

결론부터 : 문서에서 민감정보를 가리는 일을 매번 손으로 하면 번거롭습니다. 파이썬(PyMuPDF)으로 자동 마스킹 도구 를 AI에게 짜달라고 해서 만들었어요. 다만 "무엇을 가릴지"는 사람이 판단 해야 합니다 — 너무 많이 가리면 그 서류가 쓸모없어지거든요. (제가 그랬습니다.) 지난 편 → 2편 — Gemini와 Claude로 레거시 코드베이스 지도 만들기 매번 손으로 가리는 게 귀찮았습니다 어떤 문서를 제출할 일이 생기면, 그 안의 민감정보(주소 일부, 번호 등)를 가려야 할 때가 있습니다. 캡처 떠서 그림판으로 검은 칠을 하거나, PDF 편집기를 여는 식이죠. 한두 번이면 괜찮은데, 여러 장이거나 반복되면 일입니다. 위치도 매번 조금씩 어긋나고요. "이거 자동화하면 되잖아" 싶었습니다. AI에게 마스킹 스크립트를 시켰습니다 직접 라이브러리를 찾아 헤매는 대신, AI(Claude Code)에게 요구사항을 줬습니다. "PDF를 이미지로 렌더링하고, 지정한 영역에 검은 사각형을 덮어씌우는 파이썬 스크립트를 만들어줘." 라이브러리는 PyMuPDF 를 골라줬어요. 핵심 흐름은 단순했습니다. PDF 페이지를 이미지로 렌더링 (원본 PDF 텍스트를 남기지 않으려고 — 이미지로 만들면 검은 칠 밑의 글자가 복사되지 않습니다) 가릴 영역을 좌표로 지정 해서 검은 사각형을 덮음 결과를 이미지 파일로 저장 여기서 하나 배웠어요. PDF 위에 그냥 검은 박스를 얹으면 위험합니다. 박스 밑의 텍스트가 그대로 남아 있어서, 복사하거나 도구로 열면 가린 내용이 튀어나옵니다. 그래서 이미지로 굽는(rasterize) 게 확실합니다. 이건 AI가 알려준 게 아니라, "이렇게 하면 밑의 글자가 남지 않냐"고 되물으며 확인한 부분이었어요. 진짜 함정 — 너무 많이 가리면 서류가 무효가 됩니다 여기가 이 편에서 제일 솔직해야 할 부분입니다. 도구는 잘 만들었는데, ...

AI로 만들어본 것들 (2편) — Gemini와 Claude로 레거시 코드베이스 지도 만들기

결론부터 : 수만 줄짜리 오래된 코드베이스를 AI로 파악할 때, 한 모델에 다 시키면 안 됩니다. 큰 컨텍스트를 가진 Gemini로 전체 "지도"를 그리고 , 집중력이 좋은 Claude로 그 지도를 들고 깊이 파고드는 2단으로 나누세요. 그리고 각 역할에 맞게 프롬프트(지시)를 갈아끼워야 합니다. 지난 편 → 1편 — 유튜브 쇼츠를 하루 만에 만들었습니다 오래된 코드베이스 앞에서 막막했습니다 수년간 쌓인 대규모 시스템을 파악해야 할 때가 있습니다. 문서는 낡았거나 없고, 원래 짠 사람도 없고, 모듈이 서로 어떻게 얽혀 도는지 한눈에 안 들어옵니다. 혼자 읽자니 어디서 시작할지 막막하고, 그렇다고 AI에 통째로 던지면 겉핥기 요약 만 나옵니다. 둘 다 답이 아니었어요. 한 모델에 다 시키면 안 되는 이유 핵심을 먼저 깨달았습니다. "넓이"와 "깊이"는 다른 일 이라는 겁니다. 넓이 : 코드베이스 전체를 훑어 "무엇이 어디 있고 어떻게 연결되나"를 파악하는 일 — 넓은 시야가 필요 깊이 : 특정 모듈을 파고들어 "여기 이 로직이 맞나, 여기서 터지나"를 확인하는 일 — 집중력이 필요 이 둘을 한 모델에 한꺼번에 시키면, 넓게 보다가 깊이가 얕아지거나, 깊이 파다가 전체를 놓칩니다. 그래서 도구를 나눴습니다. Gemini = 넓이, "지도"를 그린다 먼저 큰 컨텍스트를 가진 Gemini 에게 코드베이스 전체를 주고, 사람이 읽을 보고서가 아니라 다음 AI가 쓸 "지도" 를 만들게 했습니다. 지도에 담은 것: 시스템 지도 : 모듈이 무엇이고, 어디가 진입점이고, 서로 어떻게 통신하는지 컴포넌트 색인 : 파일별 목적과 핵심 함수의 위치(좌표) 계약·불변식 : "항상 참이어야 하는 것"들 (예: 이 카운터는 실제 목록 길이와 같아야 함) 의심 지대 : "여기가 버그...

AI로 만들어본 것들 (1편) — 유튜브 쇼츠를 하루 만에 만들었습니다

결론부터 : 완벽한 AI 영상을 만들려다 3주를 날렸습니다. 포기하고 있는 자산(사진 몇 장 + 화면 녹화)에 AI 도구(TTS·ffmpeg)를 엮었더니 채널 개설부터 첫 영상 공개까지 하루면 됐습니다. AI 시대의 제작은 "AI가 다 만들어주는 것"이 아니라 "도구를 엮는 것" 이었어요. 3주 동안 아무것도 못 올렸습니다 분리수거 앱을 만들고 나니 홍보가 필요했습니다. 유튜브 쇼츠가 좋겠다 싶었죠. 문제는 그다음이었어요. 저는 "AI로 그럴듯한 영상을 통째로 뽑겠다" 고 마음먹었습니다. 손 연기 장면을 AI로 생성하고, 배경음악 깔고, 자막도 예쁘게. 그런데 AI 영상 생성은 계속 어긋났어요. 정량이 초과되거나, 실제 촬영분과 결이 안 맞거나. 3주 동안 완성본이 하나도 안 나왔습니다. 돌아보면 문제는 도구가 아니라 저였어요. "완벽한 한 방"을 노린 게 정체의 원인 이었습니다. "완벽 말고 완성"으로 문턱을 넘었어요 어느 순간 방향을 바꿨습니다. AI 손 연기는 버리고, 이미 가진 것으로 만들기로요. 제품 사진 몇 장 앱 실행 화면 녹화 배출 결과 화면 캡처 여기에 AI 도구를 붙였습니다. 목소리는 구글 클라우드 TTS 로, 조합은 ffmpeg 로요. 화려한 AI 생성 영상은 없지만, 돌아가는 완성본 이 그날 나왔습니다. 채널 개설부터 첫 영상 공개까지 하루였어요. 이게 첫 번째 교훈입니다. 완벽을 노리면 0편이고, 완성을 노리면 1편이 나옵니다. 상표를 피하는 법 — 제품 뒷면과 크롭 첫 번째 실무 함정은 상표 였습니다. 특정 제품이 화면에 로고째 나오면 곤란하죠. 해결은 단순했어요. 제품을 뒷면(성분표)으로 촬영 했습니다. 브랜드 로고가 안 보이니까요. 그리고 앱 결과 화면 하단에 깔린 광고 배너는 잘라냈습니다(크롭) . ffmpeg -y -i rec.mp4 -t 11 -vf "crop=1080:19...

공고 알림봇 만들기 (11편·완결) — 봇이 알려준 공고로 이사를 검토했습니다

결론부터 : 45일 동안 공고 2,756건 을 수집해 필요한 것만 알림으로 받았습니다. 그중 한 건이 제 주거 계획을 실제로 검토하게 만들었고, 저는 그 공고에 신청하지 않기로 했습니다. 그런데도 이 봇은 제 값을 했습니다. 지난 편 → 10편 — Reddit이 API를 막아서 RSS로 우회했습니다 그날 폰이 울렸습니다 7월 29일 저녁 여섯 시 십팔 분. 봇이 LH 공고 목록을 가져와 신규 열 건을 알렸습니다. 그중 하나가 이거였어요. [lh] 의정부지역 10년 공공임대주택 예비입주자모집 공고(무순위) 버튼을 눌러 공고 페이지로 들어갔고, 공고문 PDF 네 개를 받았습니다. 그리고 그걸 놓고 공공임대가 뭔지부터 따져봤어요. 저는 그때 10년 공공임대와 국민임대의 차이도 몰랐습니다. 알림에서 분석 착수까지 36분 이 걸렸습니다. 접수 13일 전이었습니다 여기가 중요합니다. 그 공고의 접수기간은 8월 11일부터 12일까지 , 이틀뿐이었어요. 제가 손으로 찾고 있었다면 어땠을까요. 1편에서 말한 대로 저는 사이트를 매주 순회했습니다. 잘해야 주 1회고, 바쁘면 건너뛰었어요. 이틀짜리 접수 창을 놓칠 확률이 꽤 높았습니다. 봇은 그걸 접수 13일 전에 가져왔습니다. 급하게 결정하지 않을 시간 을 확보한 거죠. 그리고 신청하지 않기로 했습니다 며칠 더 들여다보고 나서, 저는 접수하지 않기로 결정했습니다. 이 글을 "봇 덕분에 집을 구했습니다"로 끝내면 좋았겠지만 사실이 아닙니다. 봇은 제게 집을 주지 않았어요. 대신 이걸 줬습니다. 봇이 없었다면 봇이 있었더니 그 공고를 몰랐을 수 있음 접수 13일 전에 알았음 판단 시간 없거나 촉박 열흘 넘게 결정 못 함 안 하기로 결정 "모르고 지나간 것"과 "알고 안 한 것"은 다릅니다. 결과는 똑같이 "그 집에 안 살게 됐다"인데, 전자는 선택이 아니고 후자는 선택이에요. 알...

공고 알림봇 만들기 (10편) — Reddit이 API를 막아서 RSS로 우회했습니다

결론부터 : Reddit JSON API는 2023년부터 인증 없이 쓰면 403이 옵니다. 그런데 RSS 피드( /r/서브레딧/new.rss )는 아직 인증 없이 열려 있습니다. 단, User-Agent를 보내야 하고 호출 간격을 넉넉히 둬야 합니다. 9편에서 로컬 LLM으로 걸러내는 걸 붙였죠. 그런데 그 앞단, 글을 가져오는 쪽 에서 먼저 막혔던 얘기를 안 했네요. 지난 편 → 9편 — LM Studio 로컬 LLM으로 수집 결과를 걸렀습니다 문서대로 했는데 403이 왔습니다 Reddit에서 글 목록을 가져오는 방법은 검색하면 금방 나옵니다. 주소 끝에 .json 을 붙이면 JSON으로 받을 수 있다는 거죠. 옛날에는 그랬습니다. 지금은 403이 옵니다. 2023년에 Reddit이 API 정책을 바꾸면서 인증 없는 접근을 막았어요. 앱을 등록하고 OAuth 인증을 붙여야 합니다. 검색으로 나오는 예제 코드 상당수가 그 이전에 쓰인 것이라, 그대로 따라 하면 안 됩니다. 여기서 선택지가 갈렸어요. 방법 비용 OAuth 인증 붙이기 앱 등록 + 토큰 갱신 로직 스크래핑 HTML 구조 바뀌면 매번 깨짐 RSS 피드 인증 없음 RSS는 아직 열려 있었습니다 Reddit은 오래전부터 RSS를 제공해왔고, 그게 아직 살아 있습니다. https://www.reddit.com/r/서브레딧이름/new.rss 이걸 부르면 최신 글 목록이 Atom 형식 XML로 옵니다. 인증이 필요 없어요. 4편에서 K-Startup이 XML을 준다고 했는데, 여기서 또 XML을 만났습니다. 다만 이쪽은 표준 Atom 형식 이라 훨씬 다루기 쉬웠어요. 글마다 제목·링크·본문이 정해진 자리에 들어 있습니다. 막혔다고 포기하지 않고 다른 문을 찾은 게 이 편의 핵심입니다. 정문이 잠겼어도 옆문이 열려 있을 수 있어요. 사람인 척은 해야 합니다 인증은 필요 없지만 조건이 하나 있었어요. User-Agent를 보내야 합니...

공고 알림봇 만들기 (9편) — LM Studio 로컬 LLM으로 수집 결과를 걸렀습니다

결론부터 : 내 PC에서 도는 작은 언어 모델(LM Studio + Gemma)로 수집 결과를 1차 선별하면, 공짜로 무제한 돌릴 수 있습니다. 다만 모델이 꺼져 있으면 전부 조용히 탈락 하니, 거절된 것까지 저장해두는 게 필수입니다. 8편까지 만든 봇은 공고를 잘 물어옵니다. 그래서 소스를 하나 더 붙여봤어요. 사람들이 "이런 앱 없나요?" 하고 올린 글 을 모으는 쪽으로요. 지난 편 → 8편 — 윈도우 작업 스케줄러로 파이썬 봇을 자동 실행했습니다 키워드만으로는 걸러지지 않았어요 먼저 단어로 걸렀습니다. 없나요 , wish there was , need an app 같은 표현이 들어간 글만 남기는 식이죠. 절반은 성공이었어요. 관계없는 글은 잘 빠집니다. 그런데 남은 것들이 이랬습니다. 이미 있는 앱을 두고 불만을 말하는 글 "없나요"가 앱과 무관한 문맥에 쓰인 글 그냥 잡담 단어는 문맥을 모릅니다. 없나요 가 들어갔다고 앱 수요는 아니었어요. 클라우드 LLM은 안 쓰기로 했습니다 문맥 판단이니 언어 모델을 쓰면 됩니다. 그런데 여기서 계산이 필요했어요. 이 봇은 한 시간에 한 번씩, 무한히 돕니다. 걸러야 할 글이 하루 수십 건이고 앞으로 소스를 더 붙일 생각이었어요. 유료 API를 붙이면 켜두는 것 자체가 비용 이 됩니다. 그래서 내 PC 안에서 돌리기로 했습니다. LM Studio를 띄우고 Gemma를 올렸어요. 이러면 이런 게 달라집니다. 클라우드 API 로컬 LLM 비용 호출당 과금 0원 호출 한도 있음 없음 데이터 외부로 나감 내 PC 안 대신 — PC가 켜져 있어야 함 LM Studio는 OpenAI와 같은 형식의 API 를 열어줍니다. 그래서 코드 쪽에서는 주소만 내 PC로 바꾼 셈이고, 나중에 클라우드로 옮기고 싶으면 주소만 바꾸면 됩니다. 점수로 물어봤습니다 "이 글이 좋은가?"라고 물으면 답이 제각...

공고 알림봇 만들기 (8편) — 윈도우 작업 스케줄러로 파이썬 봇을 자동 실행했습니다

결론부터 : 파이썬 스크립트를 PC 켤 때마다 자동으로 돌리려면 윈도우 작업 스케줄러 + 로그온 시 실행 이면 충분합니다. 단, 환경변수가 전달되지 않는 함정이 있어 런처 스크립트를 한 겹 씌워야 합니다. 7편까지 만들고 나니 알림은 쓸 만해졌어요. 그런데 정작 제가 직접 켜야 돌아갔습니다. 지난 편 → 7편 — 텔레그램 봇 인라인 키보드로 버튼을 달았습니다 켜는 걸 잊으면 소용이 없어요 터미널을 열고 실행하면 잘 돌아갑니다. 문제는 그 창을 닫으면 멈춘다 는 거죠. 공고는 제가 컴퓨터를 안 볼 때도 올라옵니다. 알림봇을 만든 이유가 "놓치지 않으려고"인데, 제가 켜는 걸 잊으면 그 순간 의미가 없어져요. 켜두는 것까지가 기능 이었습니다. 클라우드에 올리는 방법도 있지만, 그건 나중 일로 미뤘어요. 일단 집 PC에서 확실히 돌아가는 것 이 먼저였습니다. 작업 스케줄러 + 로그온 시 실행 윈도우에는 작업 스케줄러가 기본으로 들어 있어요. 여기에 등록하면서 트리거를 "로그온할 때" 로 잡았습니다. 이러면 PC를 켜고 로그인하는 순간 봇이 자동으로 뜹니다. 제가 할 일이 없어요. 부팅 시 실행하는 방법도 있는데 로그온 시 실행을 골랐습니다. 이 봇은 제 계정의 환경변수를 쓰기 때문에, 로그인 전에는 필요한 값이 준비되지 않거든요. 함정 — 환경변수가 안 넘어갑니다 여기서 막혔어요. 손으로 실행하면 잘 되는데, 작업 스케줄러로 띄우면 API 키를 못 읽습니다. 원인은 이거였어요. 제 토큰과 API 키는 코드에 안 박고 윈도우 사용자 환경변수 에 넣어뒀는데, 작업 스케줄러가 띄우는 프로세스에는 그게 그대로 전달되지 않았습니다. 그래서 런처 스크립트를 한 겹 씌웠어요. 사용자 환경변수를 읽어서 → 프로세스 환경변수로 넣고 → 파이썬 실행 파워셸로 열 줄 남짓입니다. 작업 스케줄러는 이 런처를 부르고, 런처가 키를 챙겨서 봇을 띄우는 구조죠. 이렇게 하니 키가 코드에도,...

공고 알림봇 만들기 (7편) — 텔레그램 봇 인라인 키보드로 버튼을 달았습니다

결론부터 : 텔레그램 알림에 링크를 넣을 때 본문에 URL을 쓰지 말고 인라인 키보드 버튼으로 분리 하세요. 메시지가 깔끔해지고, 폰에서 누르기도 훨씬 쉽습니다. 6편까지 오면서 알림은 정확해졌어요. 올 것만 오고, 중복도 안 오죠. 그런데 막상 폰으로 받아보니 읽기가 불편했습니다. 지난 편 → 6편 — 한 공고가 일곱 번 올 뻔했습니다 처음엔 본문에 링크를 넣었어요 초기 알림은 이런 모양이었습니다. [lh] 의정부지역 10년 공공임대주택 예비입주자모집 공고 [상세 보기](https://apply.lh.or.kr/lhapply/apply/wt/wrtanc/...) 기관: LH | 기간: 2026-08-11 ~ 2026-08-12 제목 아래에 마크다운 링크를 한 줄 끼워 넣은 거죠. 동작은 합니다. 누르면 열려요. 그런데 하루에 수십 건씩 받다 보니 문제가 보였습니다. 불편했던 세 가지 ① 링크가 본문에 섞여서 눈이 피곤해요. 제목·기관·기간 사이에 파란 글씨가 끼어 있으면 정작 중요한 공고명이 안 읽힙니다. 알림이 한두 개일 땐 몰랐는데 목록이 길어지니 확 체감되더라고요. ② 누르기가 어려워요. 본문 링크는 글자 크기만 한 영역이라 폰에서 정확히 눌러야 합니다. 스크롤하다가 잘못 누르거나, 눌린 줄 알았는데 안 눌리는 일이 잦았어요. ③ 링크 미리보기가 끼어들어요. 텔레그램은 본문에 URL이 있으면 그 페이지 미리보기를 붙이려고 합니다. 공공기관 사이트는 미리보기가 예쁘게 나오지 않아서, 메시지만 길어지고 정작 정보는 밀려났어요. 인라인 키보드로 옮겼습니다 텔레그램에는 메시지 아래에 버튼을 붙이는 기능이 있어요. 인라인 키보드라고 부릅니다. 메시지를 보낼 때 이런 걸 같이 넘겨주면 됩니다. "reply_markup": { "inline_keyboard": [[ {"text": "상세 보기 →", "url": ...

공고 알림봇 만들기 (6편) — 한 공고가 일곱 번 올 뻔했습니다

5편에서 "제목+주소"를 열쇠로 삼아 중복을 막았다고 했죠. 잘 되는 줄 알았어요. 그런데 공고 하나가 알림 일곱 개로 쪼개질 뻔했습니다. 지난 편 → 5편 — 같은 공고가 계속 왔습니다 공고 하나가 여러 줄로 쪼개져 있었어요 원인은 응답을 열어보고 알았습니다. 마이홈 API는 공고 한 건을 여러 줄로 나눠서 줍니다. 한 공고 안에 아파트가 여러 단지 들어 있으면, 단지마다 한 줄씩 만들어지는 식이에요. 사람이 보기엔 공고 하나인데 데이터로는 일곱 줄인 거죠. 실제로 지금 받아보면 이렇습니다. 구분 받은 줄 수 실제 공고 수 임대 100줄 34건 분양 64줄 32건 줄 수와 공고 수가 두 배 가까이 차이 납니다. 주소에 단지 번호가 붙어 있었어요 그래도 제목이 같으니 제 열쇠에 걸렸어야 하는 것 아닌가 싶었어요. 문제는 주소 였습니다. ...ttotHouseDetailView.do?pblancId=1340&houseSn=3 ...ttotHouseDetailView.do?pblancId=1340&houseSn=8 ...ttotHouseDetailView.do?pblancId=1340&houseSn=9 앞부분(공고 번호)은 같은데 뒤에 단지 번호가 붙어서 주소가 전부 달라집니다. 제목은 같아도 주소가 다르니 제 열쇠는 다른 공고 라고 판단해버린 거예요. 숫자로 보면 이렇습니다. 구분 공고 수 만들어진 열쇠 수 임대 34건 59개 분양 32건 64개 분양은 사실상 줄 수만큼 알림이 갈 뻔했어요. 공고 번호로 대표 한 줄만 뽑았어요 해결은 단순했습니다. 데이터에 공고 번호 가 따로 들어 있었거든요. 같은 번호가 이미 나왔으면 건너뛰고, 공고당 첫 줄만 남겼습니다. 알림 대상을 고를 때 이미 본 공고 번호를 기억해두고 거르는 식이에요. 열 줄이 와도 한 줄만 통과합니다. 여기서 짚어둘 게 있어요. 이건 5편의 중복 제거와 다른 층위입...

공고 알림봇 만들기 (5편) — 같은 공고가 계속 왔습니다

4편에서 소스마다 다른 응답 구조를 겨우 맞췄다고 했죠. 이제 알림이 오기 시작했어요. 그런데 한 시간 뒤에 똑같은 공고가 또 왔습니다. 그다음 시간에도요. 지난 편 → 4편 — API마다 응답 구조가 달랐습니다 API는 "새로 올라온 것"만 주지 않아요 제가 착각한 게 있었어요. 요청하면 새 공고만 골라서 줄 거라고 막연히 생각했거든요. 아닙니다. 공고 API는 지금 열려 있는 목록 전체 를 줍니다. 어제 본 것도, 그제 본 것도 마감 전이면 계속 들어 있어요. "이전에 가져간 것 이후로만 주세요" 같은 옵션은 없었습니다. 제 봇은 한 시간마다 물어보는데, 매번 이만큼이 옵니다. 소스 한 번에 오는 양 든든전세 300건 기업마당 100건 K-Startup · LH 각 10건 마이홈 8건 합계 428건 하루 24번이면 1만 건 넘게 받아보는 셈이에요. 그런데 그중 진짜 새 공고는 하루에 많아야 수십 건입니다. 즉 "무엇이 새 것인가"는 API가 알려주지 않아요. 내가 판단해야 합니다. 그래서 "이미 본 것"을 기억하기로 했어요 방법은 단순합니다. 알림을 보낸 공고를 어딘가 적어두고, 다음에 받은 목록과 대조해서 적혀 있지 않은 것만 새 것으로 치는 거죠. 문제는 무엇을 적을 것이냐 였어요. 무엇이 같으면 "같은 공고"인가 처음엔 제목만 적으려고 했어요. 그런데 금방 걸리더라고요. 제목만 쓰면 : 기관이 다른데 제목이 같은 공고가 있어요. 2026년 창업지원사업 모집 공고 같은 건 여기저기서 씁니다. 하나를 받으면 나머지가 묻혀요. 주소만 쓰면 : 같은 공고인데 주소 뒤에 파라미터가 붙었다 말았다 하면 매번 다른 것으로 보입니다. 그래서 제목과 주소를 붙여서 하나의 열쇠 로 만들었어요. 둘 다 같아야 같은 공고로 봅니다. 실제로 저장되는 모양은 이렇습니다. [경기] 포천시 2026...