우리 교회 청년부 찬양팀에서는 매주, 네이버 밴드에 신앙점검표 라는 게시글을 쓴다. (해당 주 동안 묵상한 말씀, 기도제목, 감사제목, 라인업 피드백, 콘티 묵상, 삶 등 여러가지 주제로 일주일간의 삶을 공유한다.)
매년 밴드 게시글을 체크하는 사람은, 일일이 게시글 날짜와 시간을 보고 지각여부를 체크한다.
2025년 밴드팀장이 되어 해당 업무(?)를 맡게 되었는데, 매번 체크하기 귀찮기도 했고 충분히 자동화를 할 수 있을 것 같아, 이렇게 글을 적게 되었다.
#1 요구사항 파악
매주 글을 쓰지 않은 인원들에 대해 지각비를 부여하기 위해, 밴드 게시글을 매주 체크한다.
•
해당 주 월~토요일 05:30분까지 올린 대상자는 통과
•
해당 주 토 05:31 ~ 일 23:59분까지 올리는 대상자에게는 지각벌금 2,000원
•
해당 주에 게시글을 올리지 않는 사람은 벌금 5,000원
복잡하지 않은 정책이며, 충분히 개발 가능한 요구사항이라고 판단!
#2 개발여부 확인
필요한 API에는,
1.
해당 밴드 모임에 가입한 멤버 조회
•
해당 밴드에 가입된 유저를 대상으로 지각자 파악 필요
2.
해당 밴드 모임의 글 목록 조회
하지만,
1번 API는 보안이슈상 존재하지 않아 보였다.
(한번 뚫어볼까 하다가 블로그에 적합하지 않아보여 멈췄다..)
#3 개발 방향성 정의
처음에는 최대한 모듈화를 통한 확장성있게 재사용성에 용이한 코드를 작성하려고 했다.
하지만, 찬양팀으로 함께 한지 3년차동안 바뀐거라고는 멤버와 시간룰 밖에 없었기에, 해당 변수만 constant 로 관리하기로 하고 개발에 들어갔다.
1.
해당 밴드 모임에 가입한 멤버는 얻을 수 없는데?
→ 멤버는 신입멤버 혹은 중간에 나가는 멤버에 대한 이벤트는 자주 발생하지 않기 때문에 멤버 리스트는 하드코딩 하기로 결정!
(등록되어 있는 멤버 프로필의 이름 사용; 이름을 무작정 바꾸지마라고 통보함 ㅎㅎㅎ)
2.
해당 밴드 모임의 글 목록 조회시, 날짜 범위를 둘 수 없는데?
•
최신 20개의 글만 제공하고, 그 이전 글은 해당 호출에 next_params라는 결과 값을 넣어 API 재호출
◦
조회하고 싶은 날짜 (2025-01-06 ~ 2025-01-12)
◦
조회하고 싶은 이전 날짜 (2025-01-01 ~ 2025-01-05)
◦
조회하고 싶은 이후 날짜 (2025-01-13 ~ 2025-01-19)
→ 셋팅한 특정 날짜내 밴드 게시글만 필터링 대상에 적용 (설정한 시점 이후 글이 있는 경우 재호출 하지 않음)
3.
밴드키는 어디서 얻는가?
#4 코드
예외 처리같은 건 충분히 하지 않았습니다. 참고만 하시길 바래요.
가입한 밴드 리스트 조회
const getBandKey = async () => {
const res = await axios.get(`${HOST}/v2/bands?access_token=${ACCESS_TOKEN}`, {
headers: { 'Content-Type': 'application/json' },
});
return res.data.result_data.bands.find(band => band.name == '').band_key;;
};
JavaScript
복사
밴드 글 목록 조회
const getPosts = async after => {
const params = {
access_token: ACCESS_TOKEN,
band_key: SINJEOM2025,
locale: LOCALE,
...(after && { after }),
};
const url = `${HOST}${API}?${new URLSearchParams(params)}`;
const res = await axios.get(url, {
headers: { 'Content-Type': 'application/json' },
});
return res.data.result_data;
};
JavaScript
복사
지각대상자 추출
const filterPenaltyTargetCrews = async (from, to) => {
const penaltyTargetCrews = [];
const fromTime = new Date(`${from} ${FROM_TIME}`).getTime();
const middleTime = new Date(`${to} ${MIDDLE_TIME}`);
middleTime.setDate(middleTime.getDate() - 1);
const toTime = new Date(`${to} ${TO_TIME}`).getTime();
let toContinue = true;
let after = undefined;
while (toContinue) {
const { items, paging } = await getPosts(after);
after = paging.next_params?.after;
for (const item of items) {
const postCreatedAtTime = new Date(item.created_at);
const postCreatedAt = item.created_at;
// 날짜 범위에 포함되는 경우
if (postCreatedAt >= fromTime && postCreatedAt < toTime) {
// 제출
CREWS = CREWS.filter(crew => crew !== item.author.name);
if (postCreatedAt > middleTime) {
// 늦게 제출
penaltyTargetCrews.push({
crewName: item.author.name,
fee: LATE_FEE,
});
}
} else if (postCreatedAt > toTime) {
// 날짜 범위에 포함되지 않는 경우 (이전 날짜)
} else {
// 날짜 범위에 포함되지 않는 경우 (이후 날짜)
toContinue = false;
break;
}
}
// 더이상 글이 존재하지 않는 경우
if (!after) {
toContinue = false;
}
}
// 글을 쓰지 않은 멤버 추출
CREWS.forEach(crew => {
penaltyTargetCrews.push({ crewName: crew, fee: NOT_SUBMITTED_FEE });
});
return penaltyTargetCrews;
};
JavaScript
복사
결과 코드
(async () => {
// 날짜 설정
const startDate = '2025-01-13';
const endDate = '2025-01-19';
const penaltyCrews = await filterPenaltyTargetCrews(startDate, endDate);
console.log(`\n[${startDate} ~ ${endDate}]`);
penaltyCrews.forEach(({ crewName, fee }) => {
console.log(`${crewName}: ${fee.toLocaleString()}원`);
});
})()
JavaScript
복사
예시
[2025-01-06 ~ 2025-01-12]
안혜인: 2,000원
김창수: 5,000원
김하윤: 5,000원
송인석: 5,000원
이종탄: 5,000원
조연채: 5,000원
Plain Text
복사
이렇게 하면, 우리 찬양팀 팀장님께서 엑셀에다가 손수 기록하신다.
엑셀에다가도 자동 업데이트를 할 예정이긴 했지만, 그건 팀장님 영역이라 여기까지가 나의 영역 범위 내 최대한의 자동화였다.
간만에 THIRD API를 활용하여 실생활에 적용하는 케이스라, 간단하게 기록을 해 보았다.
매우 효율적인; 빠르고 스트레스 받지 않는, 방향으로 삶의 귀찮은 문제들을 풀어낼 수 있다는 게 개발자의 가장 큰 메리트이지 않나 싶다.
재밌었다!!!