← Về thư mục
📄 / / root / ceo-project / profiles / glv / brand_monitoring / docs / brand-monitoring-architecture-v3.md

Brand Monitoring Architecture — V3

Ngày: 2026-07-14 Dựa trên: Brand Monitoring Brief V3 (đã duyệt) Link brief: https://vmi3427693.tail8c1aaf.ts.net/files/root/.hermes/kanban/boards/brand-monitoring/workspaces/t_7f5461eb/brand-monitoring-brief.md Link file này: https://vmi3427693.tail8c1aaf.ts.net/files/opt/ai-os/products/ceo/brand-monitoring/docs/brand-monitoring-architecture-v3.md


Nguyên tắc thiết kế

# Nguyên tắc Giải thích
1 Public data only Chỉ dùng nguồn public, không phụ thuộc page API hoặc nội dung đăng nhập
2 Crisis-first Mọi luồng dữ liệu đều ưu tiên phát hiện rủi ro trước, coverage sau
3 Multi-brand by design Hệ thống hỗ trợ nhiều brand, mỗi brand có config riêng
4 Fulbright là MỘT brand FUV, FSPPM là entity con của Fulbright, KHÔNG phải brand riêng
5 Graceful degradation Nguồn tạm mất vẫn không làm sập pipeline

1. Source Architecture

1.1. Ingestion Layers

Pipeline thu thập chia làm 4 lớp:

[Layer 1: Discovery] → [Layer 2: Normalize] → [Layer 3: Triage] → [Layer 4: Store & Report]

Layer 1: Public Discovery

Thu thập bài từ nguồn public. Mỗi nguồn có 1 trong 3 trạng thái:

Trạng thái Cách thu thập Ví dụ
Public RSS Tự động qua RSS/Atom feed Google News RSS, VnExpress RSS
Public page scrape Crawl công khai, tag page, topic page Tuổi Trẻ tag page, Dân Trí search
Search only Monitor qua search engine query Google News search query

Nguồn ưu tiên V1:

Nhóm Nguồn Loại
Tổng hợp Google News Search RSS
Báo VN tier 1 VnExpress, Tuổi Trẻ, Thanh Niên RSS + Page scrape
Báo VN tier 2 Dân Trí, VietnamPlus, VietnamNews RSS + Search
Chuyên mục Tag page, topic page, newsroom Page scrape
Quốc tế Chỉ khi có mention rõ ràng Search only
Social public YouTube (public video/comment), Facebook public page, X (public) API public / scrape
Academic OpenAlex, SSRN API/Search
Forum Diễn đàn public Scrape

Nguồn LOẠI BỎ khỏi scope V1: - Page API cần quyền share riêng - Private group - Nội dung cần đăng nhập - Bất kỳ nguồn nào không có quyền public rõ ràng

Layer 2: Normalization

Bước Việc làm
2.1 Chuẩn hóa tiêu đề (strip HTML, normalize unicode)
2.2 Chuẩn hóa ngày giờ (ISO 8601, timezone VN)
2.3 Chuẩn hóa nguồn (source_id canonical)
2.4 Canonical URL (bỏ tracking params, resolve redirects)
2.5 Gắn brand_id (map entity keyword → brand)
2.6 Language detection (vi / en)

Layer 3: Deduplication

Loại trùng Cách xử lý
Cùng URL Giữ 1 bản
Cùng bài khác URL Title similarity + snippet similarity > 85% → merge
Cùng nội dung repost Giữ nguồn gốc, gắn alias cho bản repost

Layer 4: Scoring & Triage

Relevance Score (0-100):

Thành phần Điểm
Core entity trong title +30
Core entity trong body +15
Crisis trigger keyword +25
Brand variant match +15
Policy context match +10
Source tier A/B +5

Sentiment Score: positive / neutral / negative / ambiguous

Crisis Gate:

Điều kiện Hành động
Negative + Relevance >= 70 HOT ALERT → gửi ngay
Negative + engagement bất thường HOT ALERT → gửi ngay
Crisis trigger keyword xuất hiện HOT ALERT → gửi ngay
Ambiguous + source lớn (tier A) → review thủ công
Neutral / Positive → vào báo cáo tuần

2. Multi-Brand Structure

2.1. Folder Layout

brand-monitoring/
├── brands/
│   └── fulbright/              ← MỘT brand duy nhất
│       ├── brand.yaml          ← tên, mô tả, ngôn ngữ, thị trường
│       ├── keywords.yaml       ← core, variant, crisis, entity children (FUV, FSPPM)
│       ├── sources.yaml        ← nguồn ưu tiên + tier
│       ├── rules.yaml          ← relevance, sentiment, crisis threshold
│       └── report.yaml         ← kênh báo cáo, cadence, template
├── shared/
│   ├── sources/                ← nguồn dùng chung (không riêng brand nào)
│   ├── taxonomy/               ← topic tag, sentiment rule, crisis rule
│   ├── workflows/              ← quy trình thu thập, xử lý, cảnh báo
│   └── templates/              ← template báo cáo
├── runs/
│   ├── raw/                    ← dữ liệu thô theo ngày
│   ├── processed/              ← dữ liệu đã normalize + dedupe
│   ├── alerts/                 ← crisis alerts đã gửi
│   └── reports/                ← báo cáo đã tạo
└── dashboard/                  ← giao diện đọc dữ liệu

2.2. Entity Hierarchy (Fulbright)

Fulbright (brand)
├── FUV (entity con — Fulbright University Vietnam)
└── FSPPM (entity con — Fulbright School of Public Policy and Management)

FUV và FSPPM KHÔNG phải brand riêng. Chúng là entity children nằm trong keywords.yaml của brand Fulbright.

2.3. Keyword Structure mỗi brand

Nhóm keyword Mục đích Ví dụ (Fulbright)
Core entity Xác định brand chính Fulbright, Đại học Fulbright
Variant entity Biến thể tên FUV, Fulbright VN, Fulbright Việt Nam
Program entity Chương trình, khoa, school FSPPM, Chính sách Công, MPP
Crisis trigger Từ khóa rủi ro scandal, tranh cãi, chỉ trích, bê bối, học phí, kiểm định
Policy context Chính sách liên quan giáo dục đại học, kiểm định, học bổng
Sentinel phrases Bật cảnh báo nóng "khủng hoảng Fulbright", "Fulbright bê bối"

3. Storage Recommendation

3.1. Decision: SQLite + JSON Archive + Google Sheets Report View

Tầng Công nghệ Lý do
Raw event store SQLite DB Đơn giản, không cần server, backup dễ
Processed mentions SQLite DB (bảng riêng) Relational, query tốt, dedup hiệu quả
Alert log SQLite DB + JSON Track mọi alert đã gửi
Weekly report Markdown + optional Google Sheets view Dễ đọc, dễ chia sẻ
Archive Compressed JSON (daily .jsonl.gz) Lưu trữ dài hạn, tái phân tích

3.2. SQLite Schema (core tables)

-- Bài thô thu thập
CREATE TABLE raw_items (
    id          INTEGER PRIMARY KEY,
    source_id   TEXT NOT NULL,
    url         TEXT NOT NULL UNIQUE,
    title       TEXT,
    snippet     TEXT,
    published   TEXT,  -- ISO 8601
    fetched_at  TEXT,
    brand_id    TEXT,
    lang        TEXT,
    raw_json    TEXT   -- toàn bộ payload gốc
);

-- Bài đã normalize + score
CREATE TABLE mentions (
    id              INTEGER PRIMARY KEY,
    raw_item_id     INTEGER REFERENCES raw_items(id),
    brand_id        TEXT NOT NULL,
    url_canonical   TEXT,
    title_clean     TEXT,
    published       TEXT,
    source_tier     TEXT,  -- A, B, C, D
    relevance_score INTEGER,
    sentiment       TEXT,  -- positive, neutral, negative, ambiguous
    is_crisis       INTEGER DEFAULT 0,
    crisis_reason   TEXT,
    dedup_hash      TEXT,
    processed_at    TEXT
);

-- Alert log
CREATE TABLE alerts (
    id          INTEGER PRIMARY KEY,
    mention_id  INTEGER REFERENCES mentions(id),
    brand_id    TEXT,
    alert_type  TEXT,  -- hot_alert, review_manual
    sent_at     TEXT,
    channel     TEXT,  -- telegram, email, etc.
    status      TEXT   -- sent, failed, acknowledged
);

-- Weekly report metadata
CREATE TABLE reports (
    id              INTEGER PRIMARY KEY,
    brand_id        TEXT,
    report_type     TEXT,  -- daily, weekly
    period_start    TEXT,
    period_end      TEXT,
    generated_at    TEXT,
    file_path       TEXT,
    hot_alert_count INTEGER,
    negative_count  INTEGER,
    neutral_count   INTEGER,
    positive_count  INTEGER
);

3.3. File Location

/opt/ai-os/products/ceo/brand-monitoring/
├── data/
│   └── brand-monitoring.db       ← SQLite chính
├── archive/
│   └── 2026/07/14.jsonl.gz       ← archive theo ngày
├── reports/
│   └── 2026-W29-fulbright.md     ← report tuần
└── docs/
    └── brand-monitoring-architecture-v3.md  ← file này

4. Cron Schedule

4.1. Collection Jobs

Job Schedule Mô tả
collect-rss Mỗi 6 giờ (0 /6 * * ) Thu thập RSS feeds (Google News, báo VN)
collect-scrape Mỗi 12 giờ (0 /12 * * ) Crawl tag pages, topic pages
collect-social Mỗi 12 giờ (0 6,18 * * *) Thu thập YouTube, Facebook public
sentinel-check Mỗi 1 giờ (0 * * * *) Check nhanh crisis keywords trên Google News

4.2. Processing Jobs

Job Schedule Mô tả
normalize-dedupe Sau mỗi collection (event-driven hoặc cron 30 phút sau collect) Normalize + dedupe raw items
score-triage Sau normalize Relevance + sentiment + crisis gate
alert-dispatch Real-time sau crisis gate Gửi hot alert nếu crisis detected

4.3. Reporting Jobs

Job Schedule Mô tả
daily-summary Hàng ngày 21:00 VN (0 14 * * * UTC) Tổng kết ngày, highlight crisis nếu có
weekly-digest Thứ Hai 08:00 VN (0 1 * * 1 UTC) Báo cáo tuần đầy đủ
archive-daily Hàng ngày 23:00 VN (0 16 * * * UTC) Compress raw data thành .jsonl.gz

4.4. Maintenance Jobs

Job Schedule Mô tả
cleanup-raw Mỗi tuần (0 3 * * 0 UTC) Xóa raw items > 90 ngày (đã archive)
db-vacuum Mỗi tháng (0 4 1 * * UTC) SQLite VACUUM

5. Report Flow

5.1. Pipeline tạo báo cáo

mentions (DB) → filter by brand + period → group by sentiment →
    sort by crisis priority → render template → output markdown →
    optional: push to Google Sheets → deliver via Telegram/email

5.2. Cấu trúc báo cáo tuần (crisis-first)

Thứ tự Section Nội dung
1 Crisis & Risk Summary Số crisis alerts, top items nguy hiểm nhất
2 Negative Items Danh sách nội dung tiêu cực, nguồn, relevance
3 Neutral Coverage Tin nhắc đến brand nhưng trung lập
4 Positive Signals Tín hiệu tốt
5 Topic Clusters Nhóm chủ đề nổi bật, chủ đề lặp lại
6 Recommended Actions Đề xuất hành động dựa trên dữ liệu

5.3. Mẫu đầu ra báo cáo

brand: fulbright
report_date: 2026-07-14
period: 2026-07-07 to 2026-07-14
hot_alert_count: 2
negative_count: 5
neutral_count: 23
positive_count: 8
top_sources:
  - VnExpress (7 mentions)
  - Tuổi Trẻ (4 mentions)
  - Google News (12 mentions)
recommended_actions:
  - "Theo dõi bài tiêu cực trên Tuổi Trẻ về học phí"
  - "Phản hồi bài viết sai thông tin trên Dân Trí"

5.4. Delivery channels

Kênh Dùng cho
Telegram (hot alert) Crisis alert → gửi ngay vào group/topic
Telegram (weekly) Báo cáo tuần → gửi vào topic riêng
Markdown file Lưu tại /opt/ai-os/products/ceo/brand-monitoring/reports/
Google Sheets (optional) View cho stakeholders không dùng Telegram

6. Archive Flow

6.1. Archive pipeline

Raw items (SQLite) → daily export → compress → /archive/YYYY/MM/DD.jsonl.gz
Processed mentions → keep in DB forever (lightweight)
Alerts → keep in DB forever (audit trail)
Reports → keep as markdown files → organized by year-week

6.2. Retention policy

Dữ liệu Giữ ở DB Giữ ở archive
Raw items 90 ngày Vĩnh viễn (compressed)
Processed mentions Vĩnh viễn N/A (đã ở DB)
Alerts Vĩnh viễn N/A
Reports Vĩnh viễn (file) N/A

6.3. Archive format

Mỗi ngày tạo 1 file archive:

archive/2026/07/14.jsonl.gz

Mỗi dòng là 1 JSON record chứa raw item + processed mention + alert (nếu có).


7. Dashboard Decision

7.1. V1: Không build dashboard riêng

Quyết định: V1 dùng Markdown reports + optional Google Sheets view.

Lý do: 1. Chưa có đủ dữ liệu để justify dashboard riêng 2. Markdown report đọc được trên Tailscale Funnel 3. Google Sheets view cho stakeholders không kỹ thuật 4. Giảm complexity vận hành

7.2. Khi nào upgrade lên dashboard thật

Khi đạt 1 trong các điều kiện: - Chạy ổn > 4 tuần liên tục - > 100 mentions/tuần cần browse - > 2 brands cùng lúc - CEO yêu cầu real-time view

7.3. Dashboard path (khi cần)

Khi upgrade, ưu tiên: 1. Static HTML generated từ data (simple, hostable trên Tailscale Funnel) 2. Hoặc Notion/Airtable view (nếu team đã dùng) 3. Không dùng tool phức tạp (Grafana, Metabase) ở V1


8. Operational Pipeline Summary

┌─────────────────────────────────────────────────────────┐
│                    COLLECTION (Cron)                     │
│  RSS Feeds ──┐                                          │
│  Page Scrape ├──→ Raw Items → SQLite raw_items table    │
│  Social      ──┘                                        │
│  Sentinel ───→ Quick crisis keyword check (hourly)      │
└──────────────────────────┬──────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────┐
│                   PROCESSING (Cron)                      │
│  Normalize → Dedupe → Relevance Score → Sentiment Score │
│                           │                              │
│                           ▼                              │
│                     Crisis Gate                          │
│                    ╱           ╲                          │
│               YES                NO                      │
│                │                  │                       │
│           Hot Alert         Weekly Queue                  │
└──────────────────────────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────┐
│                    DELIVERY (Cron)                        │
│  Hot Alert → Telegram ngay lập tức                       │
│  Daily Summary → 21:00 VN                                │
│  Weekly Digest → Thứ Hai 08:00 VN                        │
└──────────────────────────────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────┐
│                    ARCHIVE (Cron)                         │
│  Daily: raw → .jsonl.gz                                  │
│  Weekly: cleanup raw > 90 ngày                           │
│  Monthly: DB VACUUM                                      │
└─────────────────────────────────────────────────────────┘

9. Output File

File kiến trúc này được lưu cố định tại:

/opt/ai-os/products/ceo/brand-monitoring/docs/brand-monitoring-architecture-v3.md

Truy cập qua Tailscale Funnel:

https://vmi3427693.tail8c1aaf.ts.net/files/opt/ai-os/products/ceo/brand-monitoring/docs/brand-monitoring-architecture-v3.md

10. Điểm khác so với draft cũ

Vấn đề ở draft cũ Sửa ở V3
Thiếu multi-brand structure chi tiết Có folder layout + entity hierarchy đầy đủ
FUV/FSPPM mơ hồ Ghi rõ: entity con, KHÔNG phải brand riêng
Storage chỉ liệt kê option Quyết định rõ: SQLite + JSON archive
Thiếu cron schedule Có bảng cron cụ thể với schedule, timezone
Thiếu report flow Có pipeline + template + delivery channels
Thiếu archive flow Có retention policy + format + path
Dashboard chưa quyết Quyết định V1: Markdown + optional Google Sheets
File ở workspace tạm File cố định ở /opt/ai-os/products/ceo/brand-monitoring/docs/