CuraQの技術的な話 〜技術選定編〜
CuraQの技術的な話 〜技術選定編〜
こんにちは、CuraQの開発者のおぎです。
今回は、CuraQの開発における「技術選定」の変遷についてお話ししたいと思います。
CuraQは現在、Hono x Cloudflare という構成で運用されていますが、最初からこの構成だったわけではありません。
プロトタイピングから現在に至るまで、フェーズごとの課題に合わせて技術スタックを柔軟に変えてきました。
この記事では、なぜ現在の構成に行き着いたのか、その経緯と学びを共有します。
Phase 1: Next.js x Vercel でのプロトタイプ開発
開発初期、まずは動くものを作るために選んだのは Next.js (App Router) x Vercel という、現在のWeb開発における「王道」の構成でした。
選定理由
- エコシステム: ライブラリやドキュメントが豊富。
- デプロイ: Vercelへのデプロイがゼロコンフィグで簡単。
- 機能: SSR, ISR, API Routesなど必要なものが全て揃っている。
しかし、開発が進むにつれて「今回のプロダクト(CuraQ)にとっては少し重厚すぎるのではないか?」と感じる場面が増えてきました。
特に課題だったのが キャッシュ戦略の複雑さ です。
ユーザーごとの動的なコンテンツが多いCuraQにおいて、Next.jsの強力なキャッシュ機能を適切に制御(無効化・再検証)するロジックが複雑化してしまいました。
もちろん、JotaiやReduxのような状態管理ライブラリなどを導入して、この複雑さを「管理」することはできたかもしれません。しかし、「複雑さを制御するために、さらに新しい道具を追加する(=足し算で解決する)」というアプローチは、直感的に「何かが違う」と感じました。
私が求めていたのは、複雑なものを上手く扱うことではなく、仕組みそのものを単純化する「引き算」の解決策だったのです。
もう一つの決定打:UIは「負債」になるかもしれない
そして、技術的な複雑さ以上に私を移行へと突き動かしたのが、CuraQの根底にある 「UIはいずれ不要になるかもしれない」 という仮説です。
将来的には、人間がWeb画面を操作するのではなく、AIエージェントがユーザーの意図を汲んで情報を処理する時代が来るかもしれません。その時、現在のリッチなUI/UXは価値を失いますが、ユーザーが蓄積した「思考のコンテキスト」や「データの構造」は依然として資産であり続けます。
そう考えた時、Next.jsという「UI構築に特化した重厚なフレームワーク」にロジックやデータを密結合させることは、将来「負債」になり得る層への過剰投資に思えました。
「人間向けのUIはいつ捨ててもいいように極限まで薄くし、その分、来るべきAI Nativeな体験を作ることに投資を集中させる」
当時はMCPサーバーの開発などを急ぎたかったこともあり、この戦略を実現するためには、リクエストが来たらHTMLを返して終わり、という極めてシンプルな構成こそが最適解だと考えました。
こうして私は、Next.jsを離れ、より薄く、よりシンプルなスタックへの移行を決断しました。
Phase 2: Hono x Cloudflare への移行と「シンプルさ」の追求
シンプルさを最優先に再選定した結果、Hono (v4) x Cloudflare Pages という構成に辿り着きました。
Hono x Cloudflare のメリット
-
圧倒的なシンプルさ:
HonoのSSRは非常に直感的です。POST /shareなどのアクションを受け取ったら、処理をしてredirect('/')するだけ。リダイレクト先で再度フレッシュなSSRが走るため、複雑なクライアントサイドの状態管理やキャッシュ無効化ロジックから解放されました。 -
Edgeでのパフォーマンス:
Cloudflare Workers上で動作するため、世界中のエッジロケーションから高速にレスポンスを返せます。
「SUANのバズ」に耐えた実績
この移行の恩恵を最も感じたのが、ある日「SUAN」に取り上げられてアクセスが急増した時です。
Cloudflareの堅牢なインフラとHonoの軽量なランタイムのおかげで、1日2000名を超える流入に対してもサーバー(Edge)は全く悲鳴を上げることなく、大量の流入を涼しい顔で捌き切ってくれました。
「シンプルイズベスト」を体感した瞬間でした。
Phase 3: 機能肥大化と hono/jsx/dom によるCSRへの回帰
Hono x Cloudflare SSRで順調に運用していましたが、プロダクトが成長するにつれて新たな課題が出てきました。
新たな課題: インタラクティブ性の欠如
- 即時性の要求: 「記事の既読」「アーカイブ」「削除」といった操作をサクサク行いたいが、毎回SSRのリロード(リダイレクト)が入るとUXがもっさりする。
- リアルタイム更新: 投げ銭(サポーター)機能や通知など、他ユーザーのアクションやサーバー側の状態変化をリアルタイムに画面に反映させたい。
SSRのシンプルさは捨てがたいですが、リッチな体験を提供するには限界がありました。
そこで採用したのが、HonoのJSXエコシステムを使ったCSR(Client Side Rendering)コンポーネントの導入 です。
部分的なハイドレーション
全てのページをSPAにするのではなく、インタラクションが激しい「ダッシュボード」や「記事一覧」部分だけをクライアントサイドで動かすことにしました。
ここで活躍しているのが hono/jsx/dom です。
/** @jsxImportSource hono/jsx/dom */
import { render } from 'hono/jsx/dom';
import { ArticleList } from './components/ArticleList';
// 特定のDOM要素に対してReactライクにコンポーネントをマウント
const root = document.getElementById('article-list-root');
if (root) {
render(<ArticleList initialData={...} />, root);
}
このアプローチにより、以下のメリットが得られました。
- 楽観的UI (Optimistic UI): ユーザーの操作(アーカイブなど)を通信完了前に即座に画面に反映できるため、体感速度が爆速に。
- Supabase Realtimeとの統合: クライアントサイドでWebSocket接続を維持し、データベースの変更をリアルタイムにUIに反映可能に。
- 開発体験の統一: サーバーサイド(SSR)もクライアントサイド(CSR)も同じ HonoのJSX構文で書けるため、コンテキストスイッチが最小限。
あくまで「必要な箇所に必要な分だけ」CSRを導入するこの手法なら、Next.jsのような巨大なフレームワークに全体をロックインされることなく、Phase 1で掲げた「UI層は薄く保つ」という哲学とも矛盾しません。
一方、変えなかったもの: データ基盤としてのSupabase
このように、アプリケーション層はフェーズに合わせて柔軟に形を変えてきました。
しかし一方で、プロトタイプから一貫して使い続けているのが Supabase です。
「Honoでシンプルに作る」という選択が「捨てる」戦略なら、Supabaseは「任せる」戦略の要です。
なぜSupabaseだったのか?
個人開発で最も時間をかけてはいけないのが「認証」と「データベースの運用」だと考えています。ここに時間をかけるより、コアな機能開発に集中すべきです。
-
データのポータビリティを重視
BaaS(Backend as a Service)は便利ですが、特定のベンダーにロックインされるリスクが伴います。
Supabaseの根幹はただの PostgreSQL です。これは非常に重要なポイントで、万が一Supabaseから移行したくなっても、標準的なSQLデータベースなのでデータを持ち出しやすいことを意味します。NoSQLのBaaS(例えばFirestore)だと、その独自のデータ構造にアプリケーションが密結合してしまい、移行が非常に困難になるケースを避けたかったのです。 -
認証基盤を「買えた」
認証機能を自前で実装するのは、セキュリティリスクや考慮すべき仕様(OAuth, パスワードリセット, メール認証など)が膨大で、個人開発では現実的ではありません。
Supabaseには Supabase Auth が組み込まれており、わずかなコードでセキュアな認証基盤を導入できます。これにより、開発初期に認証周りで悩む時間をゼロにして、プロダクトのコア価値の検証に集中できました。 -
Observability: SQLだけでダッシュボードが作れる
運用フェーズで意外に重宝しているのが、Supabaseの Observability(可視化) 機能です。
SQLのスニペットを書くだけで、簡単に図表付きのダッシュボードを作成できます。CuraQではこれを利用して、DAU(1日あたりのアクティブユーザー数)、課金ユーザー数の推移、時間帯ごとのユーザーアクティビティなどを可視化しています。
専用のBIツールを導入・連携させる手間なく、データベースの中にある生きたデータをそのまま経営指標として確認できるのは、スピード感が求められる個人開発において大きな武器になっています。
(余談)なぜCloudflareで統一しなかったのか?
Hono x Cloudflareを採用しているなら、データベースも Cloudflare D1 や Vectorize を使って、「フルCloudflare構成」にするのが自然ではないか?と思われるかもしれません。実際、技術的な面白さやコスト(D1は非常に安価です)の面で、その構成は非常に魅力的です。
しかし、あえてそうしませんでした。理由は 「データの資産性」と「時間の使い方」 です。
D1やVectorizeは素晴らしい技術ですが、独自の分散SQLiteや特定のベクトルストアへの依存度が高まります。
一方、Supabaseの中身は PostgreSQL です。ベクトル検索も標準的な拡張機能である pgvector を使っています。
「データはアプリケーションよりも寿命が長い」と言われます。将来、アプリケーションフレームワークを変えることはあっても、データ基盤までその道連れにするのはリスクです。Phase 1で述べた「データへの投資」を確実なものにするためにも、最も標準的で、どこへでも持ち出せるPostgreSQLを選びました。技術的な「目新しさ」やプラットフォームへの「統一感」よりも、データの「ポータビリティ(資産価値)」を優先した形です。
また、Auth(認証)、Database、Vector Store、Realtime、Storageが 「最初から繋がった状態で用意されている」 メリットも計り知れません。
バラバラのコンポーネントをAPIで繋ぎ合わせる「糊(のり)付けのコード」を書くことに時間を使うより、ユーザーに届ける機能を作ることに時間を使いたい。
CuraQの構成は、そんな「個人開発者の生存戦略」の結果でもあります。
このように、アプリケーション層は身軽さを保ちつつ、データと認証という重い責務はポータビリティを確保した上でSupabaseに任せる。この組み合わせが、CuraQの高速な開発サイクルを支えています。
まとめ:AI Nativeな未来への投資
振り返ってみると、CuraQの技術選定は一貫して 「AI Nativeな未来への備え」 が軸になっていました。
- Next.jsからの脱却: 人間向けのUI(負債)への投資を抑え、AI連携へリソースを振る。
- Hono x Cloudflare: AIエージェント時代に求められる「シンプルで高速なAPI/バックエンド」を構築する。
- Supabase (PostgreSQL): AIが最も理解しやすい標準的な形式でデータを蓄積する。
AIがUIを生成し、エージェントがタスクをこなす時代はもう既に実現しつつあります。
その波に飲まれるのではなく、波に乗るために「身軽」でいること。そのためにできるだけシンプルさを優先すること。
「UIはいずれ消えるかもしれない」という仮説に立ち、来るべきAIとの共存時代を見据えて、あえて枯れた技術やシンプルな構成を選ぶ。
これこそが、CuraQの開発を支える思想であり哲学です。
CuraQサービスサイト https://curaq.app
Discord:https://discord.gg/9xSVZ7ftcP
Discussion