2026년 02월 22일
카카오같이가치는 카카오가 운영하는 사회공헌 플랫폼으로, 좋아요와 댓글만으로도 기부에 참여할 수 있는 서비스다.
매일 접속해서 참여하면 좋겠지만, 수백 개에 달하는 기부 항목을 매번 수동으로 처리하는 것은 현실적으로 어렵다.
자동화 기술을 활용하면 꾸준하게 참여할 수 있겠다는 생각에 크롬 익스텐션으로 개발하게 됐다.
크롬 익스텐션 환경에서 카카오 API를 직접 호출하면 CORS 오류가 발생한다.
Extension의 Origin이 chrome-extension://... 형태이기 때문에 카카오 서버에서 요청을 거부한다.
이를 해결하기 위해 declarativeNetRequest API를 활용하여 요청 헤더를 자동으로 교체했다.
{
"action": {
"type": "modifyHeaders",
"requestHeaders": [
{
"header": "Origin",
"operation": "set",
"value": "https://together.kakao.com"
}
]
},
"condition": {
"urlFilter": "*together*kakao.com*",
"resourceTypes": ["xmlhttprequest"]
}
}
rules.json을 통해 글로벌 규칙을 적용하니 fetch 호출 코드에서 헤더를 별도로 관리할 필요가 없어졌다.
핵심 자동화는 Service Worker(background.js)에서 처리한다.
실행 흐름:
STATUS_FUNDING) 항목 수집chrome.storage에 저장된 참여 기록과 비교하여 미참여 항목만 선별스케줄링은 chrome.alarms API를 사용해 6시간마다 자동 실행되도록 설정했다.
이미 참여한 항목을 만나면 이후 항목들은 모두 처리된 것으로 판단하고 수집을 중단하는 최적화 로직도 넣었다.
이 덕분에 매 실행마다 22페이지를 모두 순회하지 않아도 된다.
팝업과 옵션 페이지를 각각 React 컴포넌트로 분리하여 개발했다.
댓글은 기본 5가지 메시지에서 랜덤 선택되며, 옵션 페이지에서 추가/삭제가 가능하다.
총 200개 이상의 기부 항목에 자동 참여할 수 있게 됐다.
처음 실행 시 전체 항목 처리에 약 10~15분이 소요되며, 이후 실행부터는 신규 항목만 처리해 훨씬 빠르게 동작한다.
Notion을 사용하면서 대시보드에 시계나 진행률 같은 위젯을 넣고 싶었는데, 기존 서비스들은 가입을 요구하거나 커스터마이징이 제한적이었다. 가입 없이 URL 쿼리 파라미터만으로 위젯을 커스터마이즈하고, Notion에 바로 임베드할 수 있는 서비스를 직접 만들기로 했다. ## 핵심 컨셉 **"URL = Single Source of Truth"** — 모든 위젯 설정이 URL 쿼리 파라미터에 저장된다. 별도의 가입이나 DB 저장 없이 URL 하나만 공유하면 누구든 같은 위젯을 볼 수 있다. 사용 흐름은 단순하다: 1. 갤러리에서 위젯을 고른다 2. 색상, 언어, 표시 옵션을 커스터마이즈한다 3. 생성된 URL을 Notion의 `/embed` 블록에 붙여넣는다 ## 기술 스택 - **Framework**: Next.js 16 (App Router) - **Language**: TypeScript 5 - **Styling**: Tailwind CSS 4 - **Monorepo**: Turborepo + pnpm - **Deploy**: Vercel (한국 리전) - **i18n**: 딕셔너리 패턴 (ko/en) ## 아키텍처 `Turborepo` 모노레포로 패키지를 분리하여 관리한다. - `apps/web` — Next.js 앱 (랜딩, 갤러리, 커스터마이저, 임베드) - `packages/widget-core` — 위젯 타입, 레지스트리, 파라미터 파싱, 공용 프리셋 - `packages/widgets` — 개별 위젯 구현체 (6종) 위젯 추가...
강의 시청 화면에서 cmd + i 눌러서 개발자도구 오픈 console에 스레드에 있는 코드 입력 붙여넣기 안되는 분들은 allow pasting 수기 입력 후 진행 마지막 챕터 끝에 5초 정도 듣기 var no = $("#no").val(); var num = $("#num").val(); var log_num = location.search.match(/max_num=([\d]*)\&/)[1]; var cl_start_time = Math.floor(new Date().getTime()/1000) - 4020; var cl_start_check = $("#cl_start_check").val(); var user_id1 = location.search.match(/user_id1=([a-zA-Z0-9]*)$/)[1]; var allData = { no, num, log_num, cl_start_time, cl_start_check, user_id1, page_time: 147.146, }; var allData2 = { no, num, cur_page: Number(log_num), max_num: 0, user_id1, goyong_yn: "9" }; $.ajax({ url: "jindo_check_cl.php", type:'POST', data: allData }); $.ajax({ url: "timestamp.php", cache: false }); $.ajax({ url: "ajax.jumsu2_update_page.php", type:'POST', data: allData2, async: false }); setTimeout(() => { $('#frame')[0].src = $('#frame').attr('src').replace(/[\d]{2}\.html$/, `${pad(6, 2)}.html`) }, 500);
vscode에서 검색 후 방향키를 누르면 검색어에 대한 일괄 변경 기능이 지원된다. 작업 중 .hideOverlay 함수에 대한 일괄 변경을 처리하려는데, a.hideOverlay, b.hideOverlay… 와 같이 앞에 붙어있는 문자가 모두 다른 상황에서는 단순 검색으로는 변경이 불가능하여 정규식 검색 후 그룹화하여 일괄 변경 처리를 진행했다. 우측위에 .* 아이콘을 클릭하여 정규식 검색을 활성화 후 검색어 및 수정단어에 정규식 처리하여 완료 // 검색어 : (this\.[a-zA-Z]*)\.hideOverlay\(\); // this부터 hideOverlay 앞의 값까지 모두 그룹화 지정 this.aaa.hideOverlay(); this.bbb.hideOverlay(); // 수정단어 : if($1) { $1.hideOverlay(); } // 일괄 변경된 결과 if(this.aaa) { this.aaa.hideOverlay(); }; if(this.bbb) { this.bbb.hideOverlay(); };