T-CREATOR

Convex 初期設定完全手順:CLI・環境変数・Secrets・権限までゼロから構築

Convex 初期設定完全手順:CLI・環境変数・Secrets・権限までゼロから構築

モダンな Web アプリケーション開発において、バックエンドの構築と管理は開発者にとって大きな負担となることがあります。Convex は、この課題を解決する BaaS(Backend as a Service)として注目を集めており、リアルタイム同期と型安全性を兼ね備えた革新的なプラットフォームです。

本記事では、Convex の初期設定から CLI 環境構築、環境変数と Secrets の管理、そして権限設定まで、開発者が実際にプロダクション環境で運用するために必要な全手順を体系的に解説いたします。

背景

Convex とは何か:BaaS(Backend as a Service)の基本概念

Convex は、フルスタック開発を効率化する BaaS(Backend as a Service)プラットフォームです。従来のバックエンド開発で必要だったサーバー管理、データベース設計、API 構築といった複雑な作業を抽象化し、開発者がフロントエンド開発に集中できる環境を提供します。

以下の図は、Convex のアーキテクチャ全体を示しています:

mermaidflowchart TB
    client["フロントエンド<br/>React/Next.js"] -->|リアルタイム通信| convex["Convex Platform"]
    convex --> db[("データベース<br/>自動管理")]
    convex --> functions["サーバーレス関数<br/>TypeScript"]
    convex --> auth["認証システム<br/>内蔵"]
    convex --> search["全文検索<br/>エンジン"]

    dev["開発者"] -->|CLI操作| convex
    dev -->|型安全なクエリ| client

図で理解できる要点

  • Convex は一元的なプラットフォームとして機能し、データベース、認証、検索などを統合管理します
  • フロントエンドとバックエンドの間でリアルタイム通信が可能です
  • 開発者は CLI を通じて全ての設定を管理できます

従来のバックエンド構築の課題と Convex の解決策

従来のバックエンド開発では、複数のサービスやツールを個別に設定し、それらを連携させる必要がありました。この複雑さが Convex によってどのように解決されるかを見てみましょう。

従来の課題Convex の解決策
★ データベース設計とスキーマ管理自動的なスキーマ推論と型生成
★ サーバーのスケーリングと運用フルマネージドなサーバーレス環境
★ リアルタイム機能の実装内蔵されたリアルタイム同期機能
★ 認証システムの構築統合された認証プロバイダー
★ 環境間でのデータ整合性一元的な環境管理システム

Convex では、これらの課題が統合されたプラットフォーム内で自動的に解決されます。開発者は複雑なインフラ管理から解放され、ビジネスロジックの実装に専念できるのです。

リアルタイム同期と型安全性の重要性

現代の Web アプリケーションでは、リアルタイム性と型安全性が不可欠な要素となっています。Convex は、これら両方を同時に実現する独自のアプローチを採用しています。

リアルタイム同期の仕組み

  • WebSocket ベースの自動的なデータ同期
  • クライアント間でのリアルタイムな状態共有
  • オフライン時の自動的なデータキャッシュと同期

型安全性の実現

  • TypeScript ベースの完全な型推論
  • コンパイル時のエラー検出
  • IDE での強力なオートコンプリート機能

これらの特徴により、開発者は堅牢で保守性の高いアプリケーションを効率的に構築できます。

課題

CLI 環境の初期設定の複雑さ

Convex CLI の初期設定は、初めて利用する開発者にとって複数の課題を抱えています。Node.js 環境の確認から始まり、CLI 自体のインストール、そして認証設定まで、一連の手順で躓きやすいポイントが存在します。

特に以下のような問題が頻繁に発生します:

  • Node.js のバージョン互換性の問題
  • 権限不足によるインストールエラー
  • 認証トークンの設定ミス
  • プロジェクト初期化時の設定項目の理解不足

環境変数と Secrets の管理の難しさ

Convex では、開発環境、ステージング環境、本番環境それぞれで異なる設定値を管理する必要があります。この環境別の設定管理において、以下のような課題が発生することがあります:

mermaidflowchart LR
    dev["開発環境"] -->|異なる設定値| staging["ステージング環境"]
    staging -->|異なる設定値| prod["本番環境"]

    subgraph issues ["よくある問題"]
        leak["設定値の漏洩"]
        sync["環境間の設定不整合"]
        manage["設定値の煩雑な管理"]
    end

    dev -.->|課題| issues
    staging -.->|課題| issues
    prod -.->|課題| issues

図で理解できる要点

  • 各環境で設定値が異なるため、管理が複雑になります
  • 設定の漏洩や不整合が発生しやすい構造です
  • 環境数が増えるほど管理の複雑さが指数的に増加します

権限設定とセキュリティの考慮事項

Convex アプリケーションでは、適切な権限設定がセキュリティの要となります。しかし、権限システムの理解と実装には以下のような課題があります:

  • ユーザーロールの適切な定義方法
  • API 権限の細分化と設定
  • データアクセスルールの記述
  • セキュリティホールの回避方法

権限設定を誤ると、意図しないデータアクセスやセキュリティ脆弱性を生み出す可能性があるため、慎重な設計が必要です。

開発環境と本番環境の切り分け

開発プロセスにおいて、開発環境と本番環境の適切な分離は品質保証とリスク管理の観点から極めて重要です。Convex では以下の切り分け課題に直面することがあります:

  • 環境間でのデータベーススキーマの同期
  • 本番データの誤った操作防止
  • デプロイプロセスの自動化と品質管理
  • 環境固有の設定値の管理

これらの課題を解決するためには、体系的なアプローチと適切なツールの活用が不可欠です。

解決策

Convex CLI の段階的セットアップ手順

CLI 環境構築の課題を解決するため、Convex では段階的なセットアップアプローチを採用します。各ステップを明確に分離し、エラーが発生した場合の対処法も含めて体系的に進めることで、確実な環境構築が可能です。

セットアップの基本方針

  • 前提条件の事前確認
  • 段階的なインストールと検証
  • エラー時の詳細なトラブルシューティング
  • 設定の永続化と共有方法

環境変数管理のベストプラクティス

環境変数の管理課題に対しては、以下のベストプラクティスを適用します:

項目開発環境本番環境
★ 設定ファイル.env.local環境変数として設定
★ バージョン管理Git 除外対象暗号化して管理
★ アクセス権限開発者全員限定されたメンバーのみ
★ ローテーション手動・不定期自動・定期的

これらの方針により、セキュリティを保ちながら効率的な開発が可能になります。

Secrets の安全な設定方法

Secrets の管理では、暗号化、アクセス制御、監査ログの 3 つの柱を基軸とした包括的なアプローチを採用します:

mermaidflowchart TD
    secrets["Secrets管理"] --> encrypt["暗号化"]
    secrets --> access["アクセス制御"]
    secrets --> audit["監査ログ"]

    encrypt --> storage["安全な保存"]
    encrypt --> transit["転送時の保護"]

    access --> rbac["ロールベース制御"]
    access --> mfa["多要素認証"]

    audit --> logging["操作履歴"]
    audit --> alert["異常検知"]

図で理解できる要点

  • Secrets の保護は 3 つの主要な要素で構成されます
  • 各要素が相互に連携してセキュリティを強化します
  • 包括的なアプローチにより漏洩リスクを最小化します

権限管理の体系的なアプローチ

権限設定の課題解決には、最小権限の原則に基づいた階層的な権限モデルを採用します。これにより、セキュリティを保ちながら開発効率を最大化できます。

権限設計の基本原則

  • デフォルトでアクセス拒否
  • 明示的な権限付与のみ許可
  • 定期的な権限レビューと更新
  • 権限の継承とグループ管理

具体例

CLI 環境構築

Node.js 環境の確認

Convex CLI を利用するためには、Node.js 18.0.0 以上が必要です。まず現在の環境を確認しましょう。

bash# Node.jsのバージョン確認
node --version

# npmのバージョン確認
npm --version

バージョンが要件を満たさない場合は、Node.js の公式サイトまたは nvm(Node Version Manager)を使用してアップデートを行ってください。

bash# nvmを使用したNode.js最新LTS版のインストール
nvm install --lts
nvm use --lts

Convex CLI のインストール

Node.js 環境が準備できたら、Convex CLI をグローバルにインストールします。

bash# Convex CLIのグローバルインストール
npm install -g convex

# インストール確認
convex --version

インストールが完了したら、CLI が正常に動作することを確認してください。エラーが発生する場合は、権限の問題や既存の古いバージョンとの競合が考えられます。

一般的なインストールエラーと解決方法

エラーメッセージ原因解決方法
EACCES: permission denied権限不足sudoを使用するか、npm の権限設定を変更
command not found: convexPATH の問題.bashrc.zshrcで PATH を設定
version conflict古いバージョンとの競合既存バージョンをアンインストール後再インストール

プロジェクト初期化とログイン

CLI のインストールが完了したら、新しいプロジェクトを初期化します。

bash# 新しいプロジェクトディレクトリの作成
mkdir my-convex-app
cd my-convex-app

# プロジェクトの初期化
npm init -y

次に、Convex プロジェクトとして初期化し、認証を行います。

bash# Convexプロジェクトの初期化
convex dev --once

# Convexアカウントへのログイン(ブラウザが開きます)
convex auth

ログイン処理では、ブラウザが自動的に開き、Convex ダッシュボードでの認証を行います。認証が完了すると、ローカル環境に認証トークンが保存され、CLI から Convex サービスにアクセスできるようになります。

環境変数設定

開発環境の設定

開発環境では、ローカルでの開発に必要な設定値を管理します。まず、環境変数用のファイルを作成しましょう。

bash# 開発環境用の環境変数ファイルを作成
touch .env.local

.env.localファイルに開発環境固有の設定を記述します:

env# 開発環境設定
CONVEX_DEPLOYMENT=dev:your-project-name
NEXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud
DATABASE_URL=your-dev-database-url
STRIPE_PUBLIC_KEY=pk_test_your_dev_stripe_key

このファイルは機密情報を含むため、.gitignoreに追加してバージョン管理から除外する必要があります。

gitignore# 環境変数ファイルをGitから除外
.env.local
.env.*.local
*.env

本番環境の設定

本番環境では、Convex ダッシュボードまたは CLI を通じて環境変数を設定します。セキュリティを考慮し、本番環境の設定値はローカルファイルには保存しません。

bash# 本番環境に環境変数を設定
convex env set DATABASE_URL your-prod-database-url --prod
convex env set STRIPE_PUBLIC_KEY pk_live_your_prod_stripe_key --prod

設定した環境変数は、以下のコマンドで確認できます:

bash# 環境変数の一覧表示
convex env list

# 特定の環境の環境変数を表示
convex env list --prod

環境別の変数管理

複数の環境を管理する場合、環境ごとに異なる設定値を体系的に管理することが重要です。

bash# 開発環境の設定
convex env set API_BASE_URL https://dev-api.example.com --dev

# ステージング環境の設定
convex env set API_BASE_URL https://staging-api.example.com --staging

# 本番環境の設定
convex env set API_BASE_URL https://api.example.com --prod

環境変数の命名規則を統一することで、管理の一貫性を保てます:

環境変数名用途
API_*外部 API 関連API_BASE_URL, API_KEY
DB_*データベース関連DB_URL, DB_NAME
AUTH_*認証関連AUTH_SECRET, AUTH_PROVIDER
FEATURE_*機能フラグFEATURE_ANALYTICS, FEATURE_BETA

Secrets 管理

API キーの設定

Secrets は、API キーやパスワードなど、特に機密性の高い情報を安全に管理するための Convex の機能です。環境変数とは異なり、暗号化されて保存され、より厳格なアクセス制御が適用されます。

bash# 外部サービスのAPIキーをSecretsとして設定
convex secrets set OPENAI_API_KEY sk-your-openai-api-key
convex secrets set STRIPE_SECRET_KEY sk_live_your-stripe-secret-key
convex secrets set SENDGRID_API_KEY SG.your-sendgrid-api-key

Secrets の設定後、Convex 関数内でこれらの値を安全に使用できます:

typescript// convex/openai.ts
import { v } from 'convex/values';
import { action } from './_generated/server';

export const generateText = action({
  args: { prompt: v.string() },
  handler: async (ctx, args) => {
    // SecretsからAPIキーを安全に取得
    const apiKey = process.env.OPENAI_API_KEY;

    const response = await fetch(
      'https://api.openai.com/v1/completions',
      {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${apiKey}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          model: 'gpt-3.5-turbo',
          prompt: args.prompt,
          max_tokens: 100,
        }),
      }
    );

    return await response.json();
  },
});

データベース接続情報

データベースの接続情報は、特に慎重に管理する必要があります。Convex では内蔵データベースを使用しますが、外部データベースとの連携が必要な場合もあります。

bash# 外部データベースの接続情報をSecretsとして設定
convex secrets set POSTGRES_URL postgresql://user:password@host:5432/database
convex secrets set REDIS_URL redis://user:password@host:6379

外部データベースへの接続を行う Convex 関数の例:

typescript// convex/database.ts
import { action } from './_generated/server';
import { Client } from 'pg';

export const queryExternalDB = action({
  args: {},
  handler: async (ctx) => {
    const client = new Client({
      connectionString: process.env.POSTGRES_URL,
    });

    try {
      await client.connect();
      const result = await client.query(
        'SELECT * FROM users LIMIT 10'
      );
      return result.rows;
    } catch (error) {
      console.error('Database query failed:', error);
      throw new Error('External database query failed');
    } finally {
      await client.end();
    }
  },
});

外部サービス認証情報

Oauth 認証や Webhook 検証に必要な認証情報も、Secrets として安全に管理します。

bash# OAuth認証情報の設定
convex secrets set GOOGLE_CLIENT_SECRET your-google-client-secret
convex secrets set GITHUB_CLIENT_SECRET your-github-client-secret

# Webhook検証用のシークレット
convex secrets set STRIPE_WEBHOOK_SECRET whsec_your-stripe-webhook-secret

設定した Secrets の一覧は以下のコマンドで確認できます:

bash# Secretsの一覧表示(値は表示されません)
convex secrets list

# 特定のSecretの存在確認
convex secrets list | grep OPENAI_API_KEY

権限設定

ユーザー権限の定義

Convex では、認証されたユーザーに対して細かな権限制御を実装できます。まず、基本的な権限モデルを定義しましょう。

typescript// convex/schema.ts
import { defineSchema, defineTable } from 'convex/server';
import { v } from 'convex/values';

export default defineSchema({
  users: defineTable({
    email: v.string(),
    name: v.string(),
    role: v.union(
      v.literal('admin'),
      v.literal('user'),
      v.literal('moderator')
    ),
    permissions: v.array(v.string()),
    createdAt: v.number(),
    lastLogin: v.optional(v.number()),
  }).index('by_email', ['email']),

  posts: defineTable({
    title: v.string(),
    content: v.string(),
    authorId: v.id('users'),
    published: v.boolean(),
    createdAt: v.number(),
  }).index('by_author', ['authorId']),
});

ユーザーの権限を確認するためのヘルパー関数を作成します:

typescript// convex/auth.ts
import { query } from './_generated/server';
import { v } from 'convex/values';

export const getCurrentUser = query({
  args: {},
  handler: async (ctx) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) return null;

    const user = await ctx.db
      .query('users')
      .withIndex('by_email', (q) =>
        q.eq('email', identity.email)
      )
      .first();

    return user;
  },
});

export const hasPermission = query({
  args: { permission: v.string() },
  handler: async (ctx, args) => {
    const user = await getCurrentUser(ctx, {});
    if (!user) return false;

    return (
      user.permissions.includes(args.permission) ||
      user.role === 'admin'
    );
  },
});

API 権限の設定

各 API 関数に対して、適切な権限チェックを実装します。

typescript// convex/posts.ts
import { mutation, query } from './_generated/server';
import { v } from 'convex/values';

export const createPost = mutation({
  args: {
    title: v.string(),
    content: v.string(),
    published: v.boolean(),
  },
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) {
      throw new Error('認証が必要です');
    }

    const user = await ctx.db
      .query('users')
      .withIndex('by_email', (q) =>
        q.eq('email', identity.email)
      )
      .first();

    if (!user) {
      throw new Error('ユーザーが見つかりません');
    }

    // 投稿権限のチェック
    if (
      !user.permissions.includes('create_post') &&
      user.role !== 'admin'
    ) {
      throw new Error('投稿権限がありません');
    }

    return await ctx.db.insert('posts', {
      ...args,
      authorId: user._id,
      createdAt: Date.now(),
    });
  },
});

セキュリティルールの実装

データの閲覧・編集に関するセキュリティルールを実装します。

typescript// convex/posts.ts (続き)
export const updatePost = mutation({
  args: {
    postId: v.id('posts'),
    title: v.optional(v.string()),
    content: v.optional(v.string()),
    published: v.optional(v.boolean()),
  },
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) {
      throw new Error('認証が必要です');
    }

    const user = await ctx.db
      .query('users')
      .withIndex('by_email', (q) =>
        q.eq('email', identity.email)
      )
      .first();

    if (!user) {
      throw new Error('ユーザーが見つかりません');
    }

    const post = await ctx.db.get(args.postId);
    if (!post) {
      throw new Error('投稿が見つかりません');
    }

    // 所有者または管理者のみが編集可能
    if (
      post.authorId !== user._id &&
      user.role !== 'admin'
    ) {
      throw new Error('この投稿を編集する権限がありません');
    }

    const { postId, ...updateData } = args;
    return await ctx.db.patch(postId, updateData);
  },
});

ロールベースの権限チェック機能を共通化することで、保守性を向上させます:

typescript// convex/permissions.ts
import { DatabaseReader } from './_generated/server';

export async function requireRole(
  ctx: { db: DatabaseReader; auth: any },
  requiredRole: 'admin' | 'moderator' | 'user'
) {
  const identity = await ctx.auth.getUserIdentity();
  if (!identity) {
    throw new Error('認証が必要です');
  }

  const user = await ctx.db
    .query('users')
    .withIndex('by_email', (q) =>
      q.eq('email', identity.email)
    )
    .first();

  if (!user) {
    throw new Error('ユーザーが見つかりません');
  }

  const roleHierarchy = { admin: 3, moderator: 2, user: 1 };

  if (
    roleHierarchy[user.role] < roleHierarchy[requiredRole]
  ) {
    throw new Error(`${requiredRole}権限が必要です`);
  }

  return user;
}

この共通関数を使用することで、権限チェックを簡潔に記述できます:

typescript// convex/admin.ts
import { mutation } from './_generated/server';
import { v } from 'convex/values';
import { requireRole } from './permissions';

export const deleteUser = mutation({
  args: { userId: v.id('users') },
  handler: async (ctx, args) => {
    // 管理者権限が必要
    await requireRole(ctx, 'admin');

    return await ctx.db.delete(args.userId);
  },
});

まとめ

Convex の初期設定から権限管理まで、本記事では開発者が実際のプロダクション環境で必要となる全ての手順を体系的に解説いたしました。

重要なポイントの振り返り

  1. CLI 環境構築では、Node.js 環境の確認から始まり、段階的なインストールと認証設定を行うことで、確実な開発環境を構築できます

  2. 環境変数管理では、開発環境と本番環境を適切に分離し、セキュリティを保ちながら効率的な設定管理を実現します

  3. Secrets 管理では、API キーやデータベース接続情報などの機密情報を暗号化して安全に保存し、アクセス制御を徹底します

  4. 権限設定では、ロールベースアクセス制御を実装し、最小権限の原則に基づいたセキュアなアプリケーションを構築します

これらの設定を適切に行うことで、Convex を活用したモダンな Web アプリケーションの開発基盤が整います。特に、セキュリティと保守性を両立させた設計により、長期的な運用においても安心してサービスを提供できるでしょう。

Convex のパワフルな機能を最大限に活用し、効率的で安全なアプリケーション開発を始めましょう。

関連リンク