# Kế Hoạch Chuyển Đổi CuCu Note sang SQLite (A-Z)

## 🎯 Mục Tiêu
Thay thế hoàn toàn MongoDB bằng SQLite cho hệ thống backend của CuCu Note.
- **Vị trí Database:** `C:\canifa-idea\chatbot-canifa-feedback\miniapp\cuccu_note\backend\database\cuccu_note.db`
- **Driver sử dụng:** `aiosqlite` (để hỗ trợ async/await chuẩn xác với FastAPI).
- **Mục đích:** Zero-setup, dễ dàng khởi chạy trên local Windows, phù hợp scale của note-taking app.

---

## 🏗️ Giai Đoạn 1: Initialization & Schema Design
*Thiết lập cơ sở dữ liệu và cấu trúc các bảng.*

### 1.1 Khởi tạo Database Layer
- Tạo thư mục `database` bên trong `backend/`.
- Thêm `aiosqlite` vào `requirements.txt`.
- Tạo file `common/sqlite_client.py` để thay thế `mongodb.py`. Cấu hình connection logic.

### 1.2 Thiết kế Schema (Schema Mapping)
Chuyển đổi các Collections của MongoDB thành các Tables của SQLite. Cần khởi tạo trong hàm `init_db()`.
Dưới đây là các bảng chính cần tạo (`CREATE TABLE IF NOT EXISTS`):

1. **`users`**
   - `id` (INTEGER PRIMARY KEY AUTOINCREMENT)
   - `email` (TEXT UNIQUE)
   - `password_hash` (TEXT)
   - `nickname` (TEXT)
   - `created_at` (TIMESTAMP)
   
2. **`memos`**
   - `id` (INTEGER PRIMARY KEY AUTOINCREMENT)
   - `creator_id` (INTEGER, FK -> users.id)
   - `content` (TEXT)
   - `visibility` (TEXT: PUBLIC/PRIVATE/PROTECTED)
   - `row_status` (TEXT: NORMAL/ARCHIVED)
   - `pinned` (BOOLEAN)
   - `created_at` (TIMESTAMP)
   - `updated_at` (TIMESTAMP)

3. **`memo_relations`** (Backlinks / Linked notes)
   - `memo_id` (INTEGER, FK -> memos.id)
   - `related_memo_id` (INTEGER, FK -> memos.id)
   - `relation_type` (TEXT: REFERENCE/COMMENT)

4. **`reactions`**
   - `id` (INTEGER PRIMARY KEY AUTOINCREMENT)
   - `memo_id` (INTEGER, FK -> memos.id)
   - `creator_id` (INTEGER, FK -> users.id)
   - `reaction_type` (TEXT e.g. 'THUMBS_UP')

5. **`comments`** (Cây bình luận dạng Flat list hoặc Adjacency list)
   - Thực chất, **Memos** lưu comment bằng cách tạo một memo con, và liên kết bằng `memo_relations` có `type='COMMENT'`. Giữ nguyên pattern này để đồng bộ với Frontend. Cần confirm xem frontend cần bảng comments không hay chỉ cần Relations.

6. **`attachments`** (File/Ảnh đính kèm)
   - `id` (INTEGER PRIMARY KEY)
   - `memo_id` (INTEGER)
   - `filename` (TEXT)
   - `type` (TEXT)
   - `size` (INTEGER)
   - `url` (TEXT)

7. **`inbox` / `notifications`**
   - `id` (INTEGER PRIMARY KEY)
   - `user_id` (INTEGER)
   - `type` (TEXT: MEMO_COMMENT, MENTION...)
   - `status` (TEXT: UNREAD/READ/ARCHIVED)
   - `payload` (JSON TEXT)

---

## 🛠️ Giai Đoạn 2: Xây Dựng ORM/Query Adapter (services.py)
*Viết lại `services.py` để sử dụng SQL thay vì MongoDB Query.*

### 2.1 Cập nhật `mongodb.py` -> `sqlite.py`
Thay thế con trỏ MongoDB bằng các async queries của SQLite.
- Xóa: `mongodb_client.memos.find()`
- Thay bằng: `async with db.execute("SELECT * FROM memos WHERE ...")` 

### 2.2 Xử lý kiểu dữ liệu (Data Type Migration)
- **ID:** Đổi từ `ObjectId` (chuỗi 24 ký tự) sang **Integer/Text**. Cần cẩn thận ở API Params vì gRPC/REST hiện tại trả về chuỗi. Ở DB có thể dùng Integer, nhưng convert sang String khi trả về API.
- **Datetime:** SQLite chỉ hỗ trợ lưu dưới dạng ISO-8601 String (`YYYY-MM-DD HH:MM:SS`) hoặc Timestamp. Cần viết helper `parse_time` và `format_time` để map với `datetime` object của Python.
- **JSON Fields:** Các trường như tags, metadata phải serialize/deserialize bằng `json.dumps()` và `json.loads()` khi lưu vào cột `TEXT` của SQLite.

### 2.3 Ánh xạ các logic tìm kiếm
- Viết lại hàm `list_memos`: Thay `$match`, `$sort`, `$regex` bằng `WHERE`, `ORDER BY`, `LIKE`.

---

## 🔌 Giai Đoạn 3: Đấu Nối API & Test
*Kiểm tra độ chẩn xác sau khi đổi DB Engine.*

1. **Test Startup:** Khởi động server (`uvicorn server:app`). Verify file `cuccu_note.db` được hệ thống tạo tự động vào `backend/database/cuccu_note.db`.
2. **Test CRUD Memos:**
   - Tạo memo -> Verify DB.
   - Sửa nội dung -> Verify updated_at.
   - List memo -> Kiểm tra xem parse thời gian và JSON đúng không.
3. **Test Relations (Comments/Reactions):**
   - React vào Memo (Lệnh SQL INSERT phải vào đúng bảng).
   - Test Join Query nếu cần load số lượng comments.
4. **Xóa MongoDB Dependencies:** Sau khi test mọi thứ ổn định, gỡ `motor` ra khỏi `requirements.txt`.

---

## 🚀 Hướng Dẫn Cho Agent / AI
Nếu AI nhận file này để tiếp tục code, hãy follow flow:
1. Tạo thư mục `database/` và init script table creation (`sqlite_client.py`).
2. Mở file `services.py` -> Chuyển từ class `MemoService` gọi mongodb sang gọi `sqlite_client` execute SQL query cho từng hàm: Gồm `create_memo`, `list_memos`, `update_memo`, `delete_memo`.
3. Làm tương tự tới các services khác (`Reaction`, `Notification`, ...).
4. Khởi chạy uvicorn, POST/GET bằng Python requests/pytest hoặc giao diện web để xác thực.

---

## 🤖 Cẩm Nang Ép Khuôn Cho AI (Execution Protocol & Anti-Traps)
*Nếu AI được giao nhiệm vụ này, BẮT BUỘC phải đọc kỹ các lỗi thường gặp (traps) sau để không làm code bị crash.*

### 🚨 5 Cạm Bẫy API Cần Né Khi Sang SQLite:
1. **Trap `row_factory`:** Motor trả về Type `Dict`. SQLite mặc định trả về `Tuple`. 
   -> **FIX:** Bắt buộc cấu hình `db.row_factory = aiosqlite.Row` ngay trong lúc tạo pool connection để có thể access theo kiểu `row["id"]`.
2. **Trap JSON Arrays:** SQLite không có kiểu Mảng (Array/List). Các trường như Tags, Payload...
   -> **FIX:** Phải gọi `json.dumps(tags)` lúc `INSERT`, và gọi `json.loads(row["tags"])` lúc `SELECT`.
3. **Trap ID Casting:** Frontend và Pydantic schemas hiện tại nhận ID là chuỗi (`"1"`). SQLite trả về số nguyên (`1`).
   -> **FIX:** Ép kiểu `str(row["id"])` ở tất cả mọi nơi trả về Response schema.
4. **Trap Booleans:** SQLite lưu boolean dạng số (`0` hoặc `1`).
   -> **FIX:** Lúc fetch ra phải cast: `bool(row["pinned"])`.
5. **Trap Datetime Serialization:** Pydantic đôi khi không đọc được datetime ISO tùy biến.
   -> **FIX:** Lưu timestamp float (unix epoch) hoặc ISO cứng. Hàm utc_now() phải nhất quán ghi xuống TEXT ISO.

### 📜 AI Execution Workflow (Khuyên Dùng)
Đừng refactor tất cả các service cùng một lúc! Hãy làm theo Trình tự:
1. Code `init_db()` trong file `common/sqlite_client.py` chạy độc lập trước.
2. Viết xong `AuthService` và `MemoService` -> Chạy Server test Endpoint `POST /api/v1/memos` ngay lập tức!
3. Nếu thành công, mới bắt đầu code nối tiếp các Service nhỏ lẻ lại (Reactions, Comments, Inbox).
4. Data từ MongoDB cũ: Bỏ trắng, chúng ta làm fresh DB hoàn toàn để giảm nợ kỹ thuật.

### 🧪 Automated Testing Protocol (BẮT BUỘC CHO AI)
Trách nhiệm của AI không dừng lại ở việc viết code. Mày **PHẢI** tự động chạy Test để chứng minh code chạy được!
1. Quét kho tàng test cũ: Trong `backend/tests/` đã có sẵn các file như `test_memos.py`, `test_api_integration.py`. Đừng xóa chúng, hãy SỬA để chúng chạy với SQLite.
2. **Setup Test Database:** 
   - Đừng test đè lên `database/cuccu_note.db`. 
   - Hãy cấu hình SQLite để dùng `database/test.db` hoặc database trong RAM (`sqlite:///:memory:`) khi biến môi trường `ENV=test` được bật. Điểu chỉnh lại `conftest.py` tương ứng.
3. **Lện Chạy Tự Động:** AI bắt buộc phải gọi Terminal / Run Command lệnh sau để tự nghiệm thu:
   ```bash
   cd C:\canifa-idea\chatbot-canifa-feedback\miniapp\cuccu_note\backend
   .\.venv\Scripts\activate
   pytest tests/test_memos.py -v
   pytest tests/test_api_integration.py -v
   ```
4. Chỉ khi Pass **100%** Test thì mày (AI) mới được phép báo cáo là Task hoàn thành. Đóng ticket và dời file này vào thư mục `done/`.
