汎用認証プラットフォーム & データリレーサーバー。複数の認証方式(OAuth / パスワード / MFA)、組織・チーム管理、プロジェクトの永続化、および WebSocket ベースのリアルタイムメッセージリレーを提供します。
Cernere は 常時接続セッションの強固な認証 を基盤とするセキュリティモデルを採用しています。
外部からの破壊的変更を伴うリクエスト(データの削除・上書き・権限変更など)は、認証済みかつ常時接続中のセッションからのみ受け付けます。
- 常時接続 (Always-Connected): WebSocket による持続的な接続を維持し、30 秒間隔の ping/pong で生存を検証します。接続が切れたセッションは即座に
SessionExpired状態に遷移し、以降の操作は拒否されます。 - 強固な認証 (Strong Authentication): JWT トークンまたはセッション ID による認証を接続確立時に必須とし、未認証の接続は即座に拒否します。
- 破壊的操作のブロック: 認証されていない、またはセッションが無効な状態からの破壊的リクエストはサーバ側で遮断されます。
- 最小権限の原則: リレーメッセージは同一ユーザのセッション間に制限され、他ユーザへの意図しない影響を防ぎます。
- 操作ログ: すべての WebSocket コマンドは
operation_logsテーブルに記録され、完全な監査証跡を提供します。
Layer 1: Cookie / Bearer Token 検証 (401)
Layer 2: Redis セッション TTL チェック (7 日間, 401)
Layer 3: ユーザー状態検証 (LoggedIn 必須, 403)
Layer 4: リソース所有権・ロールチェック (403)
| 分類 | 技術 |
|---|---|
| Web サーバー | TypeScript / uWebSockets.js |
| データベース | PostgreSQL 17 (Drizzle ORM) |
| セッション管理 | Redis 7 (ioredis / TTL 7 日) |
| 認証 | GitHub OAuth / Google OAuth / パスワード (bcrypt) |
| MFA | TOTP / SMS (AWS SNS) / Email (AWS SES) |
| JWT | アクセストークン (60 分) / リフレッシュトークン (30 日) |
| フロントエンド | React 19 / React Router 7 / TanStack Query / TypeScript / Vite |
├── server/ # TypeScript バックエンド (Hono)
│ └── src/
│ ├── index.ts # エントリポイント
│ ├── app.ts # ルーティング + WebSocket
│ ├── config.ts # 環境変数設定
│ ├── commands.ts # WS コマンドディスパッチ
│ ├── redis.ts # Redis クライアント・セッション管理
│ ├── auth/ # 認証 (JWT, OAuth, パスワード)
│ ├── ws/ # WebSocket (セッション, ゲスト, リレー)
│ └── db/ # Drizzle ORM スキーマ + 接続
├── packages/
│ ├── id-service/ # 汎用 Identity Service SDK
│ ├── id-cache/ # Id Service 用キャッシュレイヤー
│ ├── service-adapter/ # 外部サービス用 WebSocket 認証アダプタ
│ └── env-cli/ # Infisical シークレット管理 CLI
├── frontend/ # React フロントエンド
├── migrations/ # SQL マイグレーション
├── docs/ # 設計ドキュメント
├── spec/ # セキュリティ仕様
├── env-cli.config.ts # env-cli プロジェクト設定
├── docker-compose.yaml # 本番 + dev profile (DB 外部)
└── docker-compose.standalone.yaml # All-in-One 用 (DB 内蔵)
cd server && npm install
cd frontend && npm install.env をプロジェクトルートに作成(.env.example を参照)。
Infisical を使用する場合は env-cli で管理可能。
npm run env:setup # Infisical 初回設定
npm run env:initialize # デフォルト値を Infisical に登録すべて npm run env:up 経由で起動できます。Infisical から環境変数を取得し、.env を一時生成して docker compose up を実行、終了後に .env を自動削除します。
| コマンド | モード | DB/Redis | 説明 |
|---|---|---|---|
npm run env:up |
dev | 外部 (Infra) | ホットリロード開発 |
npm run env:up:prod |
prod | 外部 (Infra) | ビルド済みイメージで本番起動 |
npm run env:up:standalone |
standalone | 内蔵 | DB 込み All-in-One 本番 |
npm run env:up:standalone:dev |
standalone-dev | 内蔵 | DB 込み All-in-One 開発 |
npm run env:up:fg |
dev (フォアグラウンド) | 外部 | ログ表示、Ctrl+C で停止 |
LUDIARS Infra が起動済みの前提。
npm run env:up| サービス | 説明 | ポート |
|---|---|---|
| backend-dev | Node.js (tsx watch) | 8080 |
| frontend-dev | Vite dev server (HMR) | 5173 |
npm run env:up:prod| サービス | 説明 | ポート |
|---|---|---|
| backend | Node.js (dist/index.js) | 8080 |
| frontend | nginx (静的配信 + API/WS プロキシ) | 80 |
Infra なしで Cernere 単体で動かしたい場合。
# 本番
npm run env:up:standalone
# 開発
npm run env:up:standalone:dev| サービス | 説明 | ポート |
|---|---|---|
| postgres | PostgreSQL 17 | 5432 |
| redis | Redis 7 | 6379 |
| backend / backend-dev | 上記と同じ | 8080 |
| frontend / frontend-dev | 上記と同じ | 5173 |
# 環境変数を生成
npm run env:gen
# バックエンド
cd server && npm run dev
# フロントエンド (別ターミナル)
cd frontend && npm run devenv:up を使わず手動で起動することも可能。
docker compose --profile dev up # dev
docker compose up -d # prod
docker compose -f docker-compose.yaml -f docker-compose.standalone.yaml up -d # standalone
docker compose -f docker-compose.yaml -f docker-compose.standalone.yaml --profile dev up # standalone-devセキュリティモデル: 公開エンドポイントは 認証 (
/auth) のみです。セッションの確立(WebSocket アップグレード)および現在の状態確認はすべて/authで行われます。データの参照・変更を含む操作は WebSocket セッション経由で実行されます。エンドポイントの詳細はserver/src/app.tsを参照してください。
GET /auth?token=<jwt> # 新規接続 (JWT 認証)
GET /auth?session_id=<id> # 再接続 (セッション ID)
- Ping 間隔: 30 秒 (サーバー → クライアント)
- Pong タイムアウト: 10 秒
- セッション TTL: 7 日間 (Redis)
- タイムアウト時は自動切断し、セッションは
SessionExpiredに遷移
クライアント → サーバー:
サーバー → クライアント:
// 接続完了
{ "type": "connected", "session_id": "...", "user_state": { ... } }
// Ping
{ "type": "ping", "ts": 1234567890 }
// 状態変更通知
{ "type": "state_changed", "user_state": { ... } }
// コマンド応答
{ "type": "module_response", "module": "organization", "action": "list", "payload": [...] }
// リレーメッセージ受信
{ "type": "relayed", "from_session": "...", "payload": { ... } }| ターゲット | 説明 |
|---|---|
"broadcast" |
自身の他セッション全てに送信 |
{"user": "<user_id>"} |
特定ユーザーの全セッションに送信 |
{"session": "<session_id>"} |
特定セッションに直接送信 |
すべての状態変更操作は WebSocket 経由で実行されます。
| アクション | ペイロード | 権限 |
|---|---|---|
list |
— | 認証済み |
get |
{ organizationId } |
メンバー |
create |
{ name, slug, description? } |
認証済み |
update |
{ organizationId, name, description? } |
admin / owner |
delete |
{ organizationId } |
owner |
| アクション | ペイロード | 権限 |
|---|---|---|
list |
{ organizationId } |
メンバー |
add |
{ organizationId, userId, role? } |
admin / owner |
update_role |
{ organizationId, userId, role } |
admin / owner |
remove |
{ organizationId, userId } |
admin / owner / 自身 |
| アクション | ペイロード | 権限 |
|---|---|---|
list |
— | 認証済み |
get |
{ id } |
認証済み |
create |
{ code, name, dataSchema?, commands?, pluginRepository? } |
システム管理者 |
update |
{ id, name, dataSchema?, commands?, pluginRepository? } |
システム管理者 |
delete |
{ id } |
システム管理者 |
| アクション | ペイロード | 権限 |
|---|---|---|
list |
{ organizationId } |
メンバー |
enable |
{ organizationId, projectDefinitionId } |
admin / owner |
disable |
{ organizationId, projectDefinitionId } |
admin / owner |
| アクション | ペイロード | 権限 |
|---|---|---|
get |
{ userId } |
同一組織メンバー / 自身 |
MIT