Book Sân Tập: xây một marketplace hai chiều từ một nỗi bực mình cá nhân
Sản phẩm thứ ba của tôi giải quyết đúng vấn đề tôi tự gặp phải: đặt sân thể thao sao cho nhanh, không nhầm lịch. Đây là cách tôi làm.
Mở đầu: vì sao tôi muốn làm
Hai sản phẩm đầu (content-factory-web, cv-nhanh-web) đều bắt đầu từ việc quan sát người khác gặp khó khăn. Book Sân Tập thì khác — nó bắt đầu từ chính sự bực mình của tôi. Muốn đặt một sân cầu lông hay sân bóng vào cuối tuần, tôi phải nhắn tin qua lại với chủ sân, chờ xác nhận, và không ít lần bị trùng lịch vì chủ sân quản lý bằng sổ tay hoặc một cuốn Excel.
Tôi muốn xây một marketplace thật — không phải một chiều (chỉ người chơi), mà hai chiều: người chơi tìm và đặt sân, chủ sân quản lý lịch và doanh thu. Đây cũng là sản phẩm phức tạp nhất trong ba sản phẩm, vì có bài toán khó thực sự: hai người bấm đặt cùng một khung giờ cùng lúc, ai được ưu tiên?
Thân bài: các bước thực hiện và công cụ
Bước 1 — Giảm ma sát cho người chơi tối đa có thể. Tôi thiết kế để duyệt và tìm sân không cần đăng nhập — chỉ bắt đăng ký đúng lúc người dùng bấm "Đặt sân". Để không làm mất luồng thao tác của họ, tôi giữ context qua tham số ?next= xuyên suốt đăng ký → OTP → đăng nhập, để sau khi xong họ quay lại đúng trang đang xem, không phải tìm lại từ đầu.
Bước 2 — Giải bài toán double-booking triệt để. Đây là phần tôi dành nhiều thời gian nhất. Tôi dùng transaction BEGIN IMMEDIATE ở tầng database để khoá đúng lúc kiểm tra và ghi nhận một lượt đặt sân, đảm bảo hai người không thể cùng đặt trùng một khung giờ dù họ bấm nút gần như đồng thời. Tôi test lại bằng cách mô phỏng race condition thật (nhiều request bắn đồng thời) trước khi tin tưởng đưa vào production.
Bước 3 — Để chủ sân khai lịch trống bằng ngôn ngữ tự nhiên. Thay vì bắt chủ sân điền form phức tạp (giờ mở, giờ đóng, ngày nghỉ, giá theo khung giờ), tôi cho họ gõ kiểu "sáng thứ 2 đến thứ 6 mở từ 6h đến 9h, cuối tuần mở cả ngày", và dùng Claude (mô hình nhẏ, nhanh, chi phí thấp) để đọc hiểu và chuyển thành dữ liệu lịch. Nhưng tôi luôn hiện lại thẻ xác nhận bằng tiếng Việt trước khi lưu — không bao giờ để AI tự quyết định âm thầm, và vẫn giữ một form nhập tay dự phòng nếu chủ sân không quen gõ tự nhiên.
Bước 4 — Tính khoảng cách và định vị mà không phụ thuộc hoàn toàn vào một dịch vụ trả phí. Tôi tích hợp Goong Maps để geocode địa chỉ sân, nhưng có sẵn phương án dự phòng bằng toạ độ nhập tay và công thức Haversine để tính khoảng cách — để sản phẩm vẫn chạy được ngay cả khi chưa có ngân sách cho API trả phí.
Bước 5 — Tái dùng lại khung đăng ký/OTP/ví/Telegram từ hai sản phẩm trước, nhưng lần này tách domain, bot Telegram, và deploy key SSH hoàn toàn riêng — vì đây là một thương hiệu độc lập, không muốn có bất kỳ rủi ro chéo nào giữa các sản phẩm.
Công cụ chính đã dùng: Claude Code, Claude (mô hình nhỏ, nhanh) để đọc hiểu lịch trống dạng văn bản tự nhiên, FastAPI + SQLite với transaction có kiểm soát, Goong Maps API, VPS Hetzner với domain và bot Telegram riêng cho từng sản phẩm.
Kết: nếu bạn muốn biết chi tiết hơn
Bài toán double-booking hay việc để AI đọc hiểu lịch trống bằng ngôn ngữ tự nhiên đều có nhiều cách làm khác nhau, mỗi cách có đánh đổi riêng. Nếu bạn đang xây một sản phẩm có tính chất đặt chỗ / đặt lịch và muốn trao đổi kỹ hơn về cách xử lý, cứ liên hệ mình qua email hoặc LinkedIn nhé.