offon · 출퇴근⁠·⁠휴가를 관리하는 오픈소스 슬랙 앱

기간  — 

루쿠쿠에 합류했을 때 근태 관리가 제대로 되지 않아, 퇴근 후 시간에 만든 시스템에서 출발했습니다. 이 시스템은 이후 회사 온톨로지까지 붙은 전사 업무 시스템으로 커졌습니다. 그중 근태⁠·⁠휴가 기능만 떼어 오픈소스 슬랙 앱 offon을 만들었습니다.

사내 업무 시스템에서 떼어 낸, MIT 라이선스의 직접 설치형 앱

Next.js 16React 19TypeScriptTailwind CSS 4shadcn/uiPostgreSQLPrismaSlack Web APIVercel Cron

  • 자정을 넘긴 근무와 하루 여러 번의 출퇴근, 근무⁠·⁠휴식⁠·⁠초과근무 시간 자동 계산
  • 시작할 때 끝나는 시각을 정하고 복귀 알림을 보내는 60분 식사
  • 주말⁠·⁠공휴일을 뺀 종일⁠·⁠반차 휴가 신청과 남은 연차 추적
  • 달력에서 하는 근태 정정 신청과 승인 뒤 시간 재계산
  • 휴가와 근태 정정을 한곳에서 처리하는 관리자 승인함
  • 슬랙 일회용 코드 로그인, 슬래시 명령 5개, 출퇴근 누락 알림

동시에 들어온 출근 요청

문제
슬랙 재전송이나 두 번 클릭으로 출근 요청이 거의 동시에 오면, 두 요청 모두 사전 검사를 통과해 열린 근무가 두 개 생길 수 있었습니다.
해결
PostgreSQL 부분 유니크 인덱스로 근태 하나에 열린 근무를 하나만 허용했습니다. 두 번째 요청은 사전 검사와 같은 '이미 근무 중' 응답을 받습니다.

정정 신청 뒤에 생긴 기록

문제
정정을 신청한 뒤 실제로 퇴근하거나 휴식을 더 하면, 승인할 때 그 기록을 덮어쓸 수 있었습니다.
해결
신청 당시 값, 신청한 값, 승인 시점 값을 비교합니다. 신청에서 건드리지 않은 값은 이후 기록을 그대로 두고, 같은 항목이 양쪽에서 다르게 바뀌면 충돌로 처리합니다.

서버와 로컬의 시간대 차이

문제
UTC 서버와 한국 시간 로컬에서 날짜를 그대로 다루면 9시간이 두 번 더해지거나 요일이 틀릴 수 있었습니다.
해결
시각은 한국 시간으로 해석해 UTC로 저장합니다. 한국 시간으로 표시하는 함수와 날짜로 요일을 구하는 계산을 나눴습니다. 실행 환경이 달라도 같은 시각과 요일을 표시합니다.

슬랙의 재전송

문제
슬랙은 명령 응답이 늦으면 같은 요청을 다시 보냅니다. 그대로 처리하면 같은 기록과 알림이 두 번 생길 수 있었습니다.
해결
요청의 재전송 표시를 먼저 확인하고, 재전송이면 처리하지 않고 바로 200으로 응답합니다. 응답이 늦어도 같은 알림이 두 번 가지 않습니다.