本文へスキップ
芦崎楓 Ashizaki Kaede
← 作ったもの一覧

Felody

個人開発 / 公開中

自作のリラックスBGMを配信するサブスク型Webサービス。企画から課金・運用まで一人で回しています。

何を解決するものか

作業中や就寝前に「とりあえず流しておける音」がほしいとき、YouTube を開くと広告が入り、関連動画に気を取られます。Felody はカテゴリと時間を選ぶだけで、自作のBGMを指定時間だけ流し切るサービスです。

relax(lofi / nature / ambient / sleepy)と upbeat(jazz / funk / pop rock / edm)の2ムード・8カテゴリを用意し、Basic は1日30分、Premium は無制限で利用できます。

担当範囲

企画・UI設計・実装・DB設計・決済導線・インフラ・運用のすべて。

技術的に難しかった点と、どう解いたか

1. 音声ファイルを「直リンクさせずに」配信する

課金コンテンツなので、Storage の公開URLをそのまま渡すわけにはいきません。Supabase Edge Function 経由で都度 Presigned URL を発行し、クライアントには期限付きURLだけを渡す形にしました。

発行が失敗すると無音になって体験が壊れるため、1s → 2s → 3s の間隔で3回リトライしています。

2. ブラウザによって音が鳴らない

Howler.js は既定で Web Audio API を使いますが、環境によっては初期化に失敗します。失敗を検知したら HTML5 Audio へフォールバックする二段構えにして、鳴らない端末をなくしました。

加えて、UI上の状態(再生中/停止中)と実際の再生状態がずれることがあったため、5秒間隔で両者を突き合わせて補正するチェックを入れています。「押したのに反応しない」は離脱に直結するので、ここは厚めに作りました。

3. 「1日30分」をどう正確に数えるか

再生のたびにサーバーへ書くと負荷もコストも無駄になります。60秒間隔でまとめて記録し、30秒のスロットルで重複送信を防ぐ方式にしました。日付が変わったかどうかは last_reset_date を見て、ログイン時に判定してリセットします。

4. 決済とアプリ側の状態を食い違わせない

Stripe の checkout.session.completedcustomer.subscription.deleted を Webhook で受け、プラン状態を DB に同期しています。DB 書き込みはすべてサーバー側(Service Role Key)に閉じ、クライアントには Anon Key しか渡していません。

学んだこと / 次にやること

課金がある以上、「失敗したときにどう振る舞うか」がそのまま品質になります。リトライ・フォールバック・状態の突き合わせは、機能そのものより時間をかける価値がありました。

次は Player コンポーネント(約1,300行)の分割と、テストの導入を進めています。

お仕事のご相談

「まだ要件が固まっていない」「実現できるか相談したい」の段階で構いません。 技術的に可能かどうかだけでもお答えします。

お問い合わせフォームへ

メールでも受け付けています → dkae1107@gmail.com