---
url: https://docs.nemo12.com/architecture/sdd-015-student-portrait.md
description: >-
  Student Portrait (SDD-015): chân dung tương lai của learner, phiên bản, cột
  mốc, và nguyên tắc để Marlin và Nemo cùng thảo luận.
---

# SDD-015 — Student Portrait & Family Future Planning

Không gian để Marlin và Nemo **cùng tạo, quan sát và thảo luận** về chân dung tương lai. Learner Model trả lời "learner hiện tại là ai" (SDD-002 §2); **Student Portrait trả lời "chúng ta mong learner trở thành người như thế nào"** — một *shared future model* để cả nhà nhìn thấy, tranh luận, điều chỉnh; không phải "bố mẹ lập kế hoạch cuộc đời cho con".

## 1. Nguyên tắc (core rules — SRC-040 §13)

1. Mỗi Parent tối đa **3 active Portraits / learner** (3 scenario để compare → discuss → refine, không ép chọn một).
2. **Nemo luôn xem được** Portrait về mình, và có quyền phản hồi từng phần.
3. **Preference của parent và learner lưu riêng** — cấm tự merge thành một giá trị ("Chinese: learner 2/5, parent 5/5" phải hiển thị đúng như vậy).
4. Thay đổi quan trọng có **version history**; archive được, **không hard-delete** lịch sử.
5. Portrait là **aspiration input** — không override Recommendation Engine; Recommendation vẫn xét Learner Model + Context + Constraints + workload thực tế.
6. External activities là một phần của **learner context**.
7. Conflict parent ↔ learner phải được **surface**, không tự động "resolve" (khớp Q-099: escalate cho gia đình).
8. Portrait **evolve theo thời gian** — cập nhật khi quan điểm/hoàn cảnh đổi.

## 2. Portrait & versions (REQ-POR-01)

```text
portraits: id, learner_id, created_by_user_id, name, description,
  target_age?, target_date?, cover (emoji/màu; ảnh — §7),
  sections_json {academic_goals[], capabilities[], interests[], languages[], sports[],
                 creative[], personal_development[], lifestyle[], experiences[], career[]},
  notes, status[active|archived], version, created_at, updated_at
portrait_versions: id, portrait_id, version, snapshot_json, changed_by_user_id, created_at
```

* Ràng buộc ≤3 active per (parent, learner) enforce ở API; archive giữ nguyên bản ghi + versions.
* Mỗi lần sửa nội dung → snapshot version mới (edit history đọc được).
* Ví dụ scenario: *Academic Excellence* · *Balanced Explorer* (IELTS 8.0, HSK 4, guitar điện, một môn thể thao, portfolio, tự quản lý việc học) · *Independent Builder*.

### 2b. Bản của con — hai cột trong một mục (REQ-POR-09, SRC-106)

Portrait ban đầu chỉ có **một giọng**: bố mẹ viết, con bấm agree/unsure/disagree. Chỉ đạo 2026-08-14: mỗi mục lớn phải có **hai cột** — bản bố mẹ (`portraits.sections_json`) và **bản của chính con** (`portrait_learner_sections`, migration 0029, khoá `(portrait_id, section_key)`, `items_json` mảng chuỗi). **Tên mục lớn dùng chung** để hai bên nói về cùng một chuyện.

* `PUT /v1/portraits/{id}/learner-sections {section_key, items[]}` — **chỉ role `learner` được ghi** (bố mẹ đọc được qua bundle nhưng không viết hộ; viết hộ thì cột đó hết là tiếng nói của con).
* Bundle trả thêm `learner_sections`; query bọc try/catch vì migration chạy tay, thiếu bảng thì trang vẫn mở.
* UI learn: cột trái nền sand "Bố mẹ viết", cột phải nền seafoam "Con viết" (textarea mỗi dòng một ý, tự lưu khi rời ô). Con thêm được mục bố mẹ bỏ trống qua ô "Thêm mục con muốn nói".
* Phản hồi agree/unsure/disagree rút thành **icon đặt ngay dưới từng mục** (nhãn giữ ở `title`/`aria-label`).

### 2c. Hải đăng · Lighthouse — nơi ba thứ đường dài gặp nhau (REQ-LRN-19, SRC-113)

Student Portrait, Lộ trình dài hạn và Learning Plan từng là ba card rời trên trang gốc, nên không ai thấy chúng liên quan tới nhau. Gom lại thành **một mảng "Hải đăng"** (tiếng Anh: Lighthouse — giữ mạch hàng hải của Nemo12):

| Phần | Trả lời câu hỏi | Trang |
| --- | --- | --- |
| Student Portrait | con muốn thành người thế nào — **ĐÍCH** | `/student-portrait` |
| Lộ trình dài hạn | đi tới đó bằng đường nào — **ĐƯỜNG** | `/roadmap` |
| Kế hoạch học | tuần này làm gì để tiến — **BƯỚC ĐI** ([SDD-007 §6b](sdd-007-learner-orchestration.md)) | `/plan` |

Tên hiển thị là **Lighthouse** (SRC-120, bỏ chữ "Hải đăng" trên UI); nút Lighthouse nằm thẳng trên **navbar** của learn vì đây là chỗ learner quay lại thường xuyên để khai thêm.

**Khai đủ tới đâu, mở school tới đó** (REQ-LRN-21 — SRC-120): trang gốc không mở toang mọi school nữa. `GET /v1/learners/{id}/lighthouse` đọc **dữ liệu thật** (không có cờ "đã onboard" tự khai) và trả 5 bước:

| Bước | Đọc từ | Vào đâu để khai |
| --- | --- | --- |
| Hồ sơ của con (lớp) | `learners.grade` | Hồ sơ |
| Nói con nghĩ gì về Portrait | `portrait_reactions` role=learner | Student Portrait |
| Viết bản của riêng con | `portrait_learner_sections` khác `[]` | Student Portrait |
| Khai quỹ thời gian | `learner_context_events` kind=`time_budget` | Kế hoạch học |
| Có ít nhất một mục tiêu | `learner_goal_entries` active | Kế hoạch học |

School mở = **đúng số bước đã khai**: chưa khai gì thì **khoá hết** (chỉ đạo 2026-08-15) — hệ thống chưa biết learner là ai thì mở school ra cũng không xếp việc học cho đúng được. Khai **thông tin cá nhân** → mở **Turtle School**; mỗi bước sau mở thêm một trường; khai đủ 5/5 thì mở hết (5 bước / 6 thẻ nên bước cuối mở nốt hai thẻ còn lại). Thứ tự thẻ cố định theo `SCHOOLS` để "trường đầu tiên" luôn là Turtle. Hai ngoại lệ có chủ ý: **school đã enroll không bao giờ bị khoá lại**, và **API lỗi thì mở hết** — không chặn learner vì lỗi kỹ thuật.

Bước đầu (thông tin cá nhân) khai **ngay trong trang Lighthouse**, không bắt learner nhảy sang trang hồ sơ rồi tự tìm đường quay lại. Thẻ khoá vẫn hiện mascot (xám + ổ khoá) kèm câu "Khai thêm trong Lighthouse để mở" — khoá mà không nói lý do thì learner chỉ thấy bị chặn.

Hub `/lighthouse` (Marlins: `#/child/{id}/lighthouse`) **giới thiệu từng phần trước khi vào**: là gì, và "vào đó con/bạn làm gì" — chỉ đạo 2026-08-15, vì learner lẫn bố mẹ mở ra không tự hiểu ba thứ này khác nhau chỗ nào. Ba trang con **giữ nguyên URL riêng** (link đã chia sẻ không gãy), chỉ đổi breadcrumb thành `/ Hải đăng · <tên>` và nút quay lại trỏ về hub.

## 3. Milestones (REQ-POR-02)

Entity **độc lập**, liên kết Portrait (không bắt buộc):

```text
milestones: id, learner_id, portrait_id?, kind[exam|academic|capability|language|habit|
  portfolio|experience|personal], title, target_value?, target_date?, expected_value?,
  actual_result?, status[planned|in_progress|achieved|missed|rescheduled],
  confidence?, notes, created_by_user_id, created_at, updated_at
```

Ví dụ chuỗi IELTS: 09/2026 Diagnostic 5.5 → 01/2027 Attempt #1 target 6.5 → 06/2027 #2 7.0 → 12/2027 #3 7.5+. Milestone kind `exam` với target/ngày cụ thể có thể map vào exam target (SDD-011 §2b/§7) và Readiness target (SDD-002 §17) khi gia đình chốt.

## 4. External Activities & preferences (REQ-POR-03)

Hoạt động Nemo12 không trực tiếp quan sát (guitar, ukulele, đá bóng, tiếng Trung, chess, coding, art):

```text
external_activities: id, learner_id, activity, category, start_date?, frequency?,
  hours_per_week?, learner_interest? (1-5, CHỈ learner sửa), parent_support? (1-5, CHỈ parent sửa),
  importance?, notes, created_by_user_id, created_at, updated_at
```

* Hai cột preference **tách biệt theo người khai** — API enforce theo role; hiển thị song song.
* Là input cho Context (workload ngoài hệ — SDD-007 §8 committed_time) và cho Alignment (§6).

## 5. Family collaboration (REQ-POR-04, REQ-POR-08)

* **Comment/reply**: dùng Interaction System có sẵn (SDD-005, bảng `interactions`) với `target_type='portrait'` (+ `section_key` trong target_id dạng `portrait:<id>:<section>` khi comment vào từng goal/milestone/activity), `visibility='learner_parent'`, moderation chuẩn K12.
* **Reactions của Nemo**: `agree | unsure | disagree` per portrait và per section (`portrait_reactions {portrait_id, section_key?, user_id, role, reaction}`); Marlin vote/react tương tự.
* Learner participation là mục tiêu sản phẩm chính (metric: % Portrait có phản hồi của Nemo).
* **Trình bày phía learn** (SRC-087 → SRC-101): danh sách portrait là các card **chỉ có tên**, 3 card một hàng; mỗi portrait mở ra **trang riêng có URL riêng** (`/student-portrait/{id}`), lộ trình dài hạn tách hẳn sang `/roadmap` (full-width, xem theo quý / năm / 5 năm). Nút phản hồi bỏ emoji 👍/👎 — dùng nút chữ có chấm màu trạng thái (xanh · vàng · coral) cho đỡ thô và đồng bộ bảng màu DS-001; cụm **thảo luận với bố mẹ tách thành khối riêng**, không trộn vào khối đọc kỳ vọng.

## 6. Alignment (REQ-POR-05)

So mức độ đồng thuận giữa **parent aspiration ↔ learner aspiration ↔ current reality**:

* Per dimension (section/activity/milestone): parent_support vs learner_interest (external activities), reaction agree/unsure/disagree (sections), actual vs expected (milestones ↔ Learner Model/readiness khi map được).
* Hiển thị `High / Medium / Low Alignment` + bảng per-dimension (Dad/Mom/Learner). **Không phán xét ai đúng** — mục đích: chỉ ra chủ đề gia đình *cần trao đổi thêm*; low alignment → gợi ý mở thảo luận, không auto-resolve.

## 7. Photos (REQ-POR-06)

* Ảnh (avatar, portrait cover, timeline, family memory) đi qua Media System (SDD-009: R2 + moderation trước khi hiển thị, QG-008 child-safety). v1 chưa mở upload — cover dùng emoji/màu; bật khi media pipeline sẵn.
* **CẤM suy luận từ ảnh** các đặc điểm (trí tuệ, tính cách, trạng thái tâm lý, năng lực học) — ảnh không bao giờ là evidence (SDD-002 §5, QG-010).

## 8. Tích hợp models & engines (REQ-POR-07)

```text
Student Portrait → Goals/Aspirations → Milestones → Planning Engine → Recommendation Engine
```

* Portrait **không** tự sinh Goal: khi gia đình chốt một phần (đủ đồng thuận), phần đó mới thành Goal entry (SDD-002 §16, source='family_portrait') / exam target / Readiness target — có confirm, không âm thầm.
* **Planning Engine** (SDD-007 §9, Phase 2): từ Portrait + Learner Model + Context + Constraints → đề xuất milestone hợp lý, phát hiện milestone **phi thực tế** (IELTS 8.0 trước 06/2027 khi hiện tại 5.0 + sắp thi học kỳ + stress cao → giữ aspiration, điều chỉnh intermediate milestones), phân bổ theo thời gian, phát hiện conflict, đề xuất reschedule, tính khoảng cách tới Portrait.
* **Recommendation Engine** xét Portrait như **một** input cạnh Learner Model, Context, Evidence, External Activities, preferences (2 phía), Milestones, Constraints — Portrait không phải absolute instruction (rule 5).

## Trace

| REQ | Section |
| --- | --- |
| REQ-POR-01 (Portrait ≤3, versions, archive) | §2 |
| REQ-POR-09 (Hai cột: bản bố mẹ + bản của con) | §2b |
| REQ-LRN-19 (Mảng Lighthouse) | §2c |
| REQ-LRN-21 (Mở school theo mức khai báo) | §2c |
| REQ-POR-02 (Milestones) | §3 |
| REQ-POR-03 (External activities, preference riêng) | §4 |
| REQ-POR-04 (Collaboration) | §5 |
| REQ-POR-05 (Alignment) | §6 |
| REQ-POR-06 (Photos, cấm inference) | §7 |
| REQ-POR-07 (Aspiration input, Planning Engine) | §8 |
| REQ-POR-08 (Learner luôn xem + phản hồi) | §1, §5 |

Liên quan: SDD-002 §16-17 (Goal/Readiness) · SDD-005 (interactions) · SDD-007 §8-9 (workload/Planning) · SDD-009 (media) · SDD-011 §2b/§7 (exam targets) · SRC-032 (Goal Model), Q-099.
