Misskey のディメンションシステム#
概要#
ディメンションシステムは、並列的で分離されたタイムラインビューを構成可能なコンテンツ配信で実現する、Misskey のコアアーキテクチャ機能です。ディメンションは数値 ID を使用して、インタラクションパターンに基づいて重複または分離可能な独立したコンテンツ空間を作成します。
ディメンションを使用することで、同一インスタンス内に複数の「世界」を構築でき、ユーザーは特定のディメンションを選択してノート(投稿)を作成・閲覧できます。このシステムは、コミュニティの分離、コンテンツの分類、プライベート空間の作成など、様々なユースケースに対応します。
基本概念#
ディメンション番号の範囲#
ディメンションは数値 ID によって識別され、その範囲によって異なる動作を示します:
- ディメンション 0: デフォルト / パブリックディメンションで、全ユーザーに可視
- ディメンション 1-999: パブリックディメンションで、ディメンション 0 にクロスポストされる
- ディメンション ≥1000: プライベートディメンションで、ディメンション 0 にクロスポストされず、自動的にローカル専用としてマークされる
この 3 層構造により、完全にパブリックなコンテンツ(ディメンション 0)、セミパブリックなコンテンツ(1-999)、完全にプライベートなコンテンツ(1000 以上)を区別できます。
型定義#
MiNoteWithDimension 型は、ノートにオプションのディメンションフィールドを追加します:
export type MiNoteWithDimension = MiNote & { dimension?: number };
サーバーメタデータ設定には、dimensionsフィールドが含まれます(デフォルトは 10000)。
ディメンションタイプとタイムラインビュー#
全ての主要なタイムラインタイプがディメンションフィルタリングをサポートしています:
ハイブリッドタイムライン#
HybridTimelineChannelは、コンストラクタでディメンションパラメータを受け取ります。
ローカルタイムライン#
LocalTimelineChannelは、ディメンションフィルタリングをサポートします。
チャンネルタイムライン#
ChannelChannelは、ディメンションパラメータを受け取ります。
ロールタイムライン#
RoleTimelineChannelは、ディメンションベースのフィルタリングをサポートします。
全てのチャンネルは、shouldDeliverByDimension () フィルタリングを使用します。
ディメンション間のノート配信#
コアユーティリティ関数#
packages/backend/src/misc/dimension.tsは、主要な関数を提供します:
- normalizeDimension(): ディメンション値を検証・正規化します
- getNoteDimension(): ノートからディメンションを抽出し、デフォルトは 0
- shouldDeliverByDimension(): ディメンションとクロスディメンションルールに基づいて、ノートを閲覧者に配信すべきか判定
- getDeliverTargetDimensions(): ノートを配信すべき全てのディメンション ID を計算
リプライと Renote#
クロスディメンションインタラクションにより、ノートは複数のディメンションに配信されます:
- リプライ / Renote 対象のディメンションが配信ターゲットに含まれます
- メンションはディメンション境界を越えます
- 可視ユーザー ID がクロスディメンション配信に影響します
複数ディメンション配信#
ノート作成時、ノートは複数のディメンションに配信されます:
const dimensionTargets = await getDeliverTargetDimensions(
note as MiNoteWithDimension,
(noteId) => this.cacheService.noteDimensionCache.get(noteId),
);
const pushToDimension = (name: FanoutTimelineName, id: string, maxlen: number) => {
for (const dimension of dimensionTargets) {
if (dimension > 0) this.fanoutTimelineService.pushDimension(name, id, dimension, r);
else this.fanoutTimelineService.push(name, id, maxlen, r);
}
};
この仕組みにより、異なるディメンションのユーザー間でも、リプライや Renote を通じてコミュニケーションが可能になります。
ディメンション ID の処理とフォールバック#
ノート作成時の処理#
data.dimension = normalizeDimension(data.dimension, this.meta.dimensions ?? 1);
if (typeof data.dimension === 'number' && data.dimension >= 1000) data.localOnly = true;
ディメンションはキャッシュに保存されます:
if (typeof data.dimension === 'number') {
(insert as MiNoteWithDimension).dimension = data.dimension;
void this.cacheService.noteDimensionCache.set(insert.id, data.dimension);
}
ディメンション情報は、データベースの直接のカラムではなく、拡張メタデータとして保存され、パフォーマンスのために別途キャッシュされます。
Fanout タイムラインサービス#
FanoutTimelineServiceは、ディメンション対応メソッドを提供します:
- pushDimension(): Redis ソート済みセットを使用してディメンション固有のタイムラインにノートをプッシュ、時間ウィンドウ方式(1 時間保持)
- getDimension(): ディメンション固有のタイムラインからノートを取得
- getMultiDimension(): 特定のディメンション内の複数タイムラインからノートを取得
ディメンションタイムラインは、サイズ制限ではなく時間ウィンドウ(1 時間保持)を使用します。これにより、アクティビティが低いディメンションでも一定期間コンテンツが保持されます。
API エンドポイント#
タイムライン API エンドポイントは、ディメンションパラメータを受け付けます:
- notes/timeline:
dimension: { type: 'integer', minimum: 0, nullable: true } - notes/hybrid-timeline: ディメンションパラメータを受け付け
- notes/local-timeline: ディメンション対応
- notes/global-timeline: ディメンション対応
両エンドポイントとも、ノートエンティティサービスにviewerDimensionを渡してパッキングします。
ディメンション選択の UI 要素#
コアディメンション選択ユーティリティ#
selectDimension 関数は、集中的なディメンション選択を提供します:
export async function selectDimension(current?: number | null): Promise<number | undefined> {
const max = Math.max(instance.dimensions ?? 1, 1) - 1;
const { canceled, result } = await os.inputNumber({
title: i18n.ts.dimension,
default: current ?? prefer.r.dimension.value,
min: 0,
max,
step: 1,
});
if (canceled || result == null) return undefined;
return result;
}
数値入力ダイアログを使用し、範囲は 0 から instance.dimensions - 1 までです。
タイムラインページ#
タイムラインページには、ディメンション選択が含まれます:
- ヘッダーボタン(デスクトップ): 現在のディメンション値を持つキューブアイコン
- オプションメニュー: ドロップダウンでのディメンション選択
- pickDimension 関数: selectDimension () を呼び出して値を更新
ディメンションは、MkPostFormとMkTimelineコンポーネントに渡されます。
投稿フォーム#
MkPostForm コンポーネントには以下が含まれます:
- その他の設定メニュー: "..." メニューのディメンションピッカー
- pickDimension 関数: 作成時にディメンションを変更可能
- 警告表示: プライベートディメンション(≥1000)の警告を表示
- ディメンション状態: props または設定から初期化
DeckUI カラム#
DeckUI は、複数のカラムタイプでディメンション選択を含みます:
タイムラインカラム#
チャンネルカラム#
ロールタイムラインカラム#
専用ページ#
チャンネルページとロールページには、ディメンション選択のためのヘッダーアクションが含まれます。
ディメンション可用性#
hasDimension 関数は、どのタイムラインがディメンションをサポートするか決定します:
export function hasDimension(timeline: string | undefined | null): boolean {
if (!timeline) return false;
if (basicTimelineTypes.includes(timeline as BasicTimelineType)) return true;
return timeline === 'channel' || timeline === 'role';
}
サポート対象:基本タイムライン(home、local、media、social、global)、channel、role タイムライン。
UI パターン#
全てのディメンション UI は一貫したパターンに従います:
- キューブアイコン(ti ti-cube)がディメンションを表現
- アイコンと一緒に現在のディメンション番号を表示
- 選択時に数値入力ダイアログ
- ディメンション > 0 の場合、ヘッダーにディメンションバッジ
- タイムラインごとのディメンション値の永続化
ディメンションが投稿と閲覧に与える影響#
ノート作成時のディメンション選択#
notes/create エンドポイントは、dimension パラメータを受け付けます。フロントエンドの selectDimension ユーティリティは、ユーザーに数値入力(0 から instance.dimensions - 1)を促します。
ディメンションの検証は、normalizeDimension により、1 から dimensionCount - 1 の有限整数を保証します。ディメンションはノートと一緒に保存されます。
ディメンション可視性ルール#
shouldDeliverByDimension 関数は、ノートの可視性を決定します:
基本ルール:
- viewerDimension が null: 全てのノートが可視
- ディメンション 0 のノート: ディメンション 0 の閲覧者のみに可視
- ディメンション 0 の閲覧者: ディメンション 1-999 が閲覧可能(1000 以上は不可)
- デフォルトルール: 閲覧者は自身のディメンションのみ閲覧可能
クロスディメンションインタラクション:
ユーザーは常に以下のノートを閲覧可能:
- 自分宛のメンション
- visibleUserIds に含まれる
- 自分のノートへのリプライ
- 自分のノートの Renote
これらのルールにより、ディメンションが異なっても社会的インタラクションが保たれます。
タイムラインフィルタリング#
API エンドポイント:
タイムラインエンドポイントは、dimension パラメータを受け付けます:
Redis ベースのフィルタリング:
Fanout タイムラインが有効な場合、システムはディメンション固有の Redis ソート済みセットから取得します。ディメンションタイムラインは時間ウィンドウ方式(1 時間保持)です。
ノートのパッキング:
viewerDimension は NoteEntityService に渡され、ノートが閲覧者のディメンションで可視でない場合はエラーをスローします。
リアルタイムストリーミング#
ストリーミングチャンネルは閲覧者のディメンションを追跡し、shouldDeliverByDimension でフィルタリングします。適用対象:
配信ターゲット#
getDeliverTargetDimensions がノートを受信するディメンションを計算します:
インスタンス設定#
最大ディメンション数は Meta テーブルに保存され、デフォルトは 10000です。有効なディメンション: 0 から dimensions - 1 まで。
管理者によるディメンション管理#
管理者設定インターフェース#
管理者は、管理設定パネルからディメンションを設定します:
場所: 管理設定ページ
セクション: キューブアイコン付きの「Dimension」フォルダ
設定: 「dimensions」の単一数値入力(最小: 1)
管理 API エンドポイント#
ディメンションを管理する 2 つの管理者専用エンドポイント:
設定の読み取り: admin/meta
- 要件: requireAdmin: true
- 権限: read:admin
- 戻り値:現在の dimensions 値(整数、最小 1)
設定の更新: admin/update-meta
- 要件: requireAdmin: true
- 権限: write:admin
- 受け付け: dimensions パラメータ(整数、最小 1)
- バリデーション
データベース保存#
@Column('integer', {
default: 10000,
})
public dimensions: number;
デフォルト:インスタンスあたり 10000 ディメンション。
ロールベースのアクセス制御#
ディメンション固有のポリシーは存在しません。 RolePolicies 型には 47 個の権限ポリシーが含まれますが、以下を制御するものはありません:
- 誰が特定のディメンションに投稿できるか
- 誰が特定のディメンションを閲覧できるか
- 誰がディメンションを設定できるか
- ディメンションレベルのアクセス制限
アクセスモデル#
ディメンションはグローバル可用性で動作します:
- 管理者制御: ディメンションカウントのみ設定可能
- ユーザー自由度: 全ユーザーが任意のディメンション(0 から dimensions-1)に投稿可能
- 制限なし: ロール / 権限 / ユーザーグループによる制限なし
- デフォルトでパブリック: ディメンションは分離またはアクセス制御されていない
ユーザーレベル設定#
ユーザーは設定で優先デフォルトディメンションを設定可能(0 からインスタンス最大値まで)。
ローカライゼーション#
翻訳キー:
- i18n.ts.dimension - 「Dimension」
- i18n.ts._serverSettings.dimensions - 「Dimension count」
- i18n.ts._serverSettings.dimensionsDescription - 説明テキスト
- "Dimension count"
- "Number of available dimensions. Must be 1 or higher."
管理制限#
管理者はディメンション総数のみ制御可能です。不可能な操作:
- 個別の名前付きディメンションの作成
- ロールによる特定ディメンションへのアクセス制限
- ディメンション固有のポリシー設定
- モデレーターへのディメンション管理の委任
- 承認ワークフローの設定
- アクセス制御された組織構造の作成
まとめ#
Misskey のディメンションシステムは、タイムラインとノート配信のための強力で柔軟なアーキテクチャを提供します。主要なポイント:
- 3 層構造: ディメンション 0(パブリック)、1-999(セミパブリック)、1000 以上(プライベート)により、異なるコンテンツ分離レベルを実現
- クロスディメンションインタラクション: メンション、リプライ、Renote はディメンション境界を越えて動作し、社会的つながりを維持
- 包括的な UI 統合: 全ての主要なタイムラインタイプと投稿インターフェースがディメンション選択をサポート
- パフォーマンス最適化: Redis ベースの fanout システムと時間ウィンドウ保持により、スケーラブルな配信を実現
- シンプルな管理: 管理者はディメンション総数を設定可能だが、きめ細かいアクセス制御は実装されていない
このシステムにより、インスタンス管理者は、ロールベースの権限なしで、ユーザーが自由に利用できる複数の並列コンテンツ空間を作成できます。