# Planning — Menu Navbar MEDIA (nres.gov.my)

> Rujukan: `https://www.nres.gov.my/ms-my/Pages/default.aspx` · Dikemas kini: 22 Okt 2026

> **Kemas kini (22 Okt 2026):** modul `content_clipping` telah dinamakan semula menjadi **`content-media` (Media Library)** dan kini merangkumi **Keratan Akhbar + Kenyataan Media + Siaran Media + Infografik** dalam satu modul (rujuk [`content-media.md`](content-media.md)). Seksyen portal ini bernama **Pustaka Media** (BM) / **Media Library** (EN) dan mengandungi tab tahun pada halaman arkib.

## 1. Struktur menu MEDIA di portal asal

```
MEDIA
├── Video                                        → https://www.facebook.com/nresmalaysia/reels/
├── Penerbitan                                   → /ms-my/PustakaMedia/Pages/PenerbitanKementerian.aspx
├── Teks Ucapan                                  → /ucapan/Pages/default.aspx
├── Kenyataan Media & Siaran Media               → /ms-my/PustakaMedia/Pages/KenyataanMedia.aspx
├── Keratan Akhbar Semasa                        → /ms-my/PustakaMedia/Pages/KeratanAkhbarSemasa.aspx
├── Polisi, Dasar, Perundangan dan Garis Panduan → /ms-my/pustakamedia/Pages/PolisiDasarPerundangandanGarisPanduan.aspx
└── Arkib Elektronik  (href="#", tiada halaman sendiri)
    ├── Berita            → https://www.facebook.com/nresmalaysia          ⚠️ bukan halaman arkib
    ├── Teks Ucapan       → /ucapan/Pages/Arkib-Ucapan.aspx                (tab tahun)
    ├── Penerbitan        → /PustakaMedia/Pages/PenerbitanKementerian.aspx ⚠️ duplikat item MEDIA
    ├── Kenyataan Media   → /ms-my/pustakamedia/Pages/ArkibKenyataanMedia.aspx (tab tahun)
    └── Keratan Akhbar    → /ms-my/PustakaMedia/Pages/KeratanAkhbar.aspx   (tab tahun)
```

> **Disemak semula 24 Okt 2026 (HTML laman utama + CDP):** **"Arkib Elektronik" ialah induk** (`href="#"`) dengan **5 anak** — bukan "Berita" seperti yang tercatat sebelum ini. Hanya **3 arkib sebenar** berfungsi (Teks Ucapan, Kenyataan Media, Keratan Akhbar); setiap satunya guna **tab tahun `2025 · 2024 · 2023 · 2022 · 2021 · Lain-lain`** dan menyenaraikan dokumen (`Type | Tarikh | Nama` + pautan PDF). Dua pautan bermasalah: **Berita → Facebook NRES** dan **Penerbitan** (duplikat + tiada prefix `/ms-my`). Arkib berita sebenar `/ms-my/Pages/ArkibPengumuman.aspx` (pautan "More.." di laman utama) kini pulang **HTTP 401** kepada klien bukan pelayar.

Quicklink footer berkaitan: **Takwim**, **Kenyataan Media**, **e-Perkhidmatan** (Aduan & Maklum Balas, Soal Jawab Parlimen, Tender & Sebut Harga, Statistik).

---

## 2. Pemetaan: guna sedia ada vs buat baru

| Menu Media | Modul | Status | Kerja diperlukan |
|---|---|---|---|
**Berita** | `content-article` (cat `NEWS`) + `news_web` / `article_web` | ✅ guna sedia ada | Tiada (tambah data) |
**Kenyataan Media & Siaran Media** | `content-article` (cat `PRESS`) | ✅ guna sedia ada | Tambah data kategori `PRESS` |
**Semasa** (featured/terkini) | `content-article` | ✳️ guna sedia ada + 1 flag | Tambah kolum `article_is_featured` (bool) + tapisan di `news_web` |
**Video** | `content-video` + `video_web` | ✅ guna sedia ada | Tiada |
**Penerbitan** | `content-download` (cat `REPORT`/`MANUAL`) + `publication_web` | ✅ guna sedia ada | Tiada |
**Polisi, Dasar, Perundangan & Garis Panduan** | `content-download` | ✳️ guna sedia ada + metadata | Tambah kolum: `download_doc_type` (ref `DOC_TYPE`), `download_ref_no`, `download_year`, `download_effective_date` |
**Teks Ucapan** | — | 🆕 **modul baru** `content_speech` | Migration + model + controller + view + page |
**Keratan Akhbar** | — | 🆕 **modul baru** `content_clipping` | Migration + model + controller + view + page |

## 3. Field modul baru

### 3.1 `content_speech` — Teks Ucapan (M)

| Kolum | Jenis | Nota |
|---|---|---|
`speech_id` | bigint PK | |
`speech_code` | varchar(50) null | rujukan dalaman |
`speech_category` | varchar(50) | ref `SPEECH_CATEGORY` (Ucapan, Perasmian, Majlis, Kenyataan) |
`speech_speaker` | varchar(255) | nama penceramah/menteri |
`speech_position` | varchar(255) null | jawatan |
`speech_event` | varchar(255) null | nama majlis |
`speech_location` | varchar(255) null | tempat |
`speech_date` | date | tarikh ucapan |
`speech_file` | varchar(255) null | PDF teks ucapan |
`speech_status` | varchar(20) default `PUBLISHED` | DRAFT/PUBLISHED |
`speech_sort` | int default 0 | |
`created_by`, `updated_by` | varchar(50) | |

`content_speech_translation`: `language`, `title`, `content` (longtext), `main`.

**Frontend:** page `speech-web` + komponen `speech_web` (senarai + butiran `?id=`, tapisan tahun/kategori, butang muat turun PDF).

### 3.2 `content_clipping` — Keratan Akhbar (S–M)

| Kolum | Jenis | Nota |
|---|---|---|
`clipping_id` | bigint PK | |
`clipping_source` | varchar(100) | nama akhbar (ref `CLIPPING_SOURCE` atau teks bebas) |
`clipping_date` | date | tarikh terbit |
`clipping_url` | varchar(500) null | pautan artikel asal |
`clipping_file` | varchar(255) null | imbasan PDF |
`clipping_status` | varchar(20) default `PUBLISHED` | |
`clipping_sort` | int default 0 | |

`content_clipping_translation`: `language`, `title`, `summary`, `main`.

**Frontend:** page `clipping-web` + `clipping_web` (senarai ikut tarikh, tapisan akhbar/bulan).

### 3.3 `content_parliament_qa` — Soal Jawab Parlimen (M)

> ✅ **SIAP — admin sahaja** (lihat [`content-parliament-qa.md`](content-parliament-qa.md)). Dilaksanakan sebagai modul `content-parliament-qa` dengan **4 jenis dalam satu modul** (`PARLIAMENT_QA_TYPE`: `SOAL_JAWAB`, `KAMAR_KHAS`, `MQT`, `RUU`), kategori **multi-value** (`content_parliament_qa_categories`) dan lampiran berbilang (`content_parliament_qa_documents`). Jadual di bawah ialah **draf asal** (satu jenis, `qa_type` = LISAN/BERTULIS) yang telah dikembangkan.

| Kolum | Jenis | Nota |
|---|---|---|
`qa_id` | bigint PK | |
`qa_session` | varchar(100) | sidang (contoh: Mesyuarat Kedua Penggal Ketiga) |
`qa_no` | varchar(50) null | no. soalan |
`qa_type` | varchar(20) | ref `QA_TYPE` (LISAN, BERTULIS) |
`qa_date` | date | |
`qa_member` | varchar(255) null | nama ahli parlimen |
`qa_file` | varchar(255) null | PDF jawapan |
`qa_status` | varchar(20) default `PUBLISHED` | |
`qa_sort` | int default 0 | |

`content_parliament_qa_translation`: `language`, `question`, `answer`, `main`.

**Frontend:** page `parliament-qa-web` + `parliament_qa_web` (senarai + carian + butiran).

### 3.4 `content_statistic` — Statistik (L)

| Kolum | Jenis | Nota |
|---|---|---|
`statistic_id` | bigint PK | |
`statistic_category` | varchar(50) | ref `STATISTIC_CATEGORY` |
`statistic_year` | smallint | |
`statistic_type` | varchar(20) | `FILE` / `URL` / `TABLE` |
`statistic_file` | varchar(255) null | CSV/XLSX/PDF |
`statistic_url` | varchar(500) null | pautan data terbuka |
`statistic_status` | varchar(20) default `PUBLISHED` | |
`statistic_sort` | int default 0 | |

`content_statistic_translation`: `language`, `title`, `description`, `main`.

**Frontend:** page `statistic-web` + `statistic_web` (kad statistik ikut kategori/tahun + muat turun).

### 3.5 Tambahan pada modul sedia ada

**`content_article`** (kecil):
- `article_is_featured` tinyint(1) default 0 → untuk menu **Semasa** (ticker/featured di home).
- (pilihan) `article_source` varchar(100) null → nama akhbar, jika tak mahu guna modul `content_clipping`.

**`content_download`** (untuk Polisi/Dasar/Perundangan):
- `download_doc_type` varchar(50) null → ref `DOC_TYPE` (AKTA, PERATURAN, DASAR, GARIS_PANDUAN, PEKELILING)
- `download_ref_no` varchar(100) null
- `download_year` smallint null
- `download_effective_date` date null

**Ref baru:**
| Cat | Kod |
|---|---|
`SPEECH_CATEGORY` | `UCAPAN`, `PERASMIAN`, `MAJLIS`, `KENYATAAN` |
`CLIPPING_SOURCE` | `BH`, `NST`, `THE_STAR`, `SINAR_HARIAN`, `UTUSAN`, `BERNAMA`, `OTHERS` |
`QA_TYPE` | `LISAN`, `BERTULIS` |
`DOC_TYPE` | `AKTA`, `PERATURAN`, `DASAR`, `GARIS_PANDUAN`, `PEKELILIAN` |
`STATISTIC_CATEGORY` | `PERHUTANAN`, `BIODIVERSITI`, `MINERAL`, `ALAM_SEKITAR`, `IKLIM` |


**Arkib Elektronik** (induk `#`, 5 anak) | — | 🔗 halaman arkib berasingan / komposit | **3 arkib sebenar** (Teks Ucapan, Kenyataan Media, Keratan Akhbar) guna **tab tahun** `2025…2021 + Lain-lain`; **Berita** → Facebook, **Penerbitan** duplikat item MEDIA |
**Soal Jawab Parlimen** (quicklink) | — | 🆕 **modul baru** `content_parliament_qa` | Migration + CRUD + page |
**Statistik** (quicklink) | — | 🆕 **modul baru** `content_statistic` | Migration + CRUD + page |
**Takwim** (quicklink) | `content-calendar` + `calendar_web` | ✅ guna sedia ada | Tiada |
**Aduan & Maklum Balas** | `content-feedback` | ✅ guna sedia ada | Tiada |
**Tender & Sebut Harga** | `content-tender` | ✳️ admin siap, frontend belum | Fasa T3 (`tender-web`) — lihat `planning-pending-modules.md` |

**Ringkasan:** 6 item boleh guna sedia ada · 2 item tambah sedikit (flag/kolum) · **4 modul baru** (Teks Ucapan, Keratan Akhbar, Soal Jawab Parlimen, Statistik) · 1 halaman komposit (Arkib).

---

## 4. Frontend (page + komponen + menu)

> **Status 24 Okt 2026:** halaman **Arkib Elektronik** (`/nres/electronic-archive`, page ID 35) **sudah siap** — satu halaman komposit (hab + 4 tab sumber + tab tahun), seluruh kod dalam `frontend_pages.page_content` (tiada komponen). Rujuk §4.1. Belum dibina: `speech-web`, `clipping-web`, `parliament-qa-web`, `statistic-web`, `policy-web` (arkib ucapan & keratan sudah diliputi page 35).

| Page (`frontend_pages` slug) | Komponen (`PHP/*.blade.php`) | Sumber data |
|---|---|---|
`speech-web` | `speech_web` | `content_speech` |
`clipping-web` | `clipping_web` | `content_clipping` |
`archive-web` | `archive_web` | gabungan `content_speech` + `content_article` (PRESS/NEWS) + `content_clipping` |
`parliament-qa-web` | `parliament_qa_web` | `content_parliament_qa` |
`statistic-web` | `statistic_web` | `content_statistic` |
`policy-web` (pilihan) | `policy_web` | `content_download` (`download_doc_type` != null) |

Menu `frontend_menu` di bawah **Media**:
`Berita` · `Semasa` · `Kenyataan Media` · `Keratan Akhbar` · `Teks Ucapan` · `Polisi & Dasar` · `Penerbitan` · `Arkib Elektronik` · `Video` · `Statistik`.

**Pola wajib** (ikut modul sedia ada): translation `main`, dropdown dari `ref` (`descr_en` fallback `descr`), FilePond `storeAsFile`, butiran guna `?id=`, redirect create/update → index, SweetAlert untuk delete, permission `{module}.view/create/update/delete`.

---

## 5. Prioriti pelaksanaan

| # | Kerja | Saiz | Kenapa dahulu |
|---|---|---|---|
1 | **Semasa**: `article_is_featured` + tapisan `news_web` | S | Data berita dah ada, cepat nampak hasil |
2 | **Teks Ucapan** (`content_speech`) | M | Selalu dikemas kini oleh unit komunikasi |
3 | **Polisi/Dasar**: tambah `download_doc_type` + `download_year` + filter di `download_web` | S | Guna modul download sedia ada |
4 | **Keratan Akhbar** (`content_clipping`) | S–M | Ringkas, nilai paparan tinggi |
5 | **Arkib Elektronik** (komposit) | M | Gabungan 3 sumber, tiada table baru |
6 | **Teks Ucapan/Kenyataan di Berita** (submenu) | — | Selesai bila #2 & artikel PRESS wujud |
7 | **Soal Jawab Parlimen** (`content-parliament-qa`) | M | ✅ **admin siap** (`ContentParliamentQaTest` 22 ujian) — frontend (P4) belum |
8 | **Statistik** (`content_statistic`) | L | Paling kompleks (jenis data + fail) |
9 | **Tender Web (T3)** | M | Admin dah siap, portal belum papar |

---

## 6. Nota

- Menu **Media** di portal asal ada **12 item**; dengan plan ini hanya **4 modul baru** diperlukan — selebihnya guna `content-article`, `content-video`, `content-download`, `content-calendar`, `content-feedback`, `content-tender` yang sudah siap.
- Semua modul baru ikut konvensyen `content-tender` (prefix kolum, `*_translation` + `main`, `*_status`, `*_sort`, `created_by/updated_by`).
- Selepas modul admin siap: daftar `backend_menu` + `backend_role_mapping` + permission, kemudian page/komponen/menu frontend.

## 7. Arkib Elektronik — halaman siap (24 Okt 2026)

**URL:** `/nres/electronic-archive` · **Page ID:** 35 · **Slug:** `electronic-archive`

| Param | Nilai | Lalai |
|---|---|---|
| `jenis` | `berita` · `ucapan` · `kenyataan` · `keratan` | hab (**Ringkasan** — 4 kad ringkasan jenis) |
| `tahun` | tahun dokumen (cth `2026`) atau `lain` (rekod tanpa tarikh) | semua tahun |
| `q` | carian tajuk (maks 60 aksara) | — |

**Struktur:** tab sumber → tab tahun (data-driven + chip **Lain-lain** bila ada rekod tanpa tarikh) → carian →
jadual `# | Tarikh | Tajuk | <kolum ikut jenis> | Dokumen`. **Tiada paparan butiran** — tajuk & butang terus buka/muat turun fail (macam portal).

**Label kolum kedua-terakhir ikut jenis:** Berita → `Kategori` · Teks Ucapan → `Penyampai` · Kenyataan Media → `Sumber` · Keratan Akhbar → `Akhbar`.

**3 skema sumber → 1 bentuk baris seragam** (`jenis, date, title, summary, file, img, url, source, badge`):

| Sumber | Jadual | Perkara penting |
|---|---|---|
| Berita | `content_article` + `content_article_translation` | status **`ACTIVE`** (ref `ARTICLE_STATUS`); tapisan tetingkap `article_start_date`/`article_end_date` manual (kolum varchar) |
| Teks Ucapan | `content_speeches` | **terjemahan self-referencing**: induk = `speech_parent_id` NULL, anak ikut `speech_parent_id` (tajuk & fail boleh berbeza); status **`PUBLISHED`** (ref `SPEECH_STATUS`) — `->published()` **tidak boleh dipakai** kerana trait `HasPublishWindow` mencari `ACTIVE` |
| Kenyataan / Keratan | `content_media` + `content_media_translations` | `media_status = PUBLISHED`; Keratan = `media_type = KERATAN_AKHBAR` (jadual `content_clippings` = **tinggalan, jangan guna**) |

Lencana jenis tidak dipaparkan jika sama dengan nama tab (cth "Keratan Akhbar" dalam tab Keratan Akhbar); "Siaran Media" vs "Kenyataan Media" tetap dipaparkan.

**Menu** (`frontend_menu.menu_link`) — sudah diisi:

| # | Menu | `menu_link` |
|---|---|---|
| 42 | MEDIA › Teks Ucapan | `/nres/electronic-archive?jenis=ucapan` |
| 43 | MEDIA › Kenyataan Media & Siaran Media | `/nres/media-statement` |
| 44 | MEDIA › Keratan Akhbar Semasa | `/nres/electronic-archive?jenis=keratan` |
| 46 | MEDIA › Arkib Elektronik | `/nres/electronic-archive` |
| 47 | Arkib › Berita | `/nres/electronic-archive?jenis=berita` |
| 48 | Arkib › Teks Ucapan | `/nres/electronic-archive?jenis=ucapan` |
| 49 | Arkib › Kenyataan Media | `/nres/electronic-archive?jenis=kenyataan` |
| 50 | Arkib › Keratan Akhbar | `/nres/electronic-archive?jenis=keratan` |

> **Nota navbar:** `menu_link` **boleh** mengandungi query string — navbar output nilainya verbatim (`$__href`). Penentuan status **active** banding **path + query param**: param pada pautan menu mesti hadir sama dalam URL semasa (param tambahan seperti `&tahun=2026`/`&q=…` tidak menghalang), jadi item berbeza yang berkongsi path sama (anak Arkib) tidak lagi highlight serentak.
>
> **Sumber sebenar** kod navbar ialah komponen DB **`frontend_components` #20 (`navbar_nres`)** — `storage/app/private/PHP/navbar_nres.blade.php` hanyalah salinan yang dijana oleh `BladeSyncService::syncComponents()`, jadi edit pada fail itu **akan hilang**. Kemas kini melalui skrip `php storage/app/cms-page-content/fix-navbar-active.php` (idempotent + backup) dan sahkan dengan `verify-navbar-fix.php`.
>
> **Kelakuan pada halaman ber-tab:** paparan **"Semua"** (cth `/nres/electronic-archive`, `/nres/speech` tanpa param) → **tiada** anak dropdown aktif, kerana halaman itu sendiri sudah menunjukkan tab aktif; hanya apabila tab dipilih (`?jenis=keratan`, `?penyampai=MENTERI`) anak yang sepadan jadi aktif. Halaman detail (`?id=…`) juga tiada anak aktif. Induk level-3 (**Arkib Elektronik**) dipaparkan sebagai tajuk `<h6>` (bold), bukan pautan — hab boleh dicapai melalui tab **Ringkasan**. Item menu yang `menu_link` NULL (cth MEDIA, MENGENAI KAMI) memang tidak pernah "active" (induk dropdown).

Masih `menu_link = NULL`: **#41 Penerbitan** (`/nres/publication` belum diisi), **#45 Polisi, Dasar, Perundangan dan Garis Panduan** (belum ada halaman), #39 MEDIA (induk dropdown — memang NULL).

**Skrip kerja** (dalam `storage/app/cms-page-content/`, gitignored):
`template-archive.txt` → `apply-archive.php` (page 35 + cermin `PAGE_CONTENT/nres/electronic-archive.blade.php`) ·
`seed-archive-sample.php` (+ `--delete`) · `verify-archive.php` (14 kes) · `verify-archive-menu.php` (navbar + URL) ·
`assign-archive-menu.php` (backup ke `storage/app/backup/frontend_menu_backup_*.json`).

**Data contoh:** 5 keratan akhbar + 4 pasang teks ucapan (induk BM + anak EN) + 5 berita (+ 1 rekod tanpa tarikh pada setiap arkib untuk menguji chip **Lain-lain**).

