LLM以外は無料枠。Vercel × Next.js × Supabase × Inngest × Render × Claude 4.5 で構築した「raindary」というAI要約基盤の設計と実装

技術

はじめに ― 「あとで読む」を終わらせる

エンジニアは記事を保存する。

気になる技術ブログ、公式ドキュメント、パフォーマンス検証、設計思想の考察。
raindrop.io に次々とリンクを保存していく。

だが、現実はこうだ。

読まない。

正確に言えば、「今は読まない」が積み重なっていく。

そこで作ったのが raindary というアプリだ。
raindrop.io に保存した記事を自動取り込みし、本文を抽出し、AIで事実を整理し、トーン付きで要約を生成する。

そして生成された要約だけを保存する。

このプロジェクトは GitHub で公開している。

👉 https://github.com/enjoydarts/raindary

個人開発だが、設計はかなり真面目にやっている。
特に意識したのはこれだ。

LLM以外は無料プランで構築する

AIアプリは高コストというイメージがある。
しかし設計を工夫すれば、ランニングコストはClaudeのトークン消費だけにできる。

この記事では、その設計と技術スタックを、初心者にも理解できるように丁寧に解説する。


raindrop.ioを基盤にする理由

まず、なぜraindrop.ioなのか。

raindrop.io は単なるブックマーク管理サービスではない。

  • コレクション管理
  • タグ
  • API公開
  • OAuth2対応
  • RESTエンドポイント

が整っている。

つまり、

「ユーザーが保存した記事データを外部から取得できる」

ということだ。

raindaryでは、raindrop.ioを一次データストアとして扱っている。

記事のタイトル、URL、タグ、保存日時はraindrop側が管理する。
raindaryはそれを取り込み、AI生成結果だけを保存する。

この責務分離には大きな意味がある。

  • 記事削除に追従できる
  • データ重複がない
  • 同期ロジックが単純になる

基盤を信頼し、自分は付加価値に集中する。
これが設計の出発点だった。


全体アーキテクチャ

raindaryの構成は以下の通り。

User
 ↓
Vercel (Next.js 15 + Auth.js)
 ↓
Inngest Cloud
 ↓
Render (FastAPI + trafilatura)
 ↓
Anthropic Claude API
   ├ Haiku 4.5(事実抽出)
   └ Sonnet 4.5(要約生成)
 ↓
Supabase PostgreSQL

重要なのは、各レイヤーが明確に分離されていることだ。

  • UIはUI
  • 非同期は非同期
  • 抽出は抽出
  • LLMはLLM
  • DBはDB

単一サービス依存ではなく、責務で分けている。


Vercel ― フロントと軽量APIの基盤

raindaryのUIとAPIはVercel上で動いている。

使用しているのは Vercel Hobbyプラン(無料)

Hobbyプランでも、

  • GitHub連携
  • 自動デプロイ
  • Preview環境
  • Serverless Functions
  • Edge Middleware

が利用できる。

Next.jsを使うならVercelは相性が良い。

ただし設計上のポイントは、

Vercelで重い処理をしないこと。

  • OAuth認証
  • API受付
  • Inngestイベント発火

だけを担当させている。

重い処理はすべて非同期へ逃がす。


Next.js 15 ― フルスタック基盤

Next.jsはReactベースのフレームワークだが、現在はフルスタックの役割を担う。

App Routerにより、

  • ページルーティング
  • レイアウト共有
  • サーバーコンポーネント
  • API Routes

を統合できる。

初心者向けに言えば、

フロントと軽量バックエンドを一緒に書ける

という仕組みだ。

raindaryでは、Next.jsはイベントの入り口であり、処理の本体ではない。

実処理はInngestへ。

この分離がスケーラブルな設計を可能にしている。


Supabase ― 無料で使えるPostgreSQL

データベースにはSupabaseを採用。

利用しているのは Freeプラン

Freeプランでも、

  • PostgreSQL
  • Row Level Security
  • ダッシュボード管理

が利用できる。

raindaryはマルチユーザー対応。

そのため全テーブルに user_id を持たせ、RLSで

auth.uid() = user_id

を強制している。

これは、

データベースレベルでユーザーを隔離する

設計だ。

アプリにバグがあっても、DBが守る。


Inngest ― ワーカーを持たない非同期処理

raindaryでは、重い処理をすべてイベント駆動にしている。

Inngest Cloudの Hobbyプラン(無料) を使用。

通常、非同期処理にはRedisとワーカーが必要だが、Inngestなら不要。

  • イベント発火
  • リトライ
  • 並列数制御
  • エラーハンドリング

が宣言的に書ける。

raindaryの処理フローは:

  1. import.requested
  2. extract.requested
  3. summarize.requested

UIはイベントを送るだけ。

これによりUXは軽い。


Render ― trafilatura常駐とスリープ仕様

本文抽出にはPythonの trafilatura を使用。

HTMLからノイズを除去し、記事本文を高精度に抽出できる。

Node系より安定している。

この抽出APIはRenderの Hobbyプランで動かしている。

ただし重要な仕様がある。

RenderのFree / Hobby Web Serviceは、

約15分リクエストがないとスリープする。

次のリクエストで再起動(コールドスタート)が発生し、数秒〜十数秒の遅延が出る。

これは公式仕様。

つまり、

  • しばらくアクセスがない
  • サービス停止
  • 次回リクエストで起動

という挙動になる。

raindaryでは、

  • 抽出は非同期
  • UIは待たない

ため、この遅延は問題にならない。


Claude 4.5 の価格と役割分担

raindaryでは2段階生成を採用している。

事実抽出 ― Claude Haiku 4.5

価格:

  • 入力 $1 / 1M tokens
  • 出力 $5 / 1M tokens

軽量で高速。

JSON形式で事実を抽出。

要約生成 ― Claude Sonnet 4.5

価格:

  • 入力 $3 / 1M tokens
  • 出力 $15 / 1M tokens

高品質な文章生成。

なぜ分けるのか?

価格差が約3倍あるからだ。

全文をSonnetに直接投げるとコストが跳ねる。

Haikuで圧縮 → Sonnetで仕上げ。

これがコスト最適化の核心。


コスト構造

raindaryのランニングコストは、

Claudeのトークン消費のみ

  • Vercel Hobby
  • Supabase Free
  • Inngest Hobby
  • Render Hobby

は無料枠内。

api_usageテーブルでトークンとコストを保存し、月間利用量を可視化している。

AIアプリで重要なのは、

コストが見えること。


まとめ ― raindaryの設計思想

raindaryは、

  • 保存はraindrop.io
  • UIはNext.js
  • 非同期はInngest
  • 抽出はRender常駐
  • 事実抽出はHaiku 4.5
  • 要約生成はSonnet 4.5
  • 永続化はSupabase

という責務分離で構成されている。

そして最大のポイントは、

LLM以外は無料で回る

AIアプリは設計で決まる。

コードは GitHub に公開している。

👉 https://github.com/enjoydarts/raindary

設計の全体像を知りたい人の参考になれば嬉しい。

コメント

タイトルとURLをコピーしました