今まで作ってきたのはLP・ECサイト・ポートフォリオ。
今回は初めて「動くシステム」に挑戦した。
予約フォームを送信したら管理画面に反映され、メールも自動で飛ぶ——そういうやつ。
予約管理システム入りのLPを制作した。
ゲストが見るのは美しい予約フォームだけ。でもその裏では、データベースへの保存、自動メール送信、管理画面でのステータス管理が動いている。見た目はLPで、中身はシステム——それがVELAROだ。
架空のリゾートヴィラ「VELARO」向けの予約管理システム。 ゲストが予約フォームを送信すると、DBに保存されて確認メールが届く。 管理者は専用画面で予約一覧を確認し、ステータスを変更したりゲストにメールを送ったりできる。
LPは「見せる」だけでよかった。今回は「動く」ことが求められる。 フォームのバリデーション、APIの設計、DBのスキーマ、メールの自動送信—— 考えることが一気に増えた。
ゲストが予約フォームを送信
チェックイン・アウト日、人数、ヴィラ種別、名前・メール・電話を入力。送信と同時にAPIが動く。
DBに保存 → メール2通を自動送信
Supabaseに予約データを保存後、ゲストへ受付確認メール・管理者へ新規予約通知メールを同時送信。
管理者が管理画面で確認
予約一覧をステータスでフィルタ・名前やメールで検索。各予約の詳細ページで情報を確認できる。
ステータス変更 → 自動でメール通知
「確定」「キャンセル」などにステータスを変えると、内容に応じたメールがゲストに自動送信される。
任意メールの送信
管理画面から件名・本文を入力して、そのゲストに直接メールを送ることもできる。
Next.js
画面側とサーバー側の処理を1つの仕組みで作れる、Webアプリ用の土台
Supabase
予約データを保存するデータベース。誰がどのデータを見られるかも細かく制御できる
Resend
メールを自動送信するサービス。ゲスト宛・管理者宛のメールが届く
Tailwind CSS
見た目を素早く整えるためのCSS道具
Vercel
サイトを世界中に高速配信するホスティングサービス
「動いた」と思って一息ついたあと、自分のコードを自分でレビューした。 結果、5件の問題が見つかった。
管理画面に認証保護がない
URLを知っていれば誰でも全予約を閲覧・操作できる状態だった。
予約送信の回数制限がない
悪意あるユーザーが連打すれば、データベースとメール送信枠を使い切られてしまう。
日付の入力チェックなし
チェックイン日がチェックアウト日より後でも、エラーにならず通ってしまう。
メール本文に悪意あるコードが混入できる
管理画面から送るメール本文を、安全に変換せずそのまま送る設計になっていた。
全部修正して、もう一度公開し直した。 管理画面は認証で保護、予約フォームは1分間に5回までの送信制限、日付はサーバー側で検証、 メール本文は危険な文字を安全な文字に変換してから送信するように改修。
— 修正後の構成
管理画面と管理API(/admin と /api/admin/*)に認証保護を導入。本番で個人情報を扱う場合はCloudflare Accessなどの認証基盤を使う前提
同じIPアドレスから1分間に5回以上の予約送信を制限
チェックイン日 < チェックアウト日 をサーバー側で検証
カスタムメール本文を安全な文字に変換してから送信
ゲストには綺麗な予約フォームしか見えないけれど、裏側では管理者がこの画面で予約を捌いている。 予約一覧をステータス(仮受付・確定・チェックイン済・チェックアウト済・キャンセル)でフィルタしたり、 名前・メール・予約番号で検索したり、各予約の詳細ページでステータス変更や任意メール送信ができる。
ゲスト用のUIはミニマル・余白多め。管理画面は逆に情報密度を上げて、一覧で5〜10件を一目で把握できるようにした。 同じサイトでも、使う人によって設計思想を変えるのが今回の裏テーマだった。
LPは見た目が7割だと思っていた。でもシステムは見た目より設計の方が難しい。 「ゲストが何かを送信したとき、サーバー側で何が起きるか」を全部自分で考える必要がある。
それと、「動く」と「安全」は別の話だと改めて実感した。 フォームが送信できてメールが届いた時点では、まだ半分しか完成していない。 誰が触るか、どう悪用されるかを想定して初めて「完成」と言える。
次はもう少し複雑な状態管理——在庫や空室カレンダーのようなもの——に挑戦したいと思っている。