offon · open‑source Slack app for attendance and leave

Period  — 

When I joined Lukuku, attendance was not being tracked properly, so I built a system for it after work hours. That system later grew into the company‑wide work management system, now with the company ontology attached. I split off only the attendance and leave features into offon, an open‑source Slack app.

Split off from the company work management system, MIT‑licensed and self‑hosted

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

  • Shifts past midnight, several sessions a day, and automatic work, break and overtime totals
  • 60‑minute meal breaks that set their end time at the start and send a return reminder
  • Full‑day and half‑day leave excluding weekends and holidays, with remaining days tracked
  • Attendance correction requests from the calendar, with times recalculated on approval
  • One admin inbox for leave and correction approvals
  • Slack one‑time‑code login, 5 slash commands and reminders for missed clock‑ins and clock‑outs

Clock‑ins arriving at the same moment

Problem
A Slack retry or a double click could send two clock‑ins at almost the same time, and both passed the pre‑check, leaving two open sessions.
Solution
A PostgreSQL partial unique index allows one open session per attendance record. The second request gets the same already‑working response as the pre‑check.

Records made after a correction request

Problem
If someone clocked out or took another break after requesting a correction, approval could overwrite those records.
Solution
Approval compares the value at request time, the requested value and the current value. Fields the request did not touch keep later records, and a field changed differently on both sides is treated as a conflict.

Time zones on the server and locally

Problem
Handling dates as‑is on a UTC server and a Korean‑time laptop could add the 9‑hour offset twice or pick the wrong weekday.
Solution
Times are read in Korean time and stored in UTC. Displaying times in Korean time and finding the weekday from a date are separate functions. The same time and weekday appear regardless of where the code runs.

Slack retries

Problem
Slack resends a command when the reply is slow. Processing it again could create the same record and notification twice.
Solution
The handler first checks the retry marker on the request and, for a retry, replies 200 at once without processing it. A slow reply no longer sends the same notification twice.