Korat
機能

飲食店の注文システム——店内QR、厨房、会計

飲食店の注文システムはテーブルから始まります。客は QR を読めばもうメニューの中にいます。店には厨房ディスプレイと、レジと一致する明細付きの伝票と、デリバリーのキューが入ります——送ってきた端末の言う値段を、一つも信用することなく。無料で、月額はありません。

飲食店の注文ソフトウェアはたいてい二つの場所で壊れます。見知らぬ他人が自分のものではないテーブルに注文できてしまう瞬間と、客の画面の合計とレジの合計が食い違う瞬間です。Korat の飲食モジュールは、その両方から逆算して設計しました。テーブルのセッションはスタッフが発行し、使い捨てのトークンを持ちます。伝票はレジが読むのと同じ行です。そして place_dining_order はすべての行をサーバーで値付けします。オプション、ビュッフェのタイマー、割り勘の画面は、この二つの保証の上に載っています。

テーブルの QR は使い捨てトークンであって、テーブル番号ではありません

「テーブル番号を入力する」経路は意図的に用意していません。それは作るのが当たり前の機能で、そして多くの店内オーダーが駐車場から悪用できる理由でもあります。資格情報がテーブルに印刷された番号だけなら、一度でもその店で食べた人は、以後ずっとどのテーブルにでも注文を出せます。代わりに、スタッフがコンソールからテーブルを開けます。開けるたびに新しい使い捨てトークンが発行され、そのテーブルに表示される QR に埋め込まれます。撮影した QR、友だちに転送されたスクリーンショット、先週火曜の印刷物が運んでいるのは、もう現行ではないトークンです。動きません。

テーブルに歩み寄った客は、その店のメンバーでもなければ、まだ存在しないセッションのホストでもありません。だから行レベルセキュリティのもとでは dining_sessions テーブルを一行も読めません——自分の行も、他の誰の行も。RLS は誰が呼んでいるかは判定できますが、リクエストが有効なトークンを持っていることは判定できません。そこでスキャンは join_session_by_token を通ります。トークンをサーバー側で照合し、最初にスキャンした人をホストにし、一致しなければ理由を言わずに null を返す SECURITY DEFINER 関数です。「トークンが違う」と「期限切れ」を区別するエラーは、当てものの神託になります。

中に入れば、ホストはリンクかチャットのカードで同席者を招けます。遅れて来た友だちも同じセッションに入り、その料理は同じ伝票に載ります。

テーブルの QR は https のリンク——アプリでもウェブでも開きます

テーブルの QR は https の URL で、アプリ専用のスキームではありません。 Korat が入っている端末はドメイン検証済みの App Link でアプリを開き、入っていない端末——iPhone を含めて——はウェブの注文ページを開きます。これは製品全体でいちばん死んでいた瞬間の修正です。客が席に着き、カメラを構えてスキャンし、そして何も起きない。そのページはサインインしていない状態でメニュー、ビュッフェの残り時間、酒類の判定をすべて読み、注文を実際に送る瞬間——避けようのない唯一の瞬間——にだけサインインを求めます。古い korat://dine を載せて既に印刷された QR も、これからずっとスキャンできます。

注文——オプション、備考、そして閉店を知っているメニュー

メニューはカテゴリで整理され、どの品目にもオプショングループを持たせられます。追加のショット、辛さの段階、麺の種類。それぞれに価格差、必須かどうか、選べる最大数が付きます。価格差は備考欄に手書きするのではなくオプションに紐づくので、厨房の伝票と会計の行が、何が注文されたかについて一致します。品目には自由記入の備考と数量も付けられ、カートは送信するまで編集できます。

営業時間、ラストオーダー、そして酒類の年齢確認

店は営業時間とラストオーダーの余裕時間を設定します。近づけばメニューが「もうすぐ厨房が閉まります」と警告し、過ぎれば注文は受け付けたあとで静かに取り消されるのではなく、その場でブロックされます。品切れや取り扱いなしの品目は、タップする前にカード上でそう言います。酒類には専用のフラグがあり、客の生年月日による年齢確認と、スタッフがセッションごとまとめて年齢確認する手段があります。

確認キュー——人が「はい」と言うまで厨房には何も届きません

送信された注文は、そのまま調理場には行きません。厨房ディスプレイの「確認待ち」のキューに入り、スタッフが一件ずつ承認するか却下してから仕事になります。端末から厨房に伝票を直接入れられるシステムは、見知らぬ他人に店の食材を消費させる力を渡していますし、6番テーブルがうっかり同じセットを4つ頼んだことに人間が気づく瞬間を消しています。

厨房ディスプレイからスタッフは注文の状態を進めます。コンソールには数秒ごとに更新されるライブのバッジ——進行中の注文、スタッフを呼んでいるテーブル、未確認の予約、新しいデリバリー——が並び、テーブルが呼び出しを押した瞬間に赤いバナーが出ます。客側にはその輪の反対側があります。スタッフを呼ぶ、会計を頼む、席を立つ。

ライブの明細伝票と、PromptPay QR での割り勘

ライブの伝票は、レジが読むのとまったく同じ行を、料理が確認されるたびに更新して表示します。食後の答え合わせも、記憶からの再構成もありません。テーブルが閉じるとアプリは締めのシートを出し——同席した人を友だちに追加するかどうかの提案を含みます——あとからレビューの案内が来ます。レシートは自分の会計履歴に残ります。

割り勘——自分はいくら払うのか

割り勘の画面は、人が実際に揉める問いに答えます。自分はいくら払うのか。各自に、自分のアラカルト分の小計と、そのテーブルのビュッフェ代の均等割りが表示されます。金額に対して PromptPay の QR を生成でき、CRC-16 チェックサム付きのタイ標準 QR 形式です。

割り勘は内訳であって、別々の決済ではありません。 各自の負担額を計算しますが、4人分のカードに4つの請求を立てるわけではありません。お金を分けるのは、あくまでテーブルの人たちと店のあいだで行われます。

そして「テーブル番号を入力する」逃げ道は、意図的にありません。客の QR が読めないときは、スタッフがコンソールからテーブルを開け直します。手入力の経路を足すことは、トークンが塞ぐために作られた穴を、そのまま返すことです。

ビュッフェ——一人あたりのパッケージ、タイマー、食べ残しの課金

ビュッフェは、一人前いくらのメニュー品目で偽装するのではなく、専用のモデルを持っています。パッケージには一人あたりの価格、スタッフが延長できるカウントダウンタイマー、そして大人と子どもの別々の人数があります。メニューの品目にはビュッフェ上の役割——込み、アラカルト専用、追加料金つきで込み——が付くので、一つのメニューで両方の客をさばけます。食べ残しの課金も単位ラベル付きで扱えます。タイのビュッフェの多くがすでに卓上に掲示していて、ソフトウェアの多くが存在しないふりをしているルールです。

デリバリー、テイクアウト、テーブル予約

同じメニューがデリバリーとテイクアウトも支えます。注文は配送料、業者、指定の受け取り時刻、住所を持ち、新規 → 調理中 → 配達中 → 完了と進み、遷移のたびに両側に通知が飛びます。テーブル予約は日付、時刻、人数、備考を取り、店の確認を待ちます。未確認の件数はダッシュボードにライブのバッジとして出ています。

値段はすべてサーバーで計算されます

残り全部を安全にしているルールがこれです。クライアントは決して価格を決めません。place_dining_orderplace_shop_order は品目の価格、オプションの価格差、配送料をデータベースから読み、端末が送ってきた値を無視します。信用されたクライアントの項目は、セルフサービスの割引です。同じ原則がレビューにも及びます。店内で食べた、あるいはデリバリーを注文したとデータベースが証明できる客だけが書けて、星の評価はトリガーが再計算します。誰かが入力する数字ではありません。

席に着かせずに番号だけ配りたいお店は順番待ちを見てください。厨房の外で売るもの(持ち帰り、物販、作り置き)はネットショップ側で、店内と同じ在庫を読みます。

厨房とホールの今日の出勤と休みはマイ職場の同じシフト表から来ます。実際に動くお店を初めて開くところは店舗のかたへのページです。

よくある質問

テーブルの QR を読まずに注文できますか。

店内オーダーではできません。テーブル番号の手入力はありません。印刷された番号は、いずれ町じゅうが持つ資格情報だからです。スタッフがコンソールからテーブルを開け、それが QR の運ぶトークンを発行します。

デリバリーとテイクアウトは逆で、テーブルを介さず店舗ページから注文します。

うちのテーブル QR を撮影して、あとから注文されるのを何が防ぎますか。

QR の中のトークンは使い捨てで、スタッフが開けたセッションに紐づいています。そのセッションが終われば、トークンはもう一致せず、スキャンは何にも解決しません。この照合はアプリではなく SECURITY DEFINER のデータベース関数で行われるので、API を直接叩いても迂回できません。

注文はそのまま厨房に行きますか。

行きません。すべての注文はまず厨房ディスプレイの確認待ちキューに入り、スタッフが承認か却下をします。その確認の一手間が、間違いや悪用が食材の損失になる前に捕まる場所です。

テーブルの各自が自分の分をカードで払えますか。

できません。割り勘の画面が計算するのは各自の負担額——自分の品と、ビュッフェ代の均等割り——であって、支払いは店との間で完結します。Korat は一人ずつのカード決済を処理しません。

閉店ぎりぎりに客が注文したらどうなりますか。

店は営業時間と、そのうえでラストオーダーの余裕時間を設定します。余裕時間に入るとアプリが「厨房はまもなく閉まります」と警告し、過ぎたあとは、いったん受け付けてからキャンセルするのではなく注文自体を止めます。

テーブルを開けて、一周させてみる

客側とコンソール側は同じアプリです。入れて、ビジネスを作って、自分の QR を読んでみてください。