This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new d678c0b9 feat(server): use the instance name as the immutable instance 
ID (#2050)
d678c0b9 is described below

commit d678c0b988bb751aa506029e281e6714b656472a
Author: lizhimins <[email protected]>
AuthorDate: Thu Aug 13 11:51:54 2026 +0800

    feat(server): use the instance name as the immutable instance ID (#2050)
    
    Stop generating UUIDs for instances: the user-supplied name (unique,
    max 64 chars) becomes the primary key of rmq_instance and is immutable
    after creation. All lookups go through InstanceRepository#findByIdentifier,
    which prefers the instance ID and falls back to legacy primary keys,
    and existing UUID rows are migrated by the two new upgrade scripts.
    Also bump the Aliyun resource-count page size to the OpenAPI minimum.
---
 deploy/mysql/upgrade-instance-id-pk.sql            | 42 ++++++++++++++++++++++
 deploy/mysql/upgrade-instance-name-uk.sql          | 36 +++++++++++++++++++
 server/README.md                                   | 12 +++++++
 .../cluster/broker/RuntimeAdminClientResolver.java |  2 +-
 .../studio/instance/InstanceRepository.java        | 13 +++++++
 .../rocketmq/studio/instance/InstanceService.java  | 26 +++++++++++---
 .../instance/MybatisPlusInstanceRepository.java    | 13 +++++++
 .../rocketmq/studio/instance/acl/AclService.java   |  2 +-
 .../studio/provider/InstanceProviderRegistry.java  |  2 +-
 .../provider/alibaba/AliyunInstanceProvider.java   |  4 +--
 .../provider/tencent/TencentInstanceProvider.java  |  2 +-
 server/src/main/resources/db/schema.sql            |  3 +-
 .../broker/RuntimeAdminClientResolverTest.java     | 14 ++++----
 .../studio/instance/InstanceServiceTest.java       | 28 ++++++++-------
 .../studio/instance/acl/AclServiceTest.java        |  4 +--
 .../provider/InstanceProviderRegistryTest.java     |  6 ++--
 .../alibaba/AliyunInstanceProviderTest.java        | 18 +++++-----
 .../tencent/TencentInstanceProviderTest.java       |  2 +-
 18 files changed, 183 insertions(+), 46 deletions(-)

diff --git a/deploy/mysql/upgrade-instance-id-pk.sql 
b/deploy/mysql/upgrade-instance-id-pk.sql
new file mode 100644
index 00000000..284a8b5a
--- /dev/null
+++ b/deploy/mysql/upgrade-instance-id-pk.sql
@@ -0,0 +1,42 @@
+-- deploy/mysql/upgrade-instance-id-pk.sql
+-- 存量 MySQL 数据卷增量迁移(2026-08-12):废弃实例 UUID 主键,rmq_instance.id 改写为实例 ID(name)。
+-- 背景:系统不再使用 UUID 作为实例标识;实例 ID(原 name 字段,全局唯一、创建后不可变)
+--       直接作为主键,URL / API / 存储一律走实例 ID。
+-- 适用:数据卷已初始化、docker-entrypoint-initdb.d 不会再执行的存量部署。
+--       全新创建的实例 id 即实例 ID,无需本脚本。
+-- 幂等:可重复执行(所有语句带 id <> name 条件)。
+--
+-- ⚠️ 第 3 步会改写 rmq_instance 主键值,执行前建议备份:
+--   docker exec rocketmq-studio-mysql sh -c 'exec mysqldump -uroot 
-pstudio123 rocketmq' > backup.sql
+--
+-- 用法(远程容器内执行):
+--   docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq < 
upgrade-instance-id-pk.sql
+
+SET NAMES utf8mb4;
+
+-- 1. 子表引用列先改(必须在 rmq_instance 主键改写之前执行)
+UPDATE rmq_topic t
+JOIN rmq_instance i ON t.instance_id = i.id AND i.id <> i.name
+SET t.instance_id = i.name;
+
+UPDATE rmq_group g
+JOIN rmq_instance i ON g.instance_id = i.id AND i.id <> i.name
+SET g.instance_id = i.name;
+
+UPDATE rmq_acl_rule r
+JOIN rmq_instance i ON r.scope = i.id AND i.id <> i.name
+SET r.scope = i.name;
+
+-- 2. 逗号分隔 / JSON 内容按实例逐个替换
+UPDATE rmq_acl_user u
+JOIN rmq_instance i ON i.id <> i.name
+SET u.clusters = REPLACE(u.clusters, i.id, i.name)
+WHERE u.clusters LIKE CONCAT('%', i.id, '%');
+
+UPDATE rmq_data_source d
+JOIN rmq_instance i ON i.id <> i.name
+SET d.json = REPLACE(d.json, i.id, i.name)
+WHERE d.json LIKE CONCAT('%', i.id, '%');
+
+-- 3. 最后改写主键:id = 实例 ID
+UPDATE rmq_instance SET id = name WHERE id <> name;
diff --git a/deploy/mysql/upgrade-instance-name-uk.sql 
b/deploy/mysql/upgrade-instance-name-uk.sql
new file mode 100644
index 00000000..40f796b8
--- /dev/null
+++ b/deploy/mysql/upgrade-instance-name-uk.sql
@@ -0,0 +1,36 @@
+-- deploy/mysql/upgrade-instance-name-uk.sql
+-- 存量 MySQL 数据卷增量迁移(2026-08-12):rmq_instance.name 全局唯一。
+-- 背景:实例名(instanceId 概念)在 开源/阿里云/腾讯云 之间不重复,作为业务唯一标识;
+--       此前无唯一约束,重复提交会把同一云实例加入两次。
+-- 适用:数据卷已初始化、docker-entrypoint-initdb.d 不会再执行的存量部署。
+--       全新数据卷由 server/src/main/resources/db/schema.sql 直接带上 uk_instance_name。
+-- 幂等:可重复执行。
+--
+-- ⚠️ 会删除同名重复实例(保留 created_at 最早的一条)。执行前可先用下面的查询核对重复:
+--   SELECT name, COUNT(*) FROM rmq_instance GROUP BY name HAVING COUNT(*) > 1;
+--
+-- 用法(远程容器内执行):
+--   docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq < 
upgrade-instance-name-uk.sql
+
+SET NAMES utf8mb4;
+
+-- 1. 清理同名重复(保留 created_at 最早,id 最小作为并列时的决胜)
+DELETE i FROM rmq_instance i
+JOIN rmq_instance k
+  ON k.name = i.name
+ AND (k.created_at < i.created_at
+      OR (k.created_at = i.created_at AND k.id < i.id));
+
+-- 2. 追加唯一键(仅当不存在时)
+SET @uk_exists := (
+  SELECT COUNT(*) FROM information_schema.statistics
+   WHERE table_schema = DATABASE()
+     AND table_name = 'rmq_instance'
+     AND index_name = 'uk_instance_name'
+);
+SET @uk_sql := IF(@uk_exists = 0,
+    'ALTER TABLE rmq_instance ADD UNIQUE KEY uk_instance_name (name)',
+    'SELECT ''uk_instance_name already exists'' AS msg');
+PREPARE stmt FROM @uk_sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git a/server/README.md b/server/README.md
index ffca74e3..46ff1369 100644
--- a/server/README.md
+++ b/server/README.md
@@ -93,6 +93,18 @@ org.apache.rocketmq.studio
   云厂商实现放 `provider/<vendor>/` 保持高内聚
 - **敏感字段**:VO 上 `@ToString.Exclude`;存储 base64(见 `CredentialUtils`);
   列表打码、reveal 接口 admin-only
+- **实例标识:禁用 UUID**。系统不使用 UUID(或任何随机代理键)作为实例标识;
+  实例 ID(用户输入、人类可读、全局唯一、≤64 字符)是实例的唯一标识,
+  直接作为 `rmq_instance` 主键(`InstanceService.createInstance` 中 `id = name`),
+  创建后不可变(更新传入不同名称直接 400 `Instance ID cannot be changed after creation`)。
+  REST 参数(`instanceId`)与关联表外键列(`rmq_topic.instance_id`、`rmq_group.instance_id`、
+  ACL scope、数据源绑定等)一律使用实例 ID;不存在"实例名称"概念,
+  实例只有**实例 ID** 与 **备注(remark)** 两个文本属性。
+  解析实例统一走 `InstanceRepository#findByIdentifier`(优先实例 ID,兜底历史主键引用),
+  不要直接 `findById`;存量 UUID 数据经 `deploy/mysql/upgrade-instance-id-pk.sql` 迁移,
+  新功能不得新增随机 ID 作为对外标识
+- **测试命名**:Test 方法名以 `Test` 结尾(如 `syncProxyClusterAddsNewInstanceTest`)
+- **checkstyle**:validate 阶段强制,禁止中文字符,Java 代码注释一律用英文
 
 ## 构建与测试
 
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/RuntimeAdminClientResolver.java
 
b/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/RuntimeAdminClientResolver.java
index d42bb010..dee110c1 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/RuntimeAdminClientResolver.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/RuntimeAdminClientResolver.java
@@ -29,7 +29,7 @@ public class RuntimeAdminClientResolver {
         if (!StringUtils.hasText(instanceId)) {
             throw new BusinessException(400, "instanceId is required");
         }
-        return instanceRepository.findById(instanceId)
+        return instanceRepository.findByIdentifier(instanceId)
                 .orElseThrow(() -> new BusinessException(404, "Instance not 
found: " + instanceId));
     }
 
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceRepository.java
 
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceRepository.java
index 546db9b6..a48af8bc 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceRepository.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceRepository.java
@@ -33,6 +33,19 @@ public interface InstanceRepository {
 
     Optional<InstanceVO> findById(String id);
 
+    Optional<InstanceVO> findByName(String name);
+
+    /**
+     * Resolves an instance by the external instance identifier: matches the 
unique name
+     * first, falling back to the internal primary key for legacy references.
+     */
+    default Optional<InstanceVO> findByIdentifier(String identifier) {
+        if (identifier == null || identifier.isBlank()) {
+            return Optional.empty();
+        }
+        return findByName(identifier).or(() -> findById(identifier));
+    }
+
     InstanceVO save(InstanceVO instance);
 
     void deleteById(String id);
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java 
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
index 29b6f569..163f443b 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
@@ -37,7 +37,6 @@ import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
-import java.util.UUID;
 
 @Slf4j
 @Service
@@ -96,7 +95,8 @@ public class InstanceService {
             case ALIYUN, TENCENT -> createCloudInstance(instance, vendor);
         }
 
-        instance.setId(UUID.randomUUID().toString());
+        requireUniqueInstanceName(instance.getName(), null);
+        instance.setId(instance.getName());
         instance.setCreatedAt(LocalDateTime.now());
         instance.setUpdatedAt(LocalDateTime.now());
         InstanceVO saved = instanceRepository.save(instance);
@@ -105,6 +105,17 @@ public class InstanceService {
         return saved;
     }
 
+    private void requireUniqueInstanceName(String name, String excludeId) {
+        if (!StringUtils.hasText(name)) {
+            return;
+        }
+        instanceRepository.findByName(name).ifPresent(existing -> {
+            if (excludeId == null || !excludeId.equals(existing.getId())) {
+                throw new BusinessException(400, "Instance name already 
exists: " + name);
+            }
+        });
+    }
+
     private void createApacheInstance(InstanceVO instance) {
         instance.setVendor(InstanceVendor.APACHE);
         instance.setName(requireInstanceName(instance.getName()));
@@ -187,7 +198,11 @@ public class InstanceService {
         if (!StringUtils.hasText(name)) {
             throw new BusinessException(400, "InstanceVO name is required");
         }
-        return name.trim();
+        String trimmed = name.trim();
+        if (trimmed.length() > 64) {
+            throw new BusinessException(400, "InstanceVO name must not exceed 
64 characters");
+        }
+        return trimmed;
     }
 
     private String normalizeCredentialRef(String credentialRef) {
@@ -212,7 +227,10 @@ public class InstanceService {
         InstanceVO updated = copyOf(existing);
         boolean cloudInstance = existing.getVendor() != null && 
existing.getVendor() != InstanceVendor.APACHE;
         if (instance.getName() != null) {
-            updated.setName(requireInstanceName(instance.getName()));
+            String requestedName = requireInstanceName(instance.getName());
+            if (!requestedName.equals(existing.getName())) {
+                throw new BusinessException(400, "Instance ID cannot be 
changed after creation");
+            }
         }
         if (!cloudInstance) {
             if (instance.getType() != null) {
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepository.java
 
b/server/src/main/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepository.java
index 4a393e68..961f89fa 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepository.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepository.java
@@ -94,6 +94,19 @@ public class MybatisPlusInstanceRepository implements 
InstanceRepository {
         return Optional.of(toVO(entity));
     }
 
+    @Override
+    public Optional<InstanceVO> findByName(String name) {
+        if (name == null || name.isBlank()) {
+            return Optional.empty();
+        }
+        RmqInstance entity = instanceMapper.selectOne(
+                new QueryWrapper<RmqInstance>().eq("name", name).last("LIMIT 
1"));
+        if (entity == null) {
+            return Optional.empty();
+        }
+        return Optional.of(toVO(entity));
+    }
+
     @Override
     @Transactional
     public InstanceVO save(InstanceVO instance) {
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclService.java 
b/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclService.java
index bece9052..d6ea5435 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclService.java
@@ -47,7 +47,7 @@ public class AclService {
         if (!StringUtils.hasText(instanceId)) {
             throw new BusinessException(400, "instanceId is required");
         }
-        InstanceVO instance = instanceRepository.findById(instanceId)
+        InstanceVO instance = instanceRepository.findByIdentifier(instanceId)
                 .orElseThrow(() -> new BusinessException(404, "Instance not 
found: " + instanceId));
         boolean apacheInstance = instance.getVendor() == null || 
instance.getVendor() == InstanceVendor.APACHE;
         return new AclCapabilitiesVO(instance.getId(), instance.getVendor(), 
instance.getType(),
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/InstanceProviderRegistry.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/InstanceProviderRegistry.java
index 998a81a6..ebfce9ee 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/InstanceProviderRegistry.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/InstanceProviderRegistry.java
@@ -58,7 +58,7 @@ public class InstanceProviderRegistry {
         if (instanceId == null || instanceId.isBlank()) {
             return Optional.empty();
         }
-        InstanceVO instance = instanceRepository.findById(instanceId)
+        InstanceVO instance = instanceRepository.findByIdentifier(instanceId)
                 .orElseThrow(() -> new BusinessException(404, "Instance not 
found: " + instanceId));
         InstanceVendor vendor = instance.getVendor() == null ? 
InstanceVendor.APACHE : instance.getVendor();
         return Optional.of(forVendor(vendor));
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProvider.java
index 4e449078..56c38b37 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProvider.java
@@ -77,7 +77,7 @@ public class AliyunInstanceProvider implements 
InstanceProvider {
     private static final String FIXED_RETRY_POLICY = "FixedRetryPolicy";
     private static final int DEFAULT_MAX_RETRY_TIMES = 16;
     private static final int DEFAULT_FIXED_RETRY_INTERVAL_SECONDS = 10;
-    private static final int COUNT_PAGE_SIZE = 1;
+    private static final int COUNT_PAGE_SIZE = 10;
     private static final String RESET_TYPE_SPECIFIED_TIME = "SPECIFIED_TIME";
     private static final String RESET_TYPE_LATEST_OFFSET = "LATEST_OFFSET";
 
@@ -450,7 +450,7 @@ public class AliyunInstanceProvider implements 
InstanceProvider {
         if (!StringUtils.hasText(instanceId)) {
             throw new BusinessException(400, "instanceId is required");
         }
-        InstanceVO instance = instanceRepository.findById(instanceId)
+        InstanceVO instance = instanceRepository.findByIdentifier(instanceId)
                 .orElseThrow(() -> new BusinessException(404, "Instance not 
found: " + instanceId));
         if (!StringUtils.hasText(instance.getCloudInstanceId()) || 
!StringUtils.hasText(instance.getRegionId())
                 || !StringUtils.hasText(instance.getCredentialId())) {
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProvider.java
index aba0521f..f205d5bc 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProvider.java
@@ -752,7 +752,7 @@ public class TencentInstanceProvider implements 
InstanceProvider {
         if (!StringUtils.hasText(instanceId)) {
             throw new BusinessException(400, "instanceId is required");
         }
-        InstanceVO instance = instanceRepository.findById(instanceId)
+        InstanceVO instance = instanceRepository.findByIdentifier(instanceId)
                 .orElseThrow(() -> new BusinessException(404, "Instance not 
found: " + instanceId));
         if (!StringUtils.hasText(instance.getCloudInstanceId()) || 
!StringUtils.hasText(instance.getRegionId())
                 || !StringUtils.hasText(instance.getCredentialId())) {
diff --git a/server/src/main/resources/db/schema.sql 
b/server/src/main/resources/db/schema.sql
index 34d2ccf6..0841633a 100644
--- a/server/src/main/resources/db/schema.sql
+++ b/server/src/main/resources/db/schema.sql
@@ -30,7 +30,8 @@ CREATE TABLE IF NOT EXISTS rmq_instance (
   admin_credential_ref VARCHAR(128) COMMENT 'External Apache admin credential 
reference; no secret material',
   region_id VARCHAR(128),
   created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  UNIQUE KEY uk_instance_name (name)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
 -- 3. Topic 管理记录(通过 Studio 创建/管理的 Topic 元数据)
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/RuntimeAdminClientResolverTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/RuntimeAdminClientResolverTest.java
index 3ce4df4a..c410806f 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/RuntimeAdminClientResolverTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/RuntimeAdminClientResolverTest.java
@@ -54,7 +54,7 @@ class RuntimeAdminClientResolverTest {
     void resolvesTrimmedEndpointFromSelectedInstance() {
         InstanceVO instance = InstanceVO.builder().endpoint(" namesrv-a:9876 
").build();
         instance.setId("instance-a");
-        
when(instanceRepository.findById("instance-a")).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier("instance-a")).thenReturn(Optional.of(instance));
 
         RuntimeAdminClientResolver resolver = new 
RuntimeAdminClientResolver(instanceRepository, adminFactory,
                 new MqAdminProperties());
@@ -66,9 +66,9 @@ class RuntimeAdminClientResolverTest {
     void rejectsUnknownOrUnconfiguredInstances() {
         RuntimeAdminClientResolver resolver = new 
RuntimeAdminClientResolver(instanceRepository, adminFactory,
                 new MqAdminProperties());
-        
when(instanceRepository.findById("missing")).thenReturn(Optional.empty());
+        
when(instanceRepository.findByIdentifier("missing")).thenReturn(Optional.empty());
         InstanceVO noEndpoint = InstanceVO.builder().endpoint(" ").build();
-        
when(instanceRepository.findById("no-endpoint")).thenReturn(Optional.of(noEndpoint));
+        
when(instanceRepository.findByIdentifier("no-endpoint")).thenReturn(Optional.of(noEndpoint));
 
         assertThatThrownBy(() -> resolver.resolveEndpoint("missing"))
                 .isInstanceOf(BusinessException.class)
@@ -81,7 +81,7 @@ class RuntimeAdminClientResolverTest {
     @Test
     void executesAgainstTheSelectedInstanceEndpoint() {
         InstanceVO instance = 
InstanceVO.builder().endpoint("namesrv-b:9876").build();
-        
when(instanceRepository.findById("instance-b")).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier("instance-b")).thenReturn(Optional.of(instance));
         when(adminFactory.execute(eq("namesrv-b:9876"), isNull(), isNull(), 
any())).thenReturn("done");
         RuntimeAdminClientResolver resolver = new 
RuntimeAdminClientResolver(instanceRepository, adminFactory,
                 new MqAdminProperties());
@@ -98,7 +98,7 @@ class RuntimeAdminClientResolverTest {
                 .endpoint("cloud-endpoint:9876")
                 .build();
         instance.setId("cloud-instance");
-        
when(instanceRepository.findById("cloud-instance")).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier("cloud-instance")).thenReturn(Optional.of(instance));
         RuntimeAdminClientResolver resolver = new 
RuntimeAdminClientResolver(instanceRepository, adminFactory,
                 new MqAdminProperties());
 
@@ -123,7 +123,7 @@ class RuntimeAdminClientResolverTest {
         credential.setAccessKey("admin-ak");
         credential.setSecretKey("admin-sk");
         properties.getCredentials().put("production-admin", credential);
-        
when(instanceRepository.findById("instance-b")).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier("instance-b")).thenReturn(Optional.of(instance));
         when(adminFactory.execute(eq("namesrv-b:9876"), any(), 
eq("production-admin"), any()))
                 .thenReturn("done");
         RuntimeAdminClientResolver resolver = new 
RuntimeAdminClientResolver(instanceRepository, adminFactory,
@@ -154,7 +154,7 @@ class RuntimeAdminClientResolverTest {
         InstanceVO instance = InstanceVO.builder().endpoint("namesrv-b:9876")
                 .adminCredentialRef("missing").build();
         instance.setId("instance-b");
-        
when(instanceRepository.findById("instance-b")).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier("instance-b")).thenReturn(Optional.of(instance));
         RuntimeAdminClientResolver resolver = new 
RuntimeAdminClientResolver(instanceRepository, adminFactory,
                 properties);
 
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
index f0e6bb44..b29a8bd4 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
@@ -261,7 +261,7 @@ class InstanceServiceTest {
 
         InstanceVO result = instanceService.createInstance(input);
 
-        assertThat(result.getId()).isNotBlank();
+        assertThat(result.getId()).isEqualTo("new-instance");
         assertThat(result.getCreatedAt()).isNotNull();
         assertThat(result.getUpdatedAt()).isNotNull();
         assertThat(result.getName()).isEqualTo("new-instance");
@@ -391,7 +391,7 @@ class InstanceServiceTest {
         existing.setUpdatedAt(originalUpdatedAt);
 
         InstanceVO update = InstanceVO.builder()
-                .name("new-name")
+                .name("old-name")
                 .remark("new remark")
                 .build();
         update.setId("inst-1");
@@ -401,7 +401,7 @@ class InstanceServiceTest {
 
         InstanceVO result = instanceService.updateInstance(update);
 
-        assertThat(result.getName()).isEqualTo("new-name");
+        assertThat(result.getName()).isEqualTo("old-name");
         assertThat(result.getEndpoint()).isEqualTo("10.0.1.1:8080");
         assertThat(result.getType()).isEqualTo(InstanceType.PROXY);
         assertThat(result.getRemark()).isEqualTo("new remark");
@@ -415,19 +415,21 @@ class InstanceServiceTest {
         assertThat(existing.getRemark()).isEqualTo("old remark");
         assertThat(existing.getUpdatedAt()).isEqualTo(originalUpdatedAt);
         verify(operationAuditService).record(eq("UPDATE_INSTANCE"), 
eq("INSTANCE"), eq("inst-1"), eq(null),
-                eq("name=new-name, vendor=APACHE, type=PROXY"), eq("SUCCESS"), 
eq(null));
+                eq("name=old-name, vendor=APACHE, type=PROXY"), eq("SUCCESS"), 
eq(null));
     }
 
     @Test
-    void updateInstanceShouldTrimNameBeforeSaving() {
+    void updateInstanceShouldRejectInstanceIdChangeTest() {
         InstanceVO existing = 
InstanceVO.builder().name("old-name").endpoint("namesrv:9876").build();
-        existing.setId("inst-1");
-        InstanceVO update = InstanceVO.builder().name("  production  
").build();
-        update.setId("inst-1");
-        
when(instanceRepository.findById("inst-1")).thenReturn(Optional.of(existing));
-        
when(instanceRepository.save(any(InstanceVO.class))).thenAnswer(invocation -> 
invocation.getArgument(0));
+        existing.setId("old-name");
+        InstanceVO update = InstanceVO.builder().name("new-name").build();
+        update.setId("old-name");
+        
when(instanceRepository.findById("old-name")).thenReturn(Optional.of(existing));
 
-        
assertThat(instanceService.updateInstance(update).getName()).isEqualTo("production");
+        assertThatThrownBy(() -> instanceService.updateInstance(update))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Instance ID cannot be changed after creation");
+        verify(instanceRepository, never()).save(any(InstanceVO.class));
     }
 
     @Test
@@ -447,7 +449,7 @@ class InstanceServiceTest {
         stored.setUpdatedAt(originalUpdatedAt);
 
         InstanceVO update = InstanceVO.builder()
-                .name("new-name")
+                .name("old-name")
                 .remark("new remark")
                 .type(InstanceType.DIRECT)
                 .endpoint("10.0.2.2:10911")
@@ -610,7 +612,7 @@ class InstanceServiceTest {
                 .build();
         existing.setId("inst-1");
         InstanceVO update = InstanceVO.builder()
-                .name("new-name")
+                .name("existing-name")
                 .endpoint("   ")
                 .build();
         update.setId("inst-1");
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/instance/acl/AclServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/instance/acl/AclServiceTest.java
index ec0ed5f5..4408bcca 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/instance/acl/AclServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/instance/acl/AclServiceTest.java
@@ -104,7 +104,7 @@ class AclServiceTest {
                 .type(InstanceType.DIRECT)
                 .build();
         instance.setId("instance-1");
-        
when(instanceRepository.findById("instance-1")).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier("instance-1")).thenReturn(Optional.of(instance));
 
         AclCapabilitiesVO capabilities = aclService.capabilities("instance-1");
 
@@ -118,7 +118,7 @@ class AclServiceTest {
 
     @Test
     void capabilitiesShouldRejectUnknownInstance() {
-        
when(instanceRepository.findById("missing")).thenReturn(Optional.empty());
+        
when(instanceRepository.findByIdentifier("missing")).thenReturn(Optional.empty());
 
         assertThatThrownBy(() -> aclService.capabilities("missing"))
                 .isInstanceOf(BusinessException.class)
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/InstanceProviderRegistryTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/InstanceProviderRegistryTest.java
index 633c5f3e..84433c9b 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/InstanceProviderRegistryTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/InstanceProviderRegistryTest.java
@@ -71,7 +71,7 @@ class InstanceProviderRegistryTest {
 
     @Test
     void byInstanceIdShouldThrowWhenInstanceMissingTest() {
-        
when(instanceRepository.findById("missing")).thenReturn(Optional.empty());
+        
when(instanceRepository.findByIdentifier("missing")).thenReturn(Optional.empty());
 
         assertThatThrownBy(() -> registry.byInstanceId("missing"))
                 .isInstanceOf(BusinessException.class)
@@ -81,7 +81,7 @@ class InstanceProviderRegistryTest {
     @Test
     void byInstanceIdShouldResolveVendorProviderTest() {
         InstanceVO instance = 
InstanceVO.builder().vendor(InstanceVendor.ALIYUN).build();
-        
when(instanceRepository.findById("inst-1")).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier("inst-1")).thenReturn(Optional.of(instance));
 
         
assertThat(registry.byInstanceId("inst-1")).containsSame(aliyunProvider);
     }
@@ -89,7 +89,7 @@ class InstanceProviderRegistryTest {
     @Test
     void byInstanceIdShouldDefaultToApacheWhenVendorNullTest() {
         InstanceVO instance = InstanceVO.builder().build();
-        
when(instanceRepository.findById("inst-2")).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier("inst-2")).thenReturn(Optional.of(instance));
 
         
assertThat(registry.byInstanceId("inst-2")).containsSame(apacheProvider);
     }
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProviderTest.java
index 17c4f72f..a3d461f4 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProviderTest.java
@@ -380,7 +380,7 @@ class AliyunInstanceProviderTest {
                 .cloudInstanceId(CLOUD_INSTANCE_ID)
                 .regionId(REGION)
                 .build();
-        
when(instanceRepository.findById(STUDIO_INSTANCE_ID)).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier(STUDIO_INSTANCE_ID)).thenReturn(Optional.of(instance));
 
         assertThatThrownBy(() -> provider.listTopics(STUDIO_INSTANCE_ID, null, 
null))
                 .isInstanceOf(BusinessException.class)
@@ -396,7 +396,7 @@ class AliyunInstanceProviderTest {
                 .regionId(REGION)
                 .credentialId(CREDENTIAL_ID)
                 .build();
-        
when(instanceRepository.findById(STUDIO_INSTANCE_ID)).thenReturn(Optional.of(instance));
+        
when(instanceRepository.findByIdentifier(STUDIO_INSTANCE_ID)).thenReturn(Optional.of(instance));
     }
 
     private void stubCallThrough() {
@@ -438,7 +438,7 @@ class AliyunInstanceProviderTest {
                         .data(ListTopicsResponseBody.Data.builder()
                                 .list(List.of(topicRow("topic-a", "NORMAL")))
                                 .pageNumber(1L)
-                                .pageSize(1L)
+                                .pageSize(10L)
                                 .totalCount(321L)
                                 .build())
                         .build())
@@ -450,7 +450,7 @@ class AliyunInstanceProviderTest {
         ArgumentCaptor<ListTopicsRequest> captor = 
ArgumentCaptor.forClass(ListTopicsRequest.class);
         verify(asyncClient).listTopics(captor.capture());
         assertThat(captor.getValue().getPageNumber()).isEqualTo(1L);
-        assertThat(captor.getValue().getPageSize()).isEqualTo(1L);
+        assertThat(captor.getValue().getPageSize()).isEqualTo(10L);
     }
 
     @Test
@@ -465,7 +465,7 @@ class AliyunInstanceProviderTest {
                                         .consumerGroupId("GID_one")
                                         .build()))
                                 .pageNumber(1L)
-                                .pageSize(1L)
+                                .pageSize(10L)
                                 .totalCount(654L)
                                 .build())
                         .build())
@@ -478,7 +478,7 @@ class AliyunInstanceProviderTest {
                 ArgumentCaptor.forClass(ListConsumerGroupsRequest.class);
         verify(asyncClient).listConsumerGroups(captor.capture());
         assertThat(captor.getValue().getPageNumber()).isEqualTo(1L);
-        assertThat(captor.getValue().getPageSize()).isEqualTo(1L);
+        assertThat(captor.getValue().getPageSize()).isEqualTo(10L);
     }
 
     @Test
@@ -491,7 +491,7 @@ class AliyunInstanceProviderTest {
                         .data(ListTopicsResponseBody.Data.builder()
                                 .list(List.of(topicRow("topic-a", "NORMAL")))
                                 .pageNumber(1L)
-                                .pageSize(1L)
+                                .pageSize(10L)
                                 .build())
                         .build())
                 .build();
@@ -505,7 +505,7 @@ class AliyunInstanceProviderTest {
         ArgumentCaptor<ListTopicsRequest> captor = 
ArgumentCaptor.forClass(ListTopicsRequest.class);
         verify(asyncClient, times(2)).listTopics(captor.capture());
         
assertThat(captor.getAllValues()).extracting(ListTopicsRequest::getPageSize)
-                .containsExactly(1, AliyunConverters.PAGE_SIZE);
+                .containsExactly(10, AliyunConverters.PAGE_SIZE);
     }
 
     @Test
@@ -523,7 +523,7 @@ class AliyunInstanceProviderTest {
                 ArgumentCaptor.forClass(ListConsumerGroupsRequest.class);
         verify(asyncClient, times(2)).listConsumerGroups(captor.capture());
         
assertThat(captor.getAllValues()).extracting(ListConsumerGroupsRequest::getPageSize)
-                .containsExactly(1, AliyunConverters.PAGE_SIZE);
+                .containsExactly(10, AliyunConverters.PAGE_SIZE);
     }
 
     private static ListConsumerGroupsResponse groupsResponse(Long totalCount, 
String... groupIds) {
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProviderTest.java
index 8dd8fb3b..5fed4b7d 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProviderTest.java
@@ -97,7 +97,7 @@ class TencentInstanceProviderTest {
     @BeforeEach
     void setUp() {
         provider = new TencentInstanceProvider(clientFactory, 
instanceRepository);
-        
when(instanceRepository.findById(STUDIO_INSTANCE_ID)).thenReturn(Optional.of(InstanceVO.builder()
+        
when(instanceRepository.findByIdentifier(STUDIO_INSTANCE_ID)).thenReturn(Optional.of(InstanceVO.builder()
                 .name("tencent-prod")
                 .vendor(InstanceVendor.TENCENT)
                 .cloudInstanceId(CLOUD_INSTANCE_ID)

Reply via email to