Open4

ソシャゲのフレンドシステムのDB構造を考えたい

ドマオードマオー

趣味で作っているAPIにソシャゲのような フレンドシステムが必要になったので、それを実装するためのテーブル構造を考えたい回

※ 以下、普通のフロントエンドエンジニアが考える 趣味等小規模な環境での利用を想定したDB設計です。専門外なので、プロダクションでスケールする方法であるかどうかは全く保証できません。

ドマオードマオー

要件

前提

  • 既にusersというテーブルがあり、そこに idというプライマリキー と code というフレンド登録用ユーザー識別コードがある

フレンド申請の流れ

  • ユーザーは、別のユーザーに フレンド申請を送ることができる
  • ユーザーがフレンド申請を送ると、相手のユーザーのフレンド申請許可待ちリストに入る
    • 同時に、申請したユーザーのフレンド申請中リストにも入る。
    • ユーザーは、一度送ったフレンド申請をキャンセルすることができる
  • ユーザーは、自分が受け取ったフレンド申請を 許可 または 拒否することができる
  • ユーザーは、フレンド申請をほぼリアルタイムで確認できるものとする

フレンドの利用方法

  • ユーザーは、クエストの開始前に まだフレンド登録していないゲスト・フレンド登録済みのフレンドからそれぞれ ゲスト30件 / フレンド40件 を取得した 利用フレンドキャラクター選択画面を経由する
    • 都度全件取得は負荷がかかるため、"利用フレンドキャラクター選択画面"は1日1回リセットされる仕様
    • ただしユーザーが再更新を選択すると、意図的に"利用フレンドキャラクター選択画面"を随時リセットできる

フレンド解除

  • ユーザーは任意のタイミングで フレンドを解除することができる
  • 片方がフレンド解除するともう片方もフレンドから消える

備考

  • フレンド状態は 他人/一方登録/相互登録 の3ステータスがある
  • "利用フレンドキャラクター選択画面"には ユーザーが自らのパーティに入れたキャラクターは出てこない
ドマオードマオー

登場しそうなDBテーブル

  • ユーザー

  • フレンド申請状態テーブル

  • フレンドテーブル

  • フレンドキャラクター選択画面一時データ保持テーブル

ドマオードマオー

ユーザー

type User struct {
  Id value_friend.PlayerId `gorm:"primaryKey"`
  Name string
  Code string
}

フレンド (申請中)

type FriendRequest struct {
	ManagedFriendId uint                     `gorm:"primaryKey"`
	CreatedAt       time.Time                `gorm:"autoCreateTime"`
	UpdatedAt       time.Time                `gorm:"autoUpdateTime"`
	PlayerId1       value_friend.PlayerId    `gorm:"index"`
	Player1         model_user.User          `gorm:"PRELOAD:false;foreignKey:PlayerId1"`
	PlayerId2       value_friend.PlayerId    `gorm:"index"`
	Player2         model_user.User          `gorm:"PRELOAD:false;foreignKey:PlayerId2"`
	State           value_friend.FriendState `gorm:"index"`
}

フレンド (成約済み)

type Friend struct {
	ManagedFriendId uint                  `gorm:"primaryKey"`
	CreatedAt       time.Time             `gorm:"autoCreateTime"`
	UpdatedAt       time.Time             `gorm:"autoUpdateTime"`
	PlayerId1       value_friend.PlayerId `gorm:"index"`
	Player1         model_user.User       `gorm:"PRELOAD:false;foreignKey:PlayerId1"`
	PlayerId2       value_friend.PlayerId `gorm:"index"`
	Player2         model_user.User       `gorm:"PRELOAD:false;foreignKey:PlayerId2"`
}

フレンドキャラクター選択画面一時データ保持テーブル

恐らくこれは フレンド情報自体は丸ごとクライアントに返して、クライアント側でいい感じに絞り込みなりして表示しているのではないかと思う。なので、一度フレンドをランダムにピックアップして返し、その結果を一定期間保管しておくためのテーブルを定義する。

type FriendCache struct {
	ManagedFriendId uint `gorm:"primaryKey"`
	/** requester's player id */
	PlayerId  value_friend.PlayerId `gorm:"index"`
	CreatedAt time.Time             `gorm:"autoCreateTime"`
	ExpiresAt time.Time
	Direction value_friend.FriendDirection
	/** another user's player id */
	TargetPlayerId value_friend.PlayerId
	TargetPlayer   model_user.User `gorm:"PRELOAD:false;foreignKey:TargetPlayerId"`
}