diff --git a/86C111T1K131FJQU.dat b/86C111T1K131FJQU.dat
new file mode 100644
index 0000000..09ca61a
--- /dev/null
+++ b/86C111T1K131FJQU.dat
@@ -0,0 +1 @@
+EWDRGAHMADDPERCSGJDUHABIENHHJEEAFRFSATFTEFDSGZEQCYEOCOIRABDOEMEQAYAAABHEBBDWCMGEARHUJOGHBAJUFJJNFDGFAHDBJMGUBCIZBIEHIKDWBRAZIAINIGBFFFEKGQBUJGELGZIYBRGTHAEHHZCUEQJBAOGJAZBLACAFDFJKALCECDGKCQIYDJDODSDNDTIDHQJSDFFADLJLBNFAAAIODQEEILGGGVGEEKFSJRACFZDZIQEOILBLDXCRCPAOEBEDIPDDBNHCDJCKEGEJBHHBFKDNAOFOCCIQIBGVBSGPAJCDGTEMHGBCHYGLJOCPDYGWIFGIDXBUIHEKETDIFEGQHVGGFJAKAVHNJLEKBXJAFXDNHBGQAZDRHZGOGXHAALCXEZCNGLGHGOIDDKGCIYDSFJFNGIAQGMAHCXAFAVDVBPFMHSJSCODLHACXBHGUJEJLGLEREPBOEFCJDQDIDOIEFIHLCICOBWBTCAHOJTENCYDSBDGLFQBPIWCBGJDDIRCCDNEJITEJFHIWJEGLBGDMJRDGCFIFJCENCGCXHUCJGZGXAWAJCYDFIKJSIPDHFPBHGLCLGVFOEUAUIKFRISFQEXEPGEDVIFFGDOBNBFIMAUJOHJJNJAEQAMHBJVDTIUDDHBAQILFXHOGEFXIPBMDUCKCTCWGRFZIYFOENDJHPCTIYIXDXAEDGHNHTJQCWCQHAEVBDGLAZEQDPIQGIEVHNDUCUHMBMIVJKDNDJDJFGBAADHDIWJEGJJFDAEKALBMDOHTAQFFIDIBJVHQDNBXIABPIJCLAIBHHNIOGKDUCUCSAXDUCMDMGYAMBUEUBOAEATCMGBBJAOJKFRCYEXCJIZDKFAFCAJAGDYJGGPDKCJAPDWFIGAITHCEOFTIJEQGUGQHKAAHGFFEWGHDDEMDCHSAYJNCGIAJUHGDLAKFGHCGLEHHEAPENDVBAIOFEGOBKIKERHNFSIRCCAHHUBMGXDYATBYADEZCLCBDEDUHCJRESHMJCJVFTGLJJDYDYAFIMBCJKAOHEAHBMHMASIHCMGEGREQEUBSHFEECBJOJUBKDXGWJVADHLECJHHAADBKGCFQGIAYEHAJBFCVBTILJBIKBPAYFFFPCQEWJB
\ No newline at end of file
diff --git a/ArcFacePro64.dat b/ArcFacePro64.dat
new file mode 100644
index 0000000..33dd326
--- /dev/null
+++ b/ArcFacePro64.dat
@@ -0,0 +1 @@
+EWEPEPEOGMGTELIZJUGECKIUJDBCJTCNISGPBNHLJTJUBHEWGNAKGEGAIOHJDQAJGNCFDRFZJEDMJTGFGBEAAWGLBZAUCNHCCPBZCIIKBJATGYARHRAZHXFRBIEBCHIXAFDLFQBZFVJQGTCEHDIMIVGQEJAJIYHXHTISIVETBACMCCGFDPEKDQHYGGAPFXIOCJAAGOHYIFHNHZHWIGCZIGHHDMDXHQGTFLJOHGAYIVBGIHIQHHHJDJFWHMCRHJAMHZESGWGGAUJRGDHAGHIQITIJIUAXAEIZGBGZCCHJAHASGNCVIIJAIYFOEQGFELEIEDECJTCXBCAPIKHTFTHBAGJTERHQGSAFEUDIHLDDITDPIMACAOGTIIHFEMHLHIHYJTFDFDGWAKHJEIEIJFGABQJCIHIADYCXAHIMJTHOASFLGFFIBJJEHDHLHOCMDIGGDOJDHNBQCJENFUBAGOAZITIRJSFBBUCUHABLHRFVIUBWCADJCMDXDPATBPJSJRJLBRABGVFTDNFOAQDOARDEBRHJAQGYHIGMBDCJCSJKFBBLGECAEFEYCVCHAEAZJRIOFEHLCJILEHJVGYIVCWGHCMGJGLBTFMHFCAEAAUJQJLAEARDHDFHDBJJGALEHFNGSAIHOJUBOEAJDDFFYFTINITHTBNIJFDHLEAFGBFHFFQGHGFGREVFHFDCZGYEVBWAZDSCAGLDMIAAEFOAXIXFECSFQDWHFFHCFASFSGAHVJSDBBZJQAZBXARILBAJFJEHCANAIABBMECBJJFIOGYGHBXCUCVBDJOCYBZDZAJEXAXEPFRFOGVHQAOJLCYBOHFEKJFIJBDHDDCEAAUJVDRIGGGGCJOFVECAHAQFSBSGYJVGKCQDDHPGUCIARFAIEJGGDITAUDIIVBBJUEFCIDTGJGYJODRDEJPBMFNCXAKCPAIGOJQGHBZHQJUCOBKCKDPJSGGCVCAIWFVHIIEAJJMEFGRHZDEDACFBQJODGDVJBAUBXGKGCFZERAHIOALGKGAILDNHQGGAZDEIGATBTCWHMDKGSIWFMHAIZHREBJBEFENDFBRBLGLCMERJAEOBXCNDBHVCSJBDMEHCLJLCFFOGVGWATBOJBFJEQETHGESEXFDIIFDAGJPDNHEDSFNBRIVFMFPGOEEIHEFCOCKJGJAIZJIFTIGAWITGWDXGBEFDTJHFXBF
\ No newline at end of file
diff --git a/docs/rtc.md b/docs/rtc.md
new file mode 100644
index 0000000..5cb3ede
--- /dev/null
+++ b/docs/rtc.md
@@ -0,0 +1,83 @@
+很久以前,人类以为只有神仙可以听到、看到千里之外的声音和景象,称之为千里眼和顺风耳,短短几百年里,人类的技术革命实现了质的飞跃。
+
+1876 年,贝尔电话的发明,使人类可以听到千里之外声音的梦想终于成真。
+
+此后,音视频技术不断发展。一方面,视频压缩技术从 H.261 到 H.264,再到现在的 H.265 及AV1,视频压缩率越来越高;音频压缩技术也从电话使用的 G.711、G.722 等窄带音频压缩技术,发展到现代的 AAC、OPUS 等宽带音频压缩技术。
+
+另一方面,从中国 3G 网络正式商用开始,移动网络也发生了翻天覆地的变化。从 3G 到 4G ,再到马上要落地的 5G,移动网络的带宽和质量越来越高,为音视频数据传输打下了坚实的基础。
+
+尤其是 2011 年 Google 推出 WebRTC 技术后,大大降低了音视频技术的门槛,可以在浏览器上快速开发出各种音视频应用。
+
+如今,在疫情的三年里,视频会议,远程会诊,线上教学等需求将RTC技术推向高潮,成为影响社会发展不可或缺的技术之一。
+
+2023年,从用3W法学习解构RTC开始,笔者也开启了RTC分享之路。
+
+1.什么是RTC?
+RTC是Real-Time Communication的缩写,译为实时通信,目的是在设备端实时的转发音视频多媒体数据,让用户能实时的进行音频和视频的会话,即基于 IP 技术实现的实时交互的音视频通信技术。
+
+具体涵义如下:
+
+▪ 实时:音视频数据传输的延迟要达到“实时”的标准,也就是说延时要小于400ms,能够实现低延时和无卡顿,在正常通信过程中基本感受不到延迟的存在。
+
+▪ 音视频:音视频数据传输,实时音视频通信通过服务端为中转节点,即时采集、渲染、处理、传输终端用户的图像、视频、音频数据进行,实现音视频流数据在终端节点间完成通信的过程。
+
+▪ 实时音视频服务商一般以SDK的形式提供一整套解决方案。
+
+2.为什么选择RTC技术?
+痛点:
+
+基础音视频流程复杂且广泛:涵盖音视频收集、音视频压缩/解码、数据传输、终端适配、视频分发等系列环节,每个环节展开,都是复杂技术点。企业若想打造自主实时音视频方案,不仅要养一定规模软硬研发团队,还要花费一定时间沉淀,对于该企业来说,成本太高。
+
+RTC技术优势:
+
+高音质
+基于专有回声消除&降噪技术,可在嘈杂的环境下实现高音质通话,让对话里语音听得比较清晰,没有回声、啸叫的状况出现。
+
+高画质
+视频支持超高清晰度画面,一路视频提供多种分辨率,大屏幕可订阅更高分辨率提升视频通话体验,分分钟感受面对面交流感。
+
+低延迟
+全球通信节点支持,支持实时性更好的UDP协议,端到端延时低
+
+抗弱网
+自动增益控制&弱网丢包补偿技术 ,在丢包下保持音视频通话流畅。
+
+当然,基于一些特定行业的应用场景,比如多人数直播时的高并发,医疗行业的网闸透传,成熟RTC服务商都有着良好的技术沉淀,让越来越多的企业使用这项技术。
+
+3.RTC有哪些使用场景?
+随着移动互联网的普及和智能终端设备的广泛应用,实时音视频正逐渐成为主流互动方式,已在在线教育、社交娱乐、互动电商等热门领域得到广泛应用,也赋能于更多创新场景,如金融、政企服务、loT、医疗等,帮助人们享受更便捷和更人性化的生活服务。
+
+协同办公-视频会议
+丰富的会议场景,轻松实现远程办公系统,打通团队沟通渠道,帮助企业充分挖掘和整合隐形资源。
+
+典型应用:Zoom,腾讯会议
+
+社交沟通-聊天室
+支持 1v1 通话或群聊功能,频道内用户可自由发言,适用于语音通话、语音群聊、语音聊天室等场景。
+
+典型应用:微信语音通话,YY语音
+
+游戏&娱乐
+玩家可通过语音/视频聊天推进游戏进程,团战作战、协同作战,及时分享游戏信息,一起连麦开黑,拉近玩家距离。
+
+典型应用:网易游戏,虎牙直播
+
+电商直播
+通过IM+音视频拓展多样化电商直播玩法,增强购物体验,提升获客率,让购物更有趣,促进电商平台交易转化,实现全球购物零距离。
+
+典型应用:淘宝直播
+
+在线教育
+视频面对面教学,真实还原线下教学场景,支持1V1教学、1对多教学、双师课堂等多种互动教学模式。
+
+典型应用:小鹅通
+
+远程医疗
+基于IM及实时音视频RTC,通过实施互动技术,实现优质医疗资源和知识共享,满足远程会诊、手术示教多种场景需求。
+
+典型应用:微医
+
+视频双录
+根据金融监管要求,为客户提供多场景的双录服务,提供柜面双录、远程双录、移动双录、AI自助双录,帮助金融机构实现业务回溯。
+
+典型应用:招商银行app
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index d3b1568..7841d8d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -244,16 +244,33 @@
         </dependency>
 
         <!-- Elasticsearch -->
+<!--        <dependency>-->
+<!--            <groupId>org.elasticsearch.client</groupId>-->
+<!--            <artifactId>elasticsearch-rest-high-level-client</artifactId>-->
+<!--            <version>7.17.9</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>org.elasticsearch</groupId>-->
+<!--            <artifactId>elasticsearch</artifactId>-->
+<!--            <version>7.17.9</version>-->
+<!--        </dependency>-->
+
         <dependency>
             <groupId>org.elasticsearch.client</groupId>
             <artifactId>elasticsearch-rest-high-level-client</artifactId>
-            <version>7.17.9</version>
+            <version>7.14.0</version>
         </dependency>
         <dependency>
             <groupId>org.elasticsearch</groupId>
             <artifactId>elasticsearch</artifactId>
-            <version>7.17.9</version>
+            <version>7.14.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.elasticsearch.client</groupId>
+            <artifactId>elasticsearch-rest-client</artifactId>
+            <version>7.14.0</version>
+        </dependency>
+
 
     </dependencies>
 
diff --git a/src/main/java/com/guwan/backend/client/Go2RTCClient.java b/src/main/java/com/guwan/backend/client/Go2RTCClient.java
new file mode 100644
index 0000000..eaf09ed
--- /dev/null
+++ b/src/main/java/com/guwan/backend/client/Go2RTCClient.java
@@ -0,0 +1,84 @@
+package com.guwan.backend.client;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class Go2RTCClient {
+
+    private final RestTemplate restTemplate;
+
+    @Value("${go2rtc.api.url}")
+    private String apiUrl;
+
+    /**
+     * 创建流
+     */
+    public void createStream(String streamId, String sourceUrl) {
+        String url = apiUrl + "/api/streams/" + streamId;
+        StreamConfig config = new StreamConfig(sourceUrl);
+
+        try {
+            restTemplate.postForEntity(url, config, String.class);
+        } catch (Exception e) {
+            log.error("创建流失败: {}", e.getMessage());
+            throw new RuntimeException("创建流失败", e);
+        }
+    }
+
+    /**
+     * 删除流
+     */
+    public void deleteStream(String streamId) {
+        String url = apiUrl + "/api/streams/" + streamId;
+
+        try {
+            restTemplate.delete(url);
+        } catch (Exception e) {
+            log.error("删除流失败: {}", e.getMessage());
+            throw new RuntimeException("删除流失败", e);
+        }
+    }
+
+    /**
+     * 获取WebRTC Offer
+     */
+    public String getOffer(String streamId, String sdp) {
+        String url = apiUrl + "/api/stream/" + streamId + "/webrtc";
+        WebRTCRequest request = new WebRTCRequest(sdp);
+
+        try {
+            ResponseEntity<WebRTCResponse> response =
+                restTemplate.postForEntity(url, request, WebRTCResponse.class);
+            return response.getBody().getSdp();
+        } catch (Exception e) {
+            log.error("获取WebRTC Offer失败: {}", e.getMessage());
+            throw new RuntimeException("获取WebRTC Offer失败", e);
+        }
+    }
+
+    @Data
+    @AllArgsConstructor
+    static class StreamConfig {
+        private String input;
+    }
+
+    @Data
+    @AllArgsConstructor
+    static class WebRTCRequest {
+        private String sdp;
+    }
+
+    @Data
+    static class WebRTCResponse {
+        private String sdp;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/config/EasyEsConfig.java b/src/main/java/com/guwan/backend/config/EasyEsConfig.java
index f63ad93..37ab97d 100644
--- a/src/main/java/com/guwan/backend/config/EasyEsConfig.java
+++ b/src/main/java/com/guwan/backend/config/EasyEsConfig.java
@@ -1,9 +1,19 @@
 package com.guwan.backend.config;
 
+import cn.easyes.starter.factory.IndexStrategyFactory;
 import cn.easyes.starter.register.EsMapperScan;
+import cn.easyes.starter.config.EasyEsConfigProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
 @Configuration
 @EsMapperScan("com.guwan.backend.es.mapper")
+@EnableConfigurationProperties(EasyEsConfigProperties.class)
 public class EasyEsConfig {
+    
+    @Bean
+    public IndexStrategyFactory indexStrategyFactory() {
+        return new IndexStrategyFactory();
+    }
 } 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/config/ElasticsearchConfig.java b/src/main/java/com/guwan/backend/config/ElasticsearchConfig.java
index 12d1e32..dd0f699 100644
--- a/src/main/java/com/guwan/backend/config/ElasticsearchConfig.java
+++ b/src/main/java/com/guwan/backend/config/ElasticsearchConfig.java
@@ -15,12 +15,6 @@ public class ElasticsearchConfig {
     @Value("${easy-es.address}")
     private String address;
 
-    @Value("${easy-es.username:}")
-    private String username;
-
-    @Value("${easy-es.password:}")
-    private String password;
-
     @Bean
     public RestHighLevelClient restHighLevelClient() {
         String[] parts = address.split(":");
diff --git a/src/main/java/com/guwan/backend/config/RestTemplateConfig.java b/src/main/java/com/guwan/backend/config/RestTemplateConfig.java
new file mode 100644
index 0000000..e2399a2
--- /dev/null
+++ b/src/main/java/com/guwan/backend/config/RestTemplateConfig.java
@@ -0,0 +1,19 @@
+package com.guwan.backend.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import java.time.Duration;
+
+@Configuration
+public class RestTemplateConfig {
+    
+    @Bean
+    public RestTemplate restTemplate(RestTemplateBuilder builder) {
+        return builder
+            .setConnectTimeout(Duration.ofSeconds(10))
+            .setReadTimeout(Duration.ofSeconds(30))
+            .build();
+    }
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/constant/SecurityConstants.java b/src/main/java/com/guwan/backend/constant/SecurityConstants.java
index 108c2be..8bd8738 100644
--- a/src/main/java/com/guwan/backend/constant/SecurityConstants.java
+++ b/src/main/java/com/guwan/backend/constant/SecurityConstants.java
@@ -13,6 +13,7 @@ public class SecurityConstants {
      */
     public static final List<String> WHITE_LIST = List.of(
         "/demo/**",              // 测试接口
+            "/api/products",
         "/api/user/register",    // 用户注册
         "/api/user/login",       // 用户登录
         "/api/user/getEmailCode",  // 获取邮箱验证码
diff --git a/src/main/java/com/guwan/backend/controller/DemoController.java b/src/main/java/com/guwan/backend/controller/DemoController.java
index d725b0d..adbe1af 100644
--- a/src/main/java/com/guwan/backend/controller/DemoController.java
+++ b/src/main/java/com/guwan/backend/controller/DemoController.java
@@ -26,6 +26,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
+import java.util.Arrays;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -51,15 +52,15 @@ public class DemoController {
                 (bucketName, minioUtil.uploadFile(bucketName, file))));
     }
 
-
+    @GetMapping("demo111")
     public int saveTenPerson() {
 
         try {
 
            try {
                GetObjectArgs args = GetObjectArgs.builder()
-                            .bucket("images")
-                            .object("test/webwxgetmsgimg.jpg")
+                            .bucket("videos")
+                            .object("James Gosling.jpg")
                             .build();
 
                     //判断人脸照片是否合格
@@ -86,7 +87,7 @@ public class DemoController {
                         faceRecognitionResDTO.setRect(faceInfo.getRect());
                         byte[] featureBytes = faceEngineService.extractFaceFeature(rgbData, faceInfo, ExtractType.REGISTER);
                         if (featureBytes != null) {
-                            System.out.println("featureBytes = " + featureBytes);
+                            System.out.println("featureBytes = " + Arrays.toString(featureBytes));
                         }else{
                             log.error("图片不合格,未检测到人脸");
                             return 2;
diff --git a/src/main/java/com/guwan/backend/controller/LiveStreamController.java b/src/main/java/com/guwan/backend/controller/LiveStreamController.java
new file mode 100644
index 0000000..62b81c6
--- /dev/null
+++ b/src/main/java/com/guwan/backend/controller/LiveStreamController.java
@@ -0,0 +1,80 @@
+package com.guwan.backend.controller;
+
+import com.guwan.backend.common.Result;
+import com.guwan.backend.dto.live.CreateRoomRequest;
+import com.guwan.backend.dto.live.StartLiveRequest;
+import com.guwan.backend.dto.live.WebRTCRequest;
+import com.guwan.backend.dto.live.WebRTCResponse;
+import com.guwan.backend.entity.LiveRoom;
+import com.guwan.backend.service.LiveStreamService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+@Slf4j
+@Tag(name = "直播管理", description = "直播相关接口")
+@RestController
+@RequestMapping("/api/live")
+@RequiredArgsConstructor
+public class LiveStreamController {
+    
+    private final LiveStreamService liveStreamService;
+    
+    @Operation(summary = "创建直播间")
+    @PostMapping("/room")
+    public Result<LiveRoom> createLiveRoom(@RequestBody CreateRoomRequest request) {
+        try {
+            LiveRoom room = liveStreamService.createLiveRoom(
+                request.getTitle(),
+                request.getDescription(),
+                request.getUserId()
+            );
+            return Result.success(room);
+        } catch (Exception e) {
+            log.error("创建直播间失败", e);
+            return Result.error(e.getMessage());
+        }
+    }
+    
+    @Operation(summary = "开始直播")
+    @PostMapping("/room/{id}/start")
+    public Result<Void> startLive(
+            @PathVariable Long id,
+            @RequestBody StartLiveRequest request) {
+        try {
+            liveStreamService.startLive(id, request.getSourceUrl());
+            return Result.success();
+        } catch (Exception e) {
+            log.error("开始直播失败", e);
+            return Result.error(e.getMessage());
+        }
+    }
+    
+    @Operation(summary = "结束直播")
+    @PostMapping("/room/{id}/end")
+    public Result<Void> endLive(@PathVariable Long id) {
+        try {
+            liveStreamService.endLive(id);
+            return Result.success();
+        } catch (Exception e) {
+            log.error("结束直播失败", e);
+            return Result.error(e.getMessage());
+        }
+    }
+    
+    @Operation(summary = "获取WebRTC Offer")
+    @PostMapping("/room/{id}/webrtc")
+    public Result<WebRTCResponse> getWebRTCOffer(
+            @PathVariable Long id,
+            @RequestBody WebRTCRequest request) {
+        try {
+            String sdp = liveStreamService.getWebRTCOffer(id, request.getSdp());
+            return Result.success(new WebRTCResponse(sdp));
+        } catch (Exception e) {
+            log.error("获取WebRTC Offer失败", e);
+            return Result.error(e.getMessage());
+        }
+    }
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/controller/ProductController.java b/src/main/java/com/guwan/backend/controller/ProductController.java
new file mode 100644
index 0000000..ed5c39e
--- /dev/null
+++ b/src/main/java/com/guwan/backend/controller/ProductController.java
@@ -0,0 +1,63 @@
+package com.guwan.backend.controller;
+
+import com.guwan.backend.common.Result;
+import com.guwan.backend.dto.product.ProductDTO;
+import com.guwan.backend.service.ProductSearchService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import java.util.List;
+
+@Slf4j
+@Tag(name = "商品搜索", description = "商品搜索相关接口")
+@RestController
+@RequestMapping("/api/products")
+@RequiredArgsConstructor
+public class ProductController {
+
+    @Autowired(required = false)
+    private ProductSearchService productSearchService;
+
+    @Operation(summary = "保存商品")
+    @PostMapping
+    public Result<ProductDTO> save(@RequestBody ProductDTO product) {
+        try {
+            if (productSearchService == null) {
+                return Result.error("搜索服务未启用");
+            }
+            productSearchService.saveOrUpdate(product);
+            return Result.success(product);
+        } catch (Exception e) {
+            log.error("保存商品失败", e);
+            return Result.error(e.getMessage());
+        }
+    }
+
+    @Operation(summary = "搜索商品")
+    @GetMapping("/search")
+    public Result<List<ProductDTO>> search(
+            @Parameter(description = "搜索关键词") @RequestParam String keyword) {
+        try {
+            return Result.success(productSearchService.search(keyword));
+        } catch (Exception e) {
+            log.error("搜索商品失败", e);
+            return Result.error(e.getMessage());
+        }
+    }
+
+    @Operation(summary = "按分类查询商品")
+    @GetMapping("/category/{category}")
+    public Result<List<ProductDTO>> getByCategory(
+            @Parameter(description = "商品分类") @PathVariable String category) {
+        try {
+            return Result.success(productSearchService.getByCategory(category));
+        } catch (Exception e) {
+            log.error("查询商品分类失败", e);
+            return Result.error(e.getMessage());
+        }
+    }
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/controller/VideoController.java b/src/main/java/com/guwan/backend/controller/VideoController.java
index a1c169b..7e4b136 100644
--- a/src/main/java/com/guwan/backend/controller/VideoController.java
+++ b/src/main/java/com/guwan/backend/controller/VideoController.java
@@ -3,6 +3,7 @@ package com.guwan.backend.controller;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.guwan.backend.common.Result;
 import com.guwan.backend.dto.video.VideoDTO;
+import com.guwan.backend.dto.video.VideoUploadDTO;
 import com.guwan.backend.service.VideoService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -26,13 +27,10 @@ public class VideoController {
     @Operation(summary = "上传视频", description = "上传视频文件并返回视频信息")
   //  @SecurityRequirement(name = "bearer-jwt")
     @PostMapping("/upload")
-    public Result<VideoDTO> uploadVideo(
-            @Parameter(description = "视频文件") @RequestParam("fileUrl") String fileUrl,
-            @Parameter(description = "视频标题") @RequestParam("title") String title,
-            @Parameter(description = "视频描述") @RequestParam("description") String description,
-            @Parameter(description = "视频标签,多个用逗号分隔") @RequestParam(value = "tags", required = false) String tags) {
+    public Result<VideoDTO> uploadVideo(@RequestBody VideoUploadDTO videoUploadDTO) {
         try {
-            VideoDTO video = videoService.uploadVideo(fileUrl, title, description, tags);
+            VideoDTO video = videoService.uploadVideo(videoUploadDTO.getFileUrl(),
+                    videoUploadDTO.getTitle(), videoUploadDTO.getDescription(), videoUploadDTO.getTags());
             return Result.success(video);
         } catch (Exception e) {
             log.error("上传视频失败", e);
diff --git a/src/main/java/com/guwan/backend/dto/live/CreateRoomRequest.java b/src/main/java/com/guwan/backend/dto/live/CreateRoomRequest.java
new file mode 100644
index 0000000..7b75e50
--- /dev/null
+++ b/src/main/java/com/guwan/backend/dto/live/CreateRoomRequest.java
@@ -0,0 +1,18 @@
+package com.guwan.backend.dto.live;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "创建直播间请求")
+public class CreateRoomRequest {
+    
+    @Schema(description = "直播间标题")
+    private String title;
+    
+    @Schema(description = "直播间描述")
+    private String description;
+    
+    @Schema(description = "主播用户ID")
+    private Long userId;
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/dto/live/StartLiveRequest.java b/src/main/java/com/guwan/backend/dto/live/StartLiveRequest.java
new file mode 100644
index 0000000..4c6911c
--- /dev/null
+++ b/src/main/java/com/guwan/backend/dto/live/StartLiveRequest.java
@@ -0,0 +1,12 @@
+package com.guwan.backend.dto.live;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "开始直播请求")
+public class StartLiveRequest {
+    
+    @Schema(description = "推流地址(RTMP/RTSP)")
+    private String sourceUrl;
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/dto/live/WebRTCRequest.java b/src/main/java/com/guwan/backend/dto/live/WebRTCRequest.java
new file mode 100644
index 0000000..a8dc97d
--- /dev/null
+++ b/src/main/java/com/guwan/backend/dto/live/WebRTCRequest.java
@@ -0,0 +1,12 @@
+package com.guwan.backend.dto.live;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "WebRTC请求")
+public class WebRTCRequest {
+    
+    @Schema(description = "SDP offer")
+    private String sdp;
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/dto/live/WebRTCResponse.java b/src/main/java/com/guwan/backend/dto/live/WebRTCResponse.java
new file mode 100644
index 0000000..5450242
--- /dev/null
+++ b/src/main/java/com/guwan/backend/dto/live/WebRTCResponse.java
@@ -0,0 +1,14 @@
+package com.guwan.backend.dto.live;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+@Schema(description = "WebRTC响应")
+public class WebRTCResponse {
+    
+    @Schema(description = "SDP answer")
+    private String sdp;
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/dto/product/ProductDTO.java b/src/main/java/com/guwan/backend/dto/product/ProductDTO.java
new file mode 100644
index 0000000..2d1e128
--- /dev/null
+++ b/src/main/java/com/guwan/backend/dto/product/ProductDTO.java
@@ -0,0 +1,30 @@
+package com.guwan.backend.dto.product;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import java.time.LocalDateTime;
+
+@Data
+@Schema(description = "商品信息DTO")
+public class ProductDTO {
+    @Schema(description = "商品ID")
+    private String id;
+    
+    @Schema(description = "商品名称")
+    private String name;
+    
+    @Schema(description = "商品分类")
+    private String category;
+    
+    @Schema(description = "商品价格")
+    private Double price;
+    
+    @Schema(description = "库存数量")
+    private Integer stock;
+    
+    @Schema(description = "商品描述")
+    private String description;
+    
+    @Schema(description = "创建时间")
+    private LocalDateTime createdTime;
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/dto/video/VideoUploadDTO.java b/src/main/java/com/guwan/backend/dto/video/VideoUploadDTO.java
new file mode 100644
index 0000000..aee773f
--- /dev/null
+++ b/src/main/java/com/guwan/backend/dto/video/VideoUploadDTO.java
@@ -0,0 +1,19 @@
+package com.guwan.backend.dto.video;
+
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@Schema(description = "视频上传DTO")
+@Data
+public class VideoUploadDTO {
+    @Schema(description = "视频文件地址")
+    String fileUrl;
+    @Schema(description = "视频标题")
+    String title;
+    @Schema(description = "视频描述")
+    String description;
+    @Schema(description = "视频标签,多个用逗号分隔", nullable = true)
+    String tags;
+}
diff --git a/src/main/java/com/guwan/backend/entity/LiveRoom.java b/src/main/java/com/guwan/backend/entity/LiveRoom.java
index 8403d00..76edb52 100644
--- a/src/main/java/com/guwan/backend/entity/LiveRoom.java
+++ b/src/main/java/com/guwan/backend/entity/LiveRoom.java
@@ -16,10 +16,7 @@ public class LiveRoom {
     private String coverUrl;        // 封面图
     private Long userId;           // 主播ID
     private String username;       // 主播名称
-    private String streamKey;      // 推流密钥
-    private String rtmpUrl;        // RTMP推流地址
-    private String hlsUrl;         // HLS播放地址
-    private String replayUrl;      // 回放地址
+    private String streamId;       // Go2RTC流ID
     private String status;         // 状态:PREPARING-准备中,LIVING-直播中,ENDED-已结束
     private Integer onlineCount;   // 在线人数
     private Integer likeCount;     // 点赞数
diff --git a/src/main/java/com/guwan/backend/es/document/ProductDocument.java b/src/main/java/com/guwan/backend/es/document/ProductDocument.java
new file mode 100644
index 0000000..1e5d6b2
--- /dev/null
+++ b/src/main/java/com/guwan/backend/es/document/ProductDocument.java
@@ -0,0 +1,34 @@
+package com.guwan.backend.es.document;
+
+import cn.easyes.annotation.IndexField;
+import cn.easyes.annotation.IndexId;
+import cn.easyes.annotation.IndexName;
+import cn.easyes.annotation.rely.FieldType;
+import lombok.Data;
+import java.time.LocalDateTime;
+
+@Data
+@IndexName("products")
+public class ProductDocument {
+    
+    @IndexId
+    private String id;
+    
+    @IndexField(fieldType = FieldType.TEXT, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
+    private String name;
+    
+    @IndexField(fieldType = FieldType.KEYWORD)
+    private String category;
+    
+    @IndexField(fieldType = FieldType.DOUBLE) 
+    private Double price;
+    
+    @IndexField(fieldType = FieldType.INTEGER)
+    private Integer stock;
+    
+    @IndexField(fieldType = FieldType.TEXT, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
+    private String description;
+    
+    @IndexField(fieldType = FieldType.DATE)
+    private LocalDateTime createdTime;
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/es/mapper/ProductEsMapper.java b/src/main/java/com/guwan/backend/es/mapper/ProductEsMapper.java
new file mode 100644
index 0000000..1706cf1
--- /dev/null
+++ b/src/main/java/com/guwan/backend/es/mapper/ProductEsMapper.java
@@ -0,0 +1,9 @@
+package com.guwan.backend.es.mapper;
+
+import cn.easyes.core.conditions.interfaces.BaseEsMapper;
+import com.guwan.backend.es.document.ProductDocument;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ProductEsMapper extends BaseEsMapper<ProductDocument> {
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/service/LiveStreamService.java b/src/main/java/com/guwan/backend/service/LiveStreamService.java
new file mode 100644
index 0000000..067d0cb
--- /dev/null
+++ b/src/main/java/com/guwan/backend/service/LiveStreamService.java
@@ -0,0 +1,88 @@
+package com.guwan.backend.service;
+
+import com.guwan.backend.client.Go2RTCClient;
+import com.guwan.backend.entity.LiveRoom;
+import com.guwan.backend.mapper.LiveRoomMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.UUID;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class LiveStreamService {
+    
+    private final Go2RTCClient go2rtcClient;
+    private final LiveRoomMapper liveRoomMapper;
+    
+    /**
+     * 创建直播间
+     */
+    @Transactional
+    public LiveRoom createLiveRoom(String title, String description, Long userId) {
+        // 生成streamId
+        String streamId = UUID.randomUUID().toString();
+        
+        // 创建直播间记录
+        LiveRoom room = new LiveRoom();
+        room.setTitle(title);
+        room.setDescription(description);
+        room.setUserId(userId);
+        room.setStreamId(streamId);
+        room.setStatus("PREPARING");
+        
+        liveRoomMapper.insert(room);
+        return room;
+    }
+    
+    /**
+     * 开始直播
+     */
+    @Transactional
+    public void startLive(Long roomId, String sourceUrl) {
+        LiveRoom room = liveRoomMapper.selectById(roomId);
+        if (room == null) {
+            throw new IllegalArgumentException("直播间不存在");
+        }
+        
+        // 创建Go2RTC流
+        go2rtcClient.createStream(room.getStreamId(), sourceUrl);
+        
+        // 更新状态
+        room.setStatus("LIVING");
+        liveRoomMapper.updateById(room);
+    }
+    
+    /**
+     * 结束直播
+     */
+    @Transactional
+    public void endLive(Long roomId) {
+        LiveRoom room = liveRoomMapper.selectById(roomId);
+        if (room == null) {
+            throw new IllegalArgumentException("直播间不存在");
+        }
+        
+        // 删除Go2RTC流
+        go2rtcClient.deleteStream(room.getStreamId());
+        
+        // 更新状态
+        room.setStatus("ENDED");
+        liveRoomMapper.updateById(room);
+    }
+    
+    /**
+     * 获取WebRTC Offer
+     */
+    public String getWebRTCOffer(Long roomId, String sdp) {
+        LiveRoom room = liveRoomMapper.selectById(roomId);
+        if (room == null) {
+            throw new IllegalArgumentException("直播间不存在");
+        }
+        
+        return go2rtcClient.getOffer(room.getStreamId(), sdp);
+    }
+} 
\ No newline at end of file
diff --git a/src/main/java/com/guwan/backend/service/ProductSearchService.java b/src/main/java/com/guwan/backend/service/ProductSearchService.java
new file mode 100644
index 0000000..ca1a9c4
--- /dev/null
+++ b/src/main/java/com/guwan/backend/service/ProductSearchService.java
@@ -0,0 +1,81 @@
+package com.guwan.backend.service;
+
+import cn.easyes.core.conditions.LambdaEsQueryWrapper;
+import com.guwan.backend.dto.product.ProductDTO;
+import com.guwan.backend.es.document.ProductDocument;
+import com.guwan.backend.es.mapper.ProductEsMapper;
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Service;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import lombok.SneakyThrows;
+
+@Slf4j
+@Service
+@ConditionalOnProperty(name = "easy-es.enable", havingValue = "true")
+@RequiredArgsConstructor
+public class ProductSearchService {
+
+    private final ProductEsMapper productEsMapper;
+
+    public void saveOrUpdate(ProductDTO productDTO) {
+        ProductDocument document = convertToDocument(productDTO);
+        productEsMapper.insert(document);
+    }
+
+    public void delete(Long id) {
+        productEsMapper.deleteById(id);
+    }
+
+    public List<ProductDTO> search(String keyword) {
+        LambdaEsQueryWrapper<ProductDocument> wrapper = new LambdaEsQueryWrapper<>();
+        wrapper.and(w -> w
+            .match(ProductDocument::getName, keyword)
+            .or()
+            .match(ProductDocument::getDescription, keyword)
+        );
+        
+        List<ProductDocument> documents = productEsMapper.selectList(wrapper);
+        return documents.stream()
+                       .map(this::convertToDTO)
+                       .collect(Collectors.toList());
+    }
+
+    public List<ProductDTO> getByCategory(String category) {
+        LambdaEsQueryWrapper<ProductDocument> wrapper = new LambdaEsQueryWrapper<>();
+        wrapper.eq(ProductDocument::getCategory, category);
+        
+        List<ProductDocument> documents = productEsMapper.selectList(wrapper);
+        return documents.stream()
+                       .map(this::convertToDTO)
+                       .collect(Collectors.toList());
+    }
+
+    private ProductDocument convertToDocument(ProductDTO dto) {
+        ProductDocument document = new ProductDocument();
+        BeanUtils.copyProperties(dto, document);
+        return document;
+    }
+
+    private ProductDTO convertToDTO(ProductDocument document) {
+        ProductDTO dto = new ProductDTO();
+        BeanUtils.copyProperties(document, dto);
+        return dto;
+    }
+
+    @PostConstruct
+    public void init() {
+        log.info("ProductSearchService initialized with ES enabled");
+    }
+
+    @SneakyThrows
+    public void handleError(String operation, Exception e) {
+        log.error("ES {} operation failed", operation, e);
+        throw new RuntimeException("搜索服务暂时不可用");
+    }
+} 
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 11b9daf..41f3dd0 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -15,13 +15,13 @@ spring:
     driver-class-name: com.mysql.cj.jdbc.Driver
     url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
     username: root
-    password: root
+    password: 123456
     
   # Redis配置
   data:
     redis:
       host: localhost
-      port: 6379
+      port: 6380
       password: 123456 # 如果有密码,请设置
       database: 8
       timeout: 10000
@@ -117,10 +117,10 @@ springdoc:
 config:
   arcface-sdk:
     version: 4.1
-    app-id: BYYPcPa3qQaAA88HZw7awne1BqZiePgT6axtALtK2qun
-    sdk-key: 3eFAwSCMQRhoUoAaZ2Li9XUVDUubAWYksQtNPWD32UrX
-    active-key: 82K1-11TQ-W11B-H7MU
-    active-file: ArcFacePro64.dat
+    app-id: 5nPWymNAibvWTq6XPypUWxroyzjMScZ9RwVkDjCFgK32
+    sdk-key: 7dsPvanADtYAP1TiiiFjTsms2mAU85m5duVwHChhumyV
+    active-key: 86C1-11T1-K131-FJQU
+    active-file: 86C111T1K131FJQU.dat
     detect-pool-size: 16
     compare-pool-size: 16
     rec-face-thd: 0.8
@@ -132,10 +132,8 @@ srs:
     url: http://localhost:1985  # SRS HTTP API地址
 
 easy-es:
-  enable: false  # 改为false禁用Easy-Es
-  address: localhost:9200  # ES地址
-  username: ${ES_USERNAME:}  # ES用户名,可选
-  password: ${ES_PASSWORD:}  # ES密码,可选
+  enable: true
+  address: localhost:9200
   global-config:
     process-index-mode: manual
     print-dsl: true
@@ -143,7 +141,12 @@ easy-es:
     response-log: true
     db-config:
       map-underscore-to-camel-case: true
-      index-prefix: video_  # 索引前缀
+      index-prefix: product_
+    async-process: true
+    schema-update: true
+    max-connect-num: 50
+    connect-timeout: 5000
+    socket-timeout: 60000
 
 netty:
   danmaku:
@@ -155,4 +158,8 @@ netty:
   heartbeat:
     interval: 30
   cluster:
-    nodes: localhost:8088,localhost:8089
\ No newline at end of file
+    nodes: localhost:8088,localhost:8089
+
+go2rtc:
+  api:
+    url: http://localhost:1984  # Go2RTC API地址
\ No newline at end of file
diff --git a/src/main/resources/db/migration/V9__alter_live_room_add_stream_id.sql b/src/main/resources/db/migration/V9__alter_live_room_add_stream_id.sql
new file mode 100644
index 0000000..65b5a64
--- /dev/null
+++ b/src/main/resources/db/migration/V9__alter_live_room_add_stream_id.sql
@@ -0,0 +1,6 @@
+ALTER TABLE `live_room`
+ADD COLUMN `stream_id` varchar(50) NOT NULL COMMENT 'Go2RTC流ID' AFTER `username`,
+DROP COLUMN `stream_key`,
+DROP COLUMN `rtmp_url`,
+DROP COLUMN `hls_url`,
+DROP COLUMN `replay_url`; 
\ No newline at end of file