---
url: https://docs.nemo12.com/reference/data-dictionary/whale.md
description: >-
  Từ điển dữ liệu D1, domain Whale: 7 bảng, opportunities tới
  whale_universities; cột, kiểu, khoá ngoại, index.
---

# Data Dictionary · Whale

> ⚙️ **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](../data-dictionary.md). 7 bảng, `opportunities` tới `whale_universities`.

## `opportunities`

Migration 0009 — Whale: hub cơ hội học tập (toàn cầu + VN) để truyền cảm hứng. REQ-SCH-09, SDD-011. Public read (learner + parent). Content-as-data.

migration: `0009_whale_opportunities.sql`

| Cột | Kiểu | Ràng buộc / ghi chú |
| --- | --- | --- |
| `id` | TEXT | PRIMARY KEY |
| `title` | TEXT | NOT NULL |
| `region` | TEXT | NOT NULL CHECK (region IN ('vietnam','asia','europe','america','oceania','global')) |
| `category` | TEXT | NOT NULL CHECK (category IN ('scholarship','program','competition','university','summer','pathway','career')) |
| `summary` | TEXT | NOT NULL |
| `detail` | TEXT | — |
| `tags_json` | TEXT | — |
| `audience` | TEXT | NOT NULL DEFAULT 'both' CHECK (audience IN ('learner','parent','both')) |
| `featured` | INTEGER | NOT NULL DEFAULT 0 |
| `created_at` | TEXT | NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')) |

**Index:** `idx_opportunities_region`(region, category)

## `success_stories`

migration: `0010_target_kinds_whale_stories.sql`

| Cột | Kiểu | Ràng buộc / ghi chú |
| --- | --- | --- |
| `id` | TEXT | PRIMARY KEY |
| `title` | TEXT | NOT NULL |
| `persona` | TEXT | NOT NULL,            -- xuất phát: "Bạn M. — lớp 9, Hà Nội, mạnh Toán" (ẩn danh/tổng hợp) |
| `journey` | TEXT | NOT NULL,            -- hành trình: IELTS/SAT/hoạt động |
| `outcome` | TEXT | NOT NULL,            -- kết quả: trường + học bổng |
| `scholarship` | TEXT | ,                 -- tên/mức học bổng (nếu có) |
| `region` | TEXT | NOT NULL DEFAULT 'global' |
| `tags_json` | TEXT | — |
| `school_codes_json` | TEXT | ,           -- schools liên quan (squid/ray/shark…) để recommend theo enrollment |
| `featured` | INTEGER | NOT NULL DEFAULT 0 |
| `created_at` | TEXT | NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')) |

**Index:** `idx_success_stories_region`(region, featured)

## `whale_countries`

migration: `0013_whale_preferences.sql`

| Cột | Kiểu | Ràng buộc / ghi chú |
| --- | --- | --- |
| `code` | TEXT | PRIMARY KEY, name_vi TEXT NOT NULL, name_en TEXT NOT NULL, flag TEXT NOT NULL |
| `region` | TEXT | NOT NULL, why_vi TEXT NOT NULL, education_vi TEXT NOT NULL |
| `scholarship_vi` | TEXT | NOT NULL, cost_vi TEXT NOT NULL |

## `whale_preferences`

Migration 0013 — Whale destination preferences (learner/parent riêng) + country info. SRC-043, REQ-SCH-14.

migration: `0013_whale_preferences.sql`

| Cột | Kiểu | Ràng buộc / ghi chú |
| --- | --- | --- |
| `user_id` | TEXT | NOT NULL REFERENCES users(id) |
| `learner_id` | TEXT | NOT NULL REFERENCES learners(id) |
| `role` | TEXT | NOT NULL CHECK (role IN ('learner','parent')) |
| `countries_json` | TEXT | NOT NULL DEFAULT '\[]' |
| `majors_json` | TEXT | NOT NULL DEFAULT '\[]' |
| `updated_at` | TEXT | NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')) |
| — | *table constraint* | `PRIMARY KEY (user_id, learner_id)` |

**Khóa ngoại:** `user_id` → `users` · `learner_id` → `learners`

## `whale_rankings`

Migration 0024 — Bảng xếp hạng đại học theo quốc gia (SRC-084). Nguồn công khai (QS / THE / ARWU…), lưu kèm source + year để người đọc biết số này của ai, năm nào.

migration: `0024_whale_rankings.sql`

| Cột | Kiểu | Ràng buộc / ghi chú |
| --- | --- | --- |
| `id` | TEXT | PRIMARY KEY |
| `country_code` | TEXT | NOT NULL |
| `source` | TEXT | NOT NULL,          -- "QS World University Rankings" |
| `edition` | TEXT | NOT NULL,         -- "2026" |
| `rank_local` | INTEGER | NOT NULL,   -- thứ hạng trong nước |
| `rank_global` | TEXT | ,              -- thứ hạng thế giới (chuỗi vì có dạng "=54", "301-350") |
| `university_name` | TEXT | NOT NULL |
| `university_id` | TEXT | ,            -- link tới whale_universities nếu trùng |
| `note_vi` | TEXT | — |
| `source_url` | TEXT | — |

**Index:** `idx_whale_rankings_country`(country_code, rank_local)

## `whale_scholarships`

migration: `0031_whale_country_detail.sql`

| Cột | Kiểu | Ràng buộc / ghi chú |
| --- | --- | --- |
| `id` | TEXT | PRIMARY KEY |
| `country_code` | TEXT | NOT NULL |
| `name` | TEXT | NOT NULL |
| `provider_vi` | TEXT | ,            -- ai cấp |
| `level_vi` | TEXT | ,               -- bậc học áp dụng (đại học / sau đại học) |
| `coverage_vi` | TEXT | NOT NULL,   -- cấp những gì |
| `who_vi` | TEXT | ,                 -- dành cho ai |
| `note_vi` | TEXT | ,                -- mốc thời gian, lưu ý |
| `website` | TEXT | — |
| `sort_order` | INTEGER | NOT NULL DEFAULT 0 |
| `value_vi` | TEXT | ,               -- con số cụ thể: tiền, % học phí, số suất |
| `requirements_vi` | TEXT | ,        -- điều kiện và giấy tờ cần có |
| `how_vi` | TEXT | ,                 -- nộp ở đâu, theo mấy bước |
| `deadline_vi` | TEXT | ,            -- mốc thời gian lặp lại hằng năm |
| `sources_json` | TEXT | -- \[{"label":"...","url":"..."}] — trang gốc để tự kiểm chứng |

**Index:** `idx_whale_scholarships_country`(country_code, sort_order)

## `whale_universities`

Migration 0031 — Nội dung chi tiết theo quốc gia cho Whale (SRC-076, REQ-SCH-14).  ⚠️ ĐỔI TÊN, KHÔNG PHẢI MIGRATION MỚI (AS-04.1.1). File này trước đây tên `0022_whale_country_detail.sql` và ĐÃ ÁP trên D1 production dưới tên cũ (bảng `d1_migrations` có dòng '0022_whale_country_detail.sql'). Nó bị đổi số vì trùng số với `0022_user_avatar.sql` — một sequence chỉ được có một số 0022.  Vì tên đổi, wrangler coi đây là migration CHƯA áp và sẽ chạy lại. Toàn bộ lệnh dưới đây đã là idempotent (CREATE TABLE/INDEX IF NOT EXISTS) nên chạy lại KHÔNG lỗi và KHÔNG mất dữ liệu. Dù vậy, cách sạch nhất là đăng ký tên mới một lần trên production — xem migrations/README.md §3.  Trang chi tiết một quốc gia cần: học bổng của nước đó, vài trường đại học tiêu biểu, và câu chuyện người đi trước (stories dùng lại bảng success_stories, lọc theo tag).  HỆ QUẢ CỦA VIỆC ĐỔI SỐ — đọc kỹ: file này giờ chạy SAU 0026, mà 0026 lại ALTER bảng `whale_scholarships` do chính file này tạo. Trên môi trường mới (local/DR) 0026 sẽ không có bảng để ALTER. Cách gỡ: 5 cột của 0026 (value_vi, requirements_vi, how_vi, deadline_vi, sources_json) được gộp thẳng vào CREATE TABLE dưới đây — một định nghĩa duy nhất — và 0026 trở thành no-op có ghi chú. Kết quả schema cuối cùng giống hệt production (đã đối chiếu sqlite_master ngày 2026-08-15).

migration: `0031_whale_country_detail.sql`

| Cột | Kiểu | Ràng buộc / ghi chú |
| --- | --- | --- |
| `id` | TEXT | PRIMARY KEY |
| `country_code` | TEXT | NOT NULL |
| `name` | TEXT | NOT NULL |
| `name_vi` | TEXT | — |
| `city` | TEXT | — |
| `why_vi` | TEXT | NOT NULL,        -- vì sao đáng chú ý, 1-2 câu |
| `strength_vi` | TEXT | ,            -- ngành mạnh |
| `note_vi` | TEXT | ,                -- lưu ý khi apply (học phí, yêu cầu tiếng) |
| `website` | TEXT | — |
| `sort_order` | INTEGER | NOT NULL DEFAULT 0 |

**Index:** `idx_whale_universities_country`(country_code, sort_order)
