Skip to content

SDD-024 — Dory ​

Never forget the family. Thiết kế kỹ thuật cho PRD-003 phần Dory.

Dory dựng trên SDD-023, không thay thế nó: families, family_contacts, learners, family_photos giữ nguyên. Dory thêm đúng phần còn thiếu — sự kiện có cấu trúc và niềm tin có nguồn.

1. Nguyên tắc ​

  1. Ghi phải nhanh hơn nhớ. Nếu ghi lại một cuộc gọi mất hơn một phút thì Dolphin sẽ không ghi, và mọi thứ phía sau sụp theo. Interaction Capture vì thế chỉ có ba ô bắt buộc (§4).
  2. Mọi niềm tin đều có nguồn. Không có mẩu thông tin nào trong Dory tồn tại mà không trả lời được "do đâu mà biết" — xem ba tag fact/opinion/hypothesis ở §2.
  3. Suy luận không bao giờ mặc áo của lời khai. Giao diện hiển thị tầng ngay cạnh nội dung, không gộp.
  4. Timeline là một dòng duy nhất. Ghi chú, cuộc gọi, milestone, case đóng — tất cả cùng một dòng thời gian. Ba tab riêng cho ba loại sự kiện nghĩa là không ai dựng lại được câu chuyện.
  5. Không đẻ ra bảng note thứ hai. Ghi chú vẫn là interactions với target_type='family' (Q-145).

2. Dữ liệu — MỘT bảng, và mọi thứ khác là tag ​

Chỉ đạo chủ dự án 2026-08-26: "Ưu tiên notes, mỗi note có thể gắn zero tag, 1 tag, hay nhiều tag… Chỉ có đúng 1 tầng reply." Bản phác đầu của mục này có năm bảng và hơn ba mươi cột; nó đã bị thay. Lý do đầy đủ và phần rà soát các hệ tương tự: family-notes-review §10c-10f.

text
family_notes   id · family_id · body · tags_json
               · learner_id? → learners
               · contact_id? → family_contacts    -- SRC-620, migration 0160
               · reply_to_id? → family_notes      -- CHỈ trỏ tới note gốc
               · author_user_id → users · created_at · status(active|archived)

Không có family_visits. Một buổi thăm nhà là một note gắn event. Bảng thứ hai chỉ đáng tồn tại khi có truy vấn riêng cho nó, mà hiện không có; cần thống kê theo buổi thì dựng lại từ note gắn event, không mất dữ liệu nào.

Không có family_context_items, không có family_signals. Tất cả là tag.

Mười hai tag, bốn trục, một danh sách phẳng ​

TrụcTag
Nói về aiparent · child
Loại nội dungpain · jtbd · need · belief · event · goal
Mức chắc chắnfact · opinion · hypothesis
Độ nổikey — thứ nên đọc trước; thi hành Q11 ("Lưu ý cho Mentor" hiện đầu tiên)

need và belief là lần mở rộng đầu tiên của danh sách đóng (SRC-620), và có lý do cụ thể chứ không phải "cho đủ bộ": hồ sơ một người (SDD-023 §15.2) hiện bốn danh sách mà Dolphin đọc trước khi gặp gia đình — pain · jtbd · need · belief. Thiếu hai tag này thì hai trong bốn cột vĩnh viễn trống.

  • need khác pain: pain là chỗ đang đau, need là thứ phải có mới hết đau — và cùng một pain thường ra vài need khác nhau, đó chính là chỗ Dolphin chọn việc để làm.
  • belief khác opinion: opinion nói về độ chắc chắn của chính ghi chú (ai đó nghĩ vậy, chưa kiểm), còn belief nói nội dung là một niềm tin của gia đình — "học thêm mới giỏi được" có thể đồng thời là belief và fact (đã xác minh rằng họ tin như vậy).

Bộ nhãn của prompt dory.suggest-tags lên v2 cùng đợt: cùng một note nay nhận đề xuất khác trước, nên bảng đo tỉ lệ chấp nhận phải so được cùng bản.

Ba mức chắc chắn map gần như một-một vào S/O/A của bệnh án SOAP — một khuôn ngành y đã dùng từ những năm 1960 (§10e.1). Đó là bằng chứng cách chia này đúng chứ không phải một tầng trừu tượng thừa.

Danh sách đóng ở đợt đầu, không cho gõ tag mới. Không có nhóm loại trừ: gắn cả fact lẫn hypothesis vẫn được, hệ chỉ nhắc nhẹ và để nút gợi ý AI đề nghị bỏ bớt. Chặn cứng là quay lại làm biểu mẫu.

Reply đúng một tầng ​

reply_to_id chỉ trỏ tới note gốc; API từ chối reply vào một reply. Bất biến rẻ nhất có thể kiểm: note được trỏ tới phải có reply_to_id IS NULL.

Đây là lựa chọn của Slack, và có lý do: diễn đàn cho lồng vô hạn thì một câu quan trọng nằm ở tầng bảy coi như đã mất. Một tầng đủ cho bổ sung · đính chính · kết luận; cần sâu hơn thì tạo note gốc mới.

Ba thứ có được mà không tốn cột nào ​

  1. Hộp vào không còn là khái niệm riêng. Note zero tag chính là inbox. Phân loại = gắn tag.
  2. Chuỗi giả thuyết — hypothesis → tiêu chí kiểm chứng → kết luận, mỗi bước là một reply. Không cần bảng nào.
  3. Mục bắt buộc thành tín hiệu thay vì rào chắn — hệ nhìn cả nhà và nói "nhà này chưa có note nào gắn goal", không chặn người đang ghi vội.

Hồ sơ sống là thứ DẪN XUẤT, không có nút Sửa ​

Family Model (reference) dựng từ các note đã gắn tag và không sửa tay được. Muốn đổi thì ghi thêm note mới. Có nút sửa nghĩa là có một câu trong hồ sơ không có note nào đỡ lưng — đúng thứ phương án C (Q1) được chọn để tránh.

3. Family 360 (REQ-DOR-01) ​

Một truy vấn: lấy mọi note đang active của nhà đó, rồi gom theo tag. Không có bảng nào khác để join.

Thứ tự khối trên màn hình cố định, theo thứ tự câu hỏi một Dolphin thật sự hỏi khi mở một nhà:

#KhốiLấy từ
1Đọc trướcnote gắn key
2Aicontacts + learners (SDD-023 §3)
3Đang lo gìnote gắn pain
4Đang nợ gìcommitments đang mở (Anchor)
5Gần đây10 note mới nhất, bất kể tag
6Muốn gìnote gắn goal · jtbd
7Chưa phân loạinote zero tag — chỉ hiện con số, bấm vào mới mở

Khối 1 đứng đầu là cách thi hành Q11 ("Lưu ý cho Mentor" hiện đầu tiên). Khối 7 chỉ hiện con số vì nội dung chưa phân loại mà trộn vào các khối trên thì phá luôn ý nghĩa của việc phân loại.

Goals xuống gần cuối là có chủ đích: mục tiêu ít đổi, còn "đang lo gì" và "đang nợ gì" đổi từng tuần và là thứ quyết định cuộc gọi hôm nay.

4. Ghi nhanh (REQ-DOR-03) ​

Một ô. Zero tag cũng lưu được. Đây là toàn bộ luồng ghi.

Ngưỡng thiết kế: dưới 30 giây — dán cả một bài viết sau buổi thăm nhà vào cũng được. Không có trình soạn thảo giàu định dạng, không bắt chọn learner, không bắt chọn tag.

Gắn tag là một bước riêng, làm sau, và làm bởi bất kỳ ai (§6). Đây là chỗ mô hình này khác hẳn một biểu mẫu: người ghi không phải quyết định phân loại đúng lúc họ vừa đi thăm nhà về và chỉ muốn ghi cho kịp.

Reply đúng một tầng. reply_to_id chỉ trỏ tới note gốc; API từ chối reply vào một reply. Bổ sung · đính chính · kết luận cho một giả thuyết đều là reply. Cần sâu hơn thì tạo note gốc mới.

Không có cột visibility. Ghi chú gia đình là nội bộ đội Dolphin, đúng như Q42 đã chốt (chưa làm cờ khoá). Thêm một cột quyền cho một luật chưa tồn tại là thêm một cột sẽ để sai.

5. Tín hiệu (REQ-DOR-05) — luật, không phải bảng ​

Luật chạy trên family_notes và trả kết quả tại chỗ. Không có bảng family_signals: một bảng như thế sẽ đầy những hàng lặp lại mỗi lần cron chạy.

Tín hiệuLuật
no_notesnhà có learner đang học mà không có note nào
missing_goalkhông có note nào gắn goal
untagged_pileuptừ 10 note zero tag trở lên
open_hypothesisnote gắn hypothesis quá 30 ngày mà chưa có reply nào
silent_familykhông có note mới trong 45 ngày
unclaimed_familykhông Dolphin nào đang chăm (SDD-023 §11)

Mỗi tín hiệu luôn kèm câu giải thích vì sao nó bật. Một cảnh báo không nói được lý do thì người nhận chỉ có hai lựa chọn: tin mù, hoặc tắt đi.

Bỏ qua một tín hiệu thì ghi một note gắn event nói rõ đã bỏ qua — không cần bảng trạng thái riêng.

6. Gắn tag bằng AI (REQ-DOR-04) ​

POST /v1/mentor/notes/{id}/suggest-tags → Workers AI qua gateway nemo12:

json
{ "add":    [{ "tag": "pain", "why": "..." }],
  "remove": [{ "tag": "fact", "why": "note này đang phỏng đoán, không phải quan sát" }] }

Bốn ràng buộc, rút từ bài học của các hệ đã chạy AI gắn nhãn ở quy mô thật (review §10e.4):

  1. Chỉ chọn trong mười tag, không bao giờ bịa tag mới. Tag lạ do mô hình trả về bị loại bỏ ở server, không hiện ra cho người dùng.
  2. Mỗi đề xuất kèm một câu lý do.
  3. Người bấm từng cái. Có nút áp dụng tất cả, nhưng không bao giờ tự áp.
  4. Ghi lại tỉ lệ chấp nhận. Một tag bị từ chối quá nửa số lần thì định nghĩa tag đó sai hoặc prompt sai, không phải người dùng sai.

Chỉ gửi thân note đang xét. Không gửi hồ sơ gia đình, không gửi note của nhà khác, không gửi dữ liệu học của con. Workers AI chạy trong hạ tầng Cloudflare nên dữ liệu không rời nhà cung cấp, nhưng đây vẫn là lần đầu văn bản về một gia đình đi vào một mô hình — nên phạm vi gửi là thứ phải hẹp nhất có thể ngay từ đầu.

Agent kiểm thêm một quy ước không tốn tag nào: note gắn opinion mà chưa nói rõ ý kiến của ai thì nhắc (review §10f).

7. API ​

MethodPathQuyền
GET/v1/mentor/families/{id}/notes🔐 role mentor
POST/v1/mentor/families/{id}/notes🔐 role mentor
PATCH/v1/mentor/notes/{id}🔐 role mentor
POST/v1/mentor/notes/{id}/suggest-tags🔐 role mentor

Bốn endpoint, hết. GET nhận tags (danh sách), match=any|all (mặc định any), untagged=1, và person=contact:<id>|learner:<id> (SRC-620).

match sửa một lỗi im lặng (SRC-620): trước đây GET luôn lọc AND, nên bộ lọc "Goals and motivation" (goal + jtbd) chỉ khớp ghi chú mang cả hai — trên dữ liệu thật là gần như không ghi chú nào. Bộ lọc trông vẫn chạy, chỉ là luôn trả rỗng, nên không ai báo hỏng. Mọi bộ lọc gộp nhiều tag ở đầu trang đều mang nghĩa "hoặc". Không có DELETE: lưu trữ là PATCH status='archived'.

Mọi lượt đọc một nhà ghi audit_log như SDD-023 §8. Giao diện tiếng Anh theo REQ-MEN-16.

8. Cái chưa làm ​

ViệcVì sao
AI viết Relationship Summary tự doCần truy vết từng câu về bản ghi; xem §6
Đồng bộ Zalo/email tự động vào timelineCần quyền truy cập hộp thư của Dolphin, là một quyết định riêng
Gợi ý "nên nói gì với nhà này"Vượt ranh giới: Dory kể cái đã biết, không viết kịch bản hộ
Gia đình tự xem timeline của mìnhNội bộ đã, mở cho gia đình là một đợt có ràng buộc riêng tư riêng

Trace ​

REQ-DOR-01→§3, SDD-023 §15.2 · REQ-DOR-02→§2, §7 · REQ-DOR-03→§4 · REQ-DOR-04→§2, family-model §3 · REQ-DOR-05→§5 · REQ-DOR-06→§6.