# ห้องรอคิวสำหรับการเปิดขายบัตรและแฟลชเซล

> วางคิวที่ยุติธรรมและอัปเดตแบบเรียลไทม์ไว้หน้าการขาย ผู้เข้าชมเห็นลำดับของตัวเองขยับ เข้าได้ตามอัตราที่คุณตั้ง และเว็บไซต์ของคุณตรวจพาสที่มีลายเซ็น ใช้ได้กับทุกโฮสต์ รวมถึง Laravel และ Filament

Source: https://hibira.io/th/use-cases/waiting-room

การเปิดขายบัตร สินค้าลิมิเต็ด หรือการเปิดพรีออร์เดอร์ ทำให้ทราฟฟิกทั้งวันมากองอยู่ในนาทีแรกของการขาย ระบบปรับขนาดอัตโนมัติตอบสนองไม่ทัน การชำระเงินช้าลงสำหรับทุกคน และสุดท้ายคนที่เน็ตเร็วที่สุดเป็นผู้ชนะ ห้องรอคิวจะตั้งแถวที่สงบและยุติธรรมไว้หน้าหน้าเว็บที่คนแน่น ผู้เข้าชมรับหมายเลขคิว ดูแถวขยับแบบเรียลไทม์ และเข้ามาตามอัตราที่เว็บไซต์ของคุณรับไหว สมัครและตั้งค่าได้เอง ไม่ต้องคุยกับฝ่ายขาย และไม่ต้องย้ายโฮสต์หรือ CDN

## สิ่งที่ผู้เข้าชมได้รับ

- หมายเลขคิวและข้อความ "มีคนรออยู่ข้างหน้า 4,812 คน" ที่อัปเดตแบบเรียลไทม์ระหว่างรอ
- รีเฟรชหรือเปิดแท็บเพิ่มก็ไม่ทำให้เสียคิวหรือได้คิวเร็วขึ้น
- หน้ารอคิวแบบโฮสต์ให้ รองรับภาษาอังกฤษ จีนตัวเต็ม จีนตัวย่อ ญี่ปุ่น เกาหลี ไทย และเวียดนาม
- การนับถอยหลังที่ชัดเจนก่อนเริ่มขาย และข้อความ "ขายหมดแล้ว" ที่ชัดเจนเมื่อจบ

![หน้ารอคิวแบบโฮสต์ให้: ลำดับคิว จำนวนคนข้างหน้า เวลารอโดยประมาณ และประกาศของร้าน แสดงเป็นภาษาของผู้เข้าชม](https://hibira.io/portal/articles/waitroom-page-th-light.webp)

## สิ่งที่คุณได้รับ

- แถวที่ขยับตามอัตราที่คุณตั้ง เช่น 300 คนต่อนาที
- ปุ่มสำหรับช่วงเวลาสำคัญ: หยุดแถวชั่วคราว ให้ 500 คนเข้าทันที และปิดเมื่อสต็อกหมด
- ผู้เข้าชมที่ได้เข้าแต่ละคนจะได้พาสที่มีลายเซ็น ซึ่งเว็บไซต์ของคุณตรวจก่อนแสดงหน้าที่ป้องกันไว้ ใครเดา URL ก็แซงคิวไม่ได้
- ถ้าต้องการ ใช้ ticket ID ในพาสเพื่อให้หนึ่งหมายเลขคิวชำระเงินได้ครั้งเดียว
- ผู้ที่รอคิวไม่นับรวมในจำนวนการเชื่อมต่อของแอป ฟีเจอร์เรียลไทม์อื่นบนเว็บไซต์จึงยังมีที่ว่างพอในช่วงคนแน่น
- ประกาศถึงทุกคนในคิว เช่น "โซน A ขายหมดแล้ว" แสดงบนหน้ารอคิวทันที

![ห้องรอคิวในพอร์ทัล: จำนวนคนแบบเรียลไทม์ อัตราการปล่อยเข้า เวลาที่คิวจะหมด และปุ่มหยุดชั่วคราว ปล่อยเข้า ขายหมด และประกาศ](https://hibira.io/portal/articles/waitroom-console-th-light.webp)

ห้องรอคิวเป็นส่วนเสริมที่เพิ่มได้กับทุกแผนของ Hibira ใช้ฟรี 1 ห้อง และผู้เข้าคิว 5,000 คนต่อเดือน แผนแบบชำระเงินเริ่มที่ $29 ต่อเดือน และบัตรอีเวนต์ครั้งเดียว $49 ใช้ได้ 72 ชั่วโมง ผู้เข้าชมที่เกินแผนจะหักจากเครดิต และไม่มีใครถูกปฏิเสธ ดู[ราคา](https://hibira.io/th/pricing#waiting-room)

## ใช้อะไรบ้าง

- **ห้องรอคิว** ในแอป Hibira ของคุณ จัดการได้จากพอร์ทัลหรือด้วยการเรียก HTTP API ที่มีลายเซ็น
- **หน้ารอคิวแบบโฮสต์ให้** `ws.hibira.io/wait/APP_KEY/ROOM` หรือหน้าของคุณเองด้วย [@hibira-io/waiting-room](https://www.npmjs.com/package/@hibira-io/waiting-room)
- **cache channel** หนึ่งช่องต่อห้อง (`cache-waitroom-ROOM`): ข้อความเดียวบอกผู้ที่รอทุกคนว่าแถวขยับไปถึงไหน แล้วแต่ละเบราว์เซอร์คำนวณลำดับของตัวเอง
- **พาส** ที่ลงลายเซ็นด้วย app secret ของคุณ (HMAC-SHA256) เว็บไซต์ของคุณตรวจเองได้โดยไม่ต้องเรียก Hibira

```text
flow: ผู้เข้าชมที่ไม่มีพาสต้องเข้าคิว เมื่อถึงคิวจะกลับมาพร้อมพาสที่มีลายเซ็น
ผู้เข้าชม|เปิด /drop --ไม่มีพาส: เปลี่ยนเส้นทาง--> *Hibira|หน้ารอคิวแบบโฮสต์ให้ --ถึงคิว: `?hibira_pass=…`--> เว็บไซต์ของคุณ|ตรวจพาส ตั้ง cookie
== ทำให้แถวขยับ
ทีมของคุณ|พอร์ทัล Filament หรือ API --เปิด หยุด ปล่อยเข้า ปิด--> *Hibira|cache-waitroom-presale --อัปเดตครั้งเดียว--> ผู้ที่รอทุกคน|คำนวณลำดับของตัวเอง
```

## เลือกวิธีเชื่อมต่อ

เลือกตามที่ที่เว็บไซต์ของคุณทำงานอยู่ ยิ่งอยู่สูงในรายการ ยิ่งเลี่ยงได้ยาก

| เว็บไซต์ทำงานที่ไหน | เชื่อมต่ออย่างไร | ตรวจตอนไหน |
| --- | --- | --- |
| Cloudflare Workers, Next.js บน Vercel, Deno, Bun | `protect()` จาก [@hibira-io/waiting-room](https://www.npmjs.com/package/@hibira-io/waiting-room) | ก่อนส่งหน้าเว็บ |
| เซิร์ฟเวอร์ของคุณเอง: Express, Laravel และอื่น ๆ | middleware ที่ตรวจพาส | ก่อน route ทำงาน |
| หน้ารอคิวที่ทำเองทั้งหมด | `joinWaitingRoom()` ในเบราว์เซอร์ คู่กับการตรวจแบบใดแบบหนึ่งข้างบน | ก่อน route ทำงาน |
| แอป iOS, Android, Flutter หรือ Unity | endpoint สาธารณะของห้องรอคิว แล้วส่งพาสใน header ของ API | ใน API ของคุณ |
| ไม่มีแบ็กเอนด์ของตัวเอง (ร้านค้าแบบโฮสต์) | หน้ารอคิวแบบโฮสต์ให้ บวกการตรวจพาสตอนชำระเงิน | ตอนชำระเงิน |

## ขั้นที่ 1: สร้างห้อง

สร้างในพอร์ทัล หรือด้วยคำขอ HTTP API ที่ลงลายเซ็นแบบเดียวกับการเผยแพร่อีเวนต์:

```http
POST /apps/APP_ID/waiting_rooms/presale
{
  "admit_per_minute": 300,
  "state": "paused",
  "starts_at": "2026-12-04T12:00:00+09:00",
  "title": "Winter tour presale",
  "return_urls": ["https://shop.example.com/"]
}
```

`open` ปล่อยคนเข้าตามอัตรา `paused` หยุดแถวไว้ และ `closed` หยุดแจกหมายเลขเมื่อขายหมด ผู้ที่มาก่อน `starts_at` จะได้หมายเลขและเห็นการนับถอยหลัง แถวจะเริ่มขยับเมื่อถึงเวลานั้น

## ขั้นที่ 2: ป้องกันหน้าเว็บที่ edge

บน Cloudflare Workers, middleware ของ Next.js, Deno หรือ Bun เรียกครั้งเดียวก็จบ:

```js
// middleware.js (Next.js)
import { NextResponse } from 'next/server';
import { protect } from '@hibira-io/waiting-room/server';

export async function middleware(request) {
  const blocked = await protect(request, {
    appKey: process.env.HIBIRA_KEY,
    secret: process.env.HIBIRA_SECRET,
    room: 'presale',
  });
  return blocked ?? NextResponse.next();
}

export const config = { matcher: ['/drop/:path*'] };
```

ผู้เข้าชมที่ไม่มีพาสจะถูกส่งไปหน้ารอคิว เมื่อถึงคิวจะกลับมาพร้อมพาส ซึ่ง `protect()` ตรวจแล้วเก็บไว้ใน HttpOnly cookie บน Express ให้ใช้ `expressWaitingRoom()` จากแพ็กเกจเดียวกัน

## ขั้นที่ 3: Laravel

ด้วย [hibira-io/laravel](https://hibira.io/th/guides/laravel) เวอร์ชัน 0.4 ขึ้นไป (ซึ่งคุณอาจใช้ทำ broadcasting อยู่แล้ว) สร้างห้องจากคำสั่ง แล้วป้องกัน route ด้วย middleware ตัวเดียว:

```shell
composer require hibira-io/laravel:^0.4
php artisan hibira:waiting-room presale create --rate=300 --title="Winter presale"
```

```php
Route::middleware('hibira.waiting:presale')->group(function () {
    Route::get('/drop', [DropController::class, 'show']);
    Route::post('/drop/checkout', [DropController::class, 'checkout']);
});
```

ผู้เข้าชมที่ไม่มีพาสจะถูกส่งไปหน้ารอคิวในภาษาเดียวกับแอปของคุณ พาสที่นำกลับมาจะถูกตรวจด้วย app secret ของคุณโดยไม่ต้องเรียก API และเก็บไว้ในคุกกี้ HttpOnly จนหมดอายุ คำขอ `POST` ที่ไม่มีพาสจะได้ `403` ใน controller อ่านพาสได้จาก request:

```php
$pass = $request->attributes->get('hibira_pass');
$pass->number;   // queue number
$pass->ticketId; // record it at checkout: one order per number
```

ควบคุมห้องได้จากโค้ด งานในคิว หรือ command line:

```php
use Hibira\Laravel\Facades\Hibira;

Hibira::waitingRoom('presale')->pause();
Hibira::waitingRoom('presale')->admit(500);
Hibira::waitingRoom('presale')->notice('Zone A is sold out');
Hibira::waitingRoom('presale')->close();
```

ระหว่างพัฒนาบนเครื่อง ตั้ง `HIBIRA_WAITING_ROOMS=false` เพื่อข้ามคิว

## ขั้นที่ 4: ควบคุมแถวจาก Filament

ในวันขาย ทีมของคุณไม่ต้องเปิดแดชบอร์ดเพิ่มอีก ด้วย [hibira-io/filament](https://hibira.io/th/use-cases/filament) เวอร์ชัน 0.5 ขึ้นไป บรรทัดเดียวก็เพิ่มหน้า "ห้องรอคิว" ให้แผงของคุณ:

```php
HibiraPlugin::make()->waitingRooms(
    authorize: fn ($user) => $user->is_admin,
)
```

หน้านี้แสดงจำนวนคนที่รอ ความคืบหน้าของคิว และอัตราการปล่อยเข้าของแต่ละห้องแบบเรียลไทม์ ทีมสามารถหยุดและเปิดคิว ปล่อยคนเข้าทันที โพสต์ประกาศ ปิดห้องเมื่อสินค้าหมด และสร้างหรือแก้ไขห้องได้จากหน้านี้ ถ้าไม่ใส่ `authorize` ผู้ใช้แผงทุกคนจะเข้าได้

## ขั้นที่ 5: หน้ารอคิวของคุณเอง

หน้าแบบโฮสต์ให้เหมาะกับเว็บไซต์ส่วนใหญ่ ถ้าต้องการให้ตรงกับแบรนด์ทุกจุด ก็สร้างเองได้:

```js
import { joinWaitingRoom } from '@hibira-io/waiting-room';

joinWaitingRoom({
  key: 'APP_KEY',
  room: 'presale',
  onUpdate: ({ ahead, etaMinutes }) => render(ahead, etaMinutes),
  onTurn: (turn) => turn.redirect('https://shop.example.com/drop'),
  onClosed: () => showSoldOut(),
});
```

ไคลเอนต์เก็บตั๋วของผู้เข้าชมไว้ในเบราว์เซอร์ รีเฟรชแล้วคิวจึงไม่หาย หากเปิดการเชื่อมต่อไม่ได้ จะเปลี่ยนไปเช็กสถานะทุกไม่กี่วินาทีแทน ไม่มีใครถูกกันไว้ข้างนอก

## ขั้นที่ 6: ในแอปของคุณ

ไคลเอนต์มือถือหรือเกมใช้ endpoint สาธารณะชุดเดียวกับหน้าแบบโฮสต์ให้: เข้าคิว ติดตาม cache channel ของห้อง ขอพาสเมื่อถึงหมายเลข แล้วส่งพาสไปกับการเรียก API API ของคุณตรวจพาสด้วย app secret โดยไม่ต้องเรียก Hibira บน Laravel ใช้ `WaitingRoom::verifyPass($pass, 'presale')`

```http
POST /waitroom/APP_KEY/presale/join         -> {"ticket": "…", "number": 5121}
GET  /waitroom/APP_KEY/presale              -> {"admitted": 4980, "state": "open", …}
POST /waitroom/APP_KEY/presale/pass         {"ticket": "…"}  -> {"pass": "…"}
```

## เทียบกับ Queue-it และ Cloudflare Waiting Room

|  | Hibira | Queue-it | Cloudflare Waiting Room |
| --- | --- | --- | --- |
| เริ่มต้นอย่างไร | สมัครและสร้างห้องได้เอง | ติดต่อฝ่ายขาย มีแพ็กเกจรายอีเวนต์ที่เปิดเผยราคาหนึ่งแบบ | ต้องใช้แผน Business หรือ Enterprise |
| เว็บไซต์ทำงานที่ไหน | โฮสต์ CDN หรือเฟรมเวิร์กใดก็ได้ | โฮสต์ใดก็ได้ ผ่าน connector ของเขา | ทราฟฟิกต้องผ่านพร็อกซีของ Cloudflare |
| ตั้งเวลาเริ่มพร้อมนับถอยหลัง | มี | มี | Enterprise |
| หลายห้อง | มี | มี | Enterprise พร้อมแอดออน Advanced |
| หน้ารอคิวของคุณเอง | มี ด้วยไคลเอนต์เบราว์เซอร์ขนาดเล็ก | มี | เทมเพลตกำหนดเองของ Enterprise |
| ควบคุมแถวจากระบบหลังบ้านของคุณ | ได้ เช่น หน้าใน Filament | แดชบอร์ดของเขา | แดชบอร์ดหรือ API ของ Cloudflare |

อ้างอิงหน้าราคาและแผนที่เปิดเผยต่อสาธารณะของแต่ละรายเมื่อพฤศจิกายน 2026 แผนอาจเปลี่ยนได้ โปรดตรวจสอบกับแต่ละรายก่อนตัดสินใจ

เปรียบเทียบฉบับเต็ม พร้อมราคาและกรณีที่แต่ละรายเหมาะกว่า: [Queue-it](https://hibira.io/th/compare/queue-it), [Cloudflare Waiting Room](https://hibira.io/th/compare/cloudflare-waiting-room), [CrowdHandler](https://hibira.io/th/compare/crowdhandler) และ [Queue-Fair](https://hibira.io/th/compare/queue-fair)

## เคล็ดลับ

- ป้องกันหน้าที่ของหมดได้จริง: หน้าสินค้า ตะกร้า และการชำระเงิน ปล่อยหน้าแรกและรูปภาพไว้นอกห้องรอคิว
- ตรวจพาสในคำขอที่สำคัญ ไม่ใช่แค่ในเบราว์เซอร์ ผู้เข้าชมแก้สคริปต์บนหน้าของตัวเองได้ แต่ปลอมลายเซ็นไม่ได้
- ถ้าหนึ่งหมายเลขคิวซื้อได้ครั้งเดียว ให้บันทึก ticket ID ของพาสตอนชำระเงิน และปฏิเสธคำสั่งซื้อที่สองที่ใช้ ID เดิม
- เปิดห้องก่อนเริ่มขาย 15 ถึง 30 นาทีและตั้ง `starts_at` ผู้ที่มาก่อนจะรอที่หน้านับถอยหลังแทนการกดรีเฟรชรัว ๆ บนเว็บไซต์ของคุณ
- เริ่มที่อัตราที่ระบบชำระเงินรับได้สบาย ๆ แล้วค่อยเพิ่มขณะดูอัตราข้อผิดพลาด การหยุดแถวชั่วคราวอยู่ห่างแค่คลิกเดียวเสมอ
