Hệ thống tạo QR động: một mã QR in ra, nội dung sửa được mãi mãi, kèm thống kê lượt quét.
Mỗi QR động chứa URL http://localhost:3000/q/<short_code>. Khi ai đó quét, hệ thống tra
short code, ghi log lượt quét bất đồng bộ (không làm chậm), rồi tuỳ loại nội
dung mà redirect 302 tới đích hoặc render landing page. Vì QR chỉ chứa short code nên đổi nội
dung bao nhiêu lần cũng được — mã đã in vẫn dùng tốt.
Chưa có dữ liệu demo. Chạy npm run seed để tạo sẵn mỗi loại một QR mẫu, các link
"Xem demo" bên dưới sẽ hiện ra.
Trỏ tới một URL bất kỳ. Sửa URL đích lúc nào cũng được mà QR đã in không đổi.
qrType: "website"
{
"targetUrl": "https://example.com"
}
Landing page xem PDF inline kèm nút tải xuống.
qrType: "pdf"
views/pdf.hbs
{
"fileId": "<file_id>",
"title": "Brochure 2026",
"description": "Mô tả ngắn"
}
Trang kiểu Linktree: avatar, bio và danh sách nút link theo thứ tự.
qrType: "list_of_links"
views/list-of-links.hbs
{
"title": "CouponGather",
"bio": "Tất cả liên kết của chúng tôi",
"links": [
{
"label": "Website",
"url": "https://example.com"
}
]
}
Danh thiếp điện tử, nút "Lưu vào danh bạ" sinh file .vcf on-the-fly.
qrType: "vcard"
views/vcard.hbs
{
"fullName": "Nguyễn Văn A",
"phone": "+84901234567",
"company": "CouponGather"
}
Trang giới thiệu doanh nghiệp: logo, ảnh bìa, liên hệ, giờ mở cửa, bản đồ.
qrType: "business"
views/business.hbs
{
"businessName": "CouponGather JSC",
"phone": "19001234",
"openingHours": {
"mon": [
{
"open": "08:00",
"close": "17:30"
}
]
}
}
Video upload (stream có tua được) hoặc nhúng YouTube/Vimeo.
qrType: "video"
views/video.hbs
{
"videoSourceType": "youtube",
"externalUrl": "https://youtube.com/watch?v=xxxxxxxxxxx",
"title": "Video giới thiệu"
}
Gallery ảnh dạng lưới, click mở lightbox phóng to.
qrType: "images"
views/images.hbs
{
"title": "Album sự kiện",
"images": [
{
"fileId": "<file_id>",
"caption": "Ảnh 1"
}
]
}
Redirect tới fanpage, có validate URL bắt buộc thuộc facebook.com.
qrType: "facebook"
{
"pageUrl": "https://facebook.com/coupongather"
}
Redirect tới profile — nhập username là đủ, hệ thống tự dựng URL.
qrType: "instagram"
{
"username": "coupongather"
}
Gom nhiều mạng xã hội vào một QR, hiển thị danh sách để người quét chọn.
qrType: "social_media"
views/social-media.hbs
{
"title": "Kết nối với chúng tôi",
"socialLinks": [
{
"platform": "facebook",
"url": "https://facebook.com/coupongather"
}
]
}
Mở chat wa.me kèm tin nhắn soạn sẵn. Có thể tạo dạng tĩnh (isDynamic: false).
qrType: "whatsapp"
{
"phoneNumber": "84901234567",
"prefilledMessage": "Xin chào"
}
Trình phát audio HTML5, stream hỗ trợ tua, kèm ảnh bìa và nút tải.
qrType: "mp3"
views/mp3.hbs
{
"fileId": "<file_id>",
"title": "Nhạc chờ",
"artist": "CouponGather"
}
Menu nhà hàng chia theo danh mục, mỗi món có ảnh, mô tả và giá.
qrType: "menu"
views/menu.hbs
{
"restaurantName": "Quán Cơm Demo",
"categories": [
{
"name": "Đồ uống",
"items": [
{
"name": "Cà phê sữa",
"price": 25000
}
]
}
]
}
Đọc User-Agent: iPhone vào App Store, Android vào Google Play, desktop hiện trang chọn.
qrType: "apps"
views/apps.hbs
{
"appName": "CouponGather App",
"iosUrl": "https://apps.apple.com/app/id123456789",
"androidUrl": "https://play.google.com/store/apps/details?id=vn.coupongather"
}
Hiển thị mã giảm giá + nút sao chép, tự đánh dấu "hết hạn" theo expiry_date.
qrType: "coupon"
views/coupon.hbs
{
"couponCode": "DEMO2026",
"title": "Giảm 20%",
"discountValue": "20%",
"expiryDate": "2026-12-31T00:00:00.000Z"
}
QR tĩnh 100%: encode thẳng chuỗi WIFI: vào mã, quét là kết nối. Không cần short code, không tính vào giới hạn QR động.
qrType: "wifi"
{
"ssid": "Cafe WiFi",
"password": "matkhau123",
"encryptionType": "WPA"
}
| Method | Đường dẫn | Auth | Ghi chú |
|---|---|---|---|
| POST | /auth/register |
public | Đăng ký tài khoản |
| POST | /auth/login |
public | Trả access + refresh token |
| POST | /auth/refresh |
public | Làm mới access token |
| GET | /auth/me |
JWT | Thông tin user hiện tại |
| GET | /qr-codes |
JWT | Lọc ?qrType= &search= &page= &limit= |
| POST | /qr-codes |
JWT | Body: name, qrType, content |
| GET | /qr-codes/:id |
JWT | Kèm nội dung chi tiết |
| PATCH | /qr-codes/:id |
JWT | Sửa nội dung, giữ nguyên short code |
| DELETE | /qr-codes/:id |
JWT | Xoá QR và toàn bộ dữ liệu liên quan |
| GET | /qr-codes/:id/image |
JWT | ?format=svg|png&size=512 |
| GET | /qr-codes/:id/analytics |
JWT | ?from= &to= |
| GET | /analytics/overview |
JWT | Tổng hợp mọi QR của user |
| POST | /files/upload |
JWT | multipart file + ?fileType= |
| GET | /files/:id/raw |
public | Hỗ trợ HTTP Range |
| GET | /q/:shortCode |
public | Redirect / landing page + ghi log quét |
| GET | /q/:shortCode/vcard.vcf |
public | Sinh vCard on-the-fly |
# 1. Lấy access token
curl -X POST http://localhost:3000/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"[email protected]","password":"demo12345"}'
# 2. Tạo QR website (dán token vào $TOKEN)
curl -X POST http://localhost:3000/qr-codes \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"Landing page","qrType":"website","content":{"targetUrl":"https://example.com"}}'
# 3. Tải ảnh QR về (dùng id trả về ở bước 2)
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:3000/qr-codes/$ID/image?format=png&size=512" -o qr.png