2026年1月10日
バックエンドとフロントエンド
このドキュメントでは、Roxのバックエンドとフロントエンドの役割分担、技術スタック、そしてそれぞれで実現できることを説明します。
全体構成
Roxはモノレポ構成で、3つのパッケージで構成されています:
rox/
├── packages/
│ ├── backend/ # Hono Rox (APIサーバー)
│ ├── frontend/ # Waku Rox (Webクライアント)
│ └── shared/ # 共通型とユーティリティ
└── plugins/ # プラグインディレクトリ
| パッケージ | 実行環境 | 技術スタック |
|---|---|---|
| backend | サーバー (Bun) | Hono, Drizzle ORM, BullMQ |
| frontend | ブラウザ (React) | Waku, React Aria, Tailwind CSS |
| shared | 両方 | TypeScript型定義 |
バックエンド (packages/backend)
バックエンドはサーバーサイドで実行され、Roxのコアロジックを担当します。
技術スタック
| 技術 | 用途 |
|---|---|
| Bun | JavaScriptランタイム |
| Hono | Webフレームワーク |
| Drizzle ORM | データベースアクセス |
| BullMQ + Dragonfly | ジョブキュー |
| pino | ログ出力 |
主な責務
┌─────────────────────────────────────────────────────────┐
│ バックエンド │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ API Routes │ │ ActivityPub │ │ プラグイン │ │
│ │ /api/* │ │ Federation │ │ システム │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Repository │ │ Storage │ │ Job Queue │ │
│ │ Pattern │ │ Adapter │ │ (BullMQ) │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Database │ │ Auth │ │
│ │ PostgreSQL │ │ Passkey/PW │ │
│ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
1. API エンドポイント
Misskey互換APIとRox独自APIを提供します。
// Honoによるルート定義
app.post("/api/notes/create", async (c) => {
const { text, visibility } = await c.req.json();
const note = await noteRepository.create({ text, visibility });
return c.json(note);
});
エンドポイント例:
/api/notes/*- ノート操作/api/users/*- ユーザー操作/api/drive/*- ファイル操作/api/x/{pluginId}/*- プラグインAPI
2. ActivityPub連合
他のサーバーとの連合処理を担当します。
- 受信:
POST /inboxでActivityを受信 - 送信: 他サーバーへActivityを配送
- WebFinger:
/.well-known/webfingerでアカウント解決
3. データベース操作
リポジトリパターンでデータベースアクセスを抽象化。
// インターフェース
interface INoteRepository {
create(data: CreateNoteInput): Promise<Note>;
findById(id: string): Promise<Note | null>;
delete(id: string): Promise<void>;
}
// 実装(PostgreSQL用)
class PgNoteRepository implements INoteRepository {
async create(data) {
return await db.insert(notes).values(data).returning();
}
}
対応データベース:
- PostgreSQL(推奨)
- MySQL
- SQLite
4. ストレージアダプター
ファイル保存先を抽象化。
interface IStorageAdapter {
upload(file: File): Promise<string>;
delete(key: string): Promise<void>;
getUrl(key: string): string;
}
対応ストレージ:
- ローカルファイルシステム
- S3互換ストレージ(AWS S3, Cloudflare R2, MinIO)
5. プラグインシステム
バックエンドプラグインができること:
| 機能 | 説明 |
|---|---|
| イベントフック | ノート作成、ユーザー登録などをインターセプト |
| カスタムAPI | /api/x/{plugin-id}/ 配下にエンドポイント追加 |
| データ処理 | beforeイベントでデータ変更・キャンセル |
| スケジュールタスク | 定期実行タスク登録 |
| 設定ストレージ | プラグイン固有設定の永続化 |
// バックエンドプラグイン例
const plugin: RoxPlugin = {
id: "my-plugin",
onLoad({ events, logger }) {
events.on("note:afterCreate", ({ note }) => {
logger.info({ noteId: note.id }, "ノート作成");
});
},
routes(app) {
app.get("/status", (c) => c.json({ ok: true }));
},
};
フロントエンド (packages/frontend)
フロントエンドはブラウザで実行され、ユーザーインターフェースを担当します。
技術スタック
| 技術 | 用途 |
|---|---|
| Waku | React Server Components フレームワーク |
| React | UIライブラリ |
| React Aria Components | アクセシブルUIコンポーネント |
| Tailwind CSS v4 | スタイリング |
| Jotai | 状態管理 |
| Lingui | 国際化 (i18n) |
主な責務
┌─────────────────────────────────────────────────────────┐
│ フロントエンド │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Pages │ │ Components │ │ Hooks │ │
│ │ (Routes) │ │ (UI) │ │ (ロジック) │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ State │ │ i18n │ │ Styling │ │
│ │ (Jotai) │ │ (Lingui) │ │ (Tailwind) │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Auth │ │ API Client │ │
│ │ (Passkey) │ │ (fetch) │ │
│ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
1. ページとルーティング
Wakuのファイルベースルーティングでページを定義。
src/pages/
├── index.tsx # /
├── notes/
│ ├── index.tsx # /notes
│ └── [id].tsx # /notes/:id
└── settings/
└── index.tsx # /settings
2. UIコンポーネント
React Aria Componentsでアクセシブルなコンポーネントを構築。
import { Button, Dialog, Modal } from "react-aria-components";
function ComposeDialog() {
return (
<Modal>
<Dialog>
<Heading>新しいノート</Heading>
<TextField label="内容" />
<Button>投稿</Button>
</Dialog>
</Modal>
);
}
3. 状態管理
Jotaiでグローバル状態を管理。
import { atom, useAtom } from "jotai";
const userAtom = atom<User | null>(null);
const themeAtom = atom<"light" | "dark">("light");
function Header() {
const [user] = useAtom(userAtom);
return <div>{user?.name}</div>;
}
4. 国際化
Linguiで多言語対応。
import { Trans } from "@lingui/macro";
function Welcome() {
return <h1><Trans>ようこそ、Roxへ!</Trans></h1>;
}
対応言語:
- 日本語 (ja)
- 英語 (en)
5. フロントエンドプラグイン
フロントエンドプラグインができること:
| 機能 | 説明 |
|---|---|
| 設定UI | 管理画面にプラグイン設定コンポーネント追加 |
| ノートフッター | ノート下部にカスタム表示追加 |
| スタイル拡張 | カスタムCSS注入 |
// フロントエンドプラグイン例
export function PluginSettings({ pluginId }) {
return (
<div>
<h3>プラグイン設定</h3>
<p>ID: {pluginId}</p>
</div>
);
}
共通パッケージ (packages/shared)
バックエンドとフロントエンドで共有される型定義とユーティリティ。
// packages/shared/src/types/note.ts
export interface Note {
id: string;
text: string;
userId: string;
visibility: "public" | "home" | "followers" | "specified";
createdAt: Date;
}
// packages/shared/src/types/plugin.ts
export interface PluginManifest {
id: string;
name: string;
version: string;
permissions?: PluginPermission[];
}
データフロー
┌─────────────────┐ ┌──────────────────┐
│ フロントエンド │ HTTP API │ バックエンド │
│ (Browser) │ ◄────────────────► │ (Server) │
└────────┬────────┘ └────────┬─────────┘
│ │
│ fetch("/api/notes/create") │
│ ─────────────────────────────────► │
│ ▼
│ ┌────────────────┐
│ │ Event Bus │
│ │ beforeCreate │
│ └───────┬────────┘
│ │
│ ▼
│ ┌────────────────┐
│ │ Repository │
│ │ DB Insert │
│ └───────┬────────┘
│ │
│ ▼
│ ┌────────────────┐
│ │ Event Bus │
│ │ afterCreate │
│ └───────┬────────┘
│ │
│ ◄───────────────────────────────────┘
│ JSON Response
▼
┌─────────────────┐
│ 状態更新 │
│ UI再レンダリング│
└─────────────────┘
機能別の役割分担
| 機能 | バックエンド | フロントエンド |
|---|---|---|
| ノート作成 | バリデーション、DB保存、連合配送 | フォームUI、プレビュー |
| 認証 | セッション管理、Passkey検証 | ログインUI、生体認証連携 |
| ファイル管理 | アップロード、ストレージ保存 | ファイル選択UI、プレビュー |
| 検索 | 全文検索、フィルタリング | 検索UI、結果表示 |
| 通知 | 通知生成、配信 | 通知一覧UI、リアルタイム更新 |
| 設定 | 設定保存、検証 | 設定フォームUI |
| プラグイン | イベントフック、API提供 | 設定UI、表示拡張 |
開発時の考慮事項
バックエンドを修正すべき場合
- APIエンドポイントの追加・変更
- データベーススキーマの変更
- ActivityPub連合ロジックの変更
- 認証・認可ロジックの変更
- プラグインイベントの追加
フロントエンドを修正すべき場合
- UI/UXの変更
- 新しいページの追加
- コンポーネントの追加・変更
- 多言語対応の追加
- アクセシビリティの改善
両方を修正すべき場合
- 新機能の追加(API + UI)
- 新しいデータモデルの追加
- プラグインシステムの拡張
関連ドキュメント
- アーキテクチャ - 設計パターンの詳細
- プラグイン開発入門 - プラグイン入門ガイド
- プラグインアーキテクチャ - プラグインシステムの詳細
- APIリファレンス - API仕様