Vietnam Nails là tiệm nail của người Việt tại Phần Lan. DNT Digital xây dựng cho tiệm một hệ thống ba phần dùng chung một API: web đặt lịch, trang quản trị cho chủ tiệm và ứng dụng di động Flutter cho khách. Bài này tập trung vào phần app mobile — vì sao phải làm app dù đã có web, phạm vi app gồm những gì, những quyết định kỹ thuật nào quyết định chất lượng, và những gì chúng tôi làm lại nếu có cơ hội thứ hai.

Bối cảnh: khi nào web đã đủ và khi nào cần thêm app

Tiệm nail ở Phần Lan vận hành khác tiệm trong nước ở năm điểm:

  1. Khách đặt lịch qua tin nhắn và điện thoại — giờ cao điểm không ai nghe máy, lịch ghi tay dễ trùng.
  2. Hai nhóm khách, hai ngôn ngữ — khách bản địa cần tiếng Phần Lan, khách người Việt cần tiếng Việt, nhân viên cần đọc được cả hai.
  3. Giá không đồng nhất — mỗi kỹ thuật viên có bậc tay nghề và giá riêng cho cùng một dịch vụ.
  4. Hoa hồng, lương tính tay cuối kỳ — doanh thu trừ phần chủ tiệm rồi chia theo tỉ lệ từng người.
  5. Khách quên lịch — không có ai nhắc, mất doanh thu của khung giờ đã giữ.

Web đặt lịch giải quyết (1) và (3). Nhưng có một nhóm khách quay lại mỗi 3–4 tuần — với họ, việc mở trình duyệt, tìm lại link, đăng nhập lại mỗi lần là ma sát thật. Đó là lý do làm app: không phải để thay web, mà để giữ nhóm khách quen.

Phạm vi app mobile

Nhóm chức năng Nội dung Ghi chú triển khai
Đặt lịch Chọn dịch vụ → chọn kỹ thuật viên → chọn khung giờ trống → xác nhận Khung giờ tính theo lịch thật của từng người, không phải lịch chung
Giá theo kỹ thuật viên Giá và thời lượng cập nhật ngay khi đổi người làm Cùng một công thức tính tiền với web và admin
Tài khoản khách Lịch sử đặt, điểm tích luỹ, hạng thành viên, voucher Ví và điểm nằm trong cùng một tài khoản
Thông báo đẩy Nhắc trước giờ hẹn, nhắc khách quay lại, thông báo huỷ/đổi Giảm hẳn số khách quên lịch
Thanh toán trong app Trả trước hoặc trả tại quầy Đối soát bằng mã lịch hẹn
Song ngữ Tiếng Phần Lan và tiếng Anh, lưu theo tài khoản Lần sau vào đúng ngôn ngữ đã chọn
QR check-in Quét mã tại quầy khi khách đến Khớp với chấm công nhân viên ở trang quản trị

Điều không đưa vào app: quản trị dịch vụ, bảng lương, báo cáo doanh thu. Những việc đó thuộc trang quản trị web — app chỉ phục vụ khách. Ranh giới này giữ app nhẹ và giảm bề mặt bảo mật.

Kiến trúc: một API cho ba giao diện

Khách                Chủ tiệm / lễ tân
  │                        │
  ├── Web React ───────────┤
  ├── App Flutter ─────────┤
  │                        │
  └────────► API chung ◄───┘
                 │
          PostgreSQL

Ba nguyên tắc:

  1. Không có logic nghiệp vụ nào nằm trong app. Giá, thuế, khuyến mãi, kiểm tra trùng lịch đều ở máy chủ. App chỉ hiển thị và gửi yêu cầu.
  2. Một công thức tính tiền dùng chung cho web, app và admin — nếu không, cùng một lịch hẹn sẽ hiện hai con số khác nhau, và khách sẽ phát hiện ra trước bạn.
  3. Chống trùng lịch ở tầng máy chủ, không dựa vào việc giao diện đã tải lại danh sách khung giờ hay chưa. Hai người bấm cùng lúc trên hai thiết bị vẫn phải chỉ một người thành công.

Năm quyết định kỹ thuật đáng chú ý

1. Chọn Flutter thay vì hai mã nguồn native. App phục vụ khách đặt lịch — nghiệp vụ form, danh sách, thanh toán — không cần hiệu năng đặc biệt. Một mã nguồn cho phép đội 2 người duy trì cả hai nền tảng; chi phí và thời gian bảo trì giảm gần một nửa so với native.

2. Lưu tiền bằng số nguyên cent. Giá tính bằng euro, có khuyến mãi phần trăm và chia hoa hồng. Dùng số thực (float) sẽ sinh sai số khi cộng dồn doanh thu và chia lương cuối kỳ. Toàn bộ hệ thống lưu int cent, chỉ định dạng khi hiển thị.

3. Thời lượng dịch vụ là dữ liệu, không phải hằng số. Một bộ nail có thể 60 phút với người mới, 45 phút với người có bậc cao. Thời lượng gắn với cặp (dịch vụ, kỹ thuật viên), cộng thêm thời lượng của các dịch vụ cộng thêm. Nhờ vậy khung giờ trống hiển thị đúng thực tế.

4. Đồng bộ danh mục từ hệ thống cũ (Timma). Tiệm đã có danh mục dịch vụ, giá và thời lượng trong phần mềm cũ. Chúng tôi viết phần đọc dữ liệu đó để ánh xạ sang hệ thống mới, kèm số lượt đặt để biết dịch vụ nào bán chạy — thay vì bắt chủ tiệm nhập lại vài trăm dòng.

5. Thông báo đẩy phải có đường lui. Khách có thể tắt thông báo, đổi máy, hoặc dùng bản Android không có Google Play Services. Vì vậy nhắc lịch vẫn có kênh dự phòng (SMS/Zalo) cho nhóm khách quan trọng, thay vì tin tuyệt đối vào push.

Kết quả

  • Khách tự đặt lịch 24/7, khung giờ trống hiển thị đúng người làm thật.
  • Lịch hẹn, ví, voucher và điểm tích luỹ nằm trong một tài khoản khách — có dữ liệu để mời khách quay lại.
  • Cuối kỳ chốt lương bằng một lần bấm thay vì dựng lại bảng tính tay.
  • Chủ tiệm nhìn được doanh thu theo ngày, theo nhân viên và theo dịch vụ.
  • App và web không bao giờ lệch giá, vì dùng chung một API và một công thức.

Nếu làm lại, chúng tôi sẽ làm khác gì

Đây là phần ít ai viết trong case study, nhưng hữu ích hơn cả phần kết quả:

  1. Làm web trước, app sau 4–6 tuần. Chúng tôi làm song song; nếu tuần tự, app sẽ thừa hưởng toàn bộ bài học từ web và ít phải sửa giao diện hơn.
  2. Chốt quy tắc huỷ/đổi lịch bằng văn bản ngay từ đầu. Đây là chỗ phát sinh nhiều câu hỏi nhất trong quá trình làm.
  3. Đo tỷ lệ dùng app ngay từ tháng đầu. Nếu chỉ 10% khách quen tải app, cần xem lại cách mời khách (QR tại quầy, ưu đãi riêng cho app).
  4. Kiểm thử trên máy Android cấu hình thấp sớm hơn. App chạy mượt trên máy cao cấp không nói lên điều gì về trải nghiệm thật của khách.

Công nghệ sử dụng

Flutter (Android) · React 18 + TypeScript (Vite, shadcn/ui, Tailwind) · Express + Drizzle ORM · PostgreSQL · một API dùng chung · Firebase Hosting cho web · Render cho máy chủ.

Liên quan