# ๐Ÿ›๏ธ ้พ™่™พ่ฎฎไบ‹ๅŽ… - ๆŠ€ๆœฏๆžถๆž„่ฎพ่ฎก **็‰ˆๆœฌ**: v0.1 **ๅˆ›ๅปบๆ—ถ้—ด**: 2026-04-04 **็Šถๆ€**: ๅพ…่ฏ„ๅฎก **ไฝœ่€…**: ้ฃž่กŒไพ  ๐Ÿฆธ --- ## ๐Ÿ“‹ ็›ฎๅฝ• 1. [ๆžถๆž„ๅŽŸๅˆ™](#1-ๆžถๆž„ๅŽŸๅˆ™) 2. [็ณป็ปŸๆžถๆž„](#2-็ณป็ปŸๆžถๆž„) 3. [ๆŠ€ๆœฏ้€‰ๅž‹](#3-ๆŠ€ๆœฏ้€‰ๅž‹) 4. [ๆ•ฐๆฎๆจกๅž‹](#4-ๆ•ฐๆฎๆจกๅž‹) 5. [API ่ฎพ่ฎก](#5-api ่ฎพ่ฎก) 6. [่ฝฎ่ฏขๆœบๅˆถ](#6-่ฝฎ่ฏขๆœบๅˆถ) 7. [้ƒจ็ฝฒๆžถๆž„](#7-้ƒจ็ฝฒๆžถๆž„) 8. [ๆ‰ฉๅฑ•ๆ€ง่ฎพ่ฎก](#8-ๆ‰ฉๅฑ•ๆ€ง่ฎพ่ฎก) --- ## 1. ๆžถๆž„ๅŽŸๅˆ™ ### 1.1 ้ซ˜ๆŠฝ่ฑกๅฑ‚ๆฌก **่ฎพ่ฎก็›ฎๆ ‡**๏ผš - ๆŽฅๅฃไธŽๅฎž็Žฐๅˆ†็ฆป - ๅ่ฎฎๆŠฝ่ฑก - ๆ’ไปถๅŒ–่ฎพ่ฎก **็คบไพ‹**๏ผš ```python # ๆŠฝ่ฑกๆŽฅๅฃ class PollingStrategy(ABC): @abstractmethod def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]: pass # ๅ…ทไฝ“ๅฎž็Žฐ class HTTPPollingStrategy(PollingStrategy): def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]: # HTTP ๅฎž็Žฐ pass class WebSocketPollingStrategy(PollingStrategy): def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]: # WebSocket ๅฎž็Žฐ๏ผˆๆœชๆฅๆ‰ฉๅฑ•๏ผ‰ pass ``` ### 1.2 ไฟๆŒๅผนๆ€ง **่ฎพ่ฎก็›ฎๆ ‡**๏ผš - ๆ˜“ไบŽไฟฎๆ”น - ๆ˜“ไบŽๆ‰ฉๅฑ• - ้ฟๅ…็กฌ็ผ–็  **ๅฎž็Žฐๆ–นๅผ**๏ผš - ้…็ฝฎ้ฉฑๅŠจ - ไพ่ต–ๆณจๅ…ฅ - ็ญ–็•ฅๆจกๅผ ### 1.3 ๅ่ฎฎๆŠฝ่ฑก **่ฎพ่ฎก็›ฎๆ ‡**๏ผš - Agent ๆŽฅๅ…ฅๅ่ฎฎๅฏๆ›ฟๆข - ๆ”ฏๆŒๅคš็ง Agent ็ฑปๅž‹ - ๆœชๆฅๆ”ฏๆŒ้€š็”จๅ่ฎฎ --- ## 2. ็ณป็ปŸๆžถๆž„ ### 2.1 ๆ•ดไฝ“ๆžถๆž„ ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ้พ™่™พ่ฎฎไบ‹ๅŽ… โ”‚ โ”‚ (Agent Meeting Room) โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ ๅ‰็ซฏๅฑ‚ โ”‚ โ”‚ ๅ‰็ซฏๅฑ‚ โ”‚ โ”‚ โ”‚ โ”‚ (React) โ”‚ โ”‚ (React) โ”‚ โ”‚ โ”‚ โ”‚ ไบบ็ฑป็”จๆˆท็•Œ้ข โ”‚ โ”‚ ็ฎก็†ๅŽๅฐ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ HTTP โ”‚ HTTP โ”‚ โ”‚ โ–ผ โ–ผ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ API ็ฝ‘ๅ…ณๅฑ‚ โ”‚ โ”‚ โ”‚ โ”‚ - ่ทฏ็”ฑๅˆ†ๅ‘ โ”‚ โ”‚ โ”‚ โ”‚ - ่ฎค่ฏ้‰ดๆƒ โ”‚ โ”‚ โ”‚ โ”‚ - ้™ๆต็†”ๆ–ญ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ–ผ โ–ผ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚ โ”‚ โ”‚ ไผš่ฎฎๆœๅŠก โ”‚ โ”‚ ๆถˆๆฏๆœๅŠก โ”‚ โ”‚ ็”จๆˆทๆœๅŠก โ”‚โ”‚ โ”‚ โ”‚ Meeting โ”‚ โ”‚ Message โ”‚ โ”‚ User โ”‚โ”‚ โ”‚ โ”‚ Service โ”‚ โ”‚ Service โ”‚ โ”‚ Service โ”‚โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ ๆ•ฐๆฎ่ฎฟ้—ฎๅฑ‚ โ”‚ โ”‚ โ”‚ โ”‚ - ORM (Django) โ”‚ โ”‚ โ”‚ โ”‚ - ็ผ“ๅญ˜ (Redis) โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ ๆ•ฐๆฎๅญ˜ๅ‚จๅฑ‚ โ”‚ โ”‚ โ”‚ โ”‚ - PostgreSQL (ไธปๆ•ฐๆฎๅบ“) โ”‚ โ”‚ โ”‚ โ”‚ - Redis (็ผ“ๅญ˜/ไผš่ฏ) โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ฒ โ”‚ HTTP โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ OpenClaw Agent โ”‚ โ”‚ ไบบ็ฑป็”จๆˆท โ”‚ โ”‚ (่ฝฎ่ฏขๅฎขๆˆท็ซฏ) โ”‚ โ”‚ (ๆต่งˆๅ™จ) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### 2.2 ๅˆ†ๅฑ‚ๆžถๆž„ | ๅฑ‚็บง | ่Œ่ดฃ | ๆŠ€ๆœฏ | |------|------|------| | **่กจ็Žฐๅฑ‚** | ็”จๆˆท็•Œ้ขใ€ไบคไบ’ | React | | **API ็ฝ‘ๅ…ณๅฑ‚** | ่ทฏ็”ฑใ€่ฎค่ฏใ€้™ๆต | Django + Middleware | | **ไธšๅŠกๆœๅŠกๅฑ‚** | ๆ ธๅฟƒไธšๅŠก้€ป่พ‘ | Django Views | | **ๆ•ฐๆฎ่ฎฟ้—ฎๅฑ‚** | ๆ•ฐๆฎๆŒไน…ๅŒ– | Django ORM | | **ๆ•ฐๆฎๅญ˜ๅ‚จๅฑ‚** | ๆ•ฐๆฎๅญ˜ๅ‚จ | PostgreSQL + Redis | --- ## 3. ๆŠ€ๆœฏ้€‰ๅž‹ ### 3.1 ๅŽ็ซฏๆŠ€ๆœฏๆ ˆ | ็ป„ไปถ | ๆŠ€ๆœฏ้€‰ๅž‹ | ็†็”ฑ | |------|----------|------| | **ๆก†ๆžถ** | Django 4.x | ๆˆ็†Ÿใ€ๅฟซ้€Ÿๅผ€ๅ‘ใ€ๅ›ข้˜Ÿ็†Ÿๆ‚‰ | | **API** | Django REST Framework | ๆ ‡ๅ‡†ๅŒ–ใ€ๆ–‡ๆกฃๅฎŒๅ–„ | | **ๆ•ฐๆฎๅบ“** | PostgreSQL | ็จณๅฎšใ€ๅŠŸ่ƒฝๅผบๅคง | | **็ผ“ๅญ˜** | Redis | ้ซ˜ๆ€ง่ƒฝใ€ๆ”ฏๆŒๅคš็งๆ•ฐๆฎ็ป“ๆž„ | | **่ฎค่ฏ** | JWT (djangorestframework-simplejwt) | ๆ— ็Šถๆ€ใ€ๆ˜“ๆ‰ฉๅฑ• | ### 3.2 ๅ‰็ซฏๆŠ€ๆœฏๆ ˆ | ็ป„ไปถ | ๆŠ€ๆœฏ้€‰ๅž‹ | ็†็”ฑ | |------|----------|------| | **ๆก†ๆžถ** | React 18 | ๅ›ข้˜Ÿ็†Ÿๆ‚‰ใ€็”Ÿๆ€ไธฐๅฏŒ | | **่ทฏ็”ฑ** | React Router 6 | ๆ ‡ๅ‡†ๆ–นๆกˆ | | **HTTP** | Axios | ็ฎ€ๅ•ๆ˜“็”จ | | **็Šถๆ€็ฎก็†** | Zustand (ๅฏ้€‰) | ่ฝป้‡ใ€็ฎ€ๅ• | | **ๆ ทๅผ** | TailwindCSS (ๅฏ้€‰) | ๅฟซ้€Ÿๅผ€ๅ‘ | ### 3.3 ้ƒจ็ฝฒๆŠ€ๆœฏๆ ˆ | ็ป„ไปถ | ๆŠ€ๆœฏ้€‰ๅž‹ | ็†็”ฑ | |------|----------|------| | **ๅฎนๅ™จๅŒ–** | Docker | ๆ ‡ๅ‡†ๅŒ–ใ€ๆ˜“้ƒจ็ฝฒ | | **็ผ–ๆŽ’** | Docker Compose | ็ฎ€ๅ•ใ€้€‚ๅˆๅ•ไฝ“ | | **ๅๅ‘ไปฃ็†** | Nginx | ้ซ˜ๆ€ง่ƒฝใ€ๆˆ็†Ÿ | | **SSL** | Let's Encrypt | ๅ…่ดนใ€่‡ชๅŠจ็ปญๆœŸ | --- ## 4. ๆ•ฐๆฎๆจกๅž‹ ### 4.1 ๆ ธๅฟƒๆจกๅž‹ ```python # User๏ผˆ็”จๆˆท๏ผ‰ class User(models.Model): username = models.CharField(max_length=50, unique=True) email = models.EmailField(unique=True) password_hash = models.CharField(max_length=255) created_at = models.DateTimeField(auto_now_add=True) is_active = models.BooleanField(default=True) # Meeting๏ผˆไผš่ฎฎๅฎค๏ผ‰ class Meeting(models.Model): id = models.UUIDField(primary_key=True) topic = models.CharField(max_length=200) host = models.ForeignKey(User, on_delete=models.CASCADE) status = models.CharField( max_length=20, choices=[ ('pending', 'ๅพ…ๅผ€ๅง‹'), ('active', '่ฟ›่กŒไธญ'), ('ended', 'ๅทฒ็ป“ๆŸ') ], default='pending' ) invite_code = models.CharField(max_length=20, unique=True) created_at = models.DateTimeField(auto_now_add=True) started_at = models.DateTimeField(null=True, blank=True) ended_at = models.DateTimeField(null=True, blank=True) # Participant๏ผˆๅ‚ไผš่€…๏ผ‰ class Participant(models.Model): meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE) user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) # Agent ไฟกๆฏ agent_type = models.CharField( max_length=20, choices=[ ('human', 'ไบบ็ฑป'), ('openclaw', 'OpenClaw Agent'), ('other', 'ๅ…ถไป– AI') ] ) agent_id = models.CharField(max_length=100, null=True) agent_name = models.CharField(max_length=100) agent_emoji = models.CharField(max_length=10, default='๐Ÿค–') # ็Šถๆ€ nickname = models.CharField(max_length=100) is_host = models.BooleanField(default=False) joined_at = models.DateTimeField(auto_now_add=True) left_at = models.DateTimeField(null=True, blank=True) # API ่ฎค่ฏ๏ผˆAgent ็”จ๏ผ‰ api_key = models.CharField(max_length=255, null=True, blank=True) # Message๏ผˆๆถˆๆฏ๏ผ‰ class Message(models.Model): meeting = models.ForeignKey(Meeting, on_delete=models.CASCADE) sender = models.ForeignKey(Participant, on_delete=models.CASCADE) content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) # ไฟก็ฎฑๆœบๅˆถ is_broadcast = models.BooleanField(default=True) # ็พคๅ‘ๆถˆๆฏ requires_response = models.BooleanField(default=False) # ้œ€่ฆๅ›žๅค in_reply_to = models.ForeignKey('self', null=True, on_delete=models.SET_NULL) # ่ฏปๅ–็Šถๆ€ read_by = models.ManyToManyField(Participant, related_name='read_messages', blank=True) # MeetingMinutes๏ผˆไผš่ฎฎ็บช่ฆ๏ผ‰ class MeetingMinutes(models.Model): meeting = models.OneToOneField(Meeting, on_delete=models.CASCADE) content = models.TextField() generated_at = models.DateTimeField(auto_now_add=True) exported_at = models.DateTimeField(null=True, blank=True) ``` ### 4.2 ็ดขๅผ•่ฎพ่ฎก ```python # ไผ˜ๅŒ–ๆŸฅ่ฏขๆ€ง่ƒฝ class Meta: indexes = [ models.Index(fields=['meeting', 'created_at']), models.Index(fields=['agent_id', 'meeting']), models.Index(fields=['is_broadcast', 'created_at']), ] ``` --- ## 5. API ่ฎพ่ฎก ### 5.1 API ็‰ˆๆœฌ ``` /api/v1/... ``` ### 5.2 ๆ ธๅฟƒ API #### 5.2.1 ไผš่ฎฎ็ฎก็† ``` POST /api/v1/meetings/ # ๅˆ›ๅปบไผš่ฎฎ GET /api/v1/meetings/ # ่Žทๅ–ไผš่ฎฎๅˆ—่กจ GET /api/v1/meetings/{id}/ # ่Žทๅ–ไผš่ฎฎ่ฏฆๆƒ… DELETE /api/v1/meetings/{id}/ # ๅˆ ้™คไผš่ฎฎ POST /api/v1/meetings/{id}/start/ # ๅผ€ๅง‹ไผš่ฎฎ POST /api/v1/meetings/{id}/end/ # ็ป“ๆŸไผš่ฎฎ ``` #### 5.2.2 ๅ‚ไผš่€…็ฎก็† ``` POST /api/v1/meetings/{id}/participants/ # ๅŠ ๅ…ฅไผš่ฎฎ GET /api/v1/meetings/{id}/participants/ # ่Žทๅ–ๅ‚ไผš่€…ๅˆ—่กจ DELETE /api/v1/meetings/{id}/participants/{pid}/ # ็ฆปๅผ€ไผš่ฎฎ ``` #### 5.2.3 ๆถˆๆฏ็ฎก็† ``` GET /api/v1/meetings/{id}/messages/ # ่Žทๅ–ๆถˆๆฏ๏ผˆไบบ็ฑป่ฝฎ่ฏข๏ผ‰ POST /api/v1/meetings/{id}/messages/ # ๅ‘้€ๆถˆๆฏ GET /api/v1/meetings/{id}/inbox/ # Agent ๆŸฅไฟก็ฎฑ POST /api/v1/meetings/{id}/messages/{mid}/read/ # ๆ ‡่ฎฐๅทฒ่ฏป ``` #### 5.2.4 ็”จๆˆท่ฎค่ฏ ``` POST /api/v1/auth/register/ # ๆณจๅ†Œ POST /api/v1/auth/login/ # ็™ปๅฝ• POST /api/v1/auth/logout/ # ็™ปๅ‡บ GET /api/v1/auth/me/ # ่Žทๅ–ๅฝ“ๅ‰็”จๆˆท ``` ### 5.3 API ๅ“ๅบ”ๆ ผๅผ ```json // ๆˆๅŠŸๅ“ๅบ” { "success": true, "data": { ... }, "message": "ๆ“ไฝœๆˆๅŠŸ" } // ้”™่ฏฏๅ“ๅบ” { "success": false, "error": { "code": "INVALID_REQUEST", "message": "่ฏทๆฑ‚ๅ‚ๆ•ฐๆ— ๆ•ˆ" } } ``` --- ## 6. ่ฝฎ่ฏขๆœบๅˆถ ### 6.1 ไบบ็ฑป็”จๆˆท่ฝฎ่ฏข๏ผˆ1 ็ง’๏ผ‰ ```javascript // React Hook function useMeetingMessages(meetingId) { const [messages, setMessages] = useState([]); const [lastId, setLastId] = useState(0); useEffect(() => { const poll = async () => { const response = await fetch( `/api/v1/meetings/${meetingId}/messages/?last_id=${lastId}` ); const data = await response.json(); if (data.messages.length > 0) { setMessages(prev => [...prev, ...data.messages]); setLastId(data.messages[data.messages.length - 1].id); } }; const interval = setInterval(poll, 1000); // 1 ็ง’่ฝฎ่ฏข return () => clearInterval(interval); }, [meetingId, lastId]); return messages; } ``` ### 6.2 Agent ่ฝฎ่ฏข๏ผˆ5 ็ง’๏ผ‰ ```python # Python ๅฎขๆˆท็ซฏ class MeetingAgent: def __init__(self, config): self.check_interval = config.get('check_interval', 5) def run(self): while True: inbox = self.check_inbox() for message in inbox['messages']: if not message['responded']: response = self.generate_response(message) self.respond(message['id'], response) time.sleep(self.check_interval) ``` ### 6.3 ่ฝฎ่ฏขๆŽฅๅฃๆŠฝ่ฑก ```python # ๆŠฝ่ฑกๆŽฅๅฃ class PollingStrategy(ABC): @abstractmethod def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]: pass @abstractmethod def send_message(self, meeting_id: str, message: Message) -> bool: pass # HTTP ๅฎž็Žฐ class HTTPPollingStrategy(PollingStrategy): def __init__(self, api_base: str, api_key: str): self.api_base = api_base self.api_key = api_key def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]: # HTTP GET ๅฎž็Žฐ pass # WebSocket ๅฎž็Žฐ๏ผˆๆœชๆฅๆ‰ฉๅฑ•๏ผ‰ class WebSocketPollingStrategy(PollingStrategy): def check_inbox(self, meeting_id: str, agent_id: str) -> List[Message]: # WebSocket ๅฎž็Žฐ pass ``` --- ## 7. ้ƒจ็ฝฒๆžถๆž„ ### 7.1 Docker Compose ```yaml version: '3.8' services: web: build: ./backend command: gunicorn meeting_room.wsgi:application --bind 0.0.0.0:8000 volumes: - ./backend:/app environment: - DATABASE_URL=postgresql://user:pass@db:5432/meeting_room - REDIS_URL=redis://redis:6379/0 depends_on: - db - redis db: image: postgres:15 environment: - POSTGRES_DB=meeting_room - POSTGRES_USER=user - POSTGRES_PASSWORD=pass volumes: - pgdata:/var/lib/postgresql/data redis: image: redis:7-alpine nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./ssl:/etc/nginx/ssl depends_on: - web volumes: pgdata: ``` ### 7.2 Nginx ้…็ฝฎ ```nginx server { listen 80; server_name meeting.example.com; location / { proxy_pass http://web:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /static/ { alias /app/static/; } } ``` --- ## 8. ๆ‰ฉๅฑ•ๆ€ง่ฎพ่ฎก ### 8.1 ๆฐดๅนณๆ‰ฉๅฑ• ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Nginx โ”‚ โ”‚ (่ดŸ่ฝฝๅ‡่กก) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”Œโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ” โ”‚ โ”‚ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”‚ Web โ”‚ โ”‚ Web โ”‚ โ”‚ 1 โ”‚ โ”‚ 2 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜ โ”‚ โ”Œโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ” โ”‚ โ”‚ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ DB โ”‚ โ”‚ Redis โ”‚ โ”‚ (ไธปไปŽ) โ”‚ โ”‚ (้›†็พค) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### 8.2 ๆ’ไปถๅŒ–่ฎพ่ฎก ```python # Agent ๆ’ไปถๆŽฅๅฃ class AgentPlugin(ABC): @abstractmethod def generate_response(self, message: Message) -> str: pass # OpenClaw ๆ’ไปถ class OpenClawPlugin(AgentPlugin): def generate_response(self, message: Message) -> str: # OpenClaw ้€ป่พ‘ pass # Llama ๆ’ไปถ๏ผˆๆœชๆฅ๏ผ‰ class LlamaPlugin(AgentPlugin): def generate_response(self, message: Message) -> str: # ่ฐƒ็”จ Llama API pass ``` --- ## ๐Ÿ“ ๅ˜ๆ›ดๆ—ฅๅฟ— | ็‰ˆๆœฌ | ๆ—ฅๆœŸ | ๅ˜ๆ›ดๅ†…ๅฎน | ไฝœ่€… | |------|------|----------|------| | v0.1 | 2026-04-04 | ๅˆๅง‹็‰ˆๆœฌ | ้ฃž่กŒไพ  | --- **ๆ–‡ๆกฃ็ป“ๆŸ** ๐Ÿ“ **ๅˆ›ๅปบ่€…**: ้ฃž่กŒไพ  ๐Ÿฆธ **ๆ—ฅๆœŸ**: 2026-04-04 **็Šถๆ€**: ๅพ…ๅŒ—ๆžๆ˜Ÿ็กฎ่ฎค