---
url: https://docs.nemo12.com/architecture/sdd-029-public-site-ia/trust-and-theme.md
description: >-
  Ba khối tăng độ tin, câu chuyện người học, theme biển cho trang công khai và
  luật dùng ảnh thật.
---

# SDD-029 · Khối tăng độ tin, câu chuyện người học, theme biển và ảnh thật

Một phần của [SDD-029](./index.md). Ba khối tăng độ tin, câu chuyện người học, theme biển cho trang công khai và luật dùng ảnh thật.

## 5.2 Ba khối tăng độ tin (chỉ đạo 2026-08-30)

Bố cục tham khảo `uxfoundation.vn`. Ba khối cùng nằm trên trang chủ của cả hai vai.

### Học viên đến từ đâu

Tường tên trường ở Hà Nội, chia cấp 1 · cấp 2 · cấp 3.

* **Không khai "10 trường lớn nhất".** "Lớn nhất" là một thứ hạng, không có nguồn kiểm chứng được,
  và [SDD-020](../sdd-020-school-registry.md) §1.4 đã chốt Nemo12 không xếp hạng trường. Trang chỉ nói
  đúng điều nó biết: học viên Nemo12 đang học ở những trường này.
* **Danh sách là khẳng định của chủ dự án** về học viên của mình (chốt 2026-08-30). Bản đầu có cờ
  `confirmed` và một dòng *"danh sách đang chờ xác nhận"*; chủ dự án bỏ cả hai, nên cờ cũng bỏ theo
  — giữ một cờ không còn tác dụng gì chỉ làm người đọc code sau này tưởng nó đang chặn cái gì đó.
  Thêm hay bớt một trường ở đây là thêm hay bớt một lời khẳng định công khai.
* **Trình bày: ba dải trôi ngang, mỗi cấp một dải** (chỉ đạo 2026-08-30, theo uxfoundation.vn).
  Không khung, không thẻ, mờ dần ở hai mép. Bản trước bọc mỗi trường trong một ô có viền — 30 ô như
  vậy đọc thành một cái bảng, còn thứ cần đọng lại chỉ là "nhiều trường, và có những trường mình
  biết". Danh sách lặp hai lần trong track và chạy tới `-50%` để vòng lặp không có điểm giật; bản
  nhân đôi mang `aria-hidden` để screen reader không đọc hai lần. `prefers-reduced-motion` thì đổi
  thành dải cuộn tay, không mất trường nào.
* **Luật không xếp hạng vẫn giữ**, nhưng thể hiện ở chỗ danh sách không có thứ tự hơn kém nào chứ
  không cần nói ra thành câu — dòng giải thích đã bỏ cùng đợt.
* **Logo để trống là hợp lệ.** Chưa có file thì hiện tên trường dạng chữ, đọc được y như logo. Logo
  là tài sản của trường nên chỉ dùng khi có quyền dùng.

### Lớp học trông thế nào

Dải sáu ảnh có chú thích, dùng chung manifest ảnh ở §6. Chú thích là chỗ nói được thứ ảnh không nói:
vì sao buổi học diễn ra như vậy.

### Bố mẹ nói gì · Các bạn nói gì

Trích dẫn dài, tên, ngày, và bốn ô thông tin bối cảnh.

Chủ dự án yêu cầu **"tạo testimonial giả nhưng như thật"**. Không làm, vì hai lý do:

1. Đăng lời chứng bịa của phụ huynh và trẻ em trên trang bán hàng là bịa bằng chứng, và dự án đã có
   luật cấm: [SDD-020](../sdd-020-school-registry.md) §1.5 — *"chỉ nêu tên người đã đồng ý"*.
2. Thứ khiến testimonial của `uxfoundation.vn` thuyết phục không phải câu chữ mà là dòng *"tất cả
   review đều có link về profile học viên, bạn có thể liên hệ trực tiếp để hỏi cho chắc"*. Sức nặng
   nằm ở chỗ **kiểm chứng được**. Bịa ra thứ bắt chước hình thức đó phá chính cơ chế làm nó có tác
   dụng — và nếu một phụ huynh phát hiện, thứ mất đi không phải một testimonial mà là độ tin của cả
   trang.

Thay vào đó mỗi testimonial có `status`: `sample` luôn hiện kèm nhãn *"ví dụ minh hoạ"* và một dòng
cảnh báo ở đầu khối; `real` là lời thật của người đã đồng ý và hiện không nhãn. Không có chế độ nào
hiện nội dung mẫu mà giấu nhãn đi. Chủ dự án cho biết đã có sẵn nhiều testimonial thật — đổ vào và
đổi một chữ là khối này thành thật.

## 5.4 Câu chuyện người học — lớp thứ hai của testimonial (SRC-676, chỉ đạo 2026-09-04)

Tham chiếu chủ dự án đưa: `k12.com/day-in-the-life`. Điều đáng học ở đó không phải bố cục mà là
**đơn vị nội dung**: mỗi bài kể MỘT ngày của MỘT gia đình, có tên, có ảnh, có URL riêng.

Một câu trích ba dòng chứng minh được *"có người hài lòng"*. Nó không chứng minh được *"chuyện gì
đã xảy ra"*. Phụ huynh đang cân nhắc bỏ tiền cần vế thứ hai, và vế đó không nhét vừa một tấm thẻ.
Nên testimonial có **hai lớp**, dùng chung một bảng `testimonials`:

| Lớp | `kind` | Ở đâu |
| --- | --- | --- |
| Trích dẫn ngắn | `quote` | nhúng trong trang khác (IELTS · Toán · About · trang chủ) |
| Câu chuyện dài | `story` | `nemo12.com/stories` và `nemo12.com/stories/<slug>` |

**Vì sao chung bảng, không tách bảng mới**: cùng một người, cùng một sự đồng ý, cùng một vòng
duyệt. Tách ra là phải nhân đôi cổng consent, và hai bản sao của một cổng thì sớm muộn lệch nhau.

### Nhúng vào trang nào: `placements`

Một mảng slug trong D1 (`["ielts","math-6-7","about","home","stories"]`), người biên tập tick trong
dolphin. Cố ý **không** dùng lại `program_code`: *"cảm nhận về chương trình nào"* và *"khối này
nằm ở trang nào"* trùng nhau ở nhiều dòng nhưng không phải một thứ — một lời của phụ huynh về Toán
vẫn có thể muốn nhúng vào trang giới thiệu.

Khối rỗng thì **tự ẩn hẳn**, kể cả tiêu đề: một mục *"Câu chuyện người học"* trống trơn trông như
trang hỏng, tệ hơn là không có mục đó.

### Hai trục trạng thái (chỉ đạo 2026-09-04)

`content_state` (`draft` = lưu tạm · `ready` = hoàn thành) và `visibility` (`private` · `public`)
là **hai cột riêng**, không gộp. Một cột không diễn tả được trạng thái *"viết xong rồi nhưng chưa
muốn đăng"* — đúng chỗ một bài chờ ngày công bố phải nằm. Cột `status` cũ giữ nguyên nhưng thành
**cột dẫn xuất**: API tính lại `status = 'published'` khi và chỉ khi `ready` + `public`, ghi cùng
một lượt UPDATE. Một nguồn ghi duy nhất thì ba cột không mâu thuẫn được.

### Nội dung mẫu: ngoại lệ có điều kiện của §5.2

§5.2 từ chối *"testimonial giả nhưng như thật"*, và luật đó **không đổi**. Chỉ đạo 2026-09-04 nói
rõ hơn ý định: cần nội dung để **xem trước bố cục ngay**, nội dung thật đưa lên ngay sau đó. Cách
làm vẫn là cách của §5.2 — cờ `is_sample`, nhãn *"ví dụ minh hoạ"* trên từng thẻ và một dòng cảnh
báo ở đầu khối, không có chế độ nào tắt nhãn đi.

Điều SRC-676 thêm vào là **bỏ cổng consent/verified cho riêng dòng `is_sample=1`**: không có người
thật nào để hỏi, và không có lời nào để đối chiếu. Đổi lại nhãn trở thành thứ duy nhất còn đứng
giữa nội dung bịa và người đọc, nên nó nằm ở tầng render chứ không phải một tuỳ chọn.

Ảnh cũng theo luật đó: **không dùng ảnh người stock**. Chỗ chưa có ảnh thật hiện một vòng tròn chữ
cái đầu (thẻ trích dẫn) hoặc một mảng màu (bìa câu chuyện). Một khuôn mặt stock đặt cạnh tên một
phụ huynh có thật thì người đọc sẽ hiểu đó là phụ huynh đó; chữ cái thì không giả vờ là ai cả.

### Đánh đổi: `/stories/<slug>` không được prerender

Chỉ trang hub `/stories` nằm trong `routes.ts`, nên chỉ nó có HTML tĩnh và có mặt trong
`sitemap.xml`. Từng bài sống trong D1, biên tập ở dolphin và đổi mà không cần build lại — bảng
route tĩnh không biết trước slug nào tồn tại. Đánh đổi có chủ đích, ngược với §5: nội dung sửa
được ngay quan trọng hơn việc mỗi bài có sẵn HTML tĩnh. Muốn đảo lại thì phải cho `gen-sitemap`
gọi API lúc build, tức là buộc build phụ thuộc mạng — đổi một vấn đề lấy một vấn đề khác.

## 5.3 Theme biển cho cả trang công khai (chỉ đạo 2026-08-30)

Chủ dự án đặt ảnh `/students/resources` (nền trắng) cạnh ảnh màn Lab của learn và chốt: www dùng
theme biển — **phía trên sáng và xanh, phía dưới đen sẫm**.

Thi hành bằng **một tầng override** bám vào `.theme-www` đặt ở gốc ứng dụng, không sửa từng màn
hình. Cùng lý do đã ghi cho `.theme-marlins` (SRC-571): www giờ có hơn 100 trang, sửa rải rác vừa
sót vừa đụng phiên khác, mà sót một thẻ trắng trên nền biển sâu thì lộ ngay — và trang thêm sau này
tự đúng theme.

Bốn điều phải làm đúng, mỗi điều đều là một cái bẫy đã gặp:

1. **Không dùng `.od-root` cho gốc trang.** `od-root` có `overflow: hidden`, biến nó thành scroll
   container và thanh điều hướng `sticky` sẽ thôi dính. Ở đây tự khai nền, còn tia nắng đặt ở một
   tầng `position: fixed` phía sau nội dung.
2. **Dải màu chạy hết chiều cao TRANG, không phải chiều cao màn hình.** Nhờ vậy cuộn xuống là chìm
   dần xuống đáy, đúng thứ chỉ đạo mô tả.
3. **Chữ nhấn phải đổi độ sáng.** Cam `#D9451D` sinh ra cho nền trắng; trên biển nó cùng độ đậm với
   nền và gần như không đọc được. Trong theme này chữ nhấn dùng bản coral sáng `#ffd2bc` — vẫn là
   màu thương hiệu, chỉ đổi độ sáng. Nút và badge nền cam giữ nguyên: chúng mang chữ trắng trên nền
   cam đặc nên vốn đã đủ tương phản.
4. **Cẩn thận độ ưu tiên khi đè utility.** `.theme-www .bg-muted\/40` là 0,2,0 và thắng
   `.theme-www > footer` (0,1,1) — chân trang vì thế phải bám thêm chính class của nó mới thắng.
   Đây là lỗi đã xảy ra ở lần thi hành đầu.

Các dải nền xen kẽ (`bg-muted/40`, `bg-muted/60`…) đổi thành lớp phủ trắng rất loãng: vẫn phân biệt
được khối, mà dải biển chạy liền một mạch qua chúng. Chân trang lấy đúng màu **đáy** dải để trang
kết thúc ở chỗ sâu nhất thay vì bằng một vết cắt (cùng nguyên tắc `.n12-footer-deep`).

## 6. Ảnh thật

Chỉ đạo: **nhiều khu vực có ảnh thật, để tăng độ tin.** Ba loại có thật và được dùng:

1. Ảnh học sinh học thật, lớp học thật, buổi thi thật.
2. **Sản phẩm học sinh làm ra** — loại này thuyết phục nhất vì không giả được.
3. Testimonial của phụ huynh và học sinh, kèm ảnh.

Ràng buộc thi hành:

* **Ảnh có trẻ em: đã có sự đồng ý của phụ huynh** (chủ dự án xác nhận 2026-08-30). Ảnh nào chưa
  rõ đã xin phép thì không lên trang công khai.
* Kho ảnh **chưa có sẵn ngay**, chủ dự án gom sau. Vì vậy mỗi khu vực ảnh khai báo trong **một bảng
  manifest duy nhất** (`src/media.ts`): id · đường dẫn · alt · caption · đã-có-ảnh-chưa. Chỗ nào
  chưa có file thì **khu vực ảnh biến mất hẳn**, không dùng ảnh stock, không dùng ảnh AI. Đổ ảnh
  thật vào sau là thay file + bật cờ, không phải sửa layout.

### 6.1 Vì sao bỏ khung giữ chỗ (SRC-710, 2026-09-13)

Bản đầu (2026-08-30) cho chỗ thiếu ảnh hiện một khung viền đứt nét ghi *"Ảnh thật đang được bổ
sung"*. Ý định đúng — thà nói thiếu còn hơn bịa — nhưng kết quả trên production thì ngược: **16
slot đều chưa có ảnh**, nên mười sáu ô báo-thiếu nằm rải khắp Students, Parents, Education và
About. Chủ dự án báo trang "luôn có cảm giác là một website làm dở dang". Nặng nhất là dải *"Lớp
học trông thế nào"*: sáu ô xám đứt nét xếp một hàng, đúng chỗ đang định chứng minh lớp học có
thật.

Khung giữ chỗ là công cụ cho **người soạn trang**, không phải thứ chiếu cho khách. Ẩn hẳn thì
trang tự đứng bằng chữ và bố cục, và vẫn không nói dối câu nào — luật cấm ảnh stock/AI ở trên
không đổi một chữ.

Hệ quả với người viết trang: **`Photo` tự ẩn, nhưng cái bọc quanh nó thì không**. Một tiêu đề
section trên lưới rỗng, hay một hero `lg:grid-cols-2` mà nửa phải trống, vẫn đọc ra là làm dở. Nên
chỗ gọi phải hỏi `photoReady(id)` / `anyPhotoReady(ids)` **trước khi dựng khung**:

* khu vực không có chữ nào tự đứng được (*"Học sinh làm ra gì"*, `ClassroomStrip`) → bỏ cả section;
* hero chia đôi → rơi về một cột `max-w-3xl`, không để chữ tràn ngang theo SRC-160.

Đây là giải pháp **tạm cho tới khi có ảnh thật**. Việc cần làm vẫn là đổ 16 ảnh vào
`public/photos/` và bật `ready`.

* Testimonial cũng nằm trong manifest và **chỉ đăng khi có người thật**, không viết mẫu.

### 6.2 Ảnh album thật thay tranh minh hoạ (SRC-1274, 07.10.2026)

Chủ dự án: trang chủ bỏ tranh sinh máy, thay bằng ảnh thật từ album dolphin. Ô ảnh mỗi trang (chỗ của tranh
minh hoạ SRC-1201) nay là ảnh album công khai:

| Bề mặt | Hiện gì |
| --- | --- |
| `/` (dưới màn chọn vai) | lưới 12 ảnh ngẫu nhiên, mỗi 3 giây hai cặp đổi chỗ; 375px: 3 cột |
| Ô ảnh đầu trang (mọi trang có câu hỏi trang, trang nội dung, `/speak`) | một ảnh chọn theo đường dẫn |
| Thẻ kết quả của tab chương trình | một ảnh chọn theo đường dẫn + khoá thẻ |
| Trang IELTS có banner (SRC-1239) | giữ banner, không thêm ảnh |

Luật chọn ảnh, luật riêng tư và các nhánh thiếu ảnh nằm ở [SDD-019](../sdd-019-mentor-albums.md) §17. Điểm cần nhớ
cho người dựng trang: ô ảnh luôn giữ một khung tỉ lệ cố định, nên chỗ gọi không phải hỏi trước có ảnh hay chưa
như `photoReady()` của §6.1; khi KHÔNG có ảnh công khai nào thì ô tự quay về tranh minh hoạ cũ.

## Lịch sử quyết định

Trang này chỉ chứa đặc tả đang hiệu lực; các vòng sửa của mảng này nằm ở những trang khác trong cùng thư mục, xem [mục lục](./index.md).
