🎉

Next.js: アプリケーションアーキテクチャに関するハッカソンメモ

に公開

はじめに

こないだ参加したハッカソンで得た知見の備忘録です。

デプロイと環境変数

当たり前だがローカルの.envファイルは本番環境に自動で反映されない。

Vercel にデプロイする場合、プロジェクトのSettings -> Environment Variables に、本番環境で必要な全ての環境変数を設定する必要がある。

設定を追加・変更した後は、変更を反映させるために再デプロイが必須


画像アップロードのアーキテクチャ

画像のようなバイナリファイルをリレーショナルデータベースに直接保存するのは、パフォーマンスとコストの観点から非効率。

採用したフローは以下の通り。

  1. クライアントから画像ファイルをアップロード用 API に送信する。
  2. API は Vercel Blob のようなファイルストレージサービスにファイルをアップロードする。
  3. ファイルストレージは、外部からアクセス可能な公開 URL を返す。
  4. この URL(文字列)を、データベースのicon_urlカラムに保存する。

Vercel でホストする場合、Vercel Blob は連携が容易で有効な選択肢となる。


外部画像の利用 (next/image)

next/imageコンポーネントは、セキュリティ上の理由から許可されていない外部ドメインの画像を最適化できない。未許可のドメインを指定すると 400 エラーが発生する。

Vercel Blob などの外部サービスに保存した画像を表示するには、next.config.ts (または .mjs) にて、該当ドメインを許可リストに追加する必要がある。

// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "*.public.blob.vercel-storage.com",
        port: "",
        pathname: "/**",
      },
    ],
  },
};

export default nextConfig;

設定変更後は開発サーバーの再起動が必要。


低コストな生成 AI の組み込み

ハッカソンなど、コストを抑えたい状況で生成 AI を試す場合、OpenRouter が有効。

OpenRouter は複数の AI モデルへのアクセスを仲介するサービスで、DeepSeek R1 のような無料枠のあるモデルも利用できる。OpenAI の SDK と互換性のある API を提供しているため、baseURLを変更するだけで利用可能。

// OpenRouter経由でDeepSeek R1を使用
import OpenAI from "openai";

const openai = new OpenAI({
  baseURL: "https://openrouter.ai/api/v1",
  apiKey: process.env.OPENROUTER_API_KEY,
});

const KINDNESS_PROMPT = `...`; // 省略

async function transformContent(content: string): Promise<string> {
  const completion = await openai.chat.completions.create({
    model: "deepseek/deepseek-r1:free",
    messages: [
      {
        role: "system",
        content: `You are a content transformer for a "Kind SNS". ...`,
      },
      {
        role: "user",
        content: KINDNESS_PROMPT + "\n\n" + content,
      },
    ],
    // ... params
  });
  // ...
}
KA projects

Discussion