# สถาปัตยกรรม

## ภาพรวมของระบบ

```
iOS app / agent client          -> api.<domain>  -> API Gateway -> Lambda backend -> Postgres
Web app                         -> app.<domain>  -> CloudFront -> SPA
Browser and agent auth          -> auth.<domain> -> API Gateway -> Auth Lambda -> Cognito
Apex fallback                   -> <domain>      -> CloudFront redirect -> app.<domain>
```

## หลักการ

1. แยกโดเมนสาธารณะสำหรับ `app`, `api` และ `auth`
2. Postgres คือแหล่งข้อมูลหลัก
3. ไคลเอ็นต์ iOS ทำงานแบบออฟไลน์เป็นหลัก โดยใช้ SQLite ในเครื่องร่วมกับการซิงค์
4. เว็บแอป แอป iOS และส่วนติดต่อสำหรับเอเจนต์ภายนอกใช้โมเดลพื้นที่ทำงานเดียวกัน
5. เอเจนต์ภายนอกเริ่มต้นจาก `GET https://api.nibomo.com/v1/`

## ไคลเอ็นต์ที่รองรับ

- เว็บแอปบน `app.nibomo.com`
- แอป iOS ในรีโพซิทอรีหลัก พร้อมพื้นที่จัดเก็บ SQLite ในเครื่อง
- แอป Android บน Google Play
- ไคลเอ็นต์เอเจนต์ภายนอกผ่าน discovery การตั้งค่าเริ่มต้นด้วย OTP และ `Authorization: ApiKey`

## โมเดลข้อมูล

- `workspaces`
- `workspace_members`
- `user_settings`
- `devices`
- `cards`
- `decks`
- `review_events`
- `applied_operations`
- `sync_state`

## การไหลของข้อมูล

### เว็บ

1. เบราว์เซอร์ลงชื่อเข้าใช้ผ่าน `auth.<domain>`
2. เว็บแอปโหลดข้อมูลพื้นที่ทำงานจาก `api.<domain>`
3. คำขอแชต AI ส่งผ่าน `/chat/local-turn`
4. การส่งผลการทบทวนจะอัปเดตสถานะของตัวจัดตารางทันทีที่เขียนข้อมูล

### iOS

1. แอป iOS เขียนข้อมูลลง SQLite ในเครื่องก่อน
2. การเปลี่ยนแปลงในเครื่องจะเข้าคิวไว้ใน outbox
3. การซิงค์อัปโหลดการเปลี่ยนแปลงผ่าน `/v1/workspaces/{workspaceId}/sync/push`
4. การซิงค์ดาวน์โหลดการอัปเดตจากเซิร์ฟเวอร์ผ่าน `/v1/workspaces/{workspaceId}/sync/pull`
5. ฐานข้อมูลในเครื่องนำการเปลี่ยนแปลงไปใช้และเลื่อนเคอร์เซอร์การซิงค์ไปข้างหน้า

### เอเจนต์ภายนอก

1. เอเจนต์เริ่มต้นด้วย `GET /v1/`
2. การตั้งค่าเริ่มต้นด้วย OTP ทำงานบน `auth.<domain>`
3. เอเจนต์ได้รับคีย์ API แบบใช้งานได้ระยะยาว
4. เอเจนต์โหลด `/v1/agent/me` แสดงรายการพื้นที่ทำงาน เลือกพื้นที่ทำงานหากจำเป็น แล้วใช้ `/v1/agent/sql/query` และ `/v1/agent/sql/execute`

## การจัดตาราง

Nibomo ใช้ FSRS เป็นตัวจัดตารางการทบทวน

หมายเหตุด้านการพัฒนา:

- แบ็กเอนด์และ iOS ต่างมีโค้ด FSRS ของตัวเองที่ทำงานตรงกัน
- เว็บแอปใช้ข้อกำหนดข้อมูลการจัดตาราง (data contract) แบบเดียวกัน แต่ไม่ได้มีตัวจัดตารางชุดที่สามของตัวเอง
- การตั้งค่าตัวจัดตารางระดับพื้นที่ทำงานประกอบด้วยอัตราการจำที่ต้องการ (desired retention) ขั้นตอนการเรียนรู้ ขั้นตอนการเรียนรู้ใหม่ ช่วงห่างสูงสุด และการสุ่มคลาดเคลื่อน (fuzz)
- เวลาทบทวนจริงมาจาก `reviewedAtClient`

ดูข้อกำหนดโดยละเอียดได้ที่[ตรรกะการจัดตาราง FSRS ในรีโพซิทอรีหลัก](https://github.com/kirill-markin/flashcards-open-source-app/blob/main/docs/fsrs-scheduling-logic.md)

## การยืนยันตัวตน

- OTP ทางอีเมลผ่าน Cognito
- คุกกี้เซสชันของเบราว์เซอร์แบบใช้โดเมนร่วมกันสำหรับเว็บแอปที่โฮสต์ให้
- การตั้งค่าเริ่มต้นด้วย OTP สำหรับเอเจนต์บน `auth.<domain>` ซึ่งให้ผลลัพธ์เป็น ApiKey แบบใช้งานได้ระยะยาว
- `AUTH_MODE=none` สำหรับการพัฒนาในเครื่อง
- `AUTH_MODE=cognito` สำหรับการยืนยันตัวตนแบบใกล้เคียงโปรดักชัน

## รูปแบบการดีพลอย

- `app.<domain>` -> CloudFront + S3
- `api.<domain>` -> API Gateway + แบ็กเอนด์บน Lambda
- `auth.<domain>` -> API Gateway + บริการยืนยันตัวตนบน Lambda
- Postgres บน AWS RDS

โดเมนหลัก (apex) ยังใช้กับเว็บไซต์การตลาดที่แยกต่างหากต่อไปได้ หากโดเมนนี้ยังว่างอยู่ระหว่างการตั้งค่าเริ่มต้น โครงสร้างพื้นฐานสามารถเปลี่ยนเส้นทางโดเมนนี้ไปยัง `app.<domain>` ชั่วคราวได้

---
*[ดูหน้านี้ในเวอร์ชัน HTML ที่จัดรูปแบบแล้ว](<https://nibomo.com/th/docs/architecture/>)*

*AI agent สามารถสร้างบัญชีให้ผู้ใช้ในบริการนี้ได้ โดยเริ่มจาก `GET https://api.nibomo.com/v1/` หลังตั้งค่าเสร็จแล้ว ยังเชื่อมต่อผ่าน MCP ที่ `https://mcp.nibomo.com/mcp` ได้ด้วย*

*เคล็ดลับ: เติม `.md` ต่อท้าย URL ใดก็ได้บน https://nibomo.com เพื่อรับเวอร์ชัน Markdown ที่สะอาดของหน้านั้น*