career_app / docs /ARCHITECTURE_DESIGN.md
Youngger9765
fix: resolve all linting and formatting errors
efc08f7
# ่ทๆถฏ่ซฎ่ฉขๅ€‹ๆกˆ็ฎก็†็ณป็ตฑ - ๆžถๆง‹่จญ่จˆๆ–‡ไปถ
## ๅฐˆๆกˆ็›ฎๆจ™
ๆ‰“้€ ไธ€ๅ€‹**ๅทฎ็•ฐๅŒ–็š„ๅŠฉไบบ่€…ๅฐˆๆฅญๅทฅๅ…ท**๏ผŒ็›ธ่ผƒๆ–ผไธ€่ˆฌ็š„ใ€Œ้Œ„้Ÿณ โ†’ AI ๆ‘˜่ฆใ€ๅทฅๅ…ท๏ผŒๆˆ‘ๅ€‘ๆไพ›๏ผš
### ๆ ธๅฟƒๅƒนๅ€ผไธปๅผต
1. **ไธ€้ตๆ•ดๅˆ**๏ผš้Œ„้Ÿณ โ†’ ้€ๅญ—็จฟ โ†’ ๅฐˆๆฅญๅ ฑๅ‘Š โ†’ ๅ€‹ๆกˆ็ฎก็†็ณป็ตฑ
2. **ๅฐˆๆฅญๆจ™ๆบ–**๏ผš็ฌฆๅˆๅŠฉไบบๅฐˆๆฅญ็š„ๅ ฑๅ‘Š็ตๆง‹๏ผˆ่ทๆธธๆจ™ๆบ–ๆก†ๆžถ๏ผ‰
3. **็ดฏ็ฉๅž‹ๆช”ๆกˆ**๏ผšๆ”ฏๆดๅ€‹ๆกˆๆญท็จ‹่ฟฝ่นคใ€่ทจๆฌกๆ™ค่ซ‡ๅˆ†ๆž
4. **ๆ™บ่ƒฝ้€ฃๅ‹•**๏ผšๅ ฑๅ‘Š่‡ชๅ‹•่ˆ‡ใ€Œไพ†่จช่€…ๆญท็จ‹ใ€ใ€Œ่ซฎ่ฉข็ญ–็•ฅๅปบ่ญฐใ€ใ€Œๅ›ž่จชๆ้†’ใ€้€ฃๅ‹•
5. **ๅฐˆๆฅญๅŒ– AI**๏ผš็ถ“้Žๅฐˆๆฅญ้กงๅ•่ชฟๆ•™็š„ๅฐ่ฉฑ่จญ่จˆ๏ผˆ็ฌฆๅˆๅŠฉไบบๅ€ซ็†ใ€็ฃๅฐŽ็ตๆง‹๏ผ‰
6. **ๅฎข่ฃฝๅŒ–็Ÿฅ่ญ˜ๅบซ**๏ผš่ซฎ่ฉขๅธซๅฏ้ธๆ“‡็‰นๅฎšๆ–‡ไปถ้€ฒ่กŒ RAG ๆชข็ดข
---
## ็ณป็ตฑๆžถๆง‹ๆฆ‚่ฆฝ
```
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ iOS App โ”‚ ้Œ„้Ÿณ โ†’ ่ฝ‰้€ๅญ—็จฟ
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚ API Call
โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Backend API Server โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ Session Management (ๅ€‹ๆกˆ็ฎก็†) โ”‚ โ”‚
โ”‚ โ”‚ - ่‡ชๅ‹•ๅ‰ตๅปบ/ๆ›ดๆ–ฐๅ€‹ๆกˆๆช”ๆกˆ โ”‚ โ”‚
โ”‚ โ”‚ - ๆ™ค่ซ‡ๆฌกๆ•ธ็ดฏ่จˆ โ”‚ โ”‚
โ”‚ โ”‚ - ๆญท็จ‹่ฟฝ่นค โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ AI Report Generation (ๅ ฑๅ‘Š็”Ÿๆˆ) โ”‚ โ”‚
โ”‚ โ”‚ - RAG ็Ÿฅ่ญ˜ๆชข็ดข โ”‚ โ”‚
โ”‚ โ”‚ - ็ตๆง‹ๅŒ–ๅ ฑๅ‘Š็”Ÿๆˆ โ”‚ โ”‚
โ”‚ โ”‚ - ๅฐ่ฉฑ็ฏ€้Œ„ๆๅ– โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚ โ”‚ Counselor Agent (ๅฎข่ฃฝๅŒ– AI) โ”‚ โ”‚
โ”‚ โ”‚ - ๆ–‡ไปถ้ธๆ“‡ โ”‚ โ”‚
โ”‚ โ”‚ - ็Ÿฅ่ญ˜ๅบซ้Žๆฟพ โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Supabase Database โ”‚
โ”‚ - clients (ๅ€‹ๆกˆๅŸบๆœฌ่ณ‡ๆ–™) โ”‚
โ”‚ - sessions (ๆ™ค่ซ‡็ด€้Œ„) โ”‚
โ”‚ - session_reports (AI ็”Ÿๆˆๅ ฑๅ‘Š) โ”‚
โ”‚ - counselor_agents (่ซฎ่ฉขๅธซ AI ่จญๅฎš) โ”‚
โ”‚ - documents + chunks + embeddings (RAG) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```
---
## ๆ ธๅฟƒไฝฟ็”จๆƒ…ๅขƒ
### ๆƒ…ๅขƒ 1๏ผš้ฆ–ๆฌกๆ™ค่ซ‡ (iOS โ†’ Backend)
**iOS ็ซฏๆ“ไฝœ**๏ผš
1. ่ซฎ่ฉขๅธซๅœจ App ไธญ้Œ„้Ÿณ
2. App ่‡ชๅ‹•่ฝ‰้€ๅญ—็จฟ
3. ๅกซๅฏซๅ€‹ๆกˆๅŸบๆœฌ่ณ‡ๆ–™๏ผˆๅง“ๅใ€ๅนด้ฝกใ€ๆ€งๅˆฅ็ญ‰๏ผ‰
4. ้ปžๆ“Šใ€Œ็”Ÿๆˆๅ ฑๅ‘Šใ€
**API Request**๏ผš
```json
POST /api/sessions/generate-report
{
"counselor_code": "CO_ๅผต่€ๅธซ",
"client": {
"code": "CL_ๅฐๆ˜Ž",
"name": "ๅฐๆ˜Ž",
"age": 25,
"gender": "็”ท",
"occupation": "่ปŸ้ซ”ๅทฅ็จ‹ๅธซ",
"education": "ๅคงๅญธ",
"location": "ๅฐๅŒ—"
},
"session": {
"transcript": "Co: ไฝ ๅฅฝ๏ผŒไปŠๅคฉๆƒณ่Šไป€้บผ๏ผŸ\nCl: ๆˆ‘ๆœ€่ฟ‘ๅฐๅทฅไฝœๆ„Ÿๅˆฐๅพˆๅ›ฐๆƒ‘...",
"num_participants": 2,
"session_date": "2025-01-15T10:00:00"
}
}
```
**Backend ่™•็†ๆต็จ‹**๏ผš
1. โœ… ๆชขๆŸฅ `client_code` ๆ˜ฏๅฆๅญ˜ๅœจ
- ไธๅญ˜ๅœจ โ†’ ๅ‰ตๅปบๆ–ฐๅ€‹ๆกˆๆช”ๆกˆ๏ผˆ`clients` ่กจ๏ผ‰
- ๅญ˜ๅœจ โ†’ ็•ฅ้Ž
2. โœ… ๅ‰ตๅปบๆ–ฐ็š„ Session ็ด€้Œ„๏ผˆ`sessions` ่กจ๏ผ‰
- ่‡ชๅ‹•็ดฏๅŠ  `session_number` (็ฌฌ 1 ๆฌก)
- ๅ„ฒๅญ˜้€ๅญ—็จฟ
3. โœ… ๅ‘ผๅซ AI ็”Ÿๆˆๅ ฑๅ‘Š
- RAG ๆชข็ดข็›ธ้—œ็†่ซ–๏ผˆๆ นๆ“š counselor ็š„ Agent ่จญๅฎš้ธๆ“‡ๆ–‡ไปถ๏ผ‰
- ็”Ÿๆˆ็ตๆง‹ๅŒ–ๅ ฑๅ‘Š
4. โœ… ๅ„ฒๅญ˜ๅ ฑๅ‘Š๏ผˆ`session_reports` ่กจ๏ผ‰
5. โœ… ๆ›ดๆ–ฐๅ€‹ๆกˆ็ตฑ่จˆ๏ผˆ็ธฝๆ™ค่ซ‡ๆฌกๆ•ธใ€ๆœ€ๅพŒๆ™ค่ซ‡ๆ™‚้–“๏ผ‰
**API Response (SSE Stream)**๏ผš
```
data: {"step": 1, "status": "processing", "message": "ๆญฃๅœจๅˆ†ๆž้€ๅญ—็จฟ็ตๆง‹..."}
data: {"step": 2, "status": "completed", "message": "่ญ˜ๅˆฅๅˆฐ 2 ๅ€‹้—œ้ต่ญฐ้กŒ"}
data: {"step": 3, "status": "processing", "message": "ๆญฃๅœจๆชข็ดข็›ธ้—œ็†่ซ–..."}
...
data: {"step": 5, "status": "completed", "data": {"report": {...}}}
```
ๆœ€็ต‚ๅ›žๅ‚ณๅฎŒๆ•ดๅ ฑๅ‘Š JSON
---
### ๆƒ…ๅขƒ 2๏ผš็ฌฌไบŒๆฌกๆ™ค่ซ‡ (็ฐกๅŒ–ๆต็จ‹)
**iOS ็ซฏๆ“ไฝœ**๏ผš
1. ้ธๆ“‡ๆ—ขๆœ‰ๅ€‹ๆกˆใ€Œๅฐๆ˜Žใ€
2. ้Œ„้Ÿณ โ†’ ่ฝ‰้€ๅญ—็จฟ
3. ้ปžๆ“Šใ€Œ็”Ÿๆˆๅ ฑๅ‘Šใ€
**API Request**๏ผš
```json
POST /api/sessions/generate-report
{
"counselor_code": "CO_ๅผต่€ๅธซ",
"client": {
"code": "CL_ๅฐๆ˜Ž"
// ไธ้œ€่ฆๅ†ๅ‚ณๅŸบๆœฌ่ณ‡ๆ–™๏ผŒๅพŒ็ซฏ่‡ชๅ‹•ๅ–ๅพ—
},
"session": {
"transcript": "Co: ไธŠๆฌกๆˆ‘ๅ€‘่Šๅˆฐ่ทๆถฏๅ›ฐๆ“พ...",
"num_participants": 2,
"session_date": "2025-01-22T10:00:00"
}
}
```
**Backend ่™•็†**๏ผš
1. โœ… ๆ นๆ“š `client_code` ๅ–ๅพ—ๆ—ขๆœ‰ๅ€‹ๆกˆ่ณ‡ๆ–™
2. โœ… ๅ‰ตๅปบ็ฌฌ 2 ๆฌก Session๏ผˆ`session_number = 2`๏ผ‰
3. โœ… ็”Ÿๆˆๅ ฑๅ‘Šๆ™‚ๅฏๅƒ่€ƒๆญทๆฌกๆ™ค่ซ‡ๅ…งๅฎน๏ผˆoptional๏ผŒๆœชไพ†ๅŠŸ่ƒฝ๏ผ‰
4. โœ… ๅ„ฒๅญ˜ไธฆๅ›žๅ‚ณๅ ฑๅ‘Š
---
### ๆƒ…ๅขƒ 3๏ผšๆŸฅ่ฉขๅ€‹ๆกˆๆญท็จ‹ (iOS ๆˆ– Web)
**API Request**๏ผš
```json
GET /api/clients/CO_ๅผต่€ๅธซ/CL_ๅฐๆ˜Ž/history
```
**Response**๏ผš
```json
{
"client": {
"code": "CL_ๅฐๆ˜Ž",
"name": "ๅฐๆ˜Ž",
"age": 25,
"gender": "็”ท",
"total_sessions": 2,
"first_session_date": "2025-01-15T10:00:00",
"last_session_date": "2025-01-22T10:00:00",
"status": "active"
},
"sessions": [
{
"session_id": 123,
"session_number": 1,
"session_date": "2025-01-15T10:00:00",
"summary": "ๅˆๆฌกๆ™ค่ซ‡๏ผŒๆŽข็ดข่ทๆถฏๅ›ฐๆ“พ๏ผŒไฝฟ็”จ็”Ÿๆถฏๅก็‰Œ",
"main_concerns": ["่ทๆถฏ่ฝ‰ๆ›", "ๅทฅไฝœๅฃ“ๅŠ›"]
},
{
"session_id": 124,
"session_number": 2,
"session_date": "2025-01-22T10:00:00",
"summary": "ๆทฑๅ…ฅๆŽข็ดขๅƒนๅ€ผ่ง€๏ผŒ้€ฒ่กŒ่ˆˆ่ถฃๆธฌ้ฉ—",
"main_concerns": ["่‡ชๆˆ‘ๆŽข็ดข", "ๆฑบ็ญ–ๅ›ฐ้›ฃ"]
}
]
}
```
---
### ๆƒ…ๅขƒ 4๏ผšๅ–ๅพ—็‰นๅฎšๅ ฑๅ‘Š่ฉณๆƒ…
**API Request**๏ผš
```json
GET /api/sessions/123/report
```
**Response**๏ผš
```json
{
"session_id": 123,
"client_info": {
"name": "ๅฐๆ˜Ž",
"age": 25,
"gender": "็”ท"
},
"session_summary": {
"content": "ๅ€‹ๆกˆ่กจ้”ๆƒณ่ฆ่ฝ‰ๆ›่ท‘้“็š„ๆƒณๆณ•...",
"self_evaluation": "ๅˆๆฌกๆ™ค่ซ‡๏ผŒๅปบ็ซ‹่‰ฏๅฅฝ้—œไฟ‚"
},
"conceptualization": "ใ€ไธป่จดๅ•้กŒใ€‘\nๅ€‹ๆกˆ่กจ้”ๅฐ็›ฎๅ‰่ปŸ้ซ”ๅทฅ็จ‹ๅธซๅทฅไฝœๆ„Ÿๅˆฐๅ€ฆๆ€ ...",
"main_concerns": ["่ทๆถฏ่ฝ‰ๆ›", "ๅทฅไฝœ็”Ÿๆดปๅนณ่กก"],
"counseling_goals": ["้‡ๆธ…่ทๆถฏๆ–นๅ‘", "ๆ”นๅ–„ๅทฅไฝœๅฃ“ๅŠ›"],
"techniques": ["ๅŒ็†ๅฟƒๅ›žๆ‡‰", "็”ŸๆถฏๅกๆŽข็ดข"],
"theories": [
{
"text": "Super ็š„็”Ÿๆถฏ็™ผๅฑ•็†่ซ–ๆŒ‡ๅ‡บ...",
"document": "็”Ÿๆถฏ็™ผๅฑ•็†่ซ–",
"score": 0.85
}
],
"dialogue_excerpts": [
{"speaker": "speaker1", "order": 1, "text": "่ฝ่ตทไพ†ไฝ ๅฐ็›ฎๅ‰็š„ๅทฅไฝœๆ„Ÿๅˆฐไธ€ไบ›ๅ›ฐๆ“พ๏ผŸ"},
{"speaker": "speaker2", "order": 2, "text": "ๆ˜ฏ็š„๏ผŒๆˆ‘่ฆบๅพ—ๆฏๅคฉๅฏซ็จ‹ๅผๅพˆ็ดฏ"}
]
}
```
---
## ่ณ‡ๆ–™ๅบซ่จญ่จˆ
### 1. `clients` - ๅ€‹ๆกˆๅŸบๆœฌ่ณ‡ๆ–™
| ๆฌ„ไฝ | ๅž‹ๅˆฅ | ่ชชๆ˜Ž |
|------|------|------|
| id | SERIAL | Primary Key |
| client_code | VARCHAR(100) | ๅ”ฏไธ€่ญ˜ๅˆฅ็ขผ๏ผŒๆ ผๅผ๏ผš`{counselor_code}_{alias}` |
| counselor_code | VARCHAR(100) | ๆ‰€ๅฑฌ่ซฎ่ฉขๅธซ |
| name | VARCHAR(200) | ๅŒ–ๅ |
| gender | VARCHAR(50) | ๆ€งๅˆฅ |
| age | INTEGER | ๅนด้ฝก |
| occupation | VARCHAR(200) | ่ทๆฅญ |
| education | VARCHAR(200) | ๅญธๆญท |
| location | VARCHAR(200) | ๅฑ…ไฝๅœฐ |
| economic_status | VARCHAR(200) | ็ถ“ๆฟŸ็‹€ๆณ |
| family_relations | TEXT | ๅฎถๅบญ้—œไฟ‚ |
| status | VARCHAR(50) | active/inactive/completed |
| first_session_date | TIMESTAMP | ้ฆ–ๆฌกๆ™ค่ซ‡ๆ™‚้–“ |
| last_session_date | TIMESTAMP | ๆœ€ๅพŒๆ™ค่ซ‡ๆ™‚้–“ |
| total_sessions | INTEGER | ็ธฝๆ™ค่ซ‡ๆฌกๆ•ธ |
| notes | TEXT | ่ซฎ่ฉขๅธซๅ‚™่จป |
| tags | TEXT[] | ๆจ™็ฑค |
| created_at | TIMESTAMP | ๅปบๆช”ๆ™‚้–“ |
| updated_at | TIMESTAMP | ๆ›ดๆ–ฐๆ™‚้–“ |
### 2. `sessions` - ๆ™ค่ซ‡็ด€้Œ„
| ๆฌ„ไฝ | ๅž‹ๅˆฅ | ่ชชๆ˜Ž |
|------|------|------|
| id | SERIAL | Primary Key |
| client_id | INTEGER | FK โ†’ clients.id |
| counselor_code | VARCHAR(100) | ่ซฎ่ฉขๅธซไปฃ็ขผ |
| session_number | INTEGER | ็ฌฌๅนพๆฌกๆ™ค่ซ‡ |
| session_date | TIMESTAMP | ๆ™ค่ซ‡ๆ—ฅๆœŸ |
| duration_minutes | INTEGER | ๆ™‚้•ท๏ผˆๅˆ†้˜๏ผ‰ |
| session_type | VARCHAR(50) | individual/group/online/offline |
| transcript | TEXT | ๅŽŸๅง‹้€ๅญ—็จฟ |
| num_participants | INTEGER | ๆœƒ่ซ‡ไบบๆ•ธ๏ผˆdefault 2๏ผ‰ |
| status | VARCHAR(50) | draft/completed/reviewed |
| created_at | TIMESTAMP | ๅปบ็ซ‹ๆ™‚้–“ |
| updated_at | TIMESTAMP | ๆ›ดๆ–ฐๆ™‚้–“ |
**Unique Constraint**: `(client_id, session_number)`
### 3. `session_reports` - AI ็”Ÿๆˆๅ ฑๅ‘Š
| ๆฌ„ไฝ | ๅž‹ๅˆฅ | ่ชชๆ˜Ž |
|------|------|------|
| id | SERIAL | Primary Key |
| session_id | INTEGER | FK โ†’ sessions.id |
| client_info | JSONB | ๅ€‹ๆกˆๅŸบๆœฌ่ณ‡่จŠ |
| session_summary | JSONB | ๆ™ค่ซ‡ๆ‘˜่ฆ |
| conceptualization | TEXT | ๆฆ‚ๅฟตๅŒ–ๅˆ†ๆž๏ผˆๅฎŒๆ•ดๆ–‡ๅญ—๏ผ‰ |
| main_concerns | TEXT[] | ไธป่จดๅ•้กŒๅˆ—่กจ |
| counseling_goals | TEXT[] | ่ซฎ่ฉข็›ฎๆจ™ๅˆ—่กจ |
| techniques | TEXT[] | ไฝฟ็”จๆŠ€ๅทงๅˆ—่กจ |
| dialogue_excerpts | JSONB | ๅฐ่ฉฑ็ฏ€้Œ„ |
| theories | JSONB | ็›ธ้—œ็†่ซ–ๆ–‡็ป |
| client_progress | TEXT | ๅ€‹ๆกˆ้€ฒๅฑ•๏ผˆๆœชไพ†ๅŠŸ่ƒฝ๏ผ‰ |
| next_steps | TEXT | ๅพŒ็บŒๅปบ่ญฐ |
| follow_up_date | TIMESTAMP | ๅ›ž่จชๆ—ฅๆœŸ๏ผˆๆœชไพ†ๅŠŸ่ƒฝ๏ผ‰ |
| supervision_notes | TEXT | ็ฃๅฐŽ่จŽ่ซ–ๅ…งๅฎน๏ผˆๆœชไพ†ๅŠŸ่ƒฝ๏ผ‰ |
| generated_at | TIMESTAMP | ๅ ฑๅ‘Š็”Ÿๆˆๆ™‚้–“ |
| updated_at | TIMESTAMP | ๆ›ดๆ–ฐๆ™‚้–“ |
### 4. `counselor_agents` - ่ซฎ่ฉขๅธซๅฎข่ฃฝๅŒ– AI
| ๆฌ„ไฝ | ๅž‹ๅˆฅ | ่ชชๆ˜Ž |
|------|------|------|
| id | SERIAL | Primary Key |
| counselor_code | VARCHAR(100) | ่ซฎ่ฉขๅธซไปฃ็ขผ๏ผˆUnique๏ผ‰ |
| agent_name | VARCHAR(200) | Agent ๅ็จฑ |
| selected_document_ids | INTEGER[] | ้ธๆ“‡็š„ๆ–‡ๆช” IDs |
| selected_tags | TEXT[] | ๆˆ–ๆŒ‰ๆจ™็ฑค็ฏฉ้ธ๏ผˆๆœชไพ†๏ผ‰ |
| system_prompt | TEXT | ๅฎข่ฃฝๅŒ– prompt๏ผˆๆœชไพ†๏ผ‰ |
| temperature | FLOAT | ๆบซๅบฆๅƒๆ•ธ๏ผˆๆœชไพ†๏ผ‰ |
| top_k | INTEGER | RAG top_k๏ผˆdefault 5๏ผ‰ |
| similarity_threshold | FLOAT | ็›ธไผผๅบฆ้–€ๆชป๏ผˆdefault 0.5๏ผ‰ |
| specialties | TEXT[] | ๅฐˆ้•ท้ ˜ๅŸŸ๏ผˆๆœชไพ†๏ผ‰ |
| approach | TEXT | ่ซฎ่ฉขๅ–ๅ‘๏ผˆๆœชไพ†๏ผ‰ |
| total_sessions | INTEGER | ไฝฟ็”จๆฌกๆ•ธ |
| last_used_at | TIMESTAMP | ๆœ€ๅพŒไฝฟ็”จๆ™‚้–“ |
| created_at | TIMESTAMP | ๅปบ็ซ‹ๆ™‚้–“ |
| updated_at | TIMESTAMP | ๆ›ดๆ–ฐๆ™‚้–“ |
### 5. `client_progress_timeline` - ๅ€‹ๆกˆ้€ฒๅฑ•ๆ™‚้–“่ปธ๏ผˆๆœชไพ†ๅŠŸ่ƒฝ๏ผ‰
| ๆฌ„ไฝ | ๅž‹ๅˆฅ | ่ชชๆ˜Ž |
|------|------|------|
| id | SERIAL | Primary Key |
| client_id | INTEGER | FK โ†’ clients.id |
| session_id | INTEGER | FK โ†’ sessions.id |
| stage | VARCHAR(100) | ้šŽๆฎต๏ผˆๆŽข็ดขๆœŸ/ๅทฅไฝœๆœŸ/็ตๆŸๆœŸ๏ผ‰ |
| progress_score | INTEGER | ้€ฒๅฑ•่ฉ•ๅˆ† 1-10 |
| mood_score | INTEGER | ๆƒ…็ท’็‹€ๆ…‹ 1-10 |
| milestones | TEXT[] | ้‡Œ็จ‹็ข‘ |
| breakthroughs | TEXT | ็ช็ ด้ปž |
| challenges | TEXT | ๆŒ‘ๆˆฐ |
| counselor_notes | TEXT | ่ซฎ่ฉขๅธซ่ง€ๅฏŸ |
| created_at | TIMESTAMP | ๅปบ็ซ‹ๆ™‚้–“ |
---
## API ่จญ่จˆ่ฆๆ ผ
### ๆ ธๅฟƒ API๏ผˆPhase 1 - ๅ„ชๅ…ˆๅฏฆไฝœ๏ผ‰
#### 1. ็”Ÿๆˆไธฆๅ„ฒๅญ˜ๅ ฑๅ‘Š
```
POST /api/sessions/generate-report
Content-Type: application/json
Request Body:
{
"counselor_code": "CO_ๅผต่€ๅธซ",
"client": {
"code": "CL_ๅฐๆ˜Ž",
"name": "ๅฐๆ˜Ž", // ้ฆ–ๆฌกๅฟ…ๅกซ
"age": 25, // ้ฆ–ๆฌกๅฟ…ๅกซ
"gender": "็”ท", // ้ฆ–ๆฌกๅฟ…ๅกซ
"occupation": "่ปŸ้ซ”ๅทฅ็จ‹ๅธซ", // ้ธๅกซ
"education": "ๅคงๅญธ", // ้ธๅกซ
"location": "ๅฐๅŒ—", // ้ธๅกซ
"economic_status": "็ฉฉๅฎš", // ้ธๅกซ
"family_relations": "ๅทฒๅฉš" // ้ธๅกซ
},
"session": {
"transcript": "Co: ไฝ ๅฅฝ...",
"num_participants": 2,
"session_date": "2025-01-15T10:00:00",
"duration_minutes": 60 // ้ธๅกซ
}
}
Response: SSE Stream
Content-Type: text/event-stream
data: {"step": 1, "status": "processing", "message": "ๆญฃๅœจๅˆ†ๆž้€ๅญ—็จฟ็ตๆง‹..."}
data: {"step": 1, "status": "completed", "message": "้€ๅญ—็จฟๅˆ†ๆžๅฎŒๆˆ", "data": {...}}
data: {"step": 2, "status": "processing", "message": "ๆญฃๅœจ่ญ˜ๅˆฅ้—œ้ต่ญฐ้กŒ..."}
...
data: {"step": 5, "status": "completed", "message": "ๅ€‹ๆกˆๅ ฑๅ‘Š็”ŸๆˆๅฎŒๆˆ", "data": {"report": {...}, "session_id": 123}}
data: {"step": 6, "status": "completed", "message": "ๅ…จ้ƒจๅฎŒๆˆ๏ผ"}
```
**่™•็†้‚่ผฏ**๏ผš
1. ๆชขๆŸฅ `client_code` ๆ˜ฏๅฆๅญ˜ๅœจๆ–ผ `clients` ่กจ
2. ่‹ฅไธๅญ˜ๅœจ โ†’ INSERT ๆ–ฐๅ€‹ๆกˆ
3. ่‹ฅๅญ˜ๅœจ โ†’ ๅ–ๅพ— `client_id`
4. INSERT ๆ–ฐ็š„ `session` ็ด€้Œ„๏ผˆ่‡ชๅ‹•่จˆ็ฎ— `session_number`๏ผ‰
5. ๅ‘ผๅซ AI ็”Ÿๆˆๅ ฑๅ‘Š๏ผˆๆ•ดๅˆ็พๆœ‰็š„ `generate_report_stream`๏ผ‰
6. INSERT `session_reports` ็ด€้Œ„
7. UPDATE `clients` ็š„ `total_sessions`, `last_session_date`
8. ๅ›žๅ‚ณๅฎŒๆ•ดๅ ฑๅ‘Š + `session_id`
---
#### 2. ๆŸฅ่ฉข่ซฎ่ฉขๅธซ็š„ๅ€‹ๆกˆๅˆ—่กจ
```
GET /api/counselors/{counselor_code}/clients
Query Parameters:
- status: active/inactive/completed (้ธๅกซ)
- limit: 20 (้ธๅกซ)
- offset: 0 (้ธๅกซ)
Response:
{
"total": 15,
"clients": [
{
"code": "CL_ๅฐๆ˜Ž",
"name": "ๅฐๆ˜Ž",
"age": 25,
"gender": "็”ท",
"total_sessions": 3,
"last_session_date": "2025-01-22T10:00:00",
"status": "active",
"tags": ["่ทๆถฏๅ›ฐๆ“พ", "็„ฆๆ…ฎ"]
},
...
]
}
```
---
#### 3. ๆŸฅ่ฉขๅ€‹ๆกˆๆญท็จ‹
```
GET /api/clients/{counselor_code}/{client_code}/history
Response:
{
"client": {
"code": "CL_ๅฐๆ˜Ž",
"name": "ๅฐๆ˜Ž",
"age": 25,
"gender": "็”ท",
"occupation": "่ปŸ้ซ”ๅทฅ็จ‹ๅธซ",
"total_sessions": 3,
"first_session_date": "2025-01-15T10:00:00",
"last_session_date": "2025-01-22T10:00:00",
"status": "active"
},
"sessions": [
{
"session_id": 123,
"session_number": 1,
"session_date": "2025-01-15T10:00:00",
"duration_minutes": 60,
"summary": "ๅˆๆฌกๆ™ค่ซ‡๏ผŒๆŽข็ดข่ทๆถฏๅ›ฐๆ“พ",
"main_concerns": ["่ทๆถฏ่ฝ‰ๆ›", "ๅทฅไฝœๅฃ“ๅŠ›"]
},
...
]
}
```
---
#### 4. ๅ–ๅพ—็‰นๅฎšๅ ฑๅ‘Š
```
GET /api/sessions/{session_id}/report
Response:
{
"session_id": 123,
"session_number": 1,
"session_date": "2025-01-15T10:00:00",
"client_info": { ... },
"session_summary": { ... },
"conceptualization": "...",
"main_concerns": [...],
"counseling_goals": [...],
"techniques": [...],
"theories": [...],
"dialogue_excerpts": [...]
}
```
---
### Agent ่จญๅฎš API๏ผˆPhase 1 - ็ฐกๅŒ–็‰ˆ๏ผ‰
#### 5. ่จญๅฎš่ซฎ่ฉขๅธซ็š„ Agent
```
POST /api/agents/config
Request:
{
"counselor_code": "CO_ๅผต่€ๅธซ",
"agent_name": "่ทๆถฏ่ซฎ่ฉขๅฐˆ็”จ AI",
"selected_document_ids": [1, 3, 5, 7] // ้ธๆ“‡็‰นๅฎšๆ–‡ๆช”
}
Response:
{
"success": true,
"message": "Agent ่จญๅฎšๅทฒๆ›ดๆ–ฐ",
"agent": {
"id": 1,
"counselor_code": "CO_ๅผต่€ๅธซ",
"agent_name": "่ทๆถฏ่ซฎ่ฉขๅฐˆ็”จ AI",
"selected_document_ids": [1, 3, 5, 7],
"top_k": 5,
"similarity_threshold": 0.5
}
}
```
---
#### 6. ๅ–ๅพ—่ซฎ่ฉขๅธซ็š„ Agent ่จญๅฎš
```
GET /api/agents/{counselor_code}/config
Response:
{
"agent": {
"id": 1,
"counselor_code": "CO_ๅผต่€ๅธซ",
"agent_name": "่ทๆถฏ่ซฎ่ฉขๅฐˆ็”จ AI",
"selected_document_ids": [1, 3, 5, 7],
"top_k": 5,
"similarity_threshold": 0.5,
"total_sessions": 15,
"last_used_at": "2025-01-22T10:00:00"
}
}
```
---
## ่บซไปฝ่ญ˜ๅˆฅ็ญ–็•ฅ
### ่ซฎ่ฉขๅธซ่ญ˜ๅˆฅ๏ผˆCounselor Code๏ผ‰
**ๆ ผๅผๅปบ่ญฐ**๏ผš
```
CO_{ๅง“ๅ/ๆšฑ็จฑ}
ไพ‹ๅฆ‚๏ผšCO_ๅผต่€ๅธซใ€CO_ๆŽๅฟƒ็†ๅธซ
```
**็‰นๆ€ง**๏ผš
- ไธ้œ€่ฆๅฏ†็ขผ๏ผˆๆšซๆ™‚๏ผ‰
- ็”ฑ iOS ็ซฏๅ„ฒๅญ˜ไธฆ่‡ชๅ‹•ๅธถๅ…ฅ
- ๆœชไพ†ๅฏ่€ƒๆ…ฎ่ฃ็ฝฎ็ถๅฎšๆˆ–็ฐกๆ˜“ PIN ็ขผ
### ๅ€‹ๆกˆ่ญ˜ๅˆฅ๏ผˆClient Code๏ผ‰
**ๆ ผๅผๅปบ่ญฐ**๏ผš
```
CL_{ๅŒ–ๅ/ไปฃ่™Ÿ}
ๆˆ–
{counselor_code}_CL_{ๅŒ–ๅ}
ไพ‹ๅฆ‚๏ผš
- CL_ๅฐๆ˜Ž
- CO_ๅผต่€ๅธซ_CL_ๅฐๆ˜Ž
```
**็‰นๆ€ง**๏ผš
- ็”ฑ่ซฎ่ฉขๅธซๅœจ iOS ็ซฏ่ผธๅ…ฅ
- ็ขบไฟๅœจ่ฉฒ่ซฎ่ฉขๅธซไธ‹ๅ”ฏไธ€ๅณๅฏ
- ไธ้œ€่ฆ่ทจ่ซฎ่ฉขๅธซๅ”ฏไธ€๏ผˆๆœชไพ†่‹ฅ้œ€่ฝ‰ไป‹ๅ†่ชฟๆ•ด๏ผ‰
---
## ่ณ‡ๆ–™ๅ„ฒๅญ˜็ญ–็•ฅ
### โœ… ๅ„ฒๅญ˜็š„่ณ‡ๆ–™
1. **่ซฎ่ฉขๅธซๅŸบๆœฌ่ณ‡ๆ–™**
- counselor_code, name
2. **ๅ€‹ๆกˆๅŸบๆœฌ่ณ‡ๆ–™**
- ๆ‰€ๆœ‰ `clients` ่กจๆฌ„ไฝ
3. **ๆ™ค่ซ‡็ด€้Œ„**
- ้€ๅญ—็จฟ๏ผˆ`transcript`๏ผ‰
- ๆ™ค่ซ‡ๆ™‚้–“ใ€ๆฌกๆ•ธใ€ๆ™‚้•ท
4. **AI ็”Ÿๆˆๅ ฑๅ‘Š**
- ๅฎŒๆ•ด็š„็ตๆง‹ๅŒ–ๅ ฑๅ‘Šๅ…งๅฎน
5. **Agent ่จญๅฎš**
- ๆ–‡ๆช”้ธๆ“‡่จญๅฎš
### โŒ ไธๅ„ฒๅญ˜็š„่ณ‡ๆ–™
1. **้Œ„้Ÿณๆช”**
- ็”ฑ iOS ๆœฌๅœฐๅ„ฒๅญ˜
- ๆœชไพ†่‹ฅ้œ€่ฆๅฏ่€ƒๆ…ฎ S3/Supabase Storage
2. **่ซฎ่ฉขๅธซๅ€‹ไบบ่จญๅฎš**๏ผˆๆšซๆ™‚๏ผ‰
- system_prompt, temperature ็ญ‰้€ฒ้šŽ่จญๅฎš
- Phase 2 ๅ†ๅฏฆไฝœ
---
## RAG ๆ•ดๅˆ็ญ–็•ฅ
### ็พๆœ‰ RAG ๆžถๆง‹
```
documents โ†’ chunks โ†’ embeddings
```
### Agent ๅฆ‚ไฝ•้ธๆ“‡ๆ–‡ไปถ
**ๆ–นๅผ 1๏ผš้ธๆ“‡็‰นๅฎšๆ–‡ๆช”**๏ผˆPhase 1 ๅฏฆไฝœ๏ผ‰
```python
# ๅพž counselor_agents ๅ–ๅพ— selected_document_ids
agent = get_counselor_agent(counselor_code)
selected_doc_ids = agent.selected_document_ids # [1, 3, 5, 7]
# RAG ๆŸฅ่ฉขๆ™‚้Žๆฟพ
WHERE c.doc_id IN :selected_doc_ids
```
**ๆ–นๅผ 2๏ผšๆจ™็ฑค็ฏฉ้ธ**๏ผˆๆœชไพ†๏ผ‰
```python
# ๆ–‡ๆช”ๅŠ ไธŠๆจ™็ฑค
documents.tags = ["่ทๆถฏ่ซฎ่ฉข", "็”Ÿๆถฏ่ฆๅŠƒ"]
# Agent ่จญๅฎš้ธๆ“‡ๆจ™็ฑค
agent.selected_tags = ["่ทๆถฏ่ซฎ่ฉข"]
# ๆŸฅ่ฉขๆ™‚้Žๆฟพ
WHERE d.tags && :selected_tags
```
---
## Phase 1 ๅฏฆไฝœๅ„ชๅ…ˆ้ †ๅบ
### ไปŠๅคฉๅฎŒๆˆ๏ผˆๆ ธๅฟƒๅŠŸ่ƒฝ๏ผ‰
1. โœ… ่ณ‡ๆ–™ๅบซ Migration๏ผˆๅทฒๅฎŒๆˆ SQL๏ผ‰
2. โณ ๅŸท่กŒ Migration
3. โณ ๅฏฆไฝœ `POST /api/sessions/generate-report`
- ๆ•ดๅˆ็พๆœ‰็š„ `generate_report_stream`
- ๅŠ ๅ…ฅๅ€‹ๆกˆๅ‰ตๅปบ/ๆ›ดๆ–ฐ้‚่ผฏ
- ๅŠ ๅ…ฅ Session ๅ„ฒๅญ˜้‚่ผฏ
- ๅŠ ๅ…ฅ Report ๅ„ฒๅญ˜้‚่ผฏ
4. โณ ๅฏฆไฝœ็ฐกๆ˜“ Agent ่จญๅฎš API
- `POST /api/agents/config`
- `GET /api/agents/{counselor_code}/config`
5. โณ ๆธฌ่ฉฆ iOS ไธฒๆŽฅ
### ๆ˜ŽๅคฉๅฎŒๆˆ๏ผˆๆŸฅ่ฉขๅŠŸ่ƒฝ๏ผ‰
6. `GET /api/counselors/{counselor_code}/clients`
7. `GET /api/clients/{counselor_code}/{client_code}/history`
8. `GET /api/sessions/{session_id}/report`
### ๅพŒๅคฉ+๏ผˆWeb ็ฎก็†ไป‹้ข๏ผ‰
9. ่ซฎ่ฉขๅธซ็™ปๅ…ฅ้ ้ข๏ผˆ่ผธๅ…ฅ counselor_code๏ผ‰
10. ๅ€‹ๆกˆๅˆ—่กจ้ ้ข
11. ๅ€‹ๆกˆ่ฉณๆƒ… + ๆญท็จ‹ๆ™‚้–“่ปธ้ ้ข
12. Agent ่จญๅฎš้ ้ข๏ผˆ้ธๆ“‡ๆ–‡ๆช”๏ผ‰
---
## ๆœชไพ†ๆ“ดๅ……ๅŠŸ่ƒฝ๏ผˆPhase 2+๏ผ‰
### ้€ฒ้šŽ CRM ๅŠŸ่ƒฝ
- ๅ›ž่จชๆ้†’๏ผˆ`follow_up_date`๏ผ‰
- ๅ€‹ๆกˆ้€ฒๅบฆ่ฉ•ๅˆ†๏ผˆ`client_progress_timeline`๏ผ‰
- ้šŽๆฎตๅˆ†ๆž๏ผˆๆŽข็ดขๆœŸ/ๅทฅไฝœๆœŸ/็ตๆŸๆœŸ๏ผ‰
### ๅ”ไฝœๅŠŸ่ƒฝ
- ่ทจ่ซฎ่ฉขๅธซ่ฝ‰ไป‹
- ็ฃๅฐŽ่จŽ่ซ–ๅŠŸ่ƒฝ๏ผˆ`supervision_notes`๏ผ‰
- ๅœ˜้šŠๅ”ไฝœ
### ้€ฒ้šŽ Agent ๅŠŸ่ƒฝ
- ่‡ช่จ‚ system_prompt
- ่ชฟๆ•ด temperature
- ๅฐˆ้•ท้ ˜ๅŸŸๆจ™็ฑค
### ่ณ‡ๆ–™ๅˆ†ๆž
- ่ซฎ่ฉขๅธซ็ตฑ่จˆๅ„€่กจๆฟ
- ๅ€‹ๆกˆๆ”นๅ–„็އๅˆ†ๆž
- ็†ฑ้–€่ญฐ้กŒ่ฟฝ่นค
---
## ๆŠ€่ก“ๆฃง
- **Backend**: FastAPI + Python 3.10+
- **Database**: Supabase (PostgreSQL + pgvector)
- **AI**: OpenAI GPT-4o-mini + text-embedding-3-small
- **Frontend**: Next.js 14 + React + TypeScript
- **iOS**: Swift (็”ฑๅœ˜้šŠๅ…ถไป–ๆˆๅ“ก้–‹็™ผ)
---
## ่ณ‡ๆ–™้šฑ็ง่ˆ‡ๅฎ‰ๅ…จ
### ็พ้šŽๆฎต๏ผˆMVP๏ผ‰
- ไธๅ„ฒๅญ˜้Œ„้Ÿณๆช”
- ้€ๅญ—็จฟๅ’Œๅ ฑๅ‘Šๅ„ฒๅญ˜ๅœจ Supabase๏ผˆๅทฒๅŠ ๅฏ†ๅ‚ณ่ผธ๏ผ‰
- ็ฐกๆ˜“ไปฃ็ขผ่ญ˜ๅˆฅ๏ผˆcounselor_code๏ผ‰
### ๆœชไพ†่ฆๅŠƒ
- ็ซฏๅฐ็ซฏๅŠ ๅฏ†๏ผˆE2EE๏ผ‰
- ็ฌฆๅˆ GDPR/HIPAA ่ฆ็ฏ„
- ่ณ‡ๆ–™ๅŒฟๅๅŒ–้ธ้ …
- ๅฎšๆœŸ่ณ‡ๆ–™ๅ‚™ไปฝ
- ่ณ‡ๆ–™ๅˆช้™คๆฌŠ๏ผˆRight to be forgotten๏ผ‰
---
## API ้Œฏ่ชค่™•็†
### ๆจ™ๆบ–้Œฏ่ชคๆ ผๅผ
```json
{
"error": {
"code": "CLIENT_NOT_FOUND",
"message": "ๆ‰พไธๅˆฐ่ฉฒๅ€‹ๆกˆ่ณ‡ๆ–™",
"details": {
"client_code": "CL_ๅฐๆ˜Ž",
"counselor_code": "CO_ๅผต่€ๅธซ"
}
}
}
```
### ๅธธ่ฆ‹้Œฏ่ชค็ขผ
- `CLIENT_NOT_FOUND`: ๅ€‹ๆกˆไธๅญ˜ๅœจ
- `COUNSELOR_NOT_FOUND`: ่ซฎ่ฉขๅธซไธๅญ˜ๅœจ
- `SESSION_NOT_FOUND`: ๆ™ค่ซ‡็ด€้Œ„ไธๅญ˜ๅœจ
- `INVALID_TRANSCRIPT`: ้€ๅญ—็จฟๆ ผๅผ้Œฏ่ชค
- `AGENT_NOT_CONFIGURED`: Agent ๆœช่จญๅฎš
- `DOCUMENT_NOT_FOUND`: ๆ–‡ๆช”ไธๅญ˜ๅœจ
---
## ๆธฌ่ฉฆ็ญ–็•ฅ
### ๅ–ฎๅ…ƒๆธฌ่ฉฆ
- ๅ€‹ๆกˆๅ‰ตๅปบ/ๆ›ดๆ–ฐ้‚่ผฏ
- Session ็ทจ่™Ÿ่‡ชๅ‹•็ดฏๅŠ 
- Report ่ณ‡ๆ–™่งฃๆž
### ๆ•ดๅˆๆธฌ่ฉฆ
- iOS โ†’ API โ†’ Database ๅฎŒๆ•ดๆต็จ‹
- RAG ๆ–‡ๆช”้ŽๆฟพๅŠŸ่ƒฝ
- SSE ไธฒๆตๆธฌ่ฉฆ
### E2E ๆธฌ่ฉฆ
- ้ฆ–ๆฌกๆ™ค่ซ‡ๅฎŒๆ•ดๆต็จ‹
- ๅพŒ็บŒๆ™ค่ซ‡ๆต็จ‹
- ๆญท็จ‹ๆŸฅ่ฉขๅŠŸ่ƒฝ
---
## ้ƒจ็ฝฒๆžถๆง‹๏ผˆๆœชไพ†๏ผ‰
```
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ iOS App โ”‚
โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Cloudflare / CDN โ”‚
โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ FastAPI Server โ”‚ (Railway / Render / AWS)
โ”‚ (Load Balanced) โ”‚
โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚
โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Supabase โ”‚
โ”‚ (PostgreSQL + โ”‚
โ”‚ pgvector) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```
---
## ่ฎŠๆ›ดๆญทๅฒ
| ๆ—ฅๆœŸ | ็‰ˆๆœฌ | ่ฎŠๆ›ดๅ…งๅฎน |
|------|------|----------|
| 2025-01-XX | 0.1 | ๅˆ็‰ˆๆžถๆง‹่จญ่จˆ |
---
**ๆ–‡ไปถไฝœ่€…**: Claude + Young
**ๆœ€ๅพŒๆ›ดๆ–ฐ**: 2025-01-XX
**็‹€ๆ…‹**: ่ฆๅŠƒไธญ โ†’ ๆบ–ๅ‚™ๅฏฆไฝœ