Repository: robustmq/robustmq (language: rust)

Issue:
[MINOR][Refactor][Subtask] Standardize the command output format for user functions.
#752 
### Have you checked the documentation for submitting an Issue?

- [X] Yes.

### Search before asking

- [X] I have searched in the [issues](https://github.com/robustmq/robustmq/issues) and found no similar issues.


### Describe the subtask

1. Standardize the command output format for user functions.
2. Add docs for this command
3. Use `prettytable` to format the output of `list-user` into a table.

### Parent issue

no

### Are you willing to submit PR?

- [ ] Yes. I would be willing to submit a PR with guidance from the RobustMQ community to improve.
- [X] No. I cannot submit a PR at this time.


Discussion / hints:

Fix patch:
diff --git a/docs/.vitepress/src/sidebars/en.mts b/docs/.vitepress/src/sidebars/en.mts
index 685067eac..32cbfda0c 100644
--- a/docs/.vitepress/src/sidebars/en.mts
+++ b/docs/.vitepress/src/sidebars/en.mts
@@ -17,6 +17,7 @@ export const sidebar = [
             {text: "ClusterMode", link: "/QuickGuide/Run-Cluster-Mode"},
             {text: "DockerMode", link: "/QuickGuide/Run-Docker-Mode"},
             {text: "K8SMode", link: "/QuickGuide/Run-K8S-Mode"},
+            {text: "EasyStart", link: "/QuickGuide/Easy-Start"},
         ],
     },
     {
diff --git a/docs/.vitepress/src/sidebars/zh.mts b/docs/.vitepress/src/sidebars/zh.mts
index 83918af8d..fc0fd5ef9 100644
--- a/docs/.vitepress/src/sidebars/zh.mts
+++ b/docs/.vitepress/src/sidebars/zh.mts
@@ -17,6 +17,7 @@ export const sidebar = [
             {text: "集群模式", link: "/zh/QuickGuide/Run-Cluster-Mode"},
             {text: "Docker 模式", link: "/zh/QuickGuide/Run-Docker-Mode"},
             {text: "K8S 模式", link: "/zh/QuickGuide/Run-K8S-Mode"},
+            {text: "快速上手", link: "/zh/QuickGuide/Easy-Start"},
         ],
     },
     {
diff --git a/docs/en/QuickGuide/Easy-Start.md b/docs/en/QuickGuide/Easy-Start.md
new file mode 100644
index 000000000..82130809c
--- /dev/null
+++ b/docs/en/QuickGuide/Easy-Start.md
@@ -0,0 +1,85 @@
+1. User Registration
+
+    1.1 The MQTT Broker has enabled user authentication, which requires clients to provide a valid username and password for verification before publishing or subscribing to messages. Clients that do not pass the verification will be unable to communicate with the Broker. This feature can enhance system security by preventing unauthorized access.
+
+     Register a user
+    ```console
+    % cli-command mqtt user create --username=testp --password=7355608
+    Created successfully!
+    ```
+     Delete a user
+    ```console
+    % cli-command mqtt user delete --username=testp
+    Deleted successfully!
+    ```
+    1.2 View created users
+
+    ```console
+    % cli-command mqtt user list
+    +----------+--------------+
+    | username | is_superuser |
+    +----------+--------------+
+    | admin    | true         |
+    +----------+--------------+
+    | testp    | false        |
+    +----------+--------------+
+    ```
+
+2. TODO Subscribe and Publish
+
+   2.1 Subscribe to messages
+
+   ```console
+    % ./cli-command mqtt sub --username=testp --password=7355608 --topic=topic_test1
+    Subscribed!
+    ```
+
+   2.2 Publish messages
+
+   ```console
+    % ./cli-command mqtt pub --username=testp --password=7355608 --topic=topic_test1 --message=HelloWorld!
+    Published!
+    ```
+
+3. Enable Slow Subscription Feature
+
+   3.1 The slow subscription statistics function is mainly used to calculate the time (latency) it takes for the Broker to complete message processing and transmission after the message arrives at the Broker. If the latency exceeds the threshold, we will record a related piece of information in the cluster's slow subscription log. Operations personnel can query slow subscription records across the entire cluster using commands to address issues based on this information.
+
+   Enable slow subscription
+   ```console
+    % ./cli-command mqtt slow-sub --enable=true
+    The slow subscription feature has been successfully enabled.
+   ```
+
+   3.2 How to view slow subscription records
+
+    After enabling the slow subscription statistics function, the cluster begins recording slow subscriptions. To query corresponding slow subscription records, clients can enter the following command:
+
+   ```console
+    % ./cli-command mqtt slow-sub --query=true
+    +-----------+-------+----------+---------+-------------+
+    | client_id | topic | sub_name | time_ms | create_time |
+    +-----------+-------+----------+---------+-------------+
+    ```
+
+   3.3 Sorting Functionality
+
+   To obtain more slow subscription records and sort them in ascending order from smallest to largest, you can use the following command:
+
+   ```console
+    % ./cli-command mqtt slow-sub --list=200 --sort=asc
+    +-----------+-------+----------+---------+-------------+
+    | client_id | topic | sub_name | time_ms | create_time |
+    +-----------+-------+----------+---------+-------------+
+    ```
+
+   3.4 Filtering Query Functionality
+
+    For slow subscription queries, filtering queries are also supported. You can retrieve filtered results by fields such as topic, sub_name, and client_id. By default, the results are sorted in descending order from largest to smallest. Refer to the usage command below:
+
+    ```console
+    % ./cli-command mqtt slow-sub --topic=topic_test1 --list=200
+    +-----------+-------+----------+---------+-------------+
+    | client_id | topic | sub_name | time_ms | create_time |
+    +-----------+-------+----------+---------+-------------+
+    ```
diff --git a/docs/zh/QuickGuide/Easy-Start.md b/docs/zh/QuickGuide/Easy-Start.md
new file mode 100644
index 000000000..adb142a53
--- /dev/null
+++ b/docs/zh/QuickGuide/Easy-Start.md
@@ -0,0 +1,86 @@
+1. 用户注册
+
+    1.1 MQTT Broker 启用了用户验证功能，客户端在发布或订阅消息前，必须提供有效的用户名和密码以通过验证。未通过验证的客户端将无法与 Broker 通信。这一功能可以增强系统的安全性，防止未经授权的访问。
+
+     注册用户
+    ```console
+    % cli-command  mqtt user create --username=testp --password=7355608
+    Created successfully!
+    ```
+     删除用户
+    ```console
+    % cli-command  mqtt user delete --username=testp
+    Deleted successfully!
+    ```
+    1.2 查看创建的用户
+
+    ```console
+    % cli-command  mqtt user list
+    +----------+--------------+
+    | username | is_superuser |
+    +----------+--------------+
+    | admin    | true         |
+    +----------+--------------+
+    | testp    | false        |
+    +----------+--------------+
+    ```
+
+2. TODO订阅发布
+
+   2.1 订阅消息
+
+   ```console
+    % ./cli-command mqtt sub --username=testp --password=7355608 --topic=topic_test1
+    Subscribed!
+    ```
+
+   2.2 发布消息
+
+   ```console
+    % ./cli-command mqtt pub --username=testp --password=7355608 --topic=topic_test1 --message=HelloWorld!
+    Published!
+    ```
+
+
+3. 开启慢订阅功能
+
+   3.1 慢订阅统计功能主要是为了在消息到达Broker后，Broker来计算完成消息处理以及传输整个流程所消耗的时间(时延), 如果时延超过阈值，我们就会记录一条相关的信息在集群慢订阅日志当中，运维人员可以通过命令查询整个集群下的慢订阅记录信息，通过慢订阅信息来解决。
+
+   开启慢订阅
+   ```console
+    % ./cli-command mqtt slow-sub --enable=true
+    The slow subscription feature has been successfully enabled.
+   ```
+
+   3.2 如何查看慢订阅记录
+
+    当我们启动了慢订阅统计功能之后, 集群就开启慢订阅统计功能，这样我们可以通过对应的命令来去查询对应的慢订阅记录， 如果我们想要查看慢订阅记录，客户端可以输入如下命令
+
+   ```console
+    % ./cli-command mqtt slow-sub --query=true
+    +-----------+-------+----------+---------+-------------+
+    | client_id | topic | sub_name | time_ms | create_time |
+    +-----------+-------+----------+---------+-------------+
+    ```
+
+   3.3 排序功能
+
+   如果想要获取更多的慢订阅记录， 并且想要按照从小到大的顺序进行升序排序， 那么可以使用如下的命令
+
+   ```console
+    % ./cli-command mqtt slow-sub --list=200 --sort=asc
+    +-----------+-------+----------+---------+-------------+
+    | client_id | topic | sub_name | time_ms | create_time |
+    +-----------+-------+----------+---------+-------------+
+    ```
+
+   3.4 筛选查询功能
+
+    对于慢订阅查询，我们同样支持筛选查询功能，我们支持使用topic, sub_name以及client_id的方式来获取不同字段过滤后的结果，其结果默认从大到小倒序排序，参考使用命令如下
+
+    ```console
+    % ./cli-command mqtt slow-sub --topic=topic_test1 --list=200
+    +-----------+-------+----------+---------+-------------+
+    | client_id | topic | sub_name | time_ms | create_time |
+    +-----------+-------+----------+---------+-------------+
+    ```
diff --git a/src/cli-command/src/mqtt.rs b/src/cli-command/src/mqtt.rs
index f1e35cc48..6d9607335 100644
--- a/src/cli-command/src/mqtt.rs
+++ b/src/cli-command/src/mqtt.rs
@@ -160,11 +160,15 @@ impl MqttBrokerCommand {
         let request = ListUserRequest {};
         match mqtt_broker_list_user(client_pool, &grpc_addr(params.server), request).await {
             Ok(data) => {
-                println!("user list:");
+                // format table
+                let mut table = Table::new();
+                table.add_row(row!["username", "is_superuser"]);
                 for user in data.users {
                     let mqtt_user = serde_json::from_slice::<MqttUser>(user.as_slice()).unwrap();
-                    println!("{},", mqtt_user.username);
+                    table.add_row(row![mqtt_user.username.as_str(), mqtt_user.is_superuser]);
                 }
+                // output cmd
+                table.printstd()
             }
             Err(e) => {
                 println!("MQTT broker list user exception");
diff --git a/src/cli-command/src/placement.rs b/src/cli-command/src/placement.rs
index ad9bdad54..a54859408 100644
--- a/src/cli-command/src/placement.rs
+++ b/src/cli-command/src/placement.rs
@@ -32,7 +32,7 @@ pub struct PlacementCliCommandParam {
     pub action: PlacementActionType,
 }
 
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Debug)]
 pub enum PlacementActionType {
     Status,
     AddLearner(AddLearnerRequest),
diff --git a/src/cmd/src/cli-command/command.rs b/src/cmd/src/cli-command/command.rs
index 05b8944c5..b419bc2ae 100644
--- a/src/cmd/src/cli-command/command.rs
+++ b/src/cmd/src/cli-command/command.rs
@@ -19,14 +19,12 @@ use cli_command::mqtt::{MqttActionType, MqttBrokerCommand, MqttCliCommandParam};
 use cli_command::placement::{
     PlacementActionType, PlacementCenterCommand, PlacementCliCommandParam,
 };
-use protocol::broker_mqtt::broker_mqtt_admin::{
-    CreateUserRequest, DeleteUserRequest, ListTopicRequest,
-};
+use protocol::broker_mqtt::broker_mqtt_admin::ListTopicRequest;
 use protocol::placement_center::placement_center_openraft::{
     AddLearnerRequest, ChangeMembershipRequest, Node,
 };
 
-use crate::mqtt::admin::{process_slow_sub_args, CreateUserArgs, DeleteUserArgs, SlowSubArgs};
+use crate::mqtt::admin::{process_slow_sub_args, process_user_args, MqttUserCommand, SlowSubArgs};
 
 #[derive(Parser)] // requires `derive` feature
 #[command(name = "robust-ctl")]
@@ -34,7 +32,16 @@ use crate::mqtt::admin::{process_slow_sub_args, CreateUserArgs, DeleteUserArgs,
 #[command(styles = CLAP_STYLING)]
 #[command(author="RobustMQ", version="0.0.1", about="Command line tool for RobustMQ", long_about = None)]
 #[command(next_line_help = true)]
-enum RobustMQCli {
+struct RobustMQCli {
+    // Mqtt(MqttArgs),
+    // Place(PlacementArgs),
+    // Journal(JournalArgs),
+    #[command(subcommand)]
+    command: RobustMQCliCommand,
+}
+
+#[derive(Debug, Subcommand)]
+enum RobustMQCliCommand {
     Mqtt(MqttArgs),
     Place(PlacementArgs),
     Journal(JournalArgs),
@@ -64,10 +71,7 @@ struct MqttArgs {
 enum MQTTAction {
     Status,
     // User admin
-    CreateUser(CreateUserArgs),
-    DeleteUser(DeleteUserArgs),
-    ListUser,
-
+    User(MqttUserCommand),
     // Connections
     ListConnection,
 
@@ -153,10 +157,12 @@ struct JournalArgs {
 #[tokio::main]
 async fn main() {
     let args = RobustMQCli::parse();
-    match args {
-        RobustMQCli::Mqtt(args) => handle_mqtt(args, MqttBrokerCommand::new()).await,
-        RobustMQCli::Place(args) => handle_placement(args, PlacementCenterCommand::new()).await,
-        RobustMQCli::Journal(args) => handle_journal(args).await,
+    match args.command {
+        RobustMQCliCommand::Mqtt(args) => handle_mqtt(args, MqttBrokerCommand::new()).await,
+        RobustMQCliCommand::Place(args) => {
+            handle_placement(args, PlacementCenterCommand::new()).await
+        }
+        RobustMQCliCommand::Journal(args) => handle_journal(args).await,
     }
 }
 
@@ -165,15 +171,7 @@ async fn handle_mqtt(args: MqttArgs, cmd: MqttBrokerCommand) {
         server: args.server,
         action: match args.action {
             MQTTAction::Status => MqttActionType::Status,
-            MQTTAction::CreateUser(arg) => MqttActionType::CreateUser(CreateUserRequest {
-                username: arg.username,
-                password: arg.password,
-                is_superuser: arg.is_superuser,
-            }),
-            MQTTAction::DeleteUser(arg) => MqttActionType::DeleteUser(DeleteUserRequest {
-                username: arg.username,
-            }),
-            MQTTAction::ListUser => MqttActionType::ListUser,
+            MQTTAction::User(args) => process_user_args(args),
             MQTTAction::ListConnection => MqttActionType::ListConnection,
             MQTTAction::ListTopic(args) => MqttActionType::ListTopic(ListTopicRequest {
                 topic_name: args.topic_name,
diff --git a/src/cmd/src/cli-command/mqtt/admin.rs b/src/cmd/src/cli-command/mqtt/admin.rs
index 164fbce0b..5f4694db9 100644
--- a/src/cmd/src/cli-command/mqtt/admin.rs
+++ b/src/cmd/src/cli-command/mqtt/admin.rs
@@ -12,16 +12,35 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use core::option::Option::Some;
+
 use clap::builder::{
     ArgAction, BoolishValueParser, EnumValueParser, NonEmptyStringValueParser, RangedU64ValueParser,
 };
 use clap::Parser;
 use cli_command::mqtt::MqttActionType;
 use common_base::enum_type::common_enum::SortType;
+use protocol::broker_mqtt::broker_mqtt_admin::{CreateUserRequest, DeleteUserRequest};
 use protocol::broker_mqtt::broker_mqtt_admin::{
     EnableSlowSubscribeRequest, ListSlowSubscribeRequest,
 };
 
+#[derive(clap::Args, Debug)]
+#[command(author="RobustMQ", about="related operations of mqtt users, such as listing, creating, and deleting ", long_about = None)]
+#[command(next_line_help = true)]
+pub(crate) struct MqttUserCommand {
+    #[command(subcommand)]
+    pub action: Option<MqttUserActionType>,
+}
+
+#[derive(Debug, clap::Subcommand)]
+pub enum MqttUserActionType {
+    #[command(author="RobustMQ", about="action: user list", long_about = None)]
+    List,
+    Delete(DeleteUserArgs),
+    Create(CreateUserArgs),
+}
+
 // security: user feat
 #[derive(clap::Args, Debug)]
 #[command(author="RobustMQ", about="action: create user", long_about = None)]
@@ -107,10 +126,27 @@ pub fn process_slow_sub_args(args: SlowSubArgs) -> MqttActionType {
     }
 }
 
+pub fn process_user_args(args: MqttUserCommand) -> MqttActionType {
+    match args.action {
+        Some(user_action) => match user_action {
+            MqttUserActionType::List => MqttActionType::ListUser,
+            MqttUserActionType::Create(arg) => MqttActionType::CreateUser(CreateUserRequest {
+                username: arg.username,
+                password: arg.password,
+                is_superuser: arg.is_superuser,
+            }),
+            MqttUserActionType::Delete(arg) => MqttActionType::DeleteUser(DeleteUserRequest {
+                username: arg.username,
+            }),
+        },
+        None => unreachable!(),
+    }
+}
+
 #[cfg(test)]
 mod tests {
-    use super::*;
 
+    use super::*;
     #[tokio::test]
     async fn test_process_slow_sub_args_function_field_is_enable_not_none() {
         let args = SlowSubArgs {


Test patch: