English | Tiếng Việt
Hệ thống bình chọn tính năng đa ngôn ngữ (Tiếng Anh và Tiếng Việt) cho phép người dùng đề xuất và bình chọn cho các tính năng mới. Dự án này sử dụng Cloudflare Workers làm backend và React làm frontend.
- 🌐 Hỗ trợ đa ngôn ngữ (Tiếng Anh và Tiếng Việt)
- 🗳️ Bình chọn cho các tính năng (ủng hộ/không ủng hộ)
- 🔒 Xác thực quản trị viên
- 📊 Thống kê và phân tích
- 💬 Bình luận về các tính năng
- 🔄 Đề xuất tính năng mới từ người dùng
- 📧 Thông báo email khi đề xuất được duyệt/từ chối
- 📱 Giao diện thân thiện với thiết bị di động
- 🛡️ Bảo vệ reCAPTCHA v3 (chống spam)
- Frontend: Vite + React + TypeScript + Tailwind CSS + shadcn/ui
- Backend: Cloudflare Workers + D1 (SQLite)
- Hosting: Cloudflare Pages (frontend) + Cloudflare Workers (API)
- CI/CD: GitHub Actions
- Thông báo: Telegram Bot API (tùy chọn)
- Email: Resend API hoặc SendGrid (tùy chọn, để thông báo người dùng)
- Bảo mật: Google reCAPTCHA v3 (chống spam)
Dự án được chia thành hai phần chính:
frontend/
├── public/ # Tài nguyên tĩnh và file localization
│ ├── _redirects # Cấu hình chuyển hướng cho Cloudflare Pages
│ └── locales/ # File ngôn ngữ (en, vi)
├── src/
│ ├── components/ # React components
│ ├── contexts/ # Context API (Auth, etc.)
│ ├── lib/ # Utilities và API client
│ ├── pages/ # Các trang chính
│ ├── App.tsx # Component chính
│ └── main.tsx # Entry point
└── vite.config.ts # Cấu hình Vite
worker/
├── src/
│ ├── db/ # Cấu trúc cơ sở dữ liệu và truy vấn
│ ├── handlers/ # Xử lý API endpoints
│ ├── middleware/ # Middleware (rate limiting, auth)
│ ├── utils/ # Tiện ích
│ └── index.ts # Entry point
├── setup-resources.sh # Script cài đặt tài nguyên Cloudflare
└── wrangler.toml # Cấu hình Cloudflare Workers
- Node.js 18+ và npm
- Tài khoản Cloudflare (cho Workers, D1 Database, và KV Storage)
- Tài khoản GitHub
- Bot Telegram (tùy chọn, cho thông báo)
git clone https://github.com/yourusername/feature-voting.git
cd feature-voting# Cài đặt dependencies cho frontend
cd frontend
npm install
# Cài đặt dependencies cho worker
cd ../worker
npm install- Đăng nhập vào Cloudflare CLI:
npx wrangler login- Chạy script cài đặt tài nguyên:
chmod +x setup-resources.sh
./setup-resources.shScript này sẽ tạo:
- D1 Database cho lưu trữ dữ liệu
- KV Namespace cho rate limiting
- Cài đặt các biến môi trường bí mật:
npx wrangler secret put ADMIN_TOKEN
# Nhập token quản trị viên của bạn
# reCAPTCHA v3 (bắt buộc để chống spam)
npx wrangler secret put RECAPTCHA_SECRET_KEY
# Nhập secret key reCAPTCHA từ https://www.google.com/recaptcha/admin
# Nếu bạn muốn thông báo qua Telegram (tùy chọn)
npx wrangler secret put TELEGRAM_BOT_TOKEN
npx wrangler secret put TELEGRAM_CHAT_ID
# Nếu bạn muốn gửi email (tùy chọn)
npx wrangler secret put RESEND_API_KEY# Tạo cơ sở dữ liệu từ schema
npx wrangler d1 execute feature-voting-db --file=./src/db/schema.sqlTạo file .env.local trong thư mục frontend:
cd frontend
cp .env.example .env.localChỉnh sửa .env.local và cập nhật các giá trị:
VITE_API_URL=http://localhost:8787
VITE_RECAPTCHA_SITE_KEY=your_recaptcha_site_key_here# Chạy worker backend
cd worker
npm run dev
# Trong terminal khác, chạy frontend
cd frontend
npm run devFrontend sẽ chạy tại http://localhost:5173 và worker backend sẽ chạy tại http://localhost:8787.
VITE_API_URL=http://localhost:8787 # URL của worker API (local development)
VITE_RECAPTCHA_SITE_KEY=your_recaptcha_site_key # Site key reCAPTCHA v3
Trong production, VITE_API_URL nên được đặt thành URL của worker đã triển khai, ví dụ:
VITE_API_URL=https://feature-voting-worker.yourdomain.workers.dev
VITE_RECAPTCHA_SITE_KEY=your_recaptcha_site_key
Hoặc nếu bạn sử dụng tên miền tùy chỉnh:
VITE_API_URL=https://api.idea.yourdomain.com
VITE_RECAPTCHA_SITE_KEY=your_recaptcha_site_key
Cấu hình trong wrangler.toml:
name: Tên của workerAPP_URL: URL của frontendRECAPTCHA_SITE_KEY: Site key công khai reCAPTCHA v3database_id: ID của D1 databaseid: ID của KV namespace
Biến môi trường bí mật (đặt bằng wrangler secret put):
ADMIN_TOKEN: Token xác thực quản trị viênRECAPTCHA_SECRET_KEY: Secret key reCAPTCHA v3 (bắt buộc)TELEGRAM_BOT_TOKEN: Token bot Telegram (tùy chọn)TELEGRAM_CHAT_ID: ID chat Telegram (tùy chọn)RESEND_API_KEY: API key cho dịch vụ email Resend (tùy chọn)TURNSTILE_SECRET_KEY: Secret key cho Cloudflare Turnstile (tùy chọn, chống spam)
Dự án này được cấu hình để triển khai tự động thông qua GitHub Actions khi có push vào nhánh main. Quá trình triển khai sử dụng Cloudflare Pages cho frontend và Cloudflare Workers cho backend.
Thêm các secrets sau vào repository GitHub của bạn:
CF_API_KEY: Cloudflare API key (Lấy từ Cloudflare Dashboard > My Profile > API Tokens > Create Token > Edit Cloudflare Workers template)CF_EMAIL: Email Cloudflare của bạn (Email đăng nhập vào tài khoản Cloudflare)CF_ACCOUNT_ID: ID tài khoản Cloudflare (Lấy từ Cloudflare Dashboard > Workers & Pages > Overview > Account ID)CF_D1_DATABASE_ID: ID của D1 database (Lấy từ Cloudflare Dashboard > Workers & Pages > D1 > Database > Database ID)CF_KV_NAMESPACE_ID: ID của KV namespace (Lấy từ Cloudflare Dashboard > Workers & Pages > KV > Namespace ID)ADMIN_TOKEN: Token quản trị viên (Tự tạo một chuỗi ngẫu nhiên an toàn)RECAPTCHA_SITE_KEY: Site key reCAPTCHA v3 (Lấy từ https://www.google.com/recaptcha/admin)RECAPTCHA_SECRET_KEY: Secret key reCAPTCHA v3 (Lấy từ https://www.google.com/recaptcha/admin)TELEGRAM_BOT_TOKEN: Token bot Telegram (Lấy từ BotFather trên Telegram, tùy chọn)TELEGRAM_CHAT_ID: ID chat Telegram (ID của chat hoặc channel để nhận thông báo, tùy chọn)RESEND_API_KEY: API key Resend (Lấy từ trang web Resend.com, tùy chọn)APP_URL: URL của ứng dụng frontend (Mặc định là https://idea.nginxwaf.me nếu không được đặt)
-
CF_API_KEY và CF_ACCOUNT_ID:
- Đăng nhập vào Cloudflare Dashboard
- Đi đến My Profile > API Tokens > Create Token
- Chọn template "Edit Cloudflare Workers"
- Sau khi tạo, sao chép token để sử dụng làm CF_API_KEY
- Để lấy CF_ACCOUNT_ID, vào Workers & Pages > Overview, Account ID sẽ hiển thị ở góc phải
-
CF_D1_DATABASE_ID:
- Trong Cloudflare Dashboard, đi đến Workers & Pages > D1
- Chọn database của bạn (hoặc tạo mới nếu chưa có)
- Database ID sẽ hiển thị trong trang chi tiết
-
CF_KV_NAMESPACE_ID:
- Trong Cloudflare Dashboard, đi đến Workers & Pages > KV
- Tạo namespace mới hoặc chọn namespace hiện có
- ID sẽ hiển thị trong danh sách namespace
-
RECAPTCHA_SITE_KEY và RECAPTCHA_SECRET_KEY:
- Truy cập Google reCAPTCHA Admin Console
- Nhấp "+" để đăng ký trang web mới
- Chọn "reCAPTCHA v3"
- Thêm các tên miền của bạn (ví dụ:
idea.nginxwaf.me,localhostđể test) - Sau khi đăng ký, sao chép Site Key (công khai) và Secret Key (bí mật)
- Thêm cả hai key vào GitHub Secrets
# Triển khai worker
cd worker
npm run deploy
# Triển khai frontend
cd frontend
npm run build
npx wrangler pages deploy dist --project-name=feature-voting-frontendDự án sử dụng Cloudflare D1 (SQLite) với các bảng sau:
features: Lưu trữ các tính năngusers: Thông tin người dùnguser_sessions: Phiên đăng nhậpfeature_suggestions: Đề xuất tính năng từ người dùngcomments: Bình luận về tính năngvotes: Lưu trữ phiếu bầu
Schema đầy đủ có thể được tìm thấy trong worker/src/db/schema.sql.
Ứng dụng này sử dụng Google reCAPTCHA v3 để bảo vệ chống spam và lạm dụng. Tất cả các form gửi đều được bảo vệ:
- Đăng nhập người dùng (yêu cầu magic link)
- Bình chọn (ủng hộ/không ủng hộ)
- Đề xuất tính năng
- Bình luận
- Hành động quản trị (tạo/cập nhật tính năng)
Tính năng chính:
- Ẩn Badge: Badge reCAPTCHA được ẩn hoàn toàn để tránh ảnh hưởng giao diện
- Dựa trên điểm số: Sử dụng điểm phân tích rủi ro (0.0 = bot, 1.0 = người thật)
- Ngưỡng có thể cấu hình: Điểm tối thiểu mặc định là 0.5 (có thể điều chỉnh trong
worker/src/utils/recaptcha.ts) - Giảm tải nhẹ nhàng: Nếu key chưa được cấu hình, xác minh sẽ bị bỏ qua với cảnh báo
Hướng dẫn cài đặt:
Xem RECAPTCHA_SETUP.md để biết hướng dẫn cài đặt chi tiết, bao gồm:
- Cách lấy key reCAPTCHA
- Các bước cấu hình
- Hướng dẫn khắc phục sự cố
- Yêu cầu thông báo quyền riêng tư
Lưu ý quan trọng:
- reCAPTCHA v3 yêu cầu HTTPS trong môi trường production
- Thêm tên miền của bạn vào bảng điều khiển quản trị reCAPTCHA
- Bao gồm thông báo quyền riêng tư: "Trang web này được bảo vệ bởi reCAPTCHA và Chính sách quyền riêng tư cũng như Điều khoản dịch vụ của Google được áp dụng."
- Cập nhật
APP_URLtrongwrangler.toml - Cập nhật
routestrongwrangler.tomlđể trỏ đến tên miền API của bạn - Cấu hình tên miền tùy chỉnh trong cài đặt Cloudflare Pages
- Tạo file ngôn ngữ mới trong
frontend/public/locales/ - Cập nhật schema cơ sở dữ liệu để thêm các trường ngôn ngữ mới
GET /api/features: Lấy danh sách tính năngPOST /api/features/:id/vote: Bình chọn cho tính năngGET /api/suggestions: Lấy đề xuất tính năngPOST /api/suggestions: Tạo đề xuất tính năng mới
POST /api/admin/features: Tạo tính năng mớiPUT /api/admin/features/:id: Cập nhật tính năngDELETE /api/admin/features/:id: Xóa tính năngGET /api/admin/stats: Lấy thống kêGET /api/admin/suggestions: Lấy đề xuất tính năng đang chờ xử lýPUT /api/admin/suggestions/:id/approve: Phê duyệt đề xuấtPUT /api/admin/suggestions/:id/reject: Từ chối đề xuất
Đóng góp luôn được chào đón! Vui lòng tạo issue hoặc pull request.
Apache License 2.0