Skip to content

Data Dictionary · Student Portrait ​

⚙️ Trang này sinh tự động từ source code bằng scripts/gen-reference.mjs — đừng sửa tay, sửa code rồi chạy npm run gen:reference.

Thuộc Data Dictionary. 7 bảng, external_activities tới portraits.

external_activities ​

migration: 0011_student_portrait.sql

CộtKiểuRàng buộc / ghi chú
idTEXTPRIMARY KEY
learner_idTEXTNOT NULL REFERENCES learners(id)
activityTEXTNOT NULL
categoryTEXT—
start_dateTEXT—
frequencyTEXT—
hours_per_weekREAL—
learner_interestINTEGERCHECK (learner_interest BETWEEN 1 AND 5), -- CHỈ learner sửa (REQ-POR-03)
parent_supportINTEGERCHECK (parent_support BETWEEN 1 AND 5), -- CHỈ parent sửa
importanceTEXT—
notesTEXT—
created_by_user_idTEXTNOT NULL
created_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
updated_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))

Khóa ngoại: learner_id → learners

Index: idx_external_activities_learner(learner_id)

milestones ​

migration: 0011_student_portrait.sql

CộtKiểuRàng buộc / ghi chú
idTEXTPRIMARY KEY
learner_idTEXTNOT NULL REFERENCES learners(id)
portrait_idTEXTREFERENCES portraits(id)
kindTEXTNOT NULL CHECK (kind IN ('exam','academic','capability','language','habit','portfolio','experience','personal'))
titleTEXTNOT NULL
target_valueTEXT—
target_dateTEXT—
expected_valueTEXT—
actual_resultTEXT—
statusTEXTNOT NULL DEFAULT 'planned' CHECK (status IN ('planned','in_progress','achieved','missed','rescheduled'))
confidenceREAL—
notesTEXT—
created_by_user_idTEXTNOT NULL
created_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
updated_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
track_idTEXTREFERENCES portrait_tracks(id) — thêm ở 0017_portrait_tracks.sql

Khóa ngoại: learner_id → learners · portrait_id → portraits

Index: idx_milestones_learner(learner_id, target_date) · idx_milestones_track(track_id, target_date)

portrait_learner_sections ​

Bản của CON trong Student Portrait (SRC-106, chủ dự án 2026-08-14): mỗi mục lớn có hai cột — cột bố mẹ viết (portraits.sections_json, đã có) và cột con tự viết (bảng này). Tên mục lớn dùng chung để hai bên nói cùng một chuyện, nội dung thì mỗi bên một cột. Nemo có tiếng nói bằng CHÍNH LỜI của mình, không chỉ bấm đồng ý / không đồng ý (SDD-015 §1).

migration: 0029_portrait_learner_sections.sql

CộtKiểuRàng buộc / ghi chú
portrait_idTEXTNOT NULL REFERENCES portraits(id)
section_keyTEXTNOT NULL
items_jsonTEXTNOT NULL DEFAULT '[]'
updated_by_user_idTEXT—
updated_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
—table constraintPRIMARY KEY (portrait_id, section_key)

Khóa ngoại: portrait_id → portraits

Index: idx_portrait_learner_sections(portrait_id)

portrait_reactions ​

migration: 0011_student_portrait.sql

CộtKiểuRàng buộc / ghi chú
portrait_idTEXTNOT NULL REFERENCES portraits(id)
section_keyTEXTNOT NULL DEFAULT '_portrait'
user_idTEXTNOT NULL REFERENCES users(id)
roleTEXTNOT NULL
reactionTEXTNOT NULL CHECK (reaction IN ('agree','unsure','disagree'))
created_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
—table constraintPRIMARY KEY (portrait_id, section_key, user_id)

Khóa ngoại: portrait_id → portraits · user_id → users

portrait_tracks ​

Migration 0017 — Portrait Track (lộ trình dài hạn, vai trò như EPIC trong Jira). SDD-015, REQ-POR-02. Track = thứ chạy xuyên suốt nhiều năm (IELTS, SAT, nền tảng Toán, portfolio...); milestone là các mốc NẰM TRÊN track (thi thử mỗi 6 tháng, thi thật, sản phẩm nộp). portrait_id NULL = track xuyên suốt mọi hướng đi, không thuộc riêng portrait nào.

migration: 0017_portrait_tracks.sql

CộtKiểuRàng buộc / ghi chú
idTEXTPRIMARY KEY
learner_idTEXTNOT NULL REFERENCES learners(id)
portrait_idTEXTREFERENCES portraits(id)
nameTEXTNOT NULL
kindTEXTNOT NULL CHECK (kind IN ('exam','academic','capability','language','habit','portfolio','experience','personal'))
descriptionTEXT—
iconTEXT—
start_dateTEXT—
end_dateTEXT—
cadenceTEXT, -- nhịp lặp, vd "thi thử mỗi 6 tháng"
baseline_valueTEXT, -- điểm/mức xuất phát
target_valueTEXT, -- đích cuối của cả track
statusTEXTNOT NULL DEFAULT 'active' CHECK (status IN ('planned','active','paused','done','dropped'))
sort_orderINTEGERNOT NULL DEFAULT 0
created_by_user_idTEXTNOT NULL
created_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
updated_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))

Khóa ngoại: learner_id → learners · portrait_id → portraits

Index: idx_portrait_tracks_learner(learner_id, status)

portrait_versions ​

migration: 0011_student_portrait.sql

CộtKiểuRàng buộc / ghi chú
idTEXTPRIMARY KEY
portrait_idTEXTNOT NULL REFERENCES portraits(id)
versionINTEGERNOT NULL
snapshot_jsonTEXTNOT NULL
changed_by_user_idTEXTNOT NULL
created_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))

Khóa ngoại: portrait_id → portraits

Index: idx_portrait_versions(portrait_id, version)

portraits ​

Migration 0011 — Student Portrait & Family Future Planning. SDD-015, REQ-POR-01..05 (SRC-040). Comments dùng bảng interactions có sẵn (target_type='portrait'). Idempotent (QG-004).

migration: 0011_student_portrait.sql

CộtKiểuRàng buộc / ghi chú
idTEXTPRIMARY KEY
learner_idTEXTNOT NULL REFERENCES learners(id)
created_by_user_idTEXTNOT NULL REFERENCES users(id)
nameTEXTNOT NULL
descriptionTEXT—
target_ageINTEGER—
target_dateTEXT—
coverTEXT, -- emoji/màu (ảnh chờ media pipeline — SDD-015 §7)
sections_jsonTEXTNOT NULL DEFAULT '{}'
notesTEXT—
statusTEXTNOT NULL DEFAULT 'active' CHECK (status IN ('active','archived'))
versionINTEGERNOT NULL DEFAULT 1
created_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
updated_atTEXTNOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))

Khóa ngoại: learner_id → learners · created_by_user_id → users

Index: idx_portraits_learner(learner_id, status)