かごいとの最初の道具は、演劇から生まれました。
きっかけは、知人から聞いた舞台公演の予約管理の話です。予約はGoogleフォームで受け付けて、確認のメールは一通ずつ手作業で送る。稽古や準備でいちばん忙しい時期に、事務作業が積み重なっていく。話を聞いていて、大変そうだと思いました。
無料で使える予約ツールが世の中にないわけではありません。ただ、実際に試すとシステムが不安定だったり、必要な機能が足りなかったりで、結局Googleフォームと手作業に戻ってきてしまう——とのことでした。
そして演劇の現場は、お金をかけられないことを私は知っていました。チケット代は会場費や制作費でほぼ消えていく。月額数千円のツールでも、小さな劇団には重い固定費です。だったら、無料で、ちゃんと動くものを作れば喜ばれるのではないか。そう思ったのが、かごチケの始まりです。
予約する人に、アカウントを作らせない
最初に決めた設計方針は「参加者は登録不要」です。
お芝居を観に行くのに、会員登録をしたい人はいません。予約のハードルは、そのまま客足に響きます。名前と連絡先を入れたら予約が終わる。主催者の目線に立つと、自分のイベントの申込みを1件でも逃したくないので、これは譲れない部分でした。
いちばんこだわったのは、主催者の管理画面
作ってみて分かったのは、予約フォームそのものより、主催者側の管理画面のほうがずっと難しいということです。
予約が何件入っていて、誰が来るのか。回ごとの残席はいくつか。当日、受付で来場者を素早く確認できるか。公演の現場は忙しく、複雑な画面を学習する余裕はありません。
当日の受付は、予約ごとに発行されるQRコードをかざすだけでチェックインできるようにしました。会場によっては電波が不安定なことも多いため、オフラインでも受付ができる仕組みも用意しています。「マニュアルなしで、当日の受付現場で迷わず使えること」を目標に、画面の作り直しを重ねました。
土台を、丸ごと引っ越した
ここから先は、この記事を書き直すことになった理由の話です。
かごチケは当初、Go言語で書いて、無料のVPS(自分で借りるサーバー)の上で動かしていました。ところが、そのあとに作った市電なう・灰なう・涼しかといった道具は、どれもCloudflare Workersという別の土台に載せています。ひとりで7つを維持するのに、かごチケだけ運用のしかたが違うのは、地味に負担でした。
そこで2026年7月30日に、かごチケも Cloudflare Workers へ引っ越しました。データベースはD1、主催者がアップロードするチラシ画像はR2という保管庫に置いています。これでかごいとの道具は、全部が同じ土台の上に揃いました。
引っ越しといっても、画面や機能はそのままです。ルート29件・テーブル18件・メール5種・書き出すCSVの11列、それぞれが移行の前後で一致することを突き合わせて確認しました。
ただ、中身はかなり書き直すことになりました。置き場所が変わったからです。
| 置いていたもの | Go版(VPS) | Workers版 |
|---|---|---|
| 同時に動く処理の交通整理 | プログラムの中のロック | データベースの条件付き更新 |
| 「今日はもう実行したか」 | プログラムの中の変数 | データベースの行 |
| ログイン中の管理者の名簿 | プログラムの中の一覧表 | 署名付きの通行証(名簿を持たない) |
| メールの送信待ちの整列 | プログラムの中で順番待ち | データベースの行を1件ずつ確保 |
| テーブルの定義 | 起動のたびに流し直す | 変更を1ファイルずつ積み上げる |
| 在庫(残り何枚か) | 予約を数え上げて求める | カウンタ+毎日の照合 |
並べてみると、全部が同じ話をしています。これまでプログラムの中に置いていたものが、置けなくなったのです。
Workersでは、リクエストが来るたびに別々の実行単位で処理が走ります。さっきのリクエストが覚えていたことを、次のリクエストは知りません。だから「順番待ちの列」も「今日もう実行したという印」も、プログラムの中には持てない。ぜんぶ、データベースのような外側に置き直すことになりました。
言われてみれば当たり前のことですが、これを一つずつ見つけていく作業が、引っ越しの中身のほとんどでした。
時刻でも一度ずれました。Go版は「サーバーのいまの時刻」を素直に使っていて、そのサーバーは日本時間で動いていました。Workersのサーバーは常に世界標準時です。同じ書き方をそのまま持っていくと、9時間ずれます。
いまは、扱う日時を2種類だけに決めています。公演の日時のような「壁の時計としての時刻」は日本時間のまま、記録した時刻・送った時刻のような「システムの時刻」は世界標準時。混ぜないと決めておくと、どちらの意味で書かれた値なのかを毎回考えずに済みます。
引っ越しのついでに、直した弱点
書き直しているうちに、Go版の作りの弱いところにも気づきました。
ひとつは管理画面の通行証です。Go版は、イベントごとにずっと同じ値の通行証を発行していました。24時間で切れることになっていたのですが、その期限はブラウザに渡すCookieの側にしか書かれていない。つまり、いちど値を控えておけば、期限が過ぎても入れてしまいます。
いまは期限を通行証そのものに埋め込んで、サーバー側で確かめています。材料には主催者のアクセスキーも混ぜてあるので、キーを作り直せば発行済みの通行証はすべて自動的に無効になります。照合も、1文字ずつ比べて違いが出た時点で止まる方法ではなく、必ず最後まで同じ時間をかけて比べるやり方にしました。
もうひとつは認証チェックの書き方です。Go版は、画面ごとの処理の先頭に「ログインしているか」を毎回書く形でした。これは、1箇所書き忘れるとそこだけ素通りになる構造です。実際に漏れていたかどうか以前に、書き方そのものが危うい。
いまは、管理画面のURLに入る手前でまとめて確かめる形にしています。新しい画面を足しても、そこを通らずには入れません。
ついでにもう一点。存在しないイベントのURLを開いたときは、ログイン画面ではなく「見つかりません」を返すようにしました。ログイン画面が出ること自体が「そのイベントは存在する」という情報になってしまうからです。
そして、引っ越し先で新しく作り込んでしまった穴もありました。
かごチケはイベントごとに独立しています。ということは、予約フォームの中身を書き換えて、別のイベントの座席番号を送りつけることができます。画面の上ではそんな操作はできませんが、フォームは誰でも組み立てられます。Workers版は当初この確認が足りず、他のイベントの座席を押さえられる状態でした。
いまは、送られてきた番号のすべてについて「これはこのイベントのものか」を確かめています。座席なら、そのイベントのものであることに加えて、そのチケット種別で座れる区画かまで見ます。しかも事前の確認だけには頼りません。書き込むときにも、データベース側で同じ条件を引き直して、外れていれば失敗して巻き戻るようにしています。
もうひとつ、これは自分でも意外でした。座席の確認は「座席指定のあるイベント」でだけ走らせていたので、座席の設定が無いイベントでは、確認そのものが飛んでいたのです。それでも書き込む側は動いていたので、細工された値がそのまま届いていました。守りが動く条件と、書き込みが動く条件は、揃えておかないといけません。
二重に予約が入らないようにする
引っ越しでいちばん怖かったのは、残り1枚のチケットが2人に売れてしまうことでした。
最初は「残りが足りていたら書き込む」という条件を付けて守ろうとしました。ところが、これが効いていませんでした。
在庫が足りないとき、エラーにはならないのです。「0行を更新しました」と返ってくるだけで、処理は成功したことになる。そして同じまとまりの中の後続の処理はそのまま通るので、在庫を確保できていないのに予約だけが成立します。実際のデータベースで試して確かめました。
いまは、条件で守るのをやめて、データベースの制約そのもので守っています。「在庫は0未満にも上限超えにもならない」という決まりをテーブルに持たせておくと、破ろうとした時点で違反になり、まとまり全体が巻き戻ります。条件は静かに失敗しますが、制約は必ず止まります。
根っこにあるのは、「読んで、判断して、書く」のあいだに必ず隙間がある、という問題です。読んだ瞬間は空いていても、書く瞬間には埋まっているかもしれない。だから判定に使った条件を、書き込むときにデータベースへもう一度確かめさせるようにしました。外れていたら書き込みが失敗して、まとめて巻き戻る。人間が確認するのではなく、データベースに確認させます。
予約の変更では、処理の順序にも意味がありました。古い分を減らす、座席を解放する、新しい分を足す——この順でないといけません。足すのを先にすると、2枚を3枚に変えるだけの変更でも一瞬だけ上限を超えてしまい、正当な変更が失敗します。
完了メールが5分待たされていた
予約が終わったら、確認のメールが届きます。Go版はこれを裏側ですぐ送っていました。
Workersに移したあと、同じことをそのまま持ってくることができませんでした。メールは送信待ちの列に積んで、定期実行がまとめて送る形にしたのですが、これだと最大5分待たされます。予約した直後の5分は、長い。
そこで、列に積んだ直後にも送るようにしました。ここで、もうひとつ踏みます。
「1通だけ送る」実装にしていたので、古いメールが1通でも溜まっていると、たったいま積んだメールが送られなかったのです。列は古い順に処理されるからです。
本番で起きました。変更のお知らせが3通溜まっている状態でキャンセルすると、送られたのは3通前の変更メールで、肝心のキャンセル通知は次の定期実行待ちになっていました。いまは定期実行と同じ通数まで流すようにしています。
もうひとつ、地味ですが大事なこと。メールの本文には管理画面のアクセスキーが入ります。送信待ちのあいだデータベースに平文で置いておきたくないので、暗号化して保存しています。平文が入っていないことは、テストで見張っています。
在庫のズレは、自動で直さない
Go版の在庫は、予約を数え上げて求める値でした。数え直せば必ず正しいので、ズレようがありません。
Workers版はカウンタです。予約が入ったら足し、キャンセルされたら引く。速いのですが、どこか1箇所で更新を漏らすと、静かにズレます。誰も気づかないまま、残席の表示だけが間違い続けることになります。
だから、毎日1回、実際の予約から数え直した値とカウンタを突き合わせています。
ただし、ズレを見つけても自動では直しません。直すべきなのはカウンタの値ではなく、更新を漏らしているコードのほうだからです。症状だけ消してしまうと、次に同じことが起きても分かりません。ズレたときは管理画面に警告が出るようにしてあって、手で調べにいきます。
演劇から、あらゆるイベントへ
かごチケはいま、演劇に限らず、小規模ライブ、勉強会、マルシェ、展示会など、いろいろなイベントで使える道具になっています。鹿児島発ですが、仕組み上は全国どこのイベントでも使えます。
参加者は登録不要で予約でき、主催者も無料で始められる。演劇の現場から始まった「お金をかけずに、ちゃんと動くものを」という考え方は、いまもかごチケづくりの基本になっています。土台をまるごと引っ越したのも、結局は同じ理由です。ひとりで長く続けられる形にしておかないと、無料のまま維持できません。
実はまだ、きっかけをくれた知人の公演で使われたことはありません。いつか本番の受付で使ってもらえる日を、楽しみにしています。
イベントの予約管理に消耗している方がいたら、いちど試してみてください。