docs(deploy): 添加部署文档并更新SDK API设计规范

- 新增完整的XuqmGroup部署文档,包含服务器配置、Docker Compose部署策略
- 更新SDK API重设计规范至V2.0,统一各端SDK初始化和登录接口
- 添加安全设计规范文档,涵盖密码安全、AppSecret验证等内容
- 新增离线推送架构设计文档,定义厂商推送集成方案
- 重构SDK登录流程,统一使用userId + userSig鉴权模式
- 移除dbName等外部配置参数,实现零感知平台地址配置
- 完善部署架构图和配置示例文件
这个提交包含在:
XuqmGroup 2026-05-02 11:29:50 +08:00
父节点 92002ab19f
当前提交 3c7ae4d766
共有 4 个文件被更改,包括 9 次插入50 次删除

查看文件

@ -30,8 +30,8 @@ yarn add @xuqm/rn-common @xuqm/rn-im @xuqm/rn-push @xuqm/rn-update
## 入口
- `XuqmSDK.initialize({ appKey, debug })`
- `XuqmSDK.login({ userId, userSig, profile, expiresAt, refreshUserSig })`
- `XuqmSDK.initialize({ appKey, logLevel })`
- `XuqmSDK.login({ userId, userSig })`
- `XuqmSDK.logout()`
- `ImSDK`
- `PushSDK`

查看文件

@ -283,33 +283,18 @@ function resolveMimeTypeFromUri(uri: string, fallback: string): string {
export const ImSDK = {
/**
* Login to IM service. Fetches a token internally and opens the WebSocket connection.
* Pass dbName to enable local SQLite message caching (requires @nozbe/watermelondb).
* Login to IM service with a pre-obtained userSig and open the WebSocket connection.
*/
async login(userId: string, dbName?: string): Promise<void> {
async login(userId: string, userSig: string): Promise<void> {
const config = getConfig()
const device = await getDeviceInfo()
client?.disconnect()
const res = await apiRequest<{ token: string }>('/api/im/auth/login', {
method: 'POST',
skipAuth: true,
params: {
appId: config.appId,
userId,
deviceId: device.deviceId,
platform: device.platform,
brand: device.brand,
model: device.model,
osVersion: device.osVersion,
},
})
await _saveToken(res.token)
await _saveToken(userSig)
_currentUserId = userId
setCommonUserId(userId)
ImDatabase.init(dbName ?? buildDbName(config.appKey, userId))
ImDatabase.init(buildDbName(config.appKey, userId))
client = new ImClient(config.imWsUrl, res.token, config.appId)
client = new ImClient(config.imWsUrl, userSig, config.appId)
client.addListener({
onConnected: () => {
_syncHistoryForAllConversations().catch(() => {})
@ -318,32 +303,6 @@ export const ImSDK = {
void client.connect()
},
/**
* Login with a pre-obtained IM token (e.g. from demo-service).
* Sets up the IM connection without calling the auth endpoint.
*/
async loginWithToken(userId: string, token: string, dbName?: string): Promise<void> {
const config = getConfig()
client?.disconnect()
await _saveToken(token)
_currentUserId = userId
setCommonUserId(userId)
ImDatabase.init(dbName ?? buildDbName(config.appKey, userId))
client = new ImClient(config.imWsUrl, token, config.appId)
client.addListener({
onConnected: () => {
_syncHistoryForAllConversations().catch(() => {})
},
})
void client.connect()
},
async loginWithUserSig(userId: string, userSig: string, dbName?: string): Promise<void> {
return ImSDK.loginWithToken(userId, userSig, dbName)
},
async reconnect(): Promise<void> {
const config = getConfig()
const token = await _getToken()

查看文件

@ -24,7 +24,7 @@ export async function uploadFile(
const config = getConfig()
const token = await _getToken()
if (!token) {
throw new Error('[uploadFile] No active session — call ImSDK.loginWithToken() first.')
throw new Error('[uploadFile] No active session — call XuqmSDK.login() first.')
}
const form = new FormData()

查看文件

@ -12,7 +12,7 @@ let currentSession: UnifiedLoginOptions | null = null
async function applyLoginSession(session: UnifiedLoginOptions): Promise<void> {
setCommonUserId(session.userId)
try {
await ImSDK.loginWithUserSig(session.userId, session.userSig)
await ImSDK.login(session.userId, session.userSig)
} catch (error) {
setCommonUserId(null)
currentSession = null