シーケンス図

主要ユースケースの処理シーケンスを示します。

1. ユーザー登録・ログイン

sequenceDiagram
  autonumber
  actor U as 利用者(ブラウザ)
  participant API as auth ルーター
  participant SEC as security
  participant DB as SQLite

  U->>API: POST /api/auth/login {username, password}
  API->>DB: ユーザー検索(username)
  DB-->>API: User
  API->>SEC: verify_password(pw, hash)
  SEC-->>API: 照合結果
  alt 認証成功
    API->>SEC: create_access_token(user_id)
    SEC-->>API: HMAC署名トークン
    API-->>U: 200 {access_token, user}
    Note over U: トークンをローカルに保存し
以降のAPI/WSで利用 else 認証失敗 API-->>U: 401 認証エラー end
sequenceDiagram
  autonumber
  actor U as User (browser)
  participant API as auth router
  participant SEC as security
  participant DB as SQLite

  U->>API: POST /api/auth/login {username, password}
  API->>DB: find user(username)
  DB-->>API: User
  API->>SEC: verify_password(pw, hash)
  SEC-->>API: result
  alt success
    API->>SEC: create_access_token(user_id)
    SEC-->>API: HMAC-signed token
    API-->>U: 200 {access_token, user}
    Note over U: Store token locally
use for later API/WS calls else failure API-->>U: 401 auth error end
図7. ログイン。トークンは PBKDF2 で検証後、HMAC-SHA256 署名付きで発行される。

2. メッセージ送信とリアルタイム配信

sequenceDiagram
  autonumber
  actor U as 送信者
  participant API as messages ルーター
  participant DEP as get_current_user
  participant SVC as services
  participant DB as SQLite
  participant WSM as ConnectionManager
  actor O as 他メンバー(接続中)

  U->>API: POST /api/channels/{id}/messages
  API->>DEP: トークン検証
  DEP-->>API: current_user
  API->>SVC: require_membership(server, user)
  SVC-->>API: OK
  API->>DB: Message を保存 + 添付を紐付け
  DB-->>API: 保存済みメッセージ
  API->>SVC: serialize_message()
  SVC-->>API: MessagePublic
  API->>SVC: 通知対象ユーザーID解決
  SVC-->>API: [user_ids]
  API->>WSM: send_to_users(targets, message_created)
  WSM-->>O: WS イベント {type: message_created}
  Note over API: 本文に @メンションがあれば
対象へ mention イベントも送信 API-->>U: 201 MessagePublic O->>O: 画面にメッセージを追加描画
sequenceDiagram
  autonumber
  actor U as Sender
  participant API as messages router
  participant DEP as get_current_user
  participant SVC as services
  participant DB as SQLite
  participant WSM as ConnectionManager
  actor O as Other members (online)

  U->>API: POST /api/channels/{id}/messages
  API->>DEP: verify token
  DEP-->>API: current_user
  API->>SVC: require_membership(server, user)
  SVC-->>API: OK
  API->>DB: save Message + link attachments
  DB-->>API: saved message
  API->>SVC: serialize_message()
  SVC-->>API: MessagePublic
  API->>SVC: resolve target user IDs
  SVC-->>API: [user_ids]
  API->>WSM: send_to_users(targets, message_created)
  WSM-->>O: WS event {type: message_created}
  Note over API: If body has @mentions,
also send mention event API-->>U: 201 MessagePublic O->>O: append message to view
図8. メッセージ送信。保存後にWebSocketで接続中の対象メンバーへリアルタイム配信し、メンションは個別通知する。

3. WebSocket 接続確立

sequenceDiagram
  autonumber
  actor U as ブラウザ
  participant GUARD as PrivateNetworkGuard
  participant WS as ws エンドポイント
  participant SEC as security
  participant WSM as ConnectionManager

  U->>GUARD: WSS /ws?token=...
  alt 社内プライベートIP
    GUARD->>WS: ハンドシェイク継続
    WS->>SEC: decode_access_token(token)
    SEC-->>WS: user_id
    alt トークン有効かつ有効ユーザー
      WS->>WSM: connect(user_id, websocket)
      WSM-->>U: accept(接続確立)
      loop 接続中
        U->>WS: ping(受信ループ)
      end
      U-->>WS: 切断
      WS->>WSM: disconnect(user_id, websocket)
    else 無効
      WS-->>U: close(4401)
    end
  else 社外グローバルIP
    GUARD-->>U: close(4403)
  end
        
sequenceDiagram
  autonumber
  actor U as Browser
  participant GUARD as PrivateNetworkGuard
  participant WS as ws endpoint
  participant SEC as security
  participant WSM as ConnectionManager

  U->>GUARD: WSS /ws?token=...
  alt private (LAN) IP
    GUARD->>WS: continue handshake
    WS->>SEC: decode_access_token(token)
    SEC-->>WS: user_id
    alt valid token and active user
      WS->>WSM: connect(user_id, websocket)
      WSM-->>U: accept (connected)
      loop while connected
        U->>WS: ping (receive loop)
      end
      U-->>WS: disconnect
      WS->>WSM: disconnect(user_id, websocket)
    else invalid
      WS-->>U: close(4401)
    end
  else global IP
    GUARD-->>U: close(4403)
  end
        
図9. WebSocket接続。ネットワークガード → トークン検証 → 接続登録の順に多層で検証する。

4. 招待コードによるサーバー参加

sequenceDiagram
  autonumber
  actor A as 管理者/モデレーター
  actor B as 参加者
  participant INV as invites ルーター
  participant SVC as services
  participant DB as SQLite

  A->>INV: POST /servers/{id}/invites
  INV->>SVC: require_role(admin/moderator)
  SVC-->>INV: OK
  INV->>DB: 招待コード生成・保存
  DB-->>INV: ServerInvite
  INV-->>A: 201 {code, ...}
  Note over A,B: 招待コードを共有

  B->>INV: GET /api/invites/{code}(プレビュー)
  INV->>DB: コード検証(有効期限/回数/失効)
  DB-->>INV: Server
  INV-->>B: {server_name, already_member}
  B->>INV: POST /api/invites/{code}/accept
  INV->>DB: ServerMember(role=member) 追加 + uses++
  DB-->>INV: OK
  INV-->>B: 200 ServerPublic(参加完了)
        
sequenceDiagram
  autonumber
  actor A as Admin/Moderator
  actor B as Joiner
  participant INV as invites router
  participant SVC as services
  participant DB as SQLite

  A->>INV: POST /servers/{id}/invites
  INV->>SVC: require_role(admin/moderator)
  SVC-->>INV: OK
  INV->>DB: generate + save invite code
  DB-->>INV: ServerInvite
  INV-->>A: 201 {code, ...}
  Note over A,B: Share the invite code

  B->>INV: GET /api/invites/{code} (preview)
  INV->>DB: validate code (expiry/uses/revoked)
  DB-->>INV: Server
  INV-->>B: {server_name, already_member}
  B->>INV: POST /api/invites/{code}/accept
  INV->>DB: add ServerMember(role=member) + uses++
  DB-->>INV: OK
  INV-->>B: 200 ServerPublic (joined)
        
図10. 招待参加。直接参加は禁止され、有効な招待コードの提示のみで参加できる。

5. ファイル添付付きメッセージ

sequenceDiagram
  autonumber
  actor U as 送信者
  participant F as files ルーター
  participant M as messages ルーター
  participant FS as ローカルストレージ
  participant DB as SQLite

  U->>F: POST /api/files(ファイル本体)
  F->>F: サイズ上限チェック
  F->>FS: UUID名でローカル保存
  F->>DB: Attachment(message_id=null) 保存
  DB-->>F: Attachment
  F-->>U: 201 {id, filename, size}
  Note over U: 添付IDを保持して送信

  U->>M: POST .../messages {attachment_ids:[id]}
  M->>DB: Message 保存
  M->>DB: 自分の未紐付け添付を message に紐付け
  DB-->>M: OK
  M-->>U: 201 MessagePublic(添付込み)
        
sequenceDiagram
  autonumber
  actor U as Sender
  participant F as files router
  participant M as messages router
  participant FS as Local storage
  participant DB as SQLite

  U->>F: POST /api/files (file body)
  F->>F: check size limit
  F->>FS: save locally with UUID name
  F->>DB: save Attachment(message_id=null)
  DB-->>F: Attachment
  F-->>U: 201 {id, filename, size}
  Note over U: Keep attachment id, then send

  U->>M: POST .../messages {attachment_ids:[id]}
  M->>DB: save Message
  M->>DB: link own unlinked attachments to message
  DB-->>M: OK
  M-->>U: 201 MessagePublic (with attachment)
        
図11. ファイル添付。アップロードとメッセージ送信を分離し、本人がアップロードした未紐付け添付のみを紐付ける。