- Published on
[UrCheckin] Tự động hóa chấm công trên ứng dụng Base 🪲(1/3)
- Authors
- Name
- Đông Trần
- Github
- @dongitran
Hi anh em dev 👋, tớ có một câu hỏi nhỏ: Các bạn có bao giờ quên chấm công không?
Nếu câu trả lời là "có" thì bạn cũng giống mình khoảng 4 tháng trước đây :))))
Câu chuyện bắt đầu từ một vấn đề nhỏ nhưng hơi phiền phức
Công ty tớ có hai cơ chế chấm công:
- Ứng dụng Base trên điện thoại
- Hệ thống check-in bằng khuôn mặt ở lối vào
Nghe thì có vẻ đơn giản, nhưng với team TECH 30 người bọn tớ, đây lại là nguồn gốc của một loạt vấn đề:
- Mỗi tháng có ít nhất 50+ request "Quên checkin/Quên checkout" 😅
- 4 quản lý trực tiếp phải dành thời gian duyệt các request này
- Nhân viên hay quên chấm công dù đến đúng giờ vì mãi mê chạy dự án và coding 🧠
Mọi chuyện trở nên thú vị hơn khi phòng TECH chúng tớ có một group chat Timeoff - nơi mọi người đều thông báo khi:
- Đi trễ, về sớm
- Xin nghỉ phép
- Làm việc từ xa (WFH)
Và rồi một ngày, trong lúc đang phải làm 5 request "quên chấm công" cùng lúc, tớ bỗng nghĩ:
"Khoan, sao mình không tự động hóa việc này? Mọi người có vấn đề gì đều báo trên group rồi, còn lại đều là người có mặt bình thường..."
Khi developer gặp vấn đề: Automation is the way! 🤖
Tớ nhận ra mình có thể tận dụng API của ứng dụng Base để xây dựng một hệ thống tự động chấm công. Thiết kế ban đầu khá đơn giản:
- Server NodeJS sẽ thực hiện check-in/check-out tự động theo lịch định
- Bot Telegram để mọi người cài đặt tài khoản và quản lý ngày nghỉ
- Database MongoDB lưu trữ thông tin người dùng
- Cơ chế bỏ qua những người đã xin nghỉ phép
Luồng hoạt động:
Behind the scenes: Coding magic ✨
Để hiện thực hóa ý tưởng này, tớ phải đi sâu vào một số công nghệ thú vị:
1. Lập lịch thông minh với node-cron
// Server tự động chạy các job vào thời điểm cố định
cron.schedule("0 15 9 * * 1-5", () => processCheckin("9:15"), {
scheduled: true,
timezone: "Asia/Ho_Chi_Minh",
});
cron.schedule("0 55 11 * * 1-5", () => processCheckin("11:55"), {
scheduled: true,
timezone: "Asia/Ho_Chi_Minh",
});
cron.schedule("0 10 13 * * 1-5", () => processCheckin("13:10"), {
scheduled: true,
timezone: "Asia/Ho_Chi_Minh",
});
cron.schedule("0 0 18 * * 1-5", () => processCheckin("18:10"), {
scheduled: true,
timezone: "Asia/Ho_Chi_Minh",
});
Với 4 mốc thời gian trong ngày, hệ thống có thể linh hoạt xử lý các trường hợp:
- Check-in buổi sáng (~9:15)
- Check-out buổi sáng (~11:55) cho người nghỉ chiều
- Check-in buổi chiều (~13:10) cho người nghỉ sáng
- Check-out buổi chiều (~18:00)
2. Phát hiện trường hợp đặc biệt
async function shouldProcessUser(user, timeOffRequests, checkTime) {
const userTimeOff = timeOffRequests.find(
(request) => request.userId === user.userId
);
if (!userTimeOff) {
switch (checkTime) {
case "9:15":
case "18:10":
return true;
default:
return false;
}
}
switch (checkTime) {
case "9:15":
return userTimeOff.timeOffType === "AFTERNOON";
case "11:55":
return userTimeOff.timeOffType === "AFTERNOON";
case "13:10":
return userTimeOff.timeOffType === "MORNING";
case "18:10":
return userTimeOff.timeOffType === "MORNING";
default:
return false;
}
}
Logic này quyết định xem ai cần được check-in vào thời điểm nào dựa trên lịch nghỉ phép.
3. Random hóa thời gian check-in để tăng tính tự nhiên
async function getRandomDelayWithMinDiff(min, max, checkTime, minDiff) {
// Logic tính toán thời gian delay ngẫu nhiên
// nhưng đảm bảo không quá khác biệt giữa các lần
// Lưu lại thời gian delay để tham khảo cho lần sau
await LastDelay.create({
date: todayISO,
checkTime: checkTime,
delay: newDelay,
});
return newDelay * 1000;
}
Hệ thống còn thông minh đến mức tạo độ trễ ngẫu nhiên cho mỗi lần check-in để tránh mọi người check-in cùng một thời điểm, làm tăng tính tự nhiên.
4. Bot Telegram - Trái tim của hệ thống
// Các lệnh chính của bot
this.bot.command("start", async (ctx) => {
return startHandler(ctx);
});
this.bot.command("login", async (ctx) => {
return LoginHandler.handle(ctx, this);
});
this.bot.command("request_off", checkAuth, async (ctx) => {
return RequestOffHandler.handleRequestOff(ctx, this);
});
this.bot.command("my_days_off", checkAuth, async (ctx) => {
return listRequestsHandler(ctx, this);
});
this.bot.command("cancel_request_off", checkAuth, async (ctx) => {
return RequestOffHandler.handleCancelRequest(ctx, this);
});
Bot Telegram là giao diện chính giúp người dùng:
- Đăng nhập và lưu thông tin tài khoản Base
- Đăng ký ngày nghỉ theo lịch (cả ngày, buổi sáng, buổi chiều)
- Quản lý và hủy các yêu cầu nghỉ phép
- Xem lịch nghỉ phép đã đăng ký
5. Bảo mật là ưu tiên hàng đầu
// Mã hóa mật khẩu trước khi lưu vào database
const encrypt = (text) => {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(algorithm, secretKey, iv);
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
return {
iv: iv.toString("hex"),
content: encrypted.toString("hex"),
};
};
// Giải mã khi cần sử dụng
const decrypt = (hash) => {
const decipher = crypto.createDecipheriv(
algorithm,
secretKey,
Buffer.from(hash.iv, "hex")
);
const decrypted = Buffer.concat([
decipher.update(Buffer.from(hash.content, "hex")),
decipher.final(),
]);
return decrypted.toString();
};
Mọi mật khẩu người dùng đều được mã hóa AES-256-CTR trước khi lưu vào database, đảm bảo an toàn tuyệt đối!
Khi mọi thứ hoạt động: The "Wow" moment 🎉
Sau khi triển khai phiên bản đầu tiên, phản ứng ban đầu có vẻ nghi ngờ:
"Cái bot này có thực sự check-in được không?" "Liệu có bị phát hiện là tự động không?" "Mật khẩu của mình có an toàn không?"
Nhưng sau 3 tháng hoạt động, bot hoạt động khá hiệu quả và ổn định 😊 UrCheckin đã trở thành người bạn không thể thiếu của team TECH:
- Tiết kiệm khoảng 5 giờ/tháng cho cả team (tính cả thời gian tạo và duyệt request)
- Giúp mọi người loại bỏ nỗi lo 'Hôm nay mình đã chấm công chưa nhỉ?' 🤪
- Tạo một cảm giác đi làm không phải để chấm công mà để cống hiến và khám phá ^^
Next steps và ý tưởng tương lai
Hiện tại UrCheckin vẫn còn những vấn đề sau chưa được giải quyết:
- Mọi người vẫn phải tạo request thủ công(vào bot để tạo) khi ngày nào đó muốn nghỉ/remote
- Vẫn cần phải tạo request off/remote trên ứng dụng Base
Tớ vẫn đang phát triển để giải quyết các vấn đề này, hy vọng sẽ sớm có những cải tiến đầy thú vị 🥴
Đôi khi những vấn đề nhỏ trong công việc hàng ngày lại là cơ hội để tạo ra những giải pháp sáng tạo. UrCheckin ra đời từ nỗi trăn trở "quên chấm công" quen thuộc nhưng đã trở thành công cụ không thể thiếu của team chúng tớ.
Bạn có gặp vấn đề tương tự không? Hoặc có ý tưởng nào để cải thiện? Hãy chia sẻ trong phần bình luận nhé! 🚀
GitHub Repository: dongitran/UrCheckin