Metronome.fm に、サービスが動いているかを確かめられるステータスページ(status.metronome.fm)を付けました。使ったのは Better Stack です。Issue を立ててから公開までは同じ日のうちに終わりました。アプリ側の変更は、お問い合わせのフォームを開く部品と、ドキュメントからのリンクだけです。
この記事では、何を監視しているか、独自ドメインをどう向けたか、ステータスページからアプリのお問い合わせへどうつないだかを書きます。
Better Stack は無料のプラン(Free)のまま使っていて、ここに書く監視・独自ドメイン・日本語の版はどれも無料の範囲で動いています。

- 無料のプラン(Free)のまま使っている
ほかのサービスのステータスページを見て、Metronome.fm にもほしくなったのがきっかけです。エラーのログの送り先にすでに Better Stack を使っていたので、監視とステータスページも同じところにまとめました。
監視しているもの
Better Stack の監視(Uptime の Monitor)は 2 つあります。どちらも URL に GET を送り、返ってきた HTTP のステータスで動いているかを判定する種類です。
| 監視する URL | 間隔 | タイムアウト | 確認する地域 |
|---|---|---|---|
https://metronome.fm/app | 3 分 | 30 秒 | ヨーロッパ・アメリカ・アジア・オーストラリア |
https://metronome.fm/ja | 3 分 | 30 秒 | 同じ |
/app はアプリ本体、/ja は日本語の LP です。どちらもリダイレクトを追い、SSL の証明書も確かめる設定にしています。
監視の設定の画面では、何が起きたら知らせるか(Alert us when)と、監視する URL を決めます。無料のプランで選べる条件は、URL に届かなくなったとき・キーワードを含む/含まないとき・決めたステータス以外が返ったとき・ping に応えないときで、TCP・DNS・Playwright のシナリオなどは有料です。

- URL に届かなくなったら知らせる(URL becomes unavailable)
- 監視する URL
確認は 3 分ごとで、失敗を見つけたらすぐに障害として扱い(Confirmation period を Immediate start)、3 分続けて動いていれば解決とみなします(Recovery period)。

- 3 分ごとに確認する
- 失敗を見つけたら、待たずに障害として扱う
SSL の証明書の期限切れやドメインの期限切れを前もって知らせる機能は、無料のプランでは使えません。
ステータスページには、この 2 つをどちらも載せています。アプリ本体と LP のどちらが落ちても、利用者から見えます。

- アプリ本体(/app)
- 日本語の LP(/ja)
status.metronome.fm を向ける
Issue を立てたときは「Next.js で status.metronome.fm のようなサブドメインを作れるのか」が気になっていました。実際には、Next.js にもアプリのコードにも手を入れていません。ステータスページは Better Stack が配信していて、こちらは DNS で名前を向けるだけです。
metronome.fm の DNS は Cloudflare で管理しています。status に CNAME を 1 つ足し、Better Stack のステータスページの配信先に向けました。
$ dig +short status.metronome.fm CNAME
statuspage.betteruptime.com.dig で CNAME の先がそのまま見えるので、Cloudflare のプロキシは通していません(DNS だけの設定です)。
Better Stack のステータスページの設定には向ける先の CNAME がそのまま表で出ていて、正しく向くと「The CNAME is configured correctly」と表示されます。DNS が Cloudflare なら、この画面から Cloudflare にサインインして CNAME を足すこともできます。

- この CNAME を DNS(Cloudflare)に足す
- 正しく向くと、確認済みと表示される
今回はこのボタンから足しました。Cloudflare にサインインして許可すると、CNAME が足されます。
お問い合わせのボタンからアプリのフォームを開く
Better Stack のステータスページには、右上にお問い合わせのボタンを置けます。押したときに開く URL は設定の「Get in touch URL」で 1 つ指定し、空にするとボタンは出ません。mailto: も使えます。

- お問い合わせのボタン。押すとアプリのフォームが開く
Metronome.fm のお問い合わせは、アプリの中のフォーム(モーダル)で受け付けています。ページとしての URL はないので、/app に ?contact=open を付けたらフォームを開くようにしました。ステータスページの設定には https://metronome.fm/app?contact=open を入れています。

- お問い合わせのボタンの行き先(Get in touch URL)
export const ContactLinkOpener = () => {
const searchParams = useSearchParams();
const router = useRouter();
const pathname = usePathname();
const openContactFormModal = useModalState(
(state) => state.openContactFormModal,
);
const shouldOpen = searchParams.get("contact") === "open";
const open = useEffectEvent(() => {
const rest = new URLSearchParams(searchParams);
rest.delete("contact");
const query = rest.toString();
router.replace(query ? `${pathname}?${query}` : pathname);
openContactFormModal();
});
useEffect(() => {
if (shouldOpen) open();
}, [shouldOpen]);
return null;
};フォームを開いたら、URL から contact=open を消します。消さないと、ページを読み直したときや、フォームを閉じてから画面の中を移ったときに、またフォームが開いてしまうからです。ほかのクエリは残します。

この部品はヘッダーに置いています。Next.js では、useSearchParams を使う部品があると、いちばん近い Suspense までがブラウザ側で描かれます。ヘッダー全体がそうならないよう、この部品だけを Suspense で囲みました。
日本語の版と、サイトからのリンク
ステータスページは英語の版を /、日本語の版を /ja で出しています。下端の言語の切り替えでも移れます。
翻訳を使うには、ステータスページのデザインを新しい方(Modern look)にしておく必要があります。

- 翻訳などは新しいデザイン(Modern look)の機能
- デザインを Modern look にする
Better Stack には用意された翻訳(Ready-made language)がありますが、選べるのは英語・ドイツ語・フランス語・スペイン語・オランダ語・チェコ語・スウェーデン語・トルコ語で、日本語はありません。そのため、言語コードを ja にした翻訳を作り、ナビゲーション・状態の表示・障害の自動の報告など 256 か所の文言を日本語で入れました。訳は Claude に書いてもらいました。会社名は %{company_name} のような差し込みで書けます。

- 言語コードは ja
- 用意された翻訳に日本語はないので None
- 文言を 1 つずつ日本語で入れる

- 言語の切り替え
Metronome.fm の側からは、ドキュメントのトップと、リリース情報の v2.5 のページからリンクしています。リンク先は表示している言語に合わせて、英語なら /、日本語なら /ja にしています。
export const getStatusPageUrl = (locale: string) =>
locale === DEFAULT_LOCALE
? `${STATUS_PAGE_URL}/`
: `${STATUS_PAGE_URL}/${locale}`;