💡

おすすめの小説を見つけれる「リーディア 」を全体的にアップデートしました

に公開

こんにちは、もっちーです。

去年の12月に完成した「リーディア」という個人開発のアプリを改善しました。

https://zenn.dev/mnao46/articles/3dc7e4eb8d3aa3

一通りの開発が終わったらリーディアに対するモチベが下がってしまって、新しく散歩アプリの開発を始めることに。

このアプリについても記事を書こうと考えています。

そのため前回の記事から半年ほど時間が経ってしまいました。

前回からの変更点

  • デザインを全体的に調整(AI全任せで)
  • フロントとバックを分ける(どちらもTypeScript)
  • フロントのデプロイ先をCloudflare Pagesにする
  • Cloud RunのカスタムドメインはCloudflare Workersでリバースプロキシする
  • おすすめを提案するアルゴリズム改善のためには内部で取得するデータを増やす
  • マーケティングの知識を身につけるためにSEOを意識したブログをNext.jsで用意する

それぞれ詳しく書いていきます。

デザインを全体的に調整(AI全任せで)

前回はデザインが微妙すぎたので、生成AI(v0やClaude)にお願いして良い感じのデザインに調整してもらいました。

これで最低限のデザインは完成して、とりあえずアプリっぽく使えるようになった気がします。

ただ、全体的な導線がイマイチで自分でも使いづらく感じるので、周りの人に使ってもらってFBをしてもらう予定です。

マークアップ関連の知識(HTMLやCSS)がほとんどない自分でも最低限の見た目を整えられたので、生成AIの素晴らしさを感じた良い機会でした。

フロントとバックを分ける(どちらもTypeScript)

今回のリーディアが初めての個人開発だったこともあり、できるだけ思考コストを下げて開発できるように、フロントとバックどちらもNext.jsで作っていました。

ただ、実際にデプロイして動かしてみると、いろいろ問題が出てきてしまい…

たとえば

  • Cloud Runで動かすとコールドスタートで遅い
  • Next.jsのコンテナの容量が大きすぎることが判明
  • CDNを導入したいけど良いのが見つからない

などなど、、ローカル環境では問題なくても、実際の環境だと懸念点がたくさんありました

しっかり調査をして対策を入れることで解決すると思いましたが、そこまでの調査スキルがないので、Next.jsをCloud Runで動かすことは断念しました。

https://twitter.com/mnao_daily/status/1884096728498147646

その代わりにフロントとバックを分ける一般的なやり方にして、

  • フロント(Next.js):Cloudflare Pages
  • バック(hono):Cloud Run

という構成で動かすことになりました。

パフォーマンスを気にするのであれば、コンテナ化の恩恵を受けやすい(?)Goなどにした方が良いかもしれませんが、とりあえずサクッとAPIを作れると話題のHonoを使ってみました。

https://zenn.dev/yusukebe/articles/1abed4d99e8893

Expressと同じ感じでコードを書けるので、個人的には好きなフレームワークでした。

開発も熱心に進められているようなので、今後もっと使いやすくなりそうで楽しみです。

フロントのデプロイ先をCloudflare Pagesにする

さきほどの内容と被りますが、フロントをCloudflare Pagesにデプロイすることにしました。

Next.jsを使っているのでVercelにデプロイするのが無難ですが、リーディアはAmazonへの広告リンクを貼っているので、無料プランだとVercelは使えないんですよね。

かわりに無料プランでも広告を貼ることができるCloudflare Pagesを使ってみることにしました。

以下のファイルを用意(+微調整)だけで良かったので、ほとんど時間もかからずにスムーズに移行できました。

{
  "$schema": "node_modules/wrangler/config-schema.json",
  "name": "readia",
  "compatibility_date": "2025-02-04",
  "compatibility_flags": [
    "nodejs_compat"
  ],
  "pages_build_output_dir": ".vercel/output/static",
  "observability": {
    "enabled": true
  }

使用感もVercelとほとんど変わらないので、Cloudflare Pagesを選んで正解だったと思います。

https://zenn.dev/youtuber/articles/host-server-ed9d3447ffd055

最初は画像データをCloud Storageに保存していましたが、今回のタイミングでR2で管理できるようにしました。

これも以前と使用感は変わらない(むしろR2の方がシンプルで使いやすい)ので、全体的に良い感じになって満足です。

Cloud RunのカスタムドメインはCloudflare Workersでリバースプロキシする

ここが悩んだ部分です。

キャッシュやCDNまわりの知識が少ないので、まずは「Cloud Run カスタムドメイン CDN」で調べて見つかった以下の記事を参考にしました。

https://zenn.dev/kusuke/articles/2c4f49c8b6fe1f

たしかにFastlyは簡単にカスタムドメイン(とCDN)を設定できて便利でしたが、管理画面の使い方がよく分からず、自分にはオーバースペックかも…と感じていました。

無料プランだと2つしかドメインを設定できないのも微妙かもしれないです(今後もっとアプリを作りたくなる気がしたので)

https://zenn.dev/link/comments/e6b34c137b6de9

そこでZennの開発者でもあるcatnoseさんの検証記事に書かれていた「Cloudflare Workersをリバースプロキシ」として使うという方法を採用することに。

Honoの開発者でCloudflareで働いてるyuskeさんもブログで解説していたので、よく使われている一般的な良い方法だと判断しました。

https://zenn.dev/yusukebe/articles/647aa9ba8c1550

Cloudflare Workersに設置するコード自体はシンプルですし、アプリ全体のインフラをCloudflareでの管理にまとめられたのは良かったです。

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    // ここでCloud RunのURLに書き換え
    url.hostname = 'xxxxxx.run.app';
    url.protocol = 'https:';

    // オリジナルのリクエストをそのまま転送
    const modifiedRequest = new Request(url.toString(), request);

    // オプションでヘッダ追加なども可能
    return fetch(modifiedRequest);
  },
};

管理画面で設定をがんばれば、キャッシュヒット率などをコントロールできそうなので、今後は少しずつ知識を増やしていこうと思います。

おすすめを提案するアルゴリズム改善のためには内部で取得するデータを増やす

ここからはアプリケーション側の変更点について。

もともとは小説の解説文を分類してゴニョゴニョやっていましたが、それだけだと精度があんまり良くないこと気がつきました。

「機械学習をフル活用してアルゴリズムを改善しました!」とカッコよく言いたいところですが、そんなスキルは自分には無いので、とりあえず判断材料に使えそうなデータを増やすことにしました。

たとえば

  • 他のユーザーにおすすめ本を共有する機能
  • ユーザーが本を選んだことを記録する機能
  • 小説内で心に刺さった文章をメモする機能
  • 商品ページを選択したことを継続する機能

などなど、、いくつかGA4でも継続できそうなデータもありますが、できるだけアプリケーション側で取得するデータを増やしてみました。

今後の課題として、これらのデータを使って本を表示するアルゴリズムを改善していこうと思います。

このために「独学で鍛える数理思考〜先端AI技術を支える数学の基礎」という本を買いました(買っただけで読んでないけどw)

統計学などの数学的な考え方が必要になってくるので、これまでとは違った新しいチャレンジができそうで楽しみです。

マーケティングの知識を身につけるためにSEOを意識したブログをNext.jsで用意する

アプリケーションと同じドメイン内にブログを作りました。

https://twitter.com/mnao_daily/status/1910650581427118400

全体の構成は以下のような感じです。

  • /:トップページ(LP的な感じ)
  • /app:アプリケーション
  • /blog:新しく用意したブログ

ドメインを分けることも考えましたが、アプリケーションからブログ、ブログからアプリケーションという導線もあると便利そうなので、GA4での継続がしやすいように同じドメインにしました。

ブログの仕組みとしては、ビルド前にMDXファイルをJSONに変換して静的ファイルとして配信する形にしています。

ブログっぽい感じのデザインにしたかったので、JSX形式のコンポーネントを使えるようにMDXファイルを書くことにしました。

https://twitter.com/mnao_daily/status/1910923642197954863

ただ、Cloudflareのエッジ環境ではイマイチ思い通りに動かない部分があり、クライアント側でレンダリングする形になっています(本当はサーバー側でやりたい)

そのためPageSpeed Insightsのスコアが微妙(80前後くらい)になっています。

ここを100にしたいのですが、今の自分の知識では難しそうです…

記事が増える前になんとか解決したいので、直近ではこの部分を頑張って調べてみようとも思います。

今後やりたいこと

一通り使ってもらえる状態になったリーディア ですが、まだまだやりたいことはたくさんあります。

優先度が高い順番に並べていくと

  1. おすすめを表示するアルゴリズムの改善
  2. 認知してもらえようにマーケティングを頑張る
  3. (ユーザーが増えたら)サチコとGA4のデータで分析
  4. 使いやすいUI/UXを目指してデザインを調整してみる

とりあえずこんな感じですかね。

今はもう一つの個人開発(散歩アプリ)を作るモチベが高いので、すぐにはリーディアの改善には力を入れられないかもしれません。

https://twitter.com/mnao_daily/status/1890385434628485216

少しずつ自分のスキルも増やしながら、多くの人に楽しんで使ってもらえるようなアプリにしていきたいと思います。

最後に(現在の収益について)

本の詳細ページにAmazonのリンクを貼っているので、アプリ経由で本を買ってもらうとアフィリエイト報酬が発生するようになっています。

現状の収益は300円くらいなので、黒字になるのはしばらく先になりそうです…(Cloud SQLが2,000円/月かかっているので)

この記事を読んで「面白そうなアプリだな〜!」と思った人は、ぜひ使ってみてください(自分のTwitterにリンクを貼っています)

Discussion