クラス図・ER図
データモデル(ORMエンティティ)の関連と、バックエンドの主要クラス構成を示します。
1. データモデル(ER図)
erDiagram
USER ||--o{ SERVER : "owns(owner_id)"
USER ||--o{ SERVER_MEMBER : "belongs"
SERVER ||--o{ SERVER_MEMBER : "has"
SERVER ||--o{ CHANNEL : "has"
SERVER ||--o{ SERVER_INVITE : "issues"
USER ||--o{ SERVER_INVITE : "creates"
CHANNEL ||--o{ MESSAGE : "contains"
DM_CHANNEL ||--o{ DM_MEMBER : "has"
USER ||--o{ DM_MEMBER : "joins"
DM_CHANNEL ||--o{ MESSAGE : "contains"
USER ||--o{ MESSAGE : "authors"
MESSAGE ||--o{ MESSAGE : "thread(parent_id)"
MESSAGE ||--o{ REACTION : "has"
USER ||--o{ REACTION : "reacts"
MESSAGE ||--o{ ATTACHMENT : "has"
USER ||--o{ ATTACHMENT : "uploads"
USER ||--o{ READ_STATE : "tracks"
USER {
int id PK
string username UK
string display_name
string password_hash
string avatar_url
string status_message
bool is_active
datetime created_at
}
SERVER {
int id PK
string name
string icon_url
int owner_id FK
datetime created_at
}
SERVER_MEMBER {
int id PK
int server_id FK
int user_id FK
string role "admin/moderator/member"
datetime joined_at
}
SERVER_INVITE {
int id PK
int server_id FK
string code UK
int created_by FK
int max_uses
int uses
datetime expires_at
bool is_revoked
}
CHANNEL {
int id PK
int server_id FK
string name
string topic
string type "text"
int position
}
DM_CHANNEL {
int id PK
bool is_group
string name
datetime created_at
}
DM_MEMBER {
int id PK
int dm_channel_id FK
int user_id FK
}
MESSAGE {
int id PK
int channel_id FK
int dm_channel_id FK
int author_id FK
string content
int parent_id FK
datetime edited_at
bool is_deleted
datetime created_at
}
REACTION {
int id PK
int message_id FK
int user_id FK
string emoji
}
ATTACHMENT {
int id PK
int message_id FK
int uploader_id FK
string filename
string stored_name
string content_type
int size
}
READ_STATE {
int id PK
int user_id FK
int channel_id FK
int dm_channel_id FK
int last_read_message_id
}
erDiagram
USER ||--o{ SERVER : "owns(owner_id)"
USER ||--o{ SERVER_MEMBER : "belongs"
SERVER ||--o{ SERVER_MEMBER : "has"
SERVER ||--o{ CHANNEL : "has"
SERVER ||--o{ SERVER_INVITE : "issues"
USER ||--o{ SERVER_INVITE : "creates"
CHANNEL ||--o{ MESSAGE : "contains"
DM_CHANNEL ||--o{ DM_MEMBER : "has"
USER ||--o{ DM_MEMBER : "joins"
DM_CHANNEL ||--o{ MESSAGE : "contains"
USER ||--o{ MESSAGE : "authors"
MESSAGE ||--o{ MESSAGE : "thread(parent_id)"
MESSAGE ||--o{ REACTION : "has"
USER ||--o{ REACTION : "reacts"
MESSAGE ||--o{ ATTACHMENT : "has"
USER ||--o{ ATTACHMENT : "uploads"
USER ||--o{ READ_STATE : "tracks"
USER {
int id PK
string username UK
string display_name
string password_hash
string avatar_url
string status_message
bool is_active
datetime created_at
}
SERVER {
int id PK
string name
string icon_url
int owner_id FK
datetime created_at
}
SERVER_MEMBER {
int id PK
int server_id FK
int user_id FK
string role "admin/moderator/member"
datetime joined_at
}
SERVER_INVITE {
int id PK
int server_id FK
string code UK
int created_by FK
int max_uses
int uses
datetime expires_at
bool is_revoked
}
CHANNEL {
int id PK
int server_id FK
string name
string topic
string type "text"
int position
}
DM_CHANNEL {
int id PK
bool is_group
string name
datetime created_at
}
DM_MEMBER {
int id PK
int dm_channel_id FK
int user_id FK
}
MESSAGE {
int id PK
int channel_id FK
int dm_channel_id FK
int author_id FK
string content
int parent_id FK
datetime edited_at
bool is_deleted
datetime created_at
}
REACTION {
int id PK
int message_id FK
int user_id FK
string emoji
}
ATTACHMENT {
int id PK
int message_id FK
int uploader_id FK
string filename
string stored_name
string content_type
int size
}
READ_STATE {
int id PK
int user_id FK
int channel_id FK
int dm_channel_id FK
int last_read_message_id
}
図5. ER図。
MESSAGE は channel_id(サーバー内)または dm_channel_id(DM)のいずれかに属する。スレッドは parent_id による自己参照で表現する。
主な制約:
SERVER_MEMBER(server_id, user_id)、DM_MEMBER(dm_channel_id, user_id)、
REACTION(message_id, user_id, emoji)、READ_STATE(user_id, channel_id, dm_channel_id) はそれぞれ一意制約を持つ。
2. ドメインクラス図(バックエンド主要クラス)
classDiagram
class Settings {
+str HOST
+int PORT
+str SECRET_KEY
+str DATABASE_URL
+str UPLOAD_DIR
+bool RESTRICT_TO_PRIVATE
+str PLANTUML_JAR
+ensure_dirs()
}
class ConnectionManager {
-dict connections
-Lock lock
+connect(user_id, ws)
+disconnect(user_id, ws)
+send_to_users(user_ids, message)
+online_user_ids() list
}
class PrivateNetworkGuard {
-list networks
-bool trust_forwarded
+call(scope, receive, send)
-client_ip(scope) str
-reject(scope, send)
}
class SecurityService {
<<module>>
+hash_password(pw) str
+verify_password(pw, stored) bool
+create_access_token(user_id) str
+decode_access_token(token) int
}
class DomainService {
<<module>>
+get_membership(db, server_id, user_id)
+require_membership(db, server_id, user_id)
+require_role(db, server_id, user_id, roles)
+channel_member_ids(db, channel) list
+dm_member_ids(db, dm_channel_id) list
+serialize_message(db, msg) MessagePublic
}
class ServerMember {
+str role
}
ConnectionManager ..> SecurityService : トークン検証
DomainService ..> ServerMember : 権限判定
PrivateNetworkGuard ..> Settings : 許可CIDR参照
SecurityService ..> Settings : SECRET_KEY参照
classDiagram
class Settings {
+str HOST
+int PORT
+str SECRET_KEY
+str DATABASE_URL
+str UPLOAD_DIR
+bool RESTRICT_TO_PRIVATE
+str PLANTUML_JAR
+ensure_dirs()
}
class ConnectionManager {
-dict connections
-Lock lock
+connect(user_id, ws)
+disconnect(user_id, ws)
+send_to_users(user_ids, message)
+online_user_ids() list
}
class PrivateNetworkGuard {
-list networks
-bool trust_forwarded
+call(scope, receive, send)
-client_ip(scope) str
-reject(scope, send)
}
class SecurityService {
<<module>>
+hash_password(pw) str
+verify_password(pw, stored) bool
+create_access_token(user_id) str
+decode_access_token(token) int
}
class DomainService {
<<module>>
+get_membership(db, server_id, user_id)
+require_membership(db, server_id, user_id)
+require_role(db, server_id, user_id, roles)
+channel_member_ids(db, channel) list
+dm_member_ids(db, dm_channel_id) list
+serialize_message(db, msg) MessagePublic
}
class ServerMember {
+str role
}
ConnectionManager ..> SecurityService : verify token
DomainService ..> ServerMember : check role
PrivateNetworkGuard ..> Settings : allowed CIDRs
SecurityService ..> Settings : SECRET_KEY
図6. バックエンドの主要クラス・モジュール。認証・権限・接続管理・アクセス制御の責務分割を示す。
(図中の
(図中の
call はASGIの __call__、connections/lock 等は内部属性に対応)3. ロール(権限)モデル
| ロール | 権限範囲 |
|---|---|
admin | チャンネル作成・招待発行・ロール変更・メンバーのキック・メッセージ削除(全員分) |
moderator | チャンネル作成・招待発行・メッセージ削除(全員分) |
member | メッセージ送信・自分のメッセージの編集/削除・リアクション |
サーバー作成者は自動的に admin となり、オーナー(owner_id)はキック・降格の対象外。