diff --git a/chell要点.txt b/chell要点.txt index 47c7d30..9884fce 100644 --- a/chell要点.txt +++ b/chell要点.txt @@ -143,7 +143,7 @@ tinode 移除 全局禁止加好友 比如下班时间到了 不能加 从群成员去看 不能显示个人信息 个人名片也不能看 二维码也不能加 -阿里云的oss放一个域名清单 要加密 +阿里云的oss放一个域名清单 要加密 apikey动态更换 设备类型 ip 全部采集入库 离线时间 和上线时间的采集 检查一下多处存同一个信息的。尤其是用户的 @@ -201,4 +201,14 @@ Bundle ID:com.ysl.IM KEY ID:J4ZUVHW59G Team ID:2DN6KF37CH +单号登录 多设备顶号 已经实现 +多标签登录的消息到达率 +建一个千人大群 +telegram报警功能 + +加上ai翻译的功能 ai笔记 + +后端要做一下 redis 的 sentinel适配, 不然重新选举之后可能会写错节点报错 + +https://api.118im.com 简单弄一个官网,https://api.118im.com/legal/privacy-policy需要把名字改对,TestFlight的beta版需要审核,这两个可能会是卡点   diff --git a/docker/tinode/Dockerfile b/docker/tinode/Dockerfile index f98f6aa..b637831 100644 --- a/docker/tinode/Dockerfile +++ b/docker/tinode/Dockerfile @@ -51,7 +51,7 @@ ENV SAMPLE_DATA=$SAMPLE_DATA ENV DEFAULT_COUNTRY_CODE=US # The MySQL DSN connection. -ENV MYSQL_DSN='root@tcp(mysql)/tinode?parseTime=true&collation=utf8mb4_0900_ai_ci' +ENV MYSQL_DSN='root@tcp(mysql)/meeting_im?parseTime=true&collation=utf8mb4_0900_ai_ci' ENV REDIS_ADDR= ENV REDIS_USERNAME= ENV REDIS_PASSWORD= @@ -97,10 +97,12 @@ ENV KAFKA_TOPIC_FILE_SECURITY=im.file.security ENV KAFKA_TOPIC_CACHE_INVALIDATE=im.cache.invalidate ENV KAFKA_TOPIC_AUDIT_EVENT=im.audit.event ENV KAFKA_TOPIC_DEAD_LETTER=im.dead.letter -ENV INTERNAL_API_ENABLED=false +ENV INTERNAL_API_ENABLED=true ENV INTERNAL_API_TIME_WINDOW_SECONDS=300 ENV INTERNAL_API_HOTGO_SERVICE_NAME=hotgo-admin ENV INTERNAL_API_HOTGO_SECRET= +ENV INTERNAL_API_CULTIVATE_SERVICE_NAME=cultivate-server +ENV INTERNAL_API_CULTIVATE_SECRET= ENV ADMIN_INTERNAL_API_ENABLED=false ENV ADMIN_INTERNAL_API_BASE_URL= ENV ADMIN_INTERNAL_API_SERVICE_NAME=im-server diff --git a/docker/tinode/Dockerfile.build b/docker/tinode/Dockerfile.build index 853edb1..ab6464f 100644 --- a/docker/tinode/Dockerfile.build +++ b/docker/tinode/Dockerfile.build @@ -77,10 +77,12 @@ ENV KAFKA_TOPIC_FILE_SECURITY=im.file.security ENV KAFKA_TOPIC_CACHE_INVALIDATE=im.cache.invalidate ENV KAFKA_TOPIC_AUDIT_EVENT=im.audit.event ENV KAFKA_TOPIC_DEAD_LETTER=im.dead.letter -ENV INTERNAL_API_ENABLED=false +ENV INTERNAL_API_ENABLED=true ENV INTERNAL_API_TIME_WINDOW_SECONDS=300 ENV INTERNAL_API_HOTGO_SERVICE_NAME=hotgo-admin ENV INTERNAL_API_HOTGO_SECRET= +ENV INTERNAL_API_CULTIVATE_SERVICE_NAME=cultivate-server +ENV INTERNAL_API_CULTIVATE_SECRET= ENV ADMIN_INTERNAL_API_ENABLED=false ENV ADMIN_INTERNAL_API_BASE_URL= ENV ADMIN_INTERNAL_API_SERVICE_NAME=im-server @@ -88,7 +90,7 @@ ENV ADMIN_INTERNAL_API_SECRET= ENV ADMIN_INTERNAL_API_TIMEOUT_MS=3000 # Tenant registry lives in the hotgo database (shared with im_manager); tenant -# DB routing resolves to the same tinode DB for the seeded "default" tenant. +# business data lives in the shared meeting_im DB and is scoped by tenant_id. ENV TENANT_REGISTRY_DB=hotgo ENV MEDIA_HANDLER=sys_config diff --git a/docker/tinode/config.template b/docker/tinode/config.template index 17cbb0f..a0d541b 100644 --- a/docker/tinode/config.template +++ b/docker/tinode/config.template @@ -77,7 +77,7 @@ "use_adapter": "$STORE_USE_ADAPTER", "adapters": { "mysql": { - "database": "tinode", + "database": "meeting_im", "dsn": "$MYSQL_DSN", "max_open_conns": 64, "max_idle_conns": 64, @@ -87,7 +87,7 @@ "tenant_db_routing": true }, "postgres": { - "database": "tinode", + "database": "meeting_im", "dsn": "$POSTGRES_DSN" }, "rethinkdb": { @@ -154,12 +154,16 @@ } }, "internal_api": { - "enabled": true, - "time_window_seconds": 300, + "enabled": $INTERNAL_API_ENABLED, + "time_window_seconds": $INTERNAL_API_TIME_WINDOW_SECONDS, "services": { - "hotgo-admin": { + "$INTERNAL_API_HOTGO_SERVICE_NAME": { "secret": "$INTERNAL_API_HOTGO_SECRET", "allow": ["admin_query"] + }, + "$INTERNAL_API_CULTIVATE_SERVICE_NAME": { + "secret": "$INTERNAL_API_CULTIVATE_SECRET", + "allow": ["cultivate"] } } }, diff --git a/docs/third/IM-极光推送前后端对接文档.md b/docs/third/IM-极光推送前后端对接文档.md index 5f33e45..2a0719c 100644 --- a/docs/third/IM-极光推送前后端对接文档.md +++ b/docs/third/IM-极光推送前后端对接文档.md @@ -1,6 +1,31 @@ # IM 极光推送前后端对接文档 -更新时间:2026-09-04 +更新时间:2026-09-IM API → PUT https://api.118im.com/v1/im/devices/2386C7EB-FC30-4849-9FC8-7F2B50229F02/push-token [req=ab961f26-e3a9-4f5f-b0f6-2813b8af3597] +请求体 { + "sdk_version": "6.2.0", + "push_env": "test", + "app_version": "1.0", + "token": "1517bfd3f69c6928135", + "platform": "ios", + "notification_permission": "granted", + "provider": "jpush" +} +IM API ← 成功 PUT https://api.118im.com/v1/im/devices/2386C7EB-FC30-4849-9FC8-7F2B50229F02/push-token [req=ab961f26-e3a9-4f5f-b0f6-2813b8af3597, status=200] +响应体 { + "code": 0, + "data": { + "app_version": "1.0", + "device_id": "2386C7EB-FC30-4849-9FC8-7F2B50229F02", + "notification_permission": "granted", + "platform": "ios", + "provider": "jpush", + "push_env": "test", + "sdk_version": "6.2.0", + "updated_at": "2026-09-14T09:49:19.139Z" + }, + "request_id": "ab961f26-e3a9-4f5f-b0f6-2813b8af3597", + "server_time": "2026-09-14T09:49:19.167Z" +}04 ## 1. 对接边界 @@ -24,7 +49,11 @@ - iOS:配置 APNs 证书或 Token Authentication,申请通知权限。 - HarmonyOS:按鸿蒙 SDK 文档初始化并配置通知分类。 -客户端启动后取得 `registration_id`,登录 IM 后把 alias 绑定为当前 `user_id` 的极光安全别名。同一用户多设备允许绑定同一个 alias。 +客户端启动后取得 `registration_id`,登录 IM 后调用 IM 后端设备接口上报 Push Token。当前测试环境服务端配置 `jpush_use_alias=0`,使用 `registration_id` 投递,不依赖 alias。 + +`device_id` 必须稳定,同一台设备不要每次启动变化。切换账号、切换租户、清登录态后必须重新上报 Push Token;客户端本地的上报去重缓存必须按 `tenant_code + user_id + device_id + registration_id` 隔离,避免设备继续绑定在旧账号上。 + +如果后续切回 alias 模式,客户端再把 alias 绑定为当前 `user_id` 的极光安全别名。同一用户多设备允许绑定同一个 alias。 极光 alias 不支持中横线 `-` 和下划线 `_`,而 IM `user_id` 可能包含这两个字符。客户端和后端统一使用以下映射: @@ -124,12 +153,14 @@ IM Server 从后台配置读取 `im_jpush` 分组: "jpush_apns_production": "false", "jpush_default_ttl_seconds": "86400", "jpush_call_ttl_seconds": "60", - "jpush_use_alias": "true", + "jpush_use_alias": "false", "jpush_test_model": "false", "jpush_classification": "1" } ``` +测试环境当前使用 `registration_id` 模式,`jpush_use_alias=false`。服务端从 `im_device_push_tokens` 按目标用户查询 `provider=jpush` 的 token,并调用极光 `audience.registration_id`。如改为 alias 模式,需要客户端 SDK alias 绑定回调成功,并保持 alias 映射规则一致。 + ### 3.2 设备记录 设备表建议至少支持: @@ -185,22 +216,11 @@ Content-Type: application/json ```json { - "platform": "all", + "platform": "ios", "audience": { - "alias": ["usr_target"] + "registration_id": ["registration_id_from_jpush"] }, "notification": { - "alert": "你收到一条新消息", - "android": { - "title": "MeetingIM", - "alert": "你收到一条新消息", - "extras": { - "type": "im_message", - "tenant_code": "default", - "topic": "p2p...", - "seq": "128" - } - }, "ios": { "alert": { "title": "MeetingIM", @@ -228,25 +248,11 @@ Content-Type: application/json ```json { - "platform": "all", + "platform": "ios", "audience": { - "alias": ["usr_callee"] + "registration_id": ["registration_id_from_jpush"] }, "notification": { - "alert": "收到一通视频通话", - "android": { - "title": "视频通话", - "alert": "张三邀请你视频通话", - "extras": { - "type": "call_invite", - "tenant_code": "default", - "topic": "p2p...", - "seq": "30", - "call_id": "call_01K...", - "call_type": "video", - "caller_id": "usr_caller" - } - }, "ios": { "alert": { "title": "视频通话", @@ -314,8 +320,8 @@ Content-Type: application/json | 步骤 | 操作 | 验证 | | --- | --- | --- | | 1 | 客户端初始化 JPush SDK | 能拿到 `registration_id`。 | -| 2 | 登录 IM 并绑定 alias=`user_id.replace("-", ".").replace("_", "|")` | 极光控制台能查到别名或设备。 | -| 3 | 调用设备上报接口 | 服务端设备记录 provider=`jpush`。 | +| 2 | 登录 IM 后上报 `registration_id` | `im_device_push_tokens` 中 `device_id/token/user_id` 与当前登录用户一致。 | +| 3 | 调用设备上报接口 | 服务端设备记录 provider=`jpush`,并更新到当前登录用户。 | | 4 | 目标用户退出或断网 | IM 判断为离线或不可 WS 投递。 | | 5 | 发送 P2P 消息 | 离线用户收到 Push。 | | 6 | 点击 Push | App 打开对应会话并补齐 `seq`。 | @@ -323,3 +329,4 @@ Content-Type: application/json | 8 | 通话取消后点击旧 Push | 客户端查询后显示已取消或未接,不进入通话中。 | | 9 | 关闭会话免打扰 | 普通消息不发 Push,@提醒按策略执行。 | | 10 | 极光返回无效 token | 后端禁用设备 token,重新上报后恢复。 | +| 11 | iOS APNs 环境 | 测试环境 `apns_production=false` 且客户端为开发 APNs;生产包需同步切换为 true。 | diff --git a/server/admin_internal_config.go b/server/admin_internal_config.go index 1cb9d82..f4e827c 100644 --- a/server/admin_internal_config.go +++ b/server/admin_internal_config.go @@ -51,8 +51,6 @@ type adminInternalTenantDTO struct { Code string `json:"code"` Name string `json:"name"` TenantDesc *string `json:"tenant_desc,omitempty"` - DBName string `json:"db_name"` - DBDSN string `json:"db_dsn"` State types.TenantState `json:"state"` CreatedAt time.Time `json:"created_at"` CreatedBy int64 `json:"created_by"` @@ -422,8 +420,6 @@ func (t adminInternalTenantDTO) toStoreTenant() *types.Tenant { Code: strings.TrimSpace(t.Code), Name: t.Name, TenantDesc: t.TenantDesc, - DBName: t.DBName, - DBDSN: t.DBDSN, State: t.State, CreatedAt: t.CreatedAt, CreatedBy: t.CreatedBy, diff --git a/server/db/mysql/adapter.go b/server/db/mysql/adapter.go index 7f91efb..e6e561d 100644 --- a/server/db/mysql/adapter.go +++ b/server/db/mysql/adapter.go @@ -56,8 +56,8 @@ const ( adpVersion = 123 adapterName = "mysql" - defaultDSN = "root:@tcp(localhost:3306)/tinode?parseTime=true" - defaultDatabase = "tinode" + defaultDSN = "root:@tcp(localhost:3306)/meeting_im?parseTime=true" + defaultDatabase = "meeting_im" defaultMaxResults = 1024 // This is capped by the Session's send queue limit (128). @@ -421,17 +421,11 @@ func (a *adapter) TenantGetByCode(code string) (*t.Tenant, error) { db = a.registryDB } err := db.GetContext(ctx, &tenant, - `SELECT id, code, name, tenant_desc, IFNULL(db_name,'') AS db_name, IFNULL(db_dsn,'') AS db_dsn, - state, created_at, created_by, updated_at, updated_by + `SELECT id, code, name, tenant_desc, state, created_at, created_by, updated_at, updated_by FROM im_tenant WHERE code=? LIMIT 1`, code) if err == sql.ErrNoRows { return nil, t.ErrNotFound } - if isUnknownColumn(err) { - err = db.GetContext(ctx, &tenant, - `SELECT id, code, name, tenant_desc, state, created_at, created_by, updated_at, updated_by - FROM im_tenant WHERE code=? LIMIT 1`, code) - } if err != nil { return nil, err } @@ -460,14 +454,8 @@ func (a *adapter) TenantListActive(limit int) ([]t.Tenant, error) { } var tenants []t.Tenant err := db.SelectContext(ctx, &tenants, - `SELECT id, code, name, tenant_desc, IFNULL(db_name,'') AS db_name, IFNULL(db_dsn,'') AS db_dsn, - state, created_at, created_by, updated_at, updated_by + `SELECT id, code, name, tenant_desc, state, created_at, created_by, updated_at, updated_by FROM im_tenant WHERE state=? ORDER BY id ASC LIMIT ?`, t.TenantStateActive, limit) - if isUnknownColumn(err) { - err = db.SelectContext(ctx, &tenants, - `SELECT id, code, name, tenant_desc, state, created_at, created_by, updated_at, updated_by - FROM im_tenant WHERE state=? ORDER BY id ASC LIMIT ?`, t.TenantStateActive, limit) - } return tenants, err } @@ -518,8 +506,8 @@ func (a *adapter) TenantAdapterFor(tenantID t.TenantID) (dbadapter.TenantBusines baseConfig: a.baseConfig, tenantDBRouting: false, tenantID: tenantID, - // A dedicated database is still tenant-owned. Keep tenant predicates and - // explicit tenant_id writes enabled even though databases are not shared. + // Tenant adapters share the same database. Keep tenant predicates and + // explicit tenant_id writes enabled for logical isolation. tenantScopedDB: false, } a.tenantMu.Lock() @@ -543,17 +531,11 @@ func (a *adapter) tenantByID(tenantID t.TenantID) (*t.Tenant, error) { } var tenant t.Tenant err := db.GetContext(ctx, &tenant, - `SELECT id, code, name, tenant_desc, IFNULL(db_name,'') AS db_name, IFNULL(db_dsn,'') AS db_dsn, - state, created_at, created_by, updated_at, updated_by + `SELECT id, code, name, tenant_desc, state, created_at, created_by, updated_at, updated_by FROM im_tenant WHERE id=? LIMIT 1`, tenantID) if err == sql.ErrNoRows { return nil, t.ErrNotFound } - if isUnknownColumn(err) { - err = db.GetContext(ctx, &tenant, - `SELECT id, code, name, tenant_desc, state, created_at, created_by, updated_at, updated_by - FROM im_tenant WHERE id=? LIMIT 1`, tenantID) - } if err != nil { return nil, err } @@ -563,7 +545,7 @@ func (a *adapter) tenantByID(tenantID t.TenantID) (*t.Tenant, error) { return &tenant, nil } -func createTenantRegistry(tx *sql.Tx, registryDB, businessDB string) error { +func createTenantRegistry(tx *sql.Tx, registryDB, _ string) error { if _, err := tx.Exec("CREATE DATABASE IF NOT EXISTS " + quoteIdent(registryDB) + " CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci"); err != nil { return err } @@ -572,52 +554,40 @@ func createTenantRegistry(tx *sql.Tx, registryDB, businessDB string) error { } if _, err := tx.Exec( `CREATE TABLE IF NOT EXISTS im_tenant( - id BIGINT NOT NULL, - code VARCHAR(64) NOT NULL, - name VARCHAR(128) NOT NULL, - tenant_desc VARCHAR(256), - db_name VARCHAR(128) NOT NULL DEFAULT '', - db_dsn VARCHAR(1024) NOT NULL DEFAULT '', - state SMALLINT NOT NULL, - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - created_by BIGINT NOT NULL, - updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), - updated_by BIGINT NOT NULL, + id BIGINT NOT NULL, + code VARCHAR(64) NOT NULL, + name VARCHAR(128) NOT NULL, + tenant_desc VARCHAR(256), + max_users BIGINT UNSIGNED NOT NULL DEFAULT 0, + max_groups BIGINT UNSIGNED NOT NULL DEFAULT 0, + max_group_members INT UNSIGNED NOT NULL DEFAULT 0, + realname_review_policy TINYINT(1) NOT NULL DEFAULT 0, + realname_provider_mode VARCHAR(32) NOT NULL DEFAULT 'id_card_2factor', + realname_required TINYINT(1) NOT NULL DEFAULT 0, + realname_allow_skip TINYINT(1) NOT NULL DEFAULT 1, + realname_remind_after VARCHAR(32) NOT NULL DEFAULT '24h', + aliyun_moderation_enabled TINYINT(1) NOT NULL DEFAULT 0, + local_moderation_enabled TINYINT(1) NOT NULL DEFAULT 0, + message_encryption_enabled TINYINT(1) NOT NULL DEFAULT 0, + default_policy_group_id BIGINT, + security_policy_version INT UNSIGNED NOT NULL DEFAULT 0, + global_friend_enabled TINYINT(1) NOT NULL DEFAULT 1, + message_curfew_enabled TINYINT(1) NOT NULL DEFAULT 0, + state SMALLINT NOT NULL, + created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + created_by BIGINT NOT NULL, + updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + updated_by BIGINT NOT NULL, PRIMARY KEY(id), - UNIQUE INDEX uk_im_tenant_code(code), - INDEX idx_im_tenant_db_name(db_name) - )`); err != nil { - return err - } - if _, err := tx.Exec( - `CREATE TABLE IF NOT EXISTS im_tenant_config( - id BIGINT NOT NULL AUTO_INCREMENT, - tenant_id BIGINT NOT NULL, - max_users BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '0 means unlimited', - max_groups BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '0 means unlimited', - max_group_members INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '0 means unlimited', - realname_review_policy TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Real-name review policy: 0 none, 1 auto then manual', - realname_provider_mode VARCHAR(32) NOT NULL DEFAULT 'id_card_2factor' COMMENT 'id_card_2factor or smart_verify', - realname_required TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Require real-name verification', - realname_allow_skip TINYINT(1) NOT NULL DEFAULT 1 COMMENT 'Allow skipping real-name reminder', - realname_remind_after VARCHAR(32) NOT NULL DEFAULT '24h' COMMENT 'Real-name reminder interval', - aliyun_moderation_enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Enable Aliyun content moderation', - local_moderation_enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Enable local content moderation', - created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - created_by BIGINT NOT NULL, - updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), - updated_by BIGINT NOT NULL, - PRIMARY KEY(id), - UNIQUE INDEX uk_im_tenant_config_tenant_id(tenant_id), - CONSTRAINT fk_im_tenant_config_tenant FOREIGN KEY(tenant_id) REFERENCES im_tenant(id) ON DELETE CASCADE + UNIQUE INDEX uk_im_tenant_code(code) )`); err != nil { return err } _, err := tx.Exec( - `INSERT INTO im_tenant(id,code,name,tenant_desc,db_name,db_dsn,state,created_by,updated_by) - VALUES(1,'default','Default Tenant',NULL,?,'',?,0,0) - ON DUPLICATE KEY UPDATE db_name=VALUES(db_name), state=VALUES(state), updated_by=VALUES(updated_by)`, - businessDB, t.TenantStateActive) + `INSERT INTO im_tenant(id,code,name,tenant_desc,state,created_by,updated_by) + VALUES(1,'default','Default Tenant',NULL,?,0,0) + ON DUPLICATE KEY UPDATE state=VALUES(state), updated_by=VALUES(updated_by)`, + t.TenantStateActive) return err } @@ -1007,20 +977,6 @@ func createIMUserProductTables(tx *sql.Tx) error { return nil } -func ensureTenantRoutingColumns(a *adapter) error { - statements := []string{ - "ALTER TABLE im_tenant ADD COLUMN db_name VARCHAR(128) NOT NULL DEFAULT '' AFTER tenant_desc", - "ALTER TABLE im_tenant ADD COLUMN db_dsn VARCHAR(1024) NOT NULL DEFAULT '' AFTER db_name", - "UPDATE im_tenant SET db_name='tinode' WHERE code='default' AND db_name=''", - } - for _, stmt := range statements { - if _, err := a.db.Exec(stmt); err != nil && !isDuplicateColumn(err) { - return err - } - } - return nil -} - func upgradeIMMessageActions(a *adapter) error { statements := []string{ "ALTER TABLE im_messages ADD COLUMN version INT NOT NULL DEFAULT 1 AFTER client_msg_id", diff --git a/server/db/mysql/realname_policy_config.go b/server/db/mysql/realname_policy_config.go index 5f04890..5ba5de0 100644 --- a/server/db/mysql/realname_policy_config.go +++ b/server/db/mysql/realname_policy_config.go @@ -26,9 +26,9 @@ func (a *adapter) RealNamePolicy(tenantID t.TenantID) (*t.RealNamePolicy, error) defer cancel() } var policy t.RealNamePolicy - err := db.GetContext(ctx, &policy, `SELECT tenant_id, realname_review_policy, realname_provider_mode, + err := db.GetContext(ctx, &policy, `SELECT id AS tenant_id, realname_review_policy, realname_provider_mode, realname_required, realname_allow_skip, realname_remind_after - FROM im_tenant_config WHERE tenant_id=? LIMIT 1`, tenantID) + FROM im_tenant WHERE id=? LIMIT 1`, tenantID) if errors.Is(err, sql.ErrNoRows) { policy = *defaultRealNamePolicy(tenantID) return &policy, nil diff --git a/server/db/mysql/schema.sql b/server/db/mysql/schema.sql index a79084f..7deefd0 100644 --- a/server/db/mysql/schema.sql +++ b/server/db/mysql/schema.sql @@ -6,16 +6,15 @@ # Current MySQL initialization is generated by server/db/mysql/adapter.go: # # - Control database: hotgo -# - im_tenant -# - im_tenant_config +# - im_tenant (includes tenant feature and policy configuration) # - im_public_uploads, im_tenant_applications and im_tenant_entry_feedbacks # for unauthenticated enterprise registration and tenant-entry feedback # -# - Default tenant business database: tinode +# - Shared tenant business database: meeting_im # - im_users, im_topics, im_subscriptions, im_messages and extension tables # - im_http_idempotency for HTTP write idempotency # - im_file_review_tasks for asynchronous content safety and malware checks -# - business tables do not store tenant_id in independent-database mode +# - business tables store tenant_id; high-volume tables are physically partitioned by tenant # # The previous shared-table tenant_id draft has been removed from this file to # avoid accidental execution. If standalone SQL initialization scripts are diff --git a/server/db/mysql/tests/mysql_test.go b/server/db/mysql/tests/mysql_test.go index c0707a7..60f8879 100644 --- a/server/db/mysql/tests/mysql_test.go +++ b/server/db/mysql/tests/mysql_test.go @@ -263,13 +263,13 @@ func TestTenantAuthIsolation(t *testing.T) { } } } - createTenant := func(code, dbName string) types.TenantID { + createTenant := func(code, _ string) types.TenantID { var id int64 if err := db.Get(&id, "SELECT COALESCE(MAX(id),0)+1 FROM im_tenant"); err != nil { t.Fatal(err) } - _, err := db.Exec("INSERT INTO im_tenant(id,code,name,db_name,state,created_by,updated_by) VALUES(?,?,?,?,?,?,?)", - id, code+suffix, code, dbName, types.TenantStateActive, 0, 0) + _, err := db.Exec("INSERT INTO im_tenant(id,code,name,state,created_by,updated_by) VALUES(?,?,?,?,?,?)", + id, code+suffix, code, types.TenantStateActive, 0, 0) if err != nil { t.Fatal(err) } diff --git a/server/store/types/tenant.go b/server/store/types/tenant.go index 0e4753b..c479ba8 100644 --- a/server/store/types/tenant.go +++ b/server/store/types/tenant.go @@ -35,8 +35,6 @@ type Tenant struct { Code string `db:"code" json:"code"` Name string `db:"name" json:"name"` TenantDesc *string `db:"tenant_desc" json:"tenant_desc,omitempty"` - DBName string `db:"db_name" json:"-"` - DBDSN string `db:"db_dsn" json:"-"` State TenantState `db:"state" json:"-"` CreatedAt time.Time `db:"created_at" json:"-"` CreatedBy int64 `db:"created_by" json:"-"`