# Bàn giao prototype Nhật ký ăn uống

Ngày bàn giao source: 03/11/2026. Hướng đã duyệt: Material nhẹ, Roboto nhất quán, nút nền `#F8CFE0`, chữ/icon `#8F345B`. Đây là prototype HTML chỉnh sửa được, chưa phải ứng dụng native production.

**Cập nhật hiện hành theo OPEN-DESIGN-BRIEF.md — R18–R22:** Tổng quan dị ứng, chart Chi tiêu, cụm ngày Nhật ký và Giao diện đã được viết trong source. Giữ Material nhẹ/Roboto local; mặc định Theo hệ thống và màu hồng. Đây là cập nhật mở rộng, thay các giới hạn cũ về biểu đồ/dark mode. Xem mục “Cập nhật theo brief — R18–R22” cuối tài liệu. V27–V40: **Chưa kiểm tra**.

**Lịch sử cập nhật SCR-06 theo UX/R09 ngày 03/11/2026:** Chi tiêu có bốn kỳ Ngày / Tháng / Năm / Tùy chọn, mặc định tháng hiện tại. Phần cập nhật này thay mô tả Chi tiêu chỉ ngày/tháng của lượt bàn giao trước. Các chức năng khác giữ nguyên. Trạng thái V07–V08 và V23–V26 của bản cập nhật: **Chưa kiểm tra**.

## Mở và chỉnh sửa

Mở **[index.html](index.html)** trong Open Design hoặc trình duyệt hiện đại, bật JavaScript. Không cần cài package hoặc build. Giữ nguyên các file tương đối bên cạnh entry. Với trình duyệt chặn lưu trữ hoặc clipboard khi mở file trực tiếp, dùng preview HTTP của môi trường; app báo lỗi adapter thay vì tuyên bố đã lưu/sao chép thành công.

| File | Vai trò |
| --- | --- |
| [index.html](index.html) | Entry chính duy nhất; một handset, layout primitives và dữ liệu mẫu khởi tạo |
| [app.css](app.css) | Token Material, typography, component, responsive và safe area |
| [core.js](core.js) | Hợp đồng dữ liệu, ngày/giờ, tổng tiền, report, validator backup và repository trình duyệt |
| [spending.js](spending.js) | R09/SCR-06: resolve kỳ inclusive, tổng/nhóm từ cùng kết quả, bộ chọn kỳ và picker có bản nháp riêng |
| [chart-data.js](chart-data.js) | Snapshot chart theo revision dữ liệu; Gregorian date-only, bucket lazy, chất lượng giá và drill-down |
| [insights.js](insights.js) | SCR-12/13/14, chart/table, lịch, cửa sổ và chi tiết |
| [appearance.js](appearance.js) | SCR-15, token Sáng/Tối, màu nhấn và kho tùy chọn riêng |
| [insights.css](insights.css) | Bố cục chart, calendar, cụm ngày gọn, Giao diện và trạng thái semantic |
| [app.js](app.js) | Màn hình, điều hướng, form, dialog, clipboard/file/share adapter |
| [Roboto](assets/fonts/roboto.ttf) / [OFL](assets/fonts/roboto-OFL.txt) | Font variable cục bộ và giấy phép |
| [Fixtures](fixtures/README.md) | Bản sao đầu vào để đối chiếu và thử thủ công sau bàn giao |

Source tiếp tục chỉnh sửa được bằng HTML/CSS/JavaScript; không bị đóng thành ảnh. Token kiểu chữ, spacing và motion tập trung trong `app.css`; màu semantic Sáng/Tối và màu nhấn được áp dụng từ `appearance.js`, bố cục mới trong `insights.css`. Khung iPhone tiếp tục từ bản Material đã duyệt; khung chỉ phục vụ trình bày, không phải tuyên bố app chạy iOS.

## Đã triển khai trong source

Các mục dưới đây mô tả mã đã viết, **không phải kết quả kiểm thử chạy app**.

| Yêu cầu | Màn và luồng đã viết |
| --- | --- |
| R01 | Ba tab Nhật ký / Chi tiêu / Dữ liệu; mở Nhật ký theo ngày cục bộ hiện tại; một handset xuyên suốt |
| R02–R04 | Thêm bữa, nhóm theo Sáng/Trưa/Tối/Ăn vặt, nhiều bản cùng nhóm, chọn ngày, nhóm trống trung tính; món bắt buộc, thành phần/lượng/giá tùy chọn; giá 0 khác trống, không thêm giờ ăn |
| R05–R06 | Chi tiết bữa → sửa/xóa; sửa giữ id/sequence; xóa xác nhận; Lưu tường minh, khóa bấm lặp, lỗi giữ input; Back/Hủy khi dirty có Tiếp tục sửa/Bỏ thay đổi |
| R07 | Ăn lại từ chi tiết: copy món/thành phần/lượng, ngày hôm nay, chờ chọn nhóm, giá trống; chỉ Lưu mới tạo bản mới |
| R08 | Tìm món/thành phần/lượng toàn bộ dữ liệu; trim query, không phân biệt hoa thường và có phân biệt dấu; kết quả theo ngày giảm dần rồi nhóm/sequence; mở bản ghi đúng id |
| R09 | Chi tiêu Ngày/Tháng/Năm/Tùy chọn, biên lịch inclusive; tổng giá đã ghi, số bữa và thiếu giá; 0 không thiếu. Picker ngày/tháng/năm, khoảng có Áp dụng/Hủy; nhóm kết quả và giữ ngữ cảnh khi quay lại, độc lập bộ lọc khác. Xem phần cập nhật SCR-06 bên dưới |
| R10 | Xuất khoảng ngày inclusive, preset 7/30 ngày tính cả hôm nay, mặc định không giá; lỗi ngày/đảo khoảng; chấp nhận khoảng chỉ có lần dị ứng |
| R11 | ReportVersion 2: union ngày tăng dần, nhóm bữa và lần dị ứng riêng, optional Chưa ghi; giá bật/tắt đúng phạm vi; snapshot cả hai tập dùng chung preview/clipboard/file; user text được bao code fence an toàn; preview bằng textContent |
| R12 | Sao chép, chia sẻ file khi browser hỗ trợ, tải `.md` thay thế; file UTF-8/LF/newline cuối, tên theo khoảng ISO; hủy share không báo gửi thành công |
| R13 | Backup JSON schema 2 toàn bộ cả hai tập và metadata/giá/null/00:00, không phụ thuộc report; validator file/root/schema/trường/type/enum/date/time/timestamp/id/sequence/giới hạn |
| R14 | Khôi phục snapshot đã validate, giữ tên file, đối chiếu riêng bữa/lần hiện tại và trong file; sao lưu hiện tại không tự restore; xác nhận cuối thay toàn bộ, lỗi giữ dữ liệu cũ; nhận schema 1 kèm cảnh báo xóa các lần dị ứng; không merge; từ chối dailyObservations/version lạ |
| R15 | Repository trình duyệt lưu một JSON envelope bằng localStorage, commit trước cập nhật RAM; tải lại đọc snapshot; bộ đếm không tái dùng sequence đã xóa; không network/AI/account. Các yêu cầu native vẫn mô phỏng/chưa kiểm tra |
| R16 | Nhãn tiếng Việt, Roboto cục bộ, ngày DD/MM/YYYY, controls min-height 48px, error/focus/dialog semantics, chữ theo rem, reduced motion, bố cục flow cho viewport hẹp/thấp; chưa kết luận đạt render/accessibility |
| R17 | Thêm/sửa/xóa riêng từng lần nghi dị ứng: ngày/buổi bắt buộc, giờ/phút và ghi chú tùy chọn, null khác 00:00; cho trùng thời gian, không gộp hoặc suy nguyên nhân; report/backup luôn giữ các lần |

Đủ SCR-01, SCR-02, SCR-04, SCR-05, SCR-06, SCR-07, SCR-08, SCR-09, SCR-10, SCR-11, SCR-12, SCR-13, SCR-14 và SCR-15. SCR-03 giữ trống theo tài liệu. Danh sách dài có thao tác xem thêm theo lô.

Báo cáo đã tạo có thể mở lại từ **Dữ liệu → Báo cáo đã tạo** trong cùng phiên, kể cả sau khi sửa nhật ký. Báo cáo giữ snapshot cũ đến khi bấm Tạo lại hoặc đổi Kèm giá; khôi phục dữ liệu thành công xóa snapshot cũ. Snapshot báo cáo và draft form không lưu qua lần tải lại.

## Các ghi nhận lỗi đã xử lý trong source

| Ghi nhận | Thay đổi source |
| --- | --- |
| Ngày phụ thuộc locale; A-01 ngắt giữa năm | UI DD/MM/YYYY, ISO lưu riêng; ngày ở nguyên một dòng và nút điều hướng ở dòng riêng; chọn lịch bằng ngày/tháng/năm; kiểm tra ngày lịch thực |
| Điều khiển nhập giờ/giá | Giờ và phút hai ô số, không cần nhập dấu `:`; không tự điền giờ; giá hiển thị nhóm nghìn khi rời ô, 45 vẫn là 45, không thành 45.000; dữ liệu sai không tự làm tròn |
| A-02 mất tên file restore | Tên file gắn snapshot đã validate, hiển thị trong đối chiếu và xác nhận; chọn file mới vô hiệu snapshot cũ; lỗi có hướng chọn file khác và không đổi dữ liệu |
| A-03 ưu tiên bỏ draft | Tiếp tục sửa dùng nút nổi bật và focus an toàn; Bỏ thay đổi là hành động phụ có nhãn rõ |
| B1–B2 dialog/focus | Dialog có aria-labelledby/aria-describedby, focus trap/restore/Escape; route có heading focus; lỗi trường/radio/optional có aria và focus đến điều khiển cần sửa |
| B3 chữ lớn/viewport thấp | Typography rem, controls tự cao theo nội dung, header/choices wrap; viewport thấp dùng page flow thay ép handset nhỏ; chrome trang trí không nhận pointer |
| B4 timestamp bất khả thi | Validate ngày Gregorian và giờ UTC trước Date.parse; so thời điểm bằng số; file sai bị từ chối nguyên file |
| B5 vùng bấm switch | Label chứa control và text, vùng bấm cả hàng tối thiểu 48px |

Đây là cách xử lý trong mã, **chưa phải bằng chứng lỗi đã hết trên render**. Không dùng báo cáo hoặc ảnh của prototype cũ làm bằng chứng cho phiên bản này.

## Dữ liệu mẫu và cách đối chiếu

Lần mở đầu tiên chưa có dữ liệu trình duyệt dùng fixture chính: **10 bữa, 5 lần dị ứng** ngày 30/10–02/11/2026. “Hôm nay” lấy từ thiết bị; nếu hôm nay ngoài những ngày này, nhật ký hôm nay trống là trạng thái đúng. Chọn **02/11/2026** để xem 3 bữa, tổng đã ghi **85.000 ₫**, thiếu giá 1 bữa và 2 lần dị ứng. Không đổi ngày của fixture theo đồng hồ.

- Tìm `trứng`: expected 4 bữa.
- Chi tiêu 01/11/2026: expected 70.000 ₫, 5 bữa, thiếu giá 2.
- Tháng 11/2026: expected 155.000 ₫, 8 bữa, thiếu giá 3.
- Export 01–02/11/2026: expected 8 bữa, 4 lần dị ứng; giá tắt không có tiền/tổng/số thiếu giá.
- 30/10/2026: chỉ có lần dị ứng, vẫn có thể xuất. 29/10 không có cả hai, không xuất báo cáo trống.
- [backup-v1.json](fixtures/backup-v1.json): file cũ chỉ có bữa; khôi phục phải cảnh báo không có lần dị ứng.
- [backup-empty-current.json](fixtures/backup-empty-current.json): rỗng cả hai tập, khác [backup-events-only.json](fixtures/backup-events-only.json).
- File invalid-duplicate-id / invalid-duplicate-event-id / invalid-hour là đầu vào cố ý lỗi, không phải dữ liệu để tự sửa.

Các expected trên đến từ tài liệu và đối chiếu đầu vào, không phải actual của app mới.

## Còn mô phỏng và giới hạn

- **Lưu trữ:** localStorage một snapshot theo origin trình duyệt, không SQLite/secure storage hoặc transaction native. Chặn ghi khi không đọc được bản lưu cũ, báo lỗi khi không thể commit; không tuyên bố đã lưu bền. Chế độ riêng tư, dung lượng, origin hoặc xóa browser data có thể ảnh hưởng dữ liệu. Giữ bản sao lưu nếu cần.
- **Khởi tạo:** fixture tự nạp chỉ cho kho trình duyệt mới. Đây là dữ liệu giả phục vụ prototype, không phải ghi chép thật của người dùng. Kho prototype ba màn trước chỉ dùng RAM nên không có migration dữ liệu thật từ bản đó.
- **File/clipboard/share:** dùng API trình duyệt và Blob/File/download; tải file chỉ báo đã yêu cầu tải, không xác nhận file đã nằm trên đĩa. Chia sẻ tùy khả năng/permission; clipboard cần context được trình duyệt cho phép. Không có chứng nhận share sheet/picker/clipboard của iOS/Android.
- **Khôi phục:** validate rồi localStorage.setItem một envelope trước RAM commit để tránh thay nửa bộ trong prototype. Chưa chứng minh rollback do process kill, disk fault hoặc transaction độc quyền như SQLite. Chưa mô phỏng lỗi native giữa transaction.
- **Offline:** font/source cục bộ, không gọi dịch vụ mạng; chưa có service worker/cài PWA, chưa kiểm tra máy bay hoặc độc lập mạng của native. Mở source không tương đương cài app.
- **Điều hướng:** Back trong app và History API của browser được nối; browser host có thể giới hạn History API. Chưa kiểm tra thao tác back/forward thực tế hoặc native system Back.
- **Hiệu năng:** có tải thêm danh sách; chưa đo budget 10.000 record/1.000 report hoặc stress file 50 MiB/100.000 bản mỗi tập.
- **Phạm vi:** không native build/deploy, không AI tích hợp, không cloud/tài khoản, không ảnh/OCR, giờ ăn, taxonomy triệu chứng/mức độ/thuốc, nhân quả hoặc ngân sách. Biểu đồ và chế độ Sáng/Tối hiện nằm trong phạm vi R18–R22; không xuất chart PNG/PDF.

## Kiểm tra đầu vào đã thực hiện

- Đọc PRODUCT.md, UX.md, SPEC.md, VALIDATION.md, fixtures và ghi nhận A-01–A-03/B1–B5; không dùng prototype/ hoặc DESIGN.md cũ làm mẫu giao diện.
- Đối chiếu dữ liệu fixture: 10 bữa, 5 lần; tổng 31/10 là 100.000, 01/11 là 70.000/thiếu 2, 02/11 là 85.000/thiếu 1; tìm `trứng` có 4 bữa.
- Tính tương phản token sRGB: chữ nút/nền nút **5,34:1**, body/surface **17,74:1**, muted/surface **6,21:1**. Đây là tính trên cặp màu, không phải audit toàn giao diện hoặc màu mọi trạng thái.
- Roboto cục bộ đầu vào đã được kiểm tra cmap ở lượt trước cho các nhãn và ký tự tiếng Việt; không thiếu ký tự trong tập đã xét. Khai báo variable weight 100–900, dùng 400/500/600, font-synthesis none. Đây không phải bằng chứng font tải đúng hoặc dấu không bị cắt trên render mới.

## Cập nhật Chi tiêu — SCR-06 / R09

Các nội dung sau đã được viết trong source, chưa được thực thi kiểm tra trên prototype cập nhật:

- Mở Chi tiêu lần đầu trong phiên vào **Tháng hiện tại**. Bốn chế độ **Ngày / Tháng / Năm / Tùy chọn** giữ lựa chọn hợp lệ riêng. Ngày không lấy từ ngày đang xem ở Nhật ký. Khoảng tùy chọn mặc định từ đầu tháng đến hôm nay khi dùng lần đầu.
- Hàng điều hướng gồm mũi tên trước, nút nhãn kỳ có dấu mở picker và mũi tên sau. Hôm nay/Tháng này/Năm nay là text action phụ chỉ xuất hiện khi cần; hàng phụ có chỗ riêng. Không còn form Ngày chi tiêu bắt buộc hoặc nút Xem chi tiêu.
- **Ngày:** lịch tháng Thứ Hai → Chủ nhật, trước/sau tháng, chọn nhanh tháng rồi năm; chạm ngày áp dụng một lần và đóng. Không còn chia ba ô ngày/tháng/năm trên SCR-06.
- **Tháng:** lưới đủ 12 tháng; trước/sau năm hoặc mở lưới năm. Duyệt năm chưa thay kết quả. Chạm tháng mới áp dụng và đóng, không bắt nhập MM/YYYY.
- **Năm:** lưới phân trang 12 năm, trước/sau trang; nhãn Đã chọn/Hiện tại và aria state. Có đường nhập năm phụ để đi đến trang xa, không phải cách chọn duy nhất; đi đến trang không tự áp năm.
- **Tùy chọn:** một nút khoảng với hai mốc và Đổi khoảng. Picker giữ bản nháp, chỉ rõ Từ/Đến đang chỉnh; cả hai chọn được trên lịch hoặc nhập phụ DD/MM/YYYY. Chỉ **Áp dụng** xác nhận cả hai; ngày sai/đảo mốc có lỗi sát trường và giữ input. Không tự đảo hai ngày. Hủy/Back/Escape bỏ draft, giữ kỳ cũ và trả focus nút mở; không hỏi bỏ draft bộ lọc.
- Kết quả cũ trong lúc chọn khoảng có nhãn **Kỳ đã áp dụng** và **Chưa áp dụng**. Duyệt trang tháng/năm/ngày không truy vấn kỳ tạm.
- Truy vấn đồng bộ resolve `[from,to]` inclusive trong miền năm 0001–9999. Biên tháng/năm tính theo lịch Gregorian, có 29/02 năm nhuận; vô hiệu bước vượt miền. Không lấy timestamps hoặc giờ dị ứng để tính chi tiêu.
- `entryCount`, `pricedCount`, `missingPriceCount`, `totalVnd` và nhóm lấy từ cùng tập MealEntry. Query lỗi có thông báo/Thử lại, không giả 0. Query đồng bộ nên không có các request bất đồng bộ cũ về muộn.
- Ngày nhóm theo loại bữa; tháng/khoảng theo ngày mới nhất trước; năm theo tháng có năm rồi ngày mới nhất trước. Mỗi nhóm có tổng và thiếu giá riêng; mở nhóm không đổi kỳ. Nhóm đóng không dựng hàng bữa; nhóm/bữa dài có Xem thêm theo lô 20.
- Đổi tab hoặc mở chi tiết/sửa/xóa rồi quay lại giữ bộ lọc, nhóm mở và scroll trong phiên. Đổi giá hoặc chuyển ngày cập nhật lại kết quả theo dữ liệu đã commit; restore thành công reset ngữ cảnh Chi tiêu. Không ghi aggregate hoặc filter vào backup; không thay khoảng export hoặc query tìm món.
- Các control tối thiểu 48px; bộ chọn kỳ reflow 2×2 và lưới tháng/năm tự giảm cột khi chữ lớn. Lịch luôn giữ bảy cột từ Thứ Hai đến Chủ nhật và nút tối thiểu 48px; ở bề rộng không đủ có **cuộn ngang bên trong lịch** và hướng dẫn, không ép nhỏ chữ hoặc làm trang tràn ngang. Đây là lựa chọn bố cục trong source, chưa xác minh bằng render. Giữ font/màu Material đã duyệt.

### Fixture biên riêng

Đã chép thêm [backup-spending-boundaries.json](fixtures/backup-spending-boundaries.json) và [spending-boundaries-expected.json](fixtures/spending-boundaries-expected.json). Hai file là đầu vào đối chiếu riêng, **không trộn** vào 10 bữa/5 lần dị ứng mẫu khởi tạo. Nếu thử khôi phục fixture biên, hãy sao lưu dữ liệu hiện tại trước vì restore thay toàn bộ.

Expected từ tài liệu và file đầu vào, không phải actual của bản mới:

| Kỳ | Bữa | Tổng đã ghi | Thiếu giá |
| --- | --- | --- | --- |
| Fixture chính: 01/11/2026 | 5 | 70.000 ₫ | 2 |
| Fixture chính: tháng 11/2026 | 8 | 155.000 ₫ | 3 |
| Fixture chính: năm 2026 hoặc 31/10–02/11/2026 | 10 | 255.000 ₫ | 3 |
| Fixture biên: tháng 02/2024 | 2 | 10.000 ₫ | 0 |
| Fixture biên: năm 2024 | 4 | 60.000 ₫ | 0 |
| Fixture biên: năm 2026 | 4 | 60.000 ₫ | 2 |
| Fixture biên: 31/12/2024–01/01/2025 | 2 | 70.000 ₫ | 0 |
| Fixture biên: 29/02/2024–29/02/2024 | 1 | 0 ₫ | 0 |
| Fixture biên: 31/12/2025–01/01/2026 | 2 | 50.000 ₫ | 1 |
| Fixture biên: 01–02/02/2026 | 2 | 0 ₫ | 2 |
| Fixture biên: 01/03/2026 | 0 | 0 ₫ | 0 |

### Trạng thái kiểm tra SCR-06 cập nhật

| ID | Tiêu chí cập nhật | Trạng thái |
| --- | --- | --- |
| V07 | Tổng ngày/tháng/năm/khoảng fixture chính, 0 khác null, tổng nhóm khớp kỳ | **Chưa kiểm tra** |
| V08 | Mặc định tháng, đủ bốn kỳ, tự cập nhật, draft/cancel, nhãn cũ, độc lập filter và Back/scroll | **Chưa kiểm tra** |
| V23 | Fixture biên: tháng nhuận/năm 2024/năm 2026, ngày không tồn tại và đảo khoảng | **Chưa kiểm tra** |
| V24 | Khoảng cùng ngày/qua năm, toàn thiếu giá, kỳ không bữa, nhóm tháng không lẫn năm | **Chưa kiểm tra** |
| V25 | Giữ mốc riêng, sửa/xóa/chuyển ngày qua biên, không stale query, lỗi không giả 0, bốn lựa chọn/chữ lớn | **Chưa kiểm tra** |
| V26 | Picker ngày/tháng/năm không bắt gõ, duyệt không áp, range chỉ Áp dụng, Hủy/Back/Escape/focus và 320px/chữ lớn | **Chưa kiểm tra** |

Không chạy module hoặc script test/validation, không render/preview/browser thao tác hoặc screenshot sau ghi source. Chưa xác minh các cách xử lý trên bằng thực thi; không dùng bước chưa kiểm tra làm điều kiện chặn bàn giao source. Các giới hạn trình duyệt/native ở phần trước tiếp tục áp dụng.

## Chưa kiểm tra trên artifact mới

Không mở/render/preview/screenshot, chạy browser walkthrough, script kiểm thử/validation hoặc acceptance sau ghi source. Không có Pass/Fail được suy từ source hoặc từ phiên bản cũ. Những mục dưới đây không được dùng làm điều kiện chặn bàn giao source.

| ID | Phạm vi cần kiểm tra sau này | Trạng thái |
| --- | --- | --- |
| V01 | Mở hôm nay, thêm bữa không giá, nhiều bữa cùng nhóm | **Chưa kiểm tra** |
| V02 | Món trống/giá lỗi, giữ input, dirty Back | **Chưa kiểm tra** |
| V03 | Ghi bù/chọn lịch/Hôm nay, đổi timezone | **Chưa kiểm tra** |
| V04 | Sửa/chuyển ngày/xóa/hủy và cập nhật mọi truy vấn | **Chưa kiểm tra** |
| V05 | Ăn lại copy đúng 3 trường, không sinh bản khi hủy | **Chưa kiểm tra** |
| V06 | Tìm `trứng`, uppercase, query trống/không kết quả, Back | **Chưa kiểm tra** |
| V07 | Tổng ngày/tháng/năm/khoảng và tổng nhóm, null/0 đúng expected | **Chưa kiểm tra** |
| V08 | Bốn kỳ, mặc định tháng, draft/cancel, không dữ liệu/toàn thiếu giá, độc lập filter, giữ kỳ/scroll | **Chưa kiểm tra** |
| V09 | Export đúng khoảng và giá bật/tắt | **Chưa kiểm tra** |
| V10 | Lỗi khoảng/empty, clipboard failure, hủy share, report dài | **Chưa kiểm tra** |
| V11 | Snapshot immutable, regenerate, Unicode/newline/backtick/HTML | **Chưa kiểm tra** |
| V12 | Backup đủ, restore full replace, sequence mới | **Chưa kiểm tra** |
| V13 | File lỗi/schema/id/date/price/JSON/size/cancel không đổi dữ liệu | **Chưa kiểm tra** |
| V14 | File rỗng, sao lưu trước, cancel/error/rollback | **Chưa kiểm tra** |
| V15 | Native offline/force-close/persistence/airplane mode | **Chưa kiểm tra** |
| V16 | Clipboard/share/picker/cancel trên iOS và Android | **Chưa kiểm tra** |
| V17 | 375×812, 412×915, 320×568, 200% chữ, keyboard, viewport thấp | **Chưa kiểm tra** |
| V18 | Render tiếng Việt, contrast/focus/tap thực tế, Back, VoiceOver/TalkBack | **Chưa kiểm tra** |
| V19 | Budget 10.000 records, báo cáo 1.000 records, thiết bị/build cụ thể | **Chưa kiểm tra** |
| V20 | AllergyEvent CRUD, nhiều lần, null/00:00/24:00, không ảnh hưởng bữa | **Chưa kiểm tra** |
| V21 | Report luôn có các lần dị ứng, event-only, snapshot hai tập | **Chưa kiểm tra** |
| V22 | Backup schema 2, invalid enums/time/timestamps/duplicate, v1 warning, dailyObservations reject | **Chưa kiểm tra** |

Chưa xác nhận bằng render các nhãn “Nhật ký ăn uống”, “Ghi nhận dị ứng”, “Bữa sáng”, “Thành phần”, “Ăn lại”, không fallback lẫn font, clipping dấu hoặc weight thực tế. Chưa review screenshot hoặc Impeccable trên bản mới. Không có app native production đã triển khai.


## Cập nhật theo brief — R18–R22

Nguồn: OPEN-DESIGN-BRIEF.md, PRODUCT.md, UX.md, SPEC.md (R09, R18–R22 và các Spending/Chart/Appearance Contract), phần **Hiện hành** của DESIGN.md, VALIDATION.md và docs/fixtures/ trong thư mục tài liệu liên kết. Không dùng giao diện prototype/ cũ hoặc token lịch sử làm hướng thiết kế mới. Bản này tiếp tục Material đã duyệt, không mở lại vòng chọn phong cách.

### Đã viết trong source

- **Nhật ký → Tổng quan → SCR-12:** bộ chọn Tháng/Năm/Tùy chọn độc lập, mặc định tháng hiện tại mỗi lần mở mới. Số lần và số ngày có ghi nhận; lịch Thứ Hai–Chủ nhật có đỏ + số lần, trạng thái hôm nay/đã chọn/ngoài kỳ. Lịch duyệt tháng trong kỳ, không thay kỳ chart; ngày rỗng trung tính, không diễn giải là không dị ứng. Cột thời gian và phân bố năm buổi thu gọn mặc định.
- **SCR-13:** mở từ ngày, bucket ngày/tuần/tháng hoặc buổi trong chart/bảng. Nhóm ngày mới nhất trước; bữa ăn và từng lần dị ứng riêng. Chọn buổi chỉ lọc event, giữ tất cả bữa trên những ngày có event khớp; không gán buổi dị ứng sang loại bữa. Giờ trống khác 00:00. Có đường Mở Nhật ký ngày này để sửa rồi Back; danh sách tải thêm từng lô 20.
- **Chi tiêu → SCR-06/SCR-14:** giữ bốn kỳ và các nhóm kết quả. Thêm xu hướng tiền đã ghi và cơ cấu bốn loại bữa bằng cột ngang; Ngày hoặc khoảng một ngày chỉ có cơ cấu. Mở cột giữ đầy đủ bữa null/0; mở loại bữa lọc đúng loại trên toàn kỳ. Chi tiết nối tới SCR-08 để sửa. Kỳ, nhóm mở, đoạn chart, lựa chọn và cuộn giữ khi quay lại.
- **Chart Contract:** snapshot tính từ cùng một object revision của repository; CRUD thay revision để làm mới tổng/lịch/chart/bảng. Tháng đủ 28–31 cột ngày, năm đủ 12 tháng. Custom 1–31 ngày theo ngày; 32–180 ngày theo tuần bắt đầu Thứ Hai và cắt biên; hơn 180 ngày theo tháng cắt biên. Miền Gregorian 0001–9999 được tính bằng số thứ tự ngày; không cộng ngày qua timezone. Giữ mốc trống, null khác 0, bốn trạng thái chất lượng giá. Ngày tương lai vẫn tính và có nhãn riêng.
- **Cửa sổ và khả năng đọc:** tối đa 31 bucket trong một đoạn, khởi đầu đoạn đầu; bucket tạo lười. Tổng/cơ cấu và trục Y tính toàn kỳ, không thay theo đoạn. Đọc bằng chạm/kéo/phím mũi tên, mở bằng Enter hoặc nút; bảng cùng snapshot/cửa sổ có hàng/nút tối thiểu 48px. Cột SVG có thể hẹp hơn vùng chạm 48px, nên bảng và nút Mở chi tiết là đường tương đương. Cột zero không được dựng thành cột dương giả.
- **Cụm ngày Nhật ký:** Ngày đang xem và Hôm nay ở hàng nhãn; hai mũi tên bằng nhau và nút ngày mở lịch ở giữa. Không có pill Hôm nay lẻ hoặc nút Chọn ngày trùng. Kỳ Tổng quan/Chi tiêu/Xuất giữ độc lập với ngày Nhật ký.
- **Dữ liệu → Giao diện → SCR-15:** Theo hệ thống/Sáng/Tối, lưu mode ngay; theo dõi thay đổi OS trong system, manual giữ cố định. HEX 3/6 số có/không # chuẩn hóa 6 số; input sai giữ giá trị và báo lỗi. Color picker/HEX, preview cả hai mode, Áp dụng/Hủy và Về hồng theo bản nháp; màu chỉ đổi khi commit thành công. Hủy màu không rollback mode. Lỗi lưu giữ lựa chọn đã lưu và cho thử lại.
- **Semantic theme:** light mặc định giữ nút #F8CFE0 / #8F345B. Với màu tùy chọn và dark, source suy ra container/on-container, mark/focus có ngưỡng tương phản; không chỉ tô nguyên seed cho mọi trạng thái. Màu đỏ dị ứng/lỗi và vàng cảnh báo giữ vai trò riêng. Không dùng CSS invert. Đây là thuật toán đã viết, không phải audit tương phản toàn app đã chạy.
- **Restore:** khôi phục thay dữ liệu sẽ xóa ngữ cảnh/cache dữ liệu và snapshot report cũ, giữ theme. Prefs dùng khóa localStorage food-diary.appearance.v1 riêng với kho nhật ký; backup schema 2 và reportVersion 2 không thêm theme/chart/cache. Fixture chính vẫn 10 bữa/5 lần, không gộp bộ biên.

### Fixture bàn giao

[chart-expected.json](fixtures/chart-expected.json) và [README fixtures](fixtures/README.md) là bản sao đầu vào mới; không phải actual của prototype. Expected tháng 11/2026: 4 lần/2 ngày, 8 bữa/155.000 ₫/thiếu 3. Cơ cấu Sáng/Trưa/Tối/Ăn vặt: 55.000/55.000/45.000/0 ₫, thiếu 0/1/1/1. Năm 2026: 5 lần/3 ngày, 10 bữa/255.000 ₫/thiếu 3. Bộ biên chi tiêu vẫn riêng 12 bữa/0 lần.

### Còn mô phỏng

- Lưu dữ liệu và tùy chọn bằng localStorage theo origin, không SQLite, native preferences hoặc secure storage. Mode hệ thống dùng matchMedia của trình duyệt; không chứng minh vòng đời theme iOS/Android.
- Picker lịch/màu, dialog, History API, clipboard, tải/chia sẻ dùng khả năng trình duyệt; không phải tích hợp native. Preview màu trong SCR-15 là chức năng sản phẩm để người dùng thao tác, không phải agent đã mở preview kiểm tra.
- Tổng hợp đồng bộ trong bộ nhớ, cache theo revision; không có truy vấn native bất đồng bộ. Lỗi tính toán được hiển thị là lỗi có Thử lại, không thay bằng số 0/trạng thái rỗng. Chưa đo hiệu năng dữ liệu lớn hoặc miền năm tối đa trên thiết bị.

### Kiểm chứng của lượt cập nhật

Đã đọc và đối chiếu các hợp đồng cùng fixture đầu vào, tiếp tục font local và token Material đã chốt. Không chạy render/preview, screenshot, thao tác trình duyệt, test/validator trên artifact hoặc acceptance sau khi ghi source. Các số fixture nêu trên là kỳ vọng từ tài liệu. Không coi source đã viết là bằng chứng kiểm thử đạt.

| Ca | Nội dung cần kiểm chứng | Trạng thái |
| --- | --- | --- |
| V27 | Tổng tháng/năm, số lần khác số ngày, buổi 0, null/00:00 | Chưa kiểm tra |
| V28 | Ngưỡng 31/32/180/181, tuần Thứ Hai, đủ mốc và clipping | Chưa kiểm tra |
| V29 | Leap day, tuần qua năm, miền 0001–9999 và timezone | Chưa kiểm tra |
| V30 | Lịch một tháng, đỏ + số, today/selected/ngoài kỳ | Chưa kiểm tra |
| V31 | Drill-down từ chart/bảng/lịch/buổi, union ngày và Back | Chưa kiểm tra |
| V32 | Cơ cấu Chi tiêu, null/0, detail và Ngày một chart | Chưa kiểm tra |
| V33 | 36 tháng → cửa sổ 31/5, scale và tổng toàn kỳ ổn định | Chưa kiểm tra |
| V34 | Empty, giá null/0, tương lai, lỗi khác rỗng | Chưa kiểm tra |
| V35 | Đổi kỳ/CRUD/restore, giữ snapshot report và Hủy picker | Chưa kiểm tra |
| V36 | Chạm/kéo/phím/bảng, 320px/chữ 200%, nhãn dài, screen reader | Chưa kiểm tra |
| V37 | Cụm ngày, Hôm nay, lịch, độc lập kỳ và reflow | Chưa kiểm tra |
| V38 | System/manual, mọi màn ở hai theme, tương phản mọi state | Chưa kiểm tra |
| V39 | HEX cực trị/sai, preview/Cancel/Apply/reset, semantic đỏ | Chưa kiểm tra |
| V40 | Lỗi lưu prefs, mở lại/offline, restore không đổi theme | Chưa kiểm tra |

V01–V26 cũng chưa được chạy lại ở lượt này: **Chưa kiểm tra**. Render tại 375×812, 412×915, 320px/chữ 200%, font tiếng Việt/fallback/clipping, focus/Back/drag/scroll, OS đổi theme, clipboard/share/file/prefs và native persistence/offline: **Chưa kiểm tra**. Các bước bị quy trình cấm không dùng làm điều kiện chặn bàn giao source.


## Rà source với Impeccable — 03/11/2026

Đã tìm thấy skill built-in **impeccable-design-polish** trong catalog và đọc body qua CLI có đúng Workspace/member của lượt chạy. Áp dụng hướng dẫn Inspect → Harden/Polish cho artifact hiện có, theo thứ tự công việc layout → harden → polish. Phạm vi là các sửa cục bộ dưới đây, giữ Material/Roboto, semantic theme, các màn/luồng và hợp đồng dữ liệu. Đây là rà source trước khi chỉnh sửa ở lượt mới, không phải audit trực quan, không phải native audit hoặc acceptance sau khi ghi source.

| ID / ưu tiên | Màn / state | Bằng chứng từ source đầu vào | Thay đổi đã viết | Kiểm tra lại |
| --- | --- | --- | --- | --- |
| I01 / P1 | SCR-01, khung hẹp hoặc chữ lớn | Cụm ngày chia 48px / phần giữa / 48px nhưng text giữa cho break-word | Ngày giữ nguyên một dòng; container query bỏ icon phụ khi hẹp. Khi không đủ chỗ, nút ngày chiếm hàng riêng, hai mũi tên bằng nhau ở hàng kế; không thu nhỏ font hoặc mất thao tác. Bố cục bình thường vẫn ngày giữa hai mũi tên | Chưa kiểm tra |
| I02 / P1 | SCR-06/SCR-12, bảng số liệu | Button đang gán role=cell bên trong role=row, làm mất role button | Dùng table/caption/column header/tbody/tr/td thật, nút Chi tiết giữ semantics button, tên đọc gồm mốc và giá trị; cùng nguồn snapshot và cửa sổ | Chưa kiểm tra |
| I03 / P1 | Dialog/picker, Tab/Shift+Tab | Focus trap lọc disabled nhưng chưa lọc control ẩn hoặc nội dung trong disclosure đóng | Tập trung danh sách điều khiển có layout box, không disabled/hidden/inert; đưa focus vào đầu/cuối nếu bị rơi ngoài, giữ safe action và Escape/Cancel hiện tại | Chưa kiểm tra |
| I04 / P2 | SCR-15, nhập HEX rút gọn | Chuẩn hóa màu cho preview nhưng ô nhập vẫn giữ dạng rút gọn | Sau blur/Áp dụng hợp lệ, ô HEX hiện #RRGGBB viết hoa; sai vẫn giữ nguyên input và lỗi, draft chưa thay màu app | Chưa kiểm tra |
| I05 / P1 | Focus trong dialog tối/custom accent | Focus được suy ra theo surface nền thay vì surfaceElevated của dialog | Tính focus theo mặt elevated, tiếp tục dùng cùng role focus cho file/choice/switch và control; không đổi đỏ dị ứng | Chưa kiểm tra |
| I06 / P2 | SCR-12, nhóm theo buổi; hàng chart và giá dài | Chevron disclosure không có class quay theo aria-expanded; giá dài không có vùng đọc riêng ở hàng | Chevron dùng quy ước group-chevron hiện có; bổ sung phản hồi nhấn cho hàng/bộ chọn và cuộn riêng phần giá dài; không thêm animation hoặc card | Chưa kiểm tra |

**Bằng chứng ảnh:** Chưa kiểm tra / chưa chụp. Không render/preview, không chạy trình duyệt hoặc detector/test/validator trên artifact trong lượt này. Các thay đổi trên mô tả mã đã viết, không xác nhận lỗi đã hết khi chạy.

**Các bước tiếp theo ở môi trường được phép kiểm tra:** 375×812, 412×915, 320px và chữ 200%; các màn ở cả hai theme và màu cực trị; dấu tiếng Việt, date reflow, giá dài, table/button semantics với screen reader, Tab/Shift+Tab/Escape/Back, picker HEX và trạng thái nhấn. Tất cả: **Chưa kiểm tra**. V01–V40 và native persistence/offline/share/prefs giữ trạng thái chưa kiểm tra đã công bố.
