event-form
天文サークルの観測会で、申し込みから当日の集金までを扱うアプリです。2025年10月から本番で動かしています。毎月の観測会で使っています。動かしたまま何度か作り直していて、いまの形になったのが2026年8月です。

何が面倒だったのか
観測会は夜に山へ行くので、車の乗り合わせが要ります。車を出せる人が何人いて、それぞれ何人乗せられるのか。送迎してほしい人のうち、誰が先に申し込んでいて優先されるべきなのか。宿泊の回なら、部屋数の上限もあります。
LINEの投票では、この順番がつけられません。毎回、乗せられる人数と申込順を確認して、乗り合わせを決めていました。その手間をなくすために作りました。
アプリがやるのは3つです。
- 申し込みを受けて、参加できるかを自動で判定する(車の席・全体の上限・宿の定員を同時に見る)
- 締切を過ぎたら自動で動かさない。あとは運営が名簿を仕上げる
- 当日は帳簿で点呼と集金をして、翌日に5分で締められる形にする
申し込む
「現地集合/送迎してほしい/ドライバー」から選びます。集合場所を選ぶと送迎費が計算されて、当日払う額に加算されます。その時点で車の空席がなければ、「枠待ちでの申込になります」と申し込み前に表示されます。

名簿
集合場所ごとに、誰がどの車に乗るのかが並びます。席や定員を超えた人は理由付きで枠待ちに入り、空きが出たら「くり上げ」で確定します。

帳簿
帳簿は1人につき1行です。出席か欠席かを選び、参加費を受け取ったらチェックします。ドライバーには送迎費を払います。全部の行を処理し終えると完了になります。

金額は自動で消さない
欠席にしても、金額は勝手に消えません。「徴収しない」を人が選んで、理由をメモに残します。お金の記録をアプリが勝手に書き換えないのは、このアプリで一番強く決めたルールです。

作らない機能とその理由
要件書には、作らない機能とその理由を書いています。たとえば、掲示板はLINEグループを使っているので作りません。思いつきで機能を足さないために書き残しました。
Cloudflareの無料枠に合わせた設計
Cloudflare の無料枠で動かすので、できないことが多い。制約を回避するのではなく、制約に合う形を選びました。
- データベースが複数の書き込みをまとめられない → 「読んで・判断して・書く」を1文の SQL にまとめる
- 1リクエストで使える CPU が10ミリ秒 → ログイン情報を60秒だけ手元に持ち、権限が要る操作のときだけ最新を読み直す
- 定期実行の仕組みがない → 当日の帳簿は「その日いちばん最初に開いた人」のアクセスで作る。同時に開かれても1つしかできないように書いた
時期ごとのデータの更新
受付中・締切後・当日以降で、書き込んでいい場所を分けています。受付中は本人が申し込み内容を記入し、締切後は運営だけが名簿を編集し、当日以降は帳簿だけを更新します。時期の切り替わりは全部時刻から自動で決まるので、運営が押すボタンは「イベントを作る」と「当日の帳簿」の2つで足ります。
構成
- フロント
- React 19 / TanStack Start(Router・Query・Form)/ Tailwind 4 / shadcn+Base UI
- サーバ
- Cloudflare Workers 1個 / Valibot
- DB
- Cloudflare D1(SQLite)/ drizzle ORM・21テーブル
- 認証
- better-auth + LINEログイン + 管理者承認(4ロール)
- 連携
- サークルのホームページ(WordPress)へイベントを自動掲載。プラグインも自作
- テスト
- vitest(判定ロジック等の単体18ファイル)+ Playwright(業務フローの E2E 5本)
- 運用
- GitHub と連携した自動デプロイ。重要な操作は変更前後つきで監査ログに残す(29種)
アプリが使えなくなると翌日の観測会を運営できないので、障害対応もデータ移行も自分でやります。
掲載している画面のデータは紹介用に作った架空のもので、実際の会員の情報は含まれていません。