Tất cả bài viết
16 tháng 3, 2026·8 phút đọc·ERPFit Team
pime-commercetypescripterpnextproduct-management
Xây dựng hệ thống PIM cho thương mại điện tử Việt Nam

Xây dựng hệ thống PIM cho thương mại điện tử Việt Nam

Tại sao quản lý sản phẩm bằng Excel không còn đủ — và cách chúng tôi xây dựng hệ thống Product Information Management từ đầu.

Mục lục

Khi bạn bán 300 sản phẩm trên 1 website, quản lý bằng Excel vẫn ổn. Khi bạn bán 300 sản phẩm trên 5 website khác nhau, đồng bộ với ERP, và cần đẩy lên Shopee, Lazada, TikTok Shop — Excel trở thành cơn ác mộng.

Đó là tình huống thực tế mà chúng tôi gặp khi làm việc với một doanh nghiệp phân phối thiết bị trong ngành F&B. 6 thương hiệu, hàng trăm sản phẩm, 5 website vệ tinh theo từng brand, 1 hệ thống ERP quản lý kho — và không có nơi nào là "nguồn sự thật" duy nhất cho dữ liệu sản phẩm.

Vấn đề thực sự không phải là thiếu công cụ

Thị trường Việt Nam có KiotViet, MISA, Haravan — tất cả đều tốt cho việc bán hàng và quản lý đơn. Nhưng không có công cụ nào giải quyết bài toán nội dung sản phẩm: tên sản phẩm bằng tiếng Việt đúng chính tả, mô tả chi tiết cho từng kênh bán, hình ảnh đúng kích thước cho từng sàn, thông số kỹ thuật có cấu trúc để so sánh.

Product Information Management — PIM — là lớp dữ liệu nằm giữa ERP (quản lý kho, giá, đơn hàng) và các kênh bán (website, sàn TMĐT, catalog). PIM không thay thế ERP hay WooCommerce — nó là nguồn sự thật cho nội dung sản phẩm.

Thiết kế dữ liệu cho thị trường Việt Nam

Bài toán đầu tiên: i18n. Mỗi trường văn bản — tên, mô tả, thông số — đều cần hỗ trợ song ngữ Việt-Anh ngay từ schema:

// Mỗi trường text lưu dạng { vi, en }
name: { vi: "Cối xay cà phê Kinu M47", en: "Kinu M47 Hand Grinder" }
description: { vi: "...", en: "..." }

Đây không chỉ là dịch thuật. Tên sản phẩm trên Shopee khác với tên trên website riêng. Mô tả trên Lazada có giới hạn ký tự khác TikTok Shop. Hệ thống phải cho phép mỗi kênh bán có nội dung riêng, nhưng vẫn kế thừa từ bản gốc trong PIM.

Giá tiền dùng số nguyên — VND không có phần thập phân. Một sai lầm phổ biến khi dùng thư viện nước ngoài là lưu giá dạng float, dẫn đến lỗi làm tròn trên các hóa đơn lớn.

Hệ thống thuộc tính linh hoạt

Mỗi ngành hàng có thông số riêng. Cối xay cà phê cần "loại lưỡi" (burr/blade), "dung tích" (gram), "vật liệu thân" (thép/gỗ). Ấm đun nước cần "dung tích" (ml), "công suất" (W), "có đo nhiệt không".

Thay vì hardcode từng trường, chúng tôi xây dựng hệ thống thuộc tính động:

  • 15+ kiểu dữ liệu: TEXT, RICHTEXT, NUMBER, BOOLEAN, DATE, SINGLE_SELECT, MULTI_SELECT, PRICE, METRIC, IMAGE, FILE, URL, TABLE
  • Nhóm thuộc tính: Thông tin chung, Kỹ thuật, Marketing, Vận chuyển, SEO — nhóm lại theo ngữ cảnh sử dụng
  • Product Family: Mỗi nhóm sản phẩm (Grinder, Kettle, Scale) định nghĩa sẵn bộ thuộc tính bắt buộc và tùy chọn
  • Localizable + Scopable: Thuộc tính có thể khác nhau theo ngôn ngữ (vi/en) hoặc theo kênh bán (website/Shopee/Lazada)

Mô hình này lấy cảm hứng từ Akeneo — PIM open-source phổ biến nhất thế giới. Nhưng Akeneo viết bằng PHP/Symfony, yêu cầu Elasticsearch, và không có sẵn hỗ trợ cho các sàn TMĐT Đông Nam Á. Chúng tôi cần thứ nhẹ hơn, chạy được trên VPS $10/tháng.

Theo dõi nguồn gốc dữ liệu

Khi dữ liệu sản phẩm đến từ nhiều nguồn — ERP, WooCommerce, website vệ tinh, website chính hãng, nhập thủ công — câu hỏi quan trọng không phải "giá trị hiện tại là gì" mà là "giá trị này đến từ đâu và khi nào".

Chúng tôi xây dựng hệ thống provenance tracking ở cấp độ từng trường:

  • Mỗi giá trị được gán nhãn nguồn: erpnext, woocommerce, wp-kruve, scraper-fellow, manual, ai-enriched
  • Mỗi thay đổi được lưu revision: giá trị cũ, giá trị mới, ai thay đổi, lúc nào
  • Deep link ngược về nguồn gốc — click vào giá trị tồn kho có thể nhảy thẳng đến record trong ERPNext

Điều này nghe có vẻ quá kỹ cho một SME. Nhưng khi bạn phát hiện giá sản phẩm trên Shopee bị sai, bạn cần biết ngay: giá này đến từ đâu? Ai cập nhật lần cuối? Giá đúng nằm ở đâu? Provenance giải quyết những câu hỏi này trong vài giây thay vì vài giờ.

Đồng bộ với ERPNext

ERPNext là hệ thống ERP chính — quản lý kho, giá bán, đơn hàng. PIM không thay thế ERPNext — nó đọc dữ liệu tồn kho và giá từ ERPNext, rồi bổ sung thêm nội dung marketing mà ERPNext không quản lý.

Quy trình đồng bộ:

  1. PIM gọi API ERPNext, lấy danh sách Bin (tồn kho theo kho hàng) và Item Price (giá bán)
  2. Tổng hợp tồn kho từ tất cả kho, suy ra trạng thái: IN_STOCK, LOW_STOCK (≤3), OUT_OF_STOCK
  3. Lưu kết quả vào PIM kèm timestamp — không ghi đè dữ liệu gốc trong ERPNext
  4. Ghi log vào bảng DataSource — theo dõi mỗi lần sync thành công hay thất bại

Chỉ sản phẩm có trạng thái SOLD và đã liên kết mã ERPNext mới được sync. Sản phẩm INFO_ONLY (chỉ hiển thị thông tin, không bán) không cần tồn kho.

Thu thập nội dung từ website chính hãng

Mỗi thương hiệu có website riêng với thông số kỹ thuật, hình ảnh chất lượng cao, mô tả chi tiết. Thay vì copy-paste thủ công, chúng tôi viết adapter cho từng thương hiệu:

  • Adapter phân tích cấu trúc HTML của từng website — có brand chạy Shopify, có brand dùng WordPress, có brand là static site
  • Trích xuất thông số kỹ thuật dạng bảng, hình ảnh độ phân giải cao, JSON-LD structured data
  • Normalize về schema chung của PIM — specs thành key-value pairs, images kèm alt text
  • Không tự động ghi đè — dữ liệu scrape được đưa vào hàng đợi để review trước khi approve

Mỗi adapter là một class riêng, kế thừa từ BaseBrandAdapter. Khi thêm thương hiệu mới, chỉ cần viết một adapter mới — không cần sửa logic core.

Completeness scoring — sản phẩm đã sẵn sàng chưa?

Mỗi kênh bán có yêu cầu khác nhau. Shopee cần tối thiểu: tên, hình, danh mục, giá, tồn kho. Website riêng cần thêm: mô tả dài, thông số kỹ thuật, bài viết review. Lazada cần XML theo schema riêng.

Hệ thống completeness scoring tính điểm hoàn thiện cho từng sản phẩm, theo từng kênh:

  • Thiếu tên tiếng Việt? Completeness cho website giảm.
  • Thiếu hình vuông 1:1? Completeness cho Shopee giảm.
  • Đủ hết? Badge "Ready to publish" hiện lên — nhân viên biết sản phẩm nào cần bổ sung gì.

Đây không phải feature phức tạp — chỉ là đếm xem thuộc tính bắt buộc đã có giá trị chưa. Nhưng tác dụng thực tế rất lớn: thay vì hỏi "tại sao sản phẩm này chưa lên Shopee?", nhìn điểm completeness là biết ngay thiếu gì.

Stack kỹ thuật

Toàn bộ hệ thống chạy trên TypeScript/Bun:

  • API: Hono + tRPC — end-to-end type safety từ database đến UI
  • Database: PostgreSQL + Prisma — schema migrations, type-safe queries
  • Admin UI: Expo (React Native for Web) — chạy trên browser, có thể build app mobile sau
  • Static sites: Astro — generate HTML tĩnh cho từng brand site, zero JavaScript mặc định
  • Media: Cloudflare R2 — lưu trữ hình ảnh, chi phí rất thấp

Monorepo với Bun workspaces — packages chia theo chức năng (@pim/db, @pim/core, @pim/shared, @pim/ui), apps chia theo deployment target (api, app, web). Một lần thay đổi type trong shared thì API và UI đều nhận được ngay — không cần publish package hay sync version.

Bài học sau khi xây dựng

Schema-first, không feature-first. Chúng tôi dành nhiều thời gian thiết kế data model trước khi viết dòng code UI đầu tiên. Product, Brand, Category, Attribute, Family, Channel — mỗi entity phải đúng từ đầu vì migration sau này rất tốn kém.

Đừng cố thay thế ERP. PIM quản lý nội dung, ERP quản lý nghiệp vụ. Ranh giới này cần rõ ràng. Khi PIM bắt đầu quản lý đơn hàng hay tồn kho chi tiết, nó sẽ trở thành ERP thứ hai — và không ai cần hai ERP.

Provenance tracking tốn công xây nhưng tiết kiệm thời gian debug. Khi có vấn đề về dữ liệu — giá sai, tên thiếu dấu, hình bị lỗi — biết ngay nguồn gốc giúp sửa trong phút thay vì mất cả buổi tra ngược.

Completeness scoring thay đổi cách team làm việc. Thay vì quản lý dựa trên checklist manual hay nhắc nhở qua tin nhắn, mỗi người nhìn dashboard là biết sản phẩm nào cần hoàn thiện gì cho kênh nào. Tự động hóa quy trình quản lý chất lượng dữ liệu.

PIM không phải sản phẩm hào nhoáng. Nó là hạ tầng — lớp nền mà mọi thứ khác xây dựng trên đó. Nhưng với doanh nghiệp bán hàng đa kênh tại Việt Nam, đây là lớp nền đang thiếu nhất.

Chia sẻ:𝕏FBin