Docs/database-schema

データベーススキーマドキュメント

ReCoronのデータベース設計と各テーブルの詳細説明です。

📋 目次

概要

ReCoronはPrisma ORMを使用してPostgreSQLデータベースと連携しています。スキーマは以下の4つの主要カテゴリに分類されています:

  1. Enums - 基本的な型定義
  2. 認証関連 - Better Authによるユーザー管理
  3. コア機能 - ジョブとAPIキー管理
  4. 使用量追跡 - 課金と悪用防止

Enums(列挙型)

Plan(プラン)

ユーザーの料金プランを定義します。

値説明ジョブ数月次実行回数最小実行間隔
FREE無料プラン5個500回60分
HOBBY趣味プラン20個10,000回30分
PROプロプラン100個50,000回15分

Method(HTTPメソッド)

HTTPリクエストのメソッドを定義します。

  • GET - リソースの取得
  • POST - リソースの作成
  • PUT - リソースの完全更新
  • DELETE - リソースの削除
  • PATCH - リソースの部分更新

Type(実行タイプ)

ジョブの実行方法を定義します。

値説明
AUTO自動実行(スケジュールに基づく)
MANUAL手動実行(API経由)

認証関連モデル

User(ユーザー)

システムのユーザー情報を管理します。Better Authと連携しています。

フィールド

フィールド型必須デフォルト説明
idString✓-ユーザーID(主キー)
nameString✓-ユーザー名
emailString✓-メールアドレス(一意)
emailVerifiedBoolean✓falseメール認証済みフラグ
imageString?-nullプロフィール画像URL
planPlan✓FREE料金プラン
isAdminBoolean✓false管理者権限フラグ
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

リレーション

  • sessions - ユーザーのセッション(1対多)
  • accounts - OAuth連携アカウント(1対多)
  • jobs - 作成したジョブ(1対多)
  • logs - 実行ログ(1対多)
  • apiKeys - APIキー(1対多)
  • monthlyUsages - 月次使用量(1対多)
  • dailyUsages - 日次使用量(1対多)
  • resourceHistories - リソース履歴(1対多)
  • WebhookJobs - Webhookジョブ(1対多)

インデックス

  • email - 一意制約

Session(セッション)

ユーザーの認証セッションを管理します。

フィールド

フィールド型必須デフォルト説明
idString✓-セッションID(主キー)
tokenString✓-セッショントークン(一意)
expiresAtDateTime✓-有効期限
ipAddressString?-nullアクセス元IPアドレス
userAgentString?-nullユーザーエージェント
userIdString✓-ユーザーID(外部キー)
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

リレーション

  • user - ユーザー(多対1、カスケード削除)

インデックス

  • token - 一意制約

Account(アカウント)

OAuth連携情報やパスワード認証を管理します。

フィールド

フィールド型必須デフォルト説明
idString✓-アカウントID(主キー)
accountIdString✓-プロバイダー側のアカウントID
providerIdString✓-プロバイダーID(github, google等)
userIdString✓-ユーザーID(外部キー)
accessTokenString?-nullアクセストークン
refreshTokenString?-nullリフレッシュトークン
idTokenString?-nullIDトークン
accessTokenExpiresAtDateTime?-nullアクセストークン有効期限
refreshTokenExpiresAtDateTime?-nullリフレッシュトークン有効期限
scopeString?-nullスコープ
passwordString?-nullパスワードハッシュ
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

リレーション

  • user - ユーザー(多対1、カスケード削除)

Verification(検証)

メール認証などの検証トークンを管理します。

フィールド

フィールド型必須デフォルト説明
idString✓-検証ID(主キー)
identifierString✓-識別子(メールアドレス等)
valueString✓-検証トークン
expiresAtDateTime✓-有効期限
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

コア機能モデル

Job(Cronジョブ)

スケジュール実行されるHTTPリクエストを管理します。

フィールド

フィールド型必須デフォルト説明
idString✓cuid()ジョブID(主キー)
userIdString✓-ユーザーID(外部キー)
nameString✓-ジョブ名
scheduleString✓-Cron式(例: "0 9 * * *")
timezoneString✓"Asia/Tokyo"タイムゾーン
urlString✓-リクエスト先URL
methodMethod✓GETHTTPメソッド
headersJson?-nullカスタムヘッダー
bodyString?-nullリクエストボディ
enabledBoolean✓true有効/無効フラグ
lastRunAtDateTime?-null最終実行日時
nextRunAtDateTime?-null次回実行予定日時
countInt✓0実行回数
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

リレーション

  • user - ユーザー(多対1、カスケード削除)
  • runningLogs - 実行ログ(1対多)
  • WebhookJobs - Webhookジョブ(1対1、オプション)

インデックス

  • userId - パフォーマンス向上
  • (enabled, nextRunAt) - 実行対象ジョブの検索用

使用例

// ジョブ作成
const job = await prisma.job.create({
  data: {
    userId: "user_123",
    name: "Daily Report",
    schedule: "0 9 * * *",
    timezone: "Asia/Tokyo",
    url: "https://api.example.com/report",
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ report: "daily" }),
  },
});

RunningLog(実行ログ)

ジョブの実行結果を記録します。

フィールド

フィールド型必須デフォルト説明
idString✓cuid()ログID(主キー)
jobIdString?-nullジョブID(外部キー、オプション)
userIdString✓-ユーザーID(外部キー)
typeType✓AUTO実行タイプ
startedAtDateTime✓-実行開始時刻
finishedAtDateTime✓now()実行完了時刻
urlString✓-リクエストURL
statusInt✓-HTTPステータスコード
responseBodyString?-nullレスポンスボディ
responseHeadersJson?-nullレスポンスヘッダー
durationMsInt✓-実行時間(ミリ秒)
successfulBoolean✓true成功/失敗フラグ
createdAtDateTime✓now()作成日時

リレーション

  • job - ジョブ(多対1、NULL設定)
  • user - ユーザー(多対1、カスケード削除)

インデックス

  • jobId - ジョブごとのログ検索用
  • createdAt - 日時順のログ取得用

注意事項

  • jobIdは削除されたジョブの場合NULLになります
  • ユーザーが削除されるとログも削除されます

WebhookJobs(Webhookジョブ)

外部サービスからのHTTPリクエストを受け付けるジョブです。

フィールド

フィールド型必須デフォルト説明
idString✓cuid()WebhookジョブID(主キー)
userIdString✓-ユーザーID(外部キー)
jobIdString✓-ジョブID(外部キー、一意)
endpointString✓-Webhookエンドポイント
headersJson?-nullカスタムヘッダー
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

リレーション

  • user - ユーザー(多対1、カスケード削除)
  • job - ジョブ(1対1、カスケード削除)

インデックス

  • userId - パフォーマンス向上
  • jobId - 一意制約

APIKey(APIキー)

プログラマティックアクセス用の認証キーを管理します。

フィールド

フィールド型必須デフォルト説明
idString✓cuid()APIキーID(主キー)
userIdString✓-ユーザーID(外部キー)
nameString✓-APIキー名(識別用)
keyHashString✓-トークンのハッシュ値(一意)
lastUsedDateTime?-null最終使用日時
expiresAtDateTime?-null有効期限
countInt✓0使用回数
scopesString[]✓[]アクセススコープ
enabledBoolean✓true有効/無効フラグ
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

リレーション

  • user - ユーザー(多対1、カスケード削除)
  • logs - APIログ(1対多)

インデックス

  • userId - パフォーマンス向上
  • keyHash - トークン検証用(一意制約)

スコープ

APIキーには以下のスコープを設定できます:

スコープ説明
read:jobsジョブの読み取り
write:jobsジョブの作成・更新・削除
read:keysAPIキーの読み取り
write:keysAPIキーの作成・削除

セキュリティ

  • トークンはハッシュ化されて保存されます
  • 実際のトークンは作成時のみ表示されます
  • 有効期限を設定できます

APILog(APIログ)

APIキーを使用したリクエストの履歴を記録します。

フィールド

フィールド型必須デフォルト説明
idString✓cuid()ログID(主キー)
apiKeyIdString✓-APIキーID(外部キー)
urlString✓-リクエストURL
methodMethod✓-HTTPメソッド
requestHeadersJson?-nullリクエストヘッダー
requestBodyString?-nullリクエストボディ
createdAtDateTime✓now()作成日時

リレーション

  • apiKey - APIキー(多対1、カスケード削除)

インデックス

  • apiKeyId - APIキーごとのログ検索用

使用量追跡モデル

MonthlyUsage(月次使用量)

ユーザーの月ごとの使用量と課金情報を追跡します。

フィールド

フィールド型必須デフォルト説明
idString✓cuid()使用量ID(主キー)
userIdString✓-ユーザーID(外部キー)
yearInt✓-年
monthInt✓-月(1-12)
totalExecutionsInt✓0総ジョブ実行回数
totalApiCallsInt✓0総API呼び出し回数
billedAmountDecimal✓0課金額
paidBoolean✓false支払い済みフラグ
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

リレーション

  • user - ユーザー(多対1、カスケード削除)

インデックス

  • (userId, year, month) - 一意制約
  • userId - パフォーマンス向上
  • (year, month) - 期間検索用

特徴

  • 削除されたリソースの使用量も含む
  • 悪用防止(頻繁な削除・再作成)に使用
  • 課金計算の基礎データ

DailyUsage(日次使用量)

より細かい粒度での使用量を追跡します。

フィールド

フィールド型必須デフォルト説明
idString✓cuid()使用量ID(主キー)
userIdString✓-ユーザーID(外部キー)
dateDate✓-日付
executionsInt✓0実行回数
apiCallsInt✓0API呼び出し回数
peakJobCountInt✓0最大ジョブ数
peakApiKeyCountInt✓0最大APIキー数
createdAtDateTime✓now()作成日時
updatedAtDateTime✓now()更新日時

リレーション

  • user - ユーザー(多対1、カスケード削除)

インデックス

  • (userId, date) - 一意制約
  • userId - パフォーマンス向上
  • date - 日付検索用

用途

  • 日次レポート生成
  • ピーク時の把握
  • より詳細な使用パターン分析

ResourceHistory(リソース履歴)

ジョブやAPIキーの作成・削除を追跡します。

フィールド

フィールド型必須デフォルト説明
idString✓cuid()履歴ID(主キー)
userIdString✓-ユーザーID(外部キー)
resourceTypeString✓-リソースタイプ("JOB" or "API_KEY")
resourceIdString✓-リソースID
actionString✓-アクション("CREATED" or "DELETED")
createdAtDateTime✓now()作成日時

リレーション

  • user - ユーザー(多対1、カスケード削除)

インデックス

  • (userId, resourceType) - パフォーマンス向上
  • createdAt - 時系列検索用

悪用防止

このテーブルは以下の悪用を防ぐために使用されます:

// 例: 今日の作成・削除回数をチェック
const todayHistory = await prisma.resourceHistory.findMany({
  where: {
    userId: "user_123",
    resourceType: "JOB",
    createdAt: {
      gte: new Date(new Date().setHours(0, 0, 0, 0)),
    },
  },
});

const createdCount = todayHistory.filter(h => h.action === "CREATED").length;
const deletedCount = todayHistory.filter(h => h.action === "DELETED").length;

// 今日5回以上作成削除している場合は制限
if (createdCount + deletedCount >= 10) {
  throw new Error("今日の作成・削除回数の上限に達しました");
}

リレーションシップ図

User
├── Session (1:多)
├── Account (1:多)
├── Job (1:多)
│   ├── RunningLog (1:多)
│   └── WebhookJobs (1:1)
├── APIKey (1:多)
│   └── APILog (1:多)
├── MonthlyUsage (1:多)
├── DailyUsage (1:多)
└── ResourceHistory (1:多)

データベース操作のベストプラクティス

1. トランザクション

複数のテーブルを更新する場合はトランザクションを使用:

await prisma.$transaction([
  prisma.job.create({ /* ... */ }),
  prisma.resourceHistory.create({
    data: {
      userId: "user_123",
      resourceType: "JOB",
      resourceId: jobId,
      action: "CREATED",
    },
  }),
  prisma.dailyUsage.update({ /* ... */ }),
]);

2. インデックスの活用

頻繁に検索されるフィールドにはインデックスが設定されています:

// ✅ インデックスを活用(高速)
await prisma.job.findMany({
  where: {
    userId: "user_123",
    enabled: true,
  },
});

// ❌ インデックスを活用していない(低速)
await prisma.job.findMany({
  where: {
    name: { contains: "report" },
  },
});

3. カスケード削除

ユーザーを削除すると関連データも自動削除されます:

// ユーザー削除時に自動削除されるもの:
// - Session
// - Account
// - Job(→ RunningLog, WebhookJobsも削除)
// - APIKey(→ APILogも削除)
// - MonthlyUsage
// - DailyUsage
// - ResourceHistory
await prisma.user.delete({
  where: { id: "user_123" },
});

マイグレーション

マイグレーション作成

npx prisma migrate dev --name add_new_feature

マイグレーション適用

# 開発環境
npx prisma migrate dev

# 本番環境
npx prisma migrate deploy

Prisma Clientの再生成

スキーマ変更後は必ず実行:

npx prisma generate

参考リンク