Chương 10. Làm việc với dữ liệu

📚 Mục lục sách

Sau khi đã kết nối được MCP Server ở Chương 9, giờ là lúc chúng ta ghép dữ liệu thực tế cho tiệm bánh ngọt vào website, thay vì chỉ dừng lại ở giao diện và dữ liệu giả lập như các chương trước. Đây là một trong những phần việc phức tạp nhưng cũng thú vị nhất của Vibe Coding: biến một giao diện đẹp thành một sản phẩm thật sự "sống" được nhờ dữ liệu thật.

EzyPlatform mang đến một cách làm khác

Ngày nay trên thị trường có rất nhiều dịch vụ lưu trữ dữ liệu dành riêng cho vibe coding (ví dụ Supabase, Firebase, Xano...), hầu hết sẽ cấp cho bạn một kho dữ liệu trống rồi để bạn tự do tạo ra các bảng, các tập dữ liệu theo ý muốn. Cách này nhìn qua có vẻ tiện lợi, nhưng lại kéo theo không ít vấn đề: vì mọi thứ được tạo tự do, không theo một chuẩn chung nào, nên hễ sang dự án khác là AI lại phải học lại từ đầu cách bạn tổ chức dữ liệu, không tái dùng được kinh nghiệm giữa các dự án; dữ liệu và giao diện cũng nằm tách biệt hoàn toàn, nên bạn phải tự đảm bảo cả hai luôn đồng bộ với nhau. Quan trọng hơn cả, cơ sở dữ liệu đó không thuộc về bạn mà thuộc về nhà cung cấp dịch vụ — một khi dịch vụ đó gặp sự cố hoặc ngừng hoạt động, website của bạn cũng ngừng hoạt động theo, dù code của bạn không hề có lỗi gì.

Ngoài ra, bạn buộc phải truy cập cơ sở dữ liệu này qua API — nghĩa là nội dung trang không còn được render sẵn ở phía máy chủ — điều này làm triệt tiêu khả năng SEO của website.

flowchart LR
    subgraph ngoai["Dịch vụ dữ liệu ngoài"]
        direction LR
        U1["Trình duyệt"] -->|"gọi API"| S1[("Kho dữ liệu tách rời")]
        S1 -->|"trả JSON"| U1
    end
    subgraph ezy["EzyPlatform"]
        direction LR
        U2["Trình duyệt"] -->|"yêu cầu trang"| M2["Máy chủ EzyPlatform"]
        M2 -->|"trả HTML render sẵn"| U2
    end

    classDef browser fill:#6366f1,stroke:#4338ca,color:#ffffff;
    classDef data fill:#f59e0b,stroke:#b45309,color:#ffffff;
    classDef server fill:#10b981,stroke:#047857,color:#ffffff;
    class U1,U2 browser;
    class S1 data;
    class M2 server;
    linkStyle default stroke:#94a3b8,stroke-width:1.5px;

Với dịch vụ dữ liệu ngoài, trình duyệt phải tự gọi API rồi tự dựng giao diện — công cụ tìm kiếm ghé qua chỉ thấy một trang gần như trống rỗng. Với EzyPlatform, máy chủ trả về ngay HTML đã có đủ nội dung.

Nếu ai đó nói SEO đã không còn cần thiết trong thời đại AI thì không đúng: SEO vẫn cần, vì chính AI cũng phải "đi tìm kiếm" nội dung web hay tra cứu Google để trả lời câu hỏi của người dùng.

EzyPlatform mang đến cho bạn một cách tiếp cận khác, tối ưu và an toàn hơn. Nó cung cấp sẵn các API — do chính EzyPlatform hoặc các nhà phát triển khác tạo ra thông qua plugin — và bạn cũng có thể nhờ AI dùng MCP (xem lại Chương 9) để tự tạo thêm API theo đúng nghiệp vụ của mình.

API này có hai dạng, dùng cho hai tình huống khác nhau: dạng thứ nhất được gọi ngay khi render trang — với những trang cần SEO, bạn dùng các hàm ezyfunctions ngay trong template Thymeleaf để dữ liệu được render sẵn ở phía máy chủ; dạng thứ hai là gọi API bình thường, dùng cho những trang không cần SEO.

flowchart TD
    A["Trang cần hiển thị dữ liệu"] --> B{"Trang có cần SEO không?"}
    B -- "Cần SEO<br/>(trang công khai, Google lập chỉ mục)" --> C["Gọi hàm ezyfunctions<br/>ngay trong template Thymeleaf"]
    C --> D["HTML render sẵn<br/>ở phía máy chủ"]
    B -- "Không cần SEO<br/>(trang quản trị, sau đăng nhập...)" --> E["Gọi API<br/>(GraphQL/REST)"]
    E --> F["Dữ liệu trả về<br/>cho trình duyệt tự xử lý"]

    classDef start fill:#3b82f6,stroke:#1d4ed8,color:#ffffff;
    classDef decision fill:#f59e0b,stroke:#b45309,color:#ffffff;
    classDef seo fill:#10b981,stroke:#047857,color:#ffffff;
    classDef api fill:#6366f1,stroke:#4338ca,color:#ffffff;
    class A start;
    class B decision;
    class C,D seo;
    class E,F api;
    linkStyle default stroke:#94a3b8,stroke-width:1.5px;

Sức mạnh thật sự của EzyPlatform nằm ở chỗ bạn không phải đánh đổi giữa "tiện lợi" và "tối ưu" như khi dùng dịch vụ ngoài:

  • Không cần dựng hạ tầng dữ liệu riêng: entity và API cho những nghiệp vụ phổ biến (sản phẩm, đơn hàng, bài viết, khách hàng...) đã có sẵn — bạn chỉ việc dùng, không phải tự thiết kế bảng, tự viết API từ đầu như khi bắt đầu với một kho dữ liệu trống.
  • Vẫn có API riêng khi cần: nếu nghiệp vụ đặc thù chưa có sẵn, bạn nhờ AI tự tạo thêm qua MCP (fetcher, xem lại Chương 9) — không cần lập trình viên can thiệp, không cần build lại phần mềm.
  • Không phải hi sinh SEO để đổi lấy sự tiện lợi: nhờ hỗ trợ song song cả render sẵn phía máy chủ (ezyfunctions) lẫn API, bạn chọn đúng cách phù hợp cho từng trang, thay vì buộc phải chọn một trong hai cho toàn bộ website.
  • Bảo mật theo phân quyền có sẵn: mọi truy cập dữ liệu qua API hay MCP đều đi qua cùng một cơ chế phân quyền của EzyPlatform, không phải tự dựng thêm một lớp bảo mật riêng cho kho dữ liệu như khi dùng dịch vụ ngoài.
  • Bạn làm chủ cơ sở dữ liệu của chính mình: cơ sở dữ liệu chạy trên hạ tầng do bạn kiểm soát, không phải "mượn" của một nhà cung cấp thứ ba. Nếu dịch vụ dữ liệu ngoài kia gặp sự cố, sản phẩm của bạn cũng gặp sự cố theo — còn với EzyPlatform, cơ sở dữ liệu là của bạn, chỉ cần hạ tầng của bạn còn chạy thì dữ liệu vẫn còn đó, không phụ thuộc vào việc bên thứ ba có "sập" hay không.

Cài đặt phía máy chủ

Trước khi ghép dữ liệu thật cho tiệm bánh ngọt, bạn cần cấu hình một số thông tin nền tảng ở phía máy chủ để module E-Commerce hoạt động đúng cho thị trường Việt Nam: quốc gia, tỉnh/thành, ngân hàng, tiền tệ, và cửa hàng cùng chi nhánh, kho chứa của nó.

Bước 1: Cài đặt thêm hai plugin

Ngoài EzyArticle, EzySupport, Freestyle, GraphQL đã cài từ Chương 3, bạn hãy cài đặt thêm hai plugin sau (xem lại hướng dẫn cài đặt plugin cho EzyPlatform nếu cần):

  • Ecommerce: dùng cho các nghiệp vụ liên quan đến thương mại điện tử — sản phẩm, đơn hàng, cửa hàng, kho chứa...
  • Logs Monitor: dùng để xem logs khi cần, hữu ích lúc gỡ lỗi.

Bước 2: Thêm quốc gia và tải địa giới hành chính

Truy cập menu các quốc gia của E-Commerce, hoặc theo đường dẫn {đường dẫn admin của bạn}/ecommerce/countries, rồi thêm quốc gia Việt Nam.

Thêm mới quốc gia Việt Nam trong E-Commerce
Điền đầy đủ thông tin quốc gia Việt Nam — mã vn, mã vùng điện thoại +84, mã tiền tệ chuẩn ISO VND — rồi bấm Sửa để lưu.

Sau khi thêm quốc gia Việt Nam thành công, bạn có thể tải về các địa giới hành chính (tỉnh/thành phố) từ các dịch vụ có sẵn mà E-Commerce cung cấp, thay vì phải nhập tay từng tỉnh.

Tải danh sách tỉnh/thành phố Việt Nam từ dịch vụ có sẵn
Bấm Lấy từ rồi chọn một nguồn có sẵn (ví dụ Viettel Post) để tự động tải về toàn bộ tỉnh/thành phố của Việt Nam.

Bước 3: Tải danh sách ngân hàng

Truy cập menu các ngân hàng, hoặc theo đường dẫn {đường dẫn admin của bạn}/ecommerce/banks. Tại đây bạn có thể thêm mới ngân hàng thủ công hoặc tải xuống danh sách ngân hàng có sẵn, sau đó kích hoạt đúng ngân hàng mà mình đang sử dụng.

Danh sách ngân hàng, tải xuống các ngân hàng của Vietnam
Bấm Tải xuống các ngân hàng của Vietnam để lấy đầy đủ danh sách, sau đó kích hoạt ngân hàng bạn thực sự dùng.

Bước 4: Cài đặt tiền tệ

Truy cập menu các loại tiền, hoặc theo đường dẫn {đường dẫn admin của bạn}/ecommerce/currencies. E-Commerce đã có sẵn VNĐ, bạn chỉ cần chọn VNĐ làm tiền tệ mặc định.

Danh sách các loại tiền, chọn VNĐ làm mặc định
Danh sách tiền tệ đã có sẵn — bấm Lựa chọn ở dòng VND để đặt làm tiền tệ mặc định.

Bước 5: Tạo cửa hàng

Truy cập menu các cửa hàng, hoặc theo đường dẫn {đường dẫn admin của bạn}/ecommerce/shops, rồi bấm Thêm mới. Nhập tên cửa hàng tuỳ ý và đặt trạng thái đã kích hoạt — ví dụ ở đây đặt tên là "Cửa hàng bánh ngọt".

Thêm mới cửa hàng, ví dụ Cửa hàng bánh ngọt
Điền tên cửa hàng — ví dụ "Cửa hàng bánh ngọt"; các trường còn lại có thể để trống và bổ sung sau.
Danh sách cửa hàng sau khi tạo thành công
Cửa hàng vừa tạo xuất hiện trong danh sách, ở trạng thái Đã kích hoạt.

Sau khi thêm cửa hàng thành công, bạn sẽ được chuyển đến màn hình chi tiết cửa hàng — tại đây có thể bổ sung tài khoản ngân hàng để nhận thanh toán.

Thêm tài khoản ngân hàng cho cửa hàng
Thêm tài khoản ngân hàng của cửa hàng để khách hàng có thể chuyển khoản thanh toán.

Bước 6: Bổ sung chi nhánh và kho chứa

Tiếp theo, bổ sung ít nhất một chi nhánh của cửa hàng — địa chỉ chi nhánh có thể trùng với địa chỉ cửa hàng.

Danh sách chi nhánh của cửa hàng
Chi nhánh "Tiệm bánh Hà Nội" vừa tạo, thuộc vùng Miền Bắc, tỉnh/thành Hà Nội.

Cuối cùng, bổ sung ít nhất một kho chứa — thông tin kho chứa có thể trùng với thông tin chi nhánh. Đây là địa chỉ mà nhân viên giao hàng sẽ đến lấy hàng nếu bạn giao qua dịch vụ vận chuyển.

Danh sách kho chứa của cửa hàng
Kho chứa "Tiệm bánh Hà Nội" với địa chỉ và số điện thoại liên hệ để đơn vị vận chuyển đến lấy hàng.

Khởi tạo dữ liệu sản phẩm

Muốn AI lấy được dữ liệu thật để trả lời câu hỏi của bạn, trước tiên phải có dữ liệu thật để lấy. Phần này bạn sẽ tự tay tạo một vài sản phẩm mẫu cho tiệm bánh — công việc thủ công cuối cùng trước khi AI quay lại "cầm lái" ở các phần sau.

Sản phẩm cần có ảnh minh hoạ. Nếu bạn chỉ đang thử nghiệm và chưa có ảnh thật, có thể nhờ AI tự tải sẵn vài ảnh mẫu có trong các template về thư mục /api/v1/media:

📋 Prompt mẫu — Tải ảnh mẫu
Tải các ảnh trong các template về để trong thư mục api/v1/media giúp tôi

Sau khi AI tải ảnh về xong, ảnh cũng sẽ được tự động tải lên máy chủ, sẵn sàng để gắn vào sản phẩm.

Tạo sản phẩm đầu tiên

Truy cập menu các sản phẩm, hoặc theo đường dẫn {đường dẫn admin của bạn}/ecommerce/products, rồi bấm Thêm mới. Điền tên sản phẩm, mã sản phẩm, hình ảnh, giá bán, kích thước, màu sắc — và vì đây là sản phẩm cần giao hàng, nhớ tích vào ô Yêu cầu vận chuyển.

Thêm sản phẩm mới - thông tin cơ bản
Thông tin cơ bản của sản phẩm — ví dụ đặt tên "Chocolate Dream Cake", mã chocolate-dream-cake, kèm ảnh biểu tượng và băng rôn.
Thông tin giá bán sản phẩm
Thông tin giá bán — giá gốc, phần trăm chiết khấu, giá sau chiết khấu, và cửa hàng sở hữu sản phẩm.
Thông tin vận chuyển sản phẩm
Tích vào Yêu cầu vận chuyển, chọn kho chứa, rồi nhập cân nặng và kích thước đóng gói.

Thêm màu sắc và kích thước

Ở màn hình chi tiết sản phẩm, bấm vào phần Các màu sắc để thêm một màu mới.

Thêm màu sản phẩm mới
Đặt tên (dùng làm đường dẫn) và tên hiển thị cho màu — ví dụ để mặc định là default / "Mặc định" nếu sản phẩm chỉ có một biến thể.
Danh sách màu sắc sau khi thêm
Màu vừa thêm xuất hiện trong danh sách, có thể sửa hoặc xoá bất cứ lúc nào.

Truy cập vào bên trong màu để bổ sung hình ảnh — những ảnh này sẽ được hiển thị ở màn hình chi tiết sản phẩm ngoài website.

Các ảnh đa phương tiện bên trong màu sản phẩm
Gắn thêm các ảnh minh hoạ cho từng màu sản phẩm — đây là các ảnh mẫu vừa được AI tải về.

Tương tự, ở phần Các kích thước, bạn nhập các giá trị cách nhau bởi dấu phẩy.

Cài đặt các kích thước sản phẩm
Nhập các kích thước cách nhau bởi dấu phẩy, ví dụ Nhỏ,Vừa,Lớn.

Tạo danh mục và gắn sản phẩm vào danh mục

Truy cập menu các danh mục sản phẩm, hoặc theo đường dẫn {đường dẫn admin của bạn}/ecommerce/product-categories, rồi bấm Thêm mới. Nhập tên, tên hiển thị và mô tả cho danh mục — ví dụ đặt tên là banh.

Thêm mới danh mục sản phẩm
Tên danh mục banh, tên hiển thị "Bánh" — dùng chung cho mọi loại bánh của cửa hàng.

Sau khi tạo xong, bạn có thể gắn sản phẩm vào danh mục theo hai chiều: thêm sản phẩm vào danh mục ngay ở màn hình chi tiết danh mục,

Thêm sản phẩm vào danh mục
Ở màn hình chi tiết danh mục, chọn sản phẩm rồi bấm Thực thi để gắn vào danh mục.

hoặc ngược lại, gắn danh mục ngay ở màn hình chi tiết sản phẩm.

Gắn danh mục ở màn hình chi tiết sản phẩm
Ở màn hình chi tiết sản phẩm, gõ tên danh mục rồi bấm Thêm để gắn ngay tại đây.

Ghép dữ liệu cho màn hình trang chủ cửa hàng bánh

Có lẽ bạn đã rất sốt ruột rồi — sau khá nhiều thao tác thủ công, giờ là lúc quay lại "giao việc" cho AI. Mở một phiên chat mới, kiểm tra kết nối MCP như ở Chương 9 và đảm bảo nó kết nối thành công, sau đó gõ prompt sau để AI nắm được danh sách các hàm ezyfunctions đang có:

📋 Prompt mẫu — Tải schema ezyfunction
Thông qua mcp server hãy tải tập tin web ezyfunction schema về

AI sẽ tải tập tin web-ezy-function-schema.json về thư mục .agents. Sau khi tải xong, bạn gõ tiếp prompt để thay dữ liệu giả trên trang chủ bằng dữ liệu thật:

📋 Prompt mẫu — Ghép dữ liệu trang chủ
Hiện tại trang sweet-home-bakery đang sử dụng localStorage hãy chuyển qua sử dụng ezy function gọi hàm get_product_pagination lấy các sản phẩm nằm trong danh mục "banh"

Lúc này AI sẽ đi tải một loạt tập tin thông qua MCP Server để hiểu bối cảnh, rồi tự cài đặt lại trang chủ giúp bạn — quá trình này có thể tốn 5 đến 15 phút. Sau khi AI thực thi xong, bạn lưu lại tập tin content.html trong thư mục sweet-home-bakery rồi Preview trang: kết quả sẽ tương ứng với đúng những sản phẩm đã lưu trên admin. Ví dụ của tôi chỉ có một sản phẩm được hiển thị, vì tôi mới thêm một sản phẩm.

Hiển thị chi tiết sản phẩm khi click vào bánh

Tiếp theo, để lấy đúng tên các API đang có sẵn, bạn gõ prompt:

📋 Prompt mẫu — Tải tài liệu Swagger
Bây giờ hãy tải tập tin web swagger về

AI sẽ tải tập tin web-swagger.yaml và lưu vào .agents. Sau đó bạn tiếp tục gõ prompt để nhờ AI gọi API chi tiết sản phẩm mỗi khi người dùng click vào một sản phẩm:

📋 Prompt mẫu — Gọi API chi tiết sản phẩm
Giờ hãy gọi API '/api/v1/products/{code}/details' khi người dùng click vào sản phẩm để hiển thị hộp thoại chi tiết sản phẩm

AI sẽ cài đặt việc gọi API này giúp bạn — kết quả là một hộp thoại chi tiết sản phẩm xuất hiện ngay khi click vào bánh.

Hộp thoại chi tiết sản phẩm bánh
Hộp thoại chi tiết sản phẩm hiển thị khi người dùng click vào bánh, dữ liệu lấy từ API /api/v1/products/{code}/details.

Cài đặt giá riêng cho từng kích thước bánh

Có một vấn đề ở đây: các kích thước bánh khác nhau thường có giá khác nhau, vì bánh lớn tốn nguyên liệu hơn bánh bé. Vì vậy, bạn cần quay lại màn hình chi tiết sản phẩm trên admin và cài đặt giá riêng cho từng kích thước.

Nhập giá sản phẩm theo từng kích thước
Ở màn hình chi tiết sản phẩm, nhập giá riêng cho từng kích thước — kích thước càng lớn, giá càng cao.

Sau khi đã có giá cho từng kích thước, bạn quay lại AI và gõ tiếp prompt sau để trang chủ lấy đúng giá khi người dùng chọn kích thước:

📋 Prompt mẫu — Gọi API giá theo kích thước
Hãy gọi api '/api/v1/products/{productId}/size-color-price' để lấy giá sản phẩm khi người dùng click vào kích thước bánh

Sau khi AI thực hiện xong, bạn lưu tập tin thay đổi và Preview lại: nhấn vào xem chi tiết sản phẩm, rồi thử nhấn vào từng kích thước — bạn sẽ thấy giá tự động thay đổi tương ứng.

Giá sản phẩm thay đổi khi người dùng chọn kích thước khác
Giá tự động cập nhật khi người dùng chọn kích thước khác, nhờ gọi API /api/v1/products/{productId}/size-color-price.

Ghép API cho tính năng thêm giỏ hàng

Hiện tại nút Thêm giỏ hàng đang hoạt động giả lập, chúng ta sẽ cần ghép API thật cho nó. Vì tiệm bánh của chúng ta cho phép khách đặt hàng mà không cần đăng nhập, nên trước tiên cần cấu hình một chút phía admin.

Bạn cài đặt và kích hoạt module EzyLogin. Sau khi EzyPlatform khởi động lại xong, vào menu Cài đặt thường của EzyLogin, hoặc truy cập trực tiếp đường dẫn {đường dẫn admin của bạn}/ezylogin/settings/regular, tích vào ô Cho phép người dùng ẩn danh rồi lưu lại.

Cấu hình cho phép người dùng ẩn danh trong EzyLogin
Ở trang Cài đặt thường của EzyLogin, tích vào ô Cho phép người dùng ẩn danh để khách có thể thêm giỏ hàng mà không cần đăng nhập.

Sau đó bạn quay lại VS Code và gõ prompt sau để nhờ AI ghép API:

📋 Prompt mẫu — Ghép API thêm giỏ hàng
Hãy gọi API POST '/api/v1/products/{code}/checkout' cho tính năng thêm giỏ hàng, đừng quên làm mới số lượng sản phẩm trong giỏ hàng khi thêm thành công, sử dụng API '/api/v1/shopping-cart/product-count' để lấy số lượng sản phẩm trong giỏ hàng.

Sau khi AI thực hiện xong, bạn lưu lại tập tin và Preview lại. Thử bấm nút Thêm giỏ hàng — khi thêm thành công, bạn sẽ thấy số lượng sản phẩm trong giỏ hàng tự động thay đổi.

Số lượng sản phẩm trong giỏ hàng thay đổi sau khi thêm
Số lượng sản phẩm trong giỏ hàng tự động cập nhật sau khi thêm thành công, nhờ gọi API /api/v1/shopping-cart/product-count.

Ghép dữ liệu cho màn hình chi tiết sản phẩm

Sau khi xem hộp thoại sản phẩm, người dùng có thể nhấn nút xem chi tiết, nên chúng ta cũng cần ghép dữ liệu thật cho màn hình này. Mở một phiên chat mới và hỏi AI xem có còn kết nối được MCP Server không, ví dụ qua prompt:

📋 Prompt mẫu — Kiểm tra kết nối MCP
Bạn kết nối được đến mcp server freestyle-admin.ezyplatform.com chứ?

Khi AI xác nhận kết nối thành công, bạn gõ tiếp prompt:

📋 Prompt mẫu — Ghép dữ liệu màn chi tiết sản phẩm
Sử dụng mcp server cài đặt màn chi tiết bánh gọi ezy function get_product_details

Sau khi AI thực thi xong, bạn lưu lại tập tin thay đổi và xuất bản lên máy chủ. Từ trang chủ, chọn một sản phẩm, nhấn vào để mở hộp thoại, rồi từ hộp thoại nhấn xem chi tiết — trang chi tiết sản phẩm sẽ mở ra với dữ liệu lấy trực tiếp từ EzyPlatform.

Màn hình chi tiết sản phẩm sau khi ghép dữ liệu thật
Trang chi tiết sản phẩm hiển thị đúng dữ liệu thật từ EzyPlatform, lấy qua ezy function get_product_details.

Tuy nhiên AI vẫn chưa ghép API để lấy giá sản phẩm khi người dùng chọn kích thước bánh trên màn hình này. Bạn dùng lại prompt tương tự như ở trang chủ:

📋 Prompt mẫu — Giá theo kích thước ở màn chi tiết
Hãy ghép API /api/v1/products/{productId}/size-color-price để lấy giá của sản phẩm theo kích thước người dùng chọn cho màn hình chi tiết sản phẩm này.

Sau khi AI thực hiện xong, bạn lưu tập tin thay đổi, xuất bản lên máy chủ, rồi thử nhấn lại vào từng kích thước — bạn sẽ thấy giá thay đổi tương ứng.

Giá sản phẩm thay đổi theo kích thước ở màn hình chi tiết
Giá tự động cập nhật khi chọn kích thước khác ngay trên màn hình chi tiết sản phẩm.

Ghép dữ liệu cho màn hình thực đơn

Sau khi đã xong màn hình trang chủ và màn hình chi tiết sản phẩm, tiếp theo chúng ta sẽ ghép màn hình thực đơn.

Bổ sung thêm sản phẩm mẫu

Trước hết, hãy bổ sung thêm sản phẩm bằng cách truy cập vào màn hình chi tiết sản phẩm và sử dụng tính năng tạo bản sao. Tính năng này cho phép bạn sao chép toàn bộ thông tin của một sản phẩm sang sản phẩm khác, sau đó bạn chỉ cần chỉnh lại các thông tin như tên, ảnh, giá bán, mô tả cho phù hợp.

Tạo bản sao sản phẩm ở màn hình chi tiết sản phẩm
Dùng tính năng tạo bản sao để nhân nhanh sản phẩm mới từ một sản phẩm có sẵn, rồi chỉnh lại tên, ảnh, giá bán cho phù hợp.

Bạn hãy tạo khoảng 12 sản phẩm để chúng ta có thể kiểm thử được tốt hơn.

Danh sách khoảng 12 sản phẩm mẫu trong danh mục bánh
Danh sách khoảng 12 sản phẩm mẫu trong danh mục banh, đủ để kiểm thử phân trang và tải thêm.

Ghép API cho màn hình thực đơn

Quay trở lại VS Code, mở một phiên chat mới, hỏi AI xem đã kết nối được MCP Server chưa, sau đó gõ prompt:

📋 Prompt mẫu — Ghép dữ liệu màn hình thực đơn
Cài đặt màn hình thực đơn, hãy sử dụng ezy function get_product_pagination để lấy 9 sản phẩm cho trang đầu, kết hợp với việc sử dụng API /api/v1/products để khi người dùng nhấn vào nút load more (bổ sung nút này nếu chưa có) thì gọi API này tải thêm các sản phẩm, lưu ý chỉ lấy sản phẩm trong danh mục "banh".

Sau khi AI thực hiện xong, bạn lưu lại tập tin thay đổi và Preview lại: trang thực đơn sẽ hiển thị đúng 9 sản phẩm đầu tiên trong danh mục banh, lấy từ ezy function get_product_pagination.

Danh sách sản phẩm trong màn hình thực đơn sau khi ghép API
Màn hình thực đơn hiển thị 9 sản phẩm đầu tiên trong danh mục banh, lấy qua ezy function get_product_pagination.

Nhấn vào nút Tải thêm, các sản phẩm còn lại sẽ được tải bổ sung nhờ gọi API /api/v1/products.

Nút tải thêm sản phẩm ở màn hình thực đơn
Nhấn nút Tải thêm để gọi API /api/v1/products, tải bổ sung các sản phẩm còn lại trong danh mục banh.

Ghép màn hình giỏ hàng

Tiếp theo, chúng ta ghép màn hình giỏ hàng với dữ liệu thật từ server. Gõ prompt sau:

📋 Prompt mẫu — Ghép dữ liệu màn hình giỏ hàng
Ghép màn hình gio-hang với giỏ hàng thật từ server: dùng GET /api/v1/shopping-cart để lấy dữ liệu hiển thị, tìm API tương ứng để sửa số lượng và xóa sản phẩm trong tập tin web swagger. Cần hỗ trợ: xem danh sách, tăng/giảm số lượng, xóa sản phẩm, cập nhật tổng tiền + badge số lượng trên header. Đồng thời chuyển đổi luôn thuc-don và chi-tiet-banh sang dùng chung cơ chế giỏ hàng server này để tránh lệch dữ liệu với sweet-home-bakery.

Sau khi AI thực hiện xong, bạn lưu các tập tin thay đổi và xuất bản lên máy chủ. Nhấn vào icon giỏ hàng trên header để mở màn hình giỏ hàng và xem kết quả.

Màn hình giỏ hàng sau khi ghép dữ liệu thật từ server
Màn hình giỏ hàng hiển thị đúng dữ liệu thật từ server — xem danh sách, tăng/giảm số lượng, xóa sản phẩm và cập nhật tổng tiền đều hoạt động.

Ghép màn hình thanh toán

Đây là màn hình phức tạp nhất trong toàn bộ chương, vì nó gộp cả thông tin giỏ hàng, thông tin giao hàng lẫn nhiều phương thức thanh toán khác nhau. Chúng ta sẽ chuẩn bị dữ liệu ở phía admin trước, sau đó mới nhờ AI ghép API cho màn hình.

Cài đặt EzyPayment và các dịch vụ thanh toán

Trước khi ghép màn hình thanh toán, bạn cần cài đặt module EzyPayment. Sau khi cài đặt xong, truy cập danh sách dịch vụ thanh toán qua menu Các dịch vụ thanh toán của EzyPayment, hoặc theo đường dẫn {đường dẫn admin của bạn}/ecommerce/payment-services.

Danh sách các dịch vụ thanh toán trong EzyPayment
Danh sách dịch vụ thanh toán — mỗi dịch vụ thuộc một trong hai nhóm: cổng thanh toán hoặc lắng nghe biến động số dư.

Ở đây có hai nhóm dịch vụ. Nhóm cổng thanh toán, ví dụ VNPAY, PAYPAL — bạn cần để trạng thái Đã kích hoạt. Nhóm lắng nghe biến động số dư, ví dụ PAYFS, PAY2S, SEPAY — bạn cần để trạng thái Đang lắng nghe. Ví dụ ở đây tôi dùng VNPay và PAYFS. Nếu bạn là cửa hàng nhỏ, tôi đề xuất dùng dịch vụ lắng nghe biến động số dư như PAYFS, vì nó rất đơn giản từ khâu tích hợp đến khâu sử dụng — không cần đăng ký cổng thanh toán, chỉ cần kết nối tài khoản ngân hàng.

Ghép API cho màn hình thanh toán

Đây là prompt dài và khá chi tiết, vì màn hình thanh toán có nhiều nhánh xử lý (nhận hàng, phương thức thanh toán, cập nhật badge...). Nếu dự án của bạn có sẵn mã nguồn gốc của plugin E-Commerce, bạn có thể trỏ AI đọc thẳng vào đó để bám đúng logic gốc, tránh việc AI tự suy luận sai field hay sai chiều dữ liệu từ swagger:

📋 Prompt mẫu — Ghép API màn hình thanh toán
Ghép màn hình thanh toán với API thật:

1. Load dữ liệu ban đầu: /api/v1/checkout/context, /api/v1/shopping-cart, /api/v1/checkout/selected-delivery-information (để tự điền lại thông tin giao hàng lần gần nhất), /api/v1/checkout/receive-at-shop-branches, /api/v1/available-payment-services, /api/v1/default-shop-bank-accounts.

2. Nhận hàng: 2 lựa chọn — giao tận nơi (chỉ cần 1 ô địa chỉ tự do, không ép chọn tỉnh/huyện/xã, mặc định quốc gia Việt Nam) hoặc nhận tại chi nhánh (chọn từ danh sách chi nhánh). Phí ship tính qua /api/v1/delivery/calculate-fee.

3. Thanh toán — map rõ từng phương thức với đúng endpoint, không dùng chung 1 API cho tất cả:

COD: POST /api/v1/orders/create-waiting-to-confirm (chỉ dùng cho COD).
QR/chuyển khoản: POST /api/v1/orders/create để tạo đơn trước → hiện QR → khi người dùng xác nhận đã chuyển khoản, gọi PUT /api/v1/orders/{id}/waiting-to-confirm để chốt đơn rồi mới chuyển trang.
Cổng thanh toán: gọi thẳng POST /api/v1/orders/create-payment-url (kèm paymentServiceCode) — response là text/plain chứa URL thô (đọc bằng response.text(), không phải response.json()), không cần tạo đơn 2 bước.

4. Lưu ý về response dễ hiểu sai: khi một API trả về kiểu Map/dictionary, đừng tự đoán chiều key/value — nếu không chắc, hỏi lại hoặc kiểm tra kỹ mô tả API trước khi parse. Field format tiền dùng formattedWithSymbol/formattedValueIncludeSymbol, không phải formatted/formattedValue.

5. Sau khi đặt hàng thành công: gọi lại /api/v1/shopping-cart/product-count để cập nhật badge số lượng trên header.

6. Đồng bộ với các trang khác: sau khi tạo đơn, redirect sang /xac-nhan-don-hang?id=&lt;order id&gt; — trang này hiện vẫn đọc theo SweetHomeBakeryCart cục bộ (?ma=), cần migrate song song nếu muốn luồng hoàn chỉnh.

Sau khi AI thực hiện xong, bạn lưu tập tin thay đổi và xuất bản lên máy chủ. Ở bước nhận hàng, bạn có thể nhập địa chỉ giao tận nơi hoặc chọn nhận tại chi nhánh — phí ship sẽ tự động tính lại mỗi khi thay đổi.

Nhập thông tin nhận hàng ở màn hình thanh toán
Nhập thông tin nhận hàng — chọn giao tận nơi hoặc nhận tại chi nhánh, phí ship tự động tính qua /api/v1/delivery/calculate-fee.

Tiếp theo, chọn phương thức thanh toán tương ứng với các dịch vụ đã kích hoạt ở phần admin — COD, chuyển khoản/QR, hoặc cổng thanh toán như VNPay.

Chọn phương thức thanh toán ở màn hình thanh toán
Chọn phương thức thanh toán — mỗi phương thức gọi đúng một endpoint riêng, không dùng chung một API cho tất cả.

Nếu chọn chuyển khoản, một mã QR sẽ hiện ra để quét thanh toán; sau khi xác nhận đã chuyển khoản, đơn hàng được chốt và chuyển sang trang xác nhận.

Thanh toán qua chuyển khoản với mã QR
Thanh toán qua chuyển khoản — mã QR được dựng từ dữ liệu trả về của /api/v1/checkout/shopping-cart/qr-codes.

Ghép màn hình chi tiết đơn hàng

Sau khi đặt hàng thành công ở màn hình thanh toán, người dùng được chuyển đến trang xác nhận đơn hàng — đây chính là màn hình chúng ta sẽ ghép dữ liệu tiếp theo. Bạn gõ prompt sau:

📋 Prompt mẫu — Ghép dữ liệu màn hình chi tiết đơn hàng
Hãy sử dụng API '/api/v1/orders/{id}' trong web swagger để ghép dữ liệu cho màn hình xác nhận đơn hàng. Không cần hiện trạng thái thanh toán, đừng sử dụng nguyên giá trị enum cho trạng thái đơn hàng hãy ánh xạ nó với tiếng Việt trong mã nguồn javascript.

Sau khi AI thực hiện xong, bạn lưu tập tin thay đổi và xuất bản lên máy chủ. Đặt thử một đơn hàng, trang xác nhận sẽ hiển thị đầy đủ thông tin người nhận, địa chỉ giao hàng và phương thức thanh toán đã chọn — trạng thái đơn hàng được dịch sang tiếng Việt qua i18n thay vì hiện nguyên giá trị enum.

Thông tin đơn hàng ở màn hình xác nhận đơn hàng
Thông tin đơn hàng — người nhận, địa chỉ giao hàng, phương thức thanh toán và trạng thái đơn hàng đã qua i18n.

Kéo xuống bên dưới, bạn sẽ thấy danh sách chi tiết các sản phẩm đã đặt, kèm số lượng, đơn giá và thành tiền của từng sản phẩm.

Danh sách chi tiết sản phẩm trong đơn hàng
Danh sách chi tiết sản phẩm trong đơn hàng — số lượng, đơn giá và thành tiền lấy trực tiếp từ API /api/v1/orders/{id}.

Ghép màn hình danh sách đơn hàng

Vì tiệm bánh của chúng ta cho phép đặt hàng mà không cần đăng nhập, nên thay vì có một trang "Đơn hàng của tôi" gắn với tài khoản, chúng ta cần một màn hình Tra cứu đơn hàng để khách tự tìm lại đơn đã đặt. Bạn gõ prompt:

📋 Prompt mẫu — Ghép dữ liệu màn hình tra cứu đơn hàng
Tiếp tục cài đặt màn hình tra cứu đơn hàng hiển thị danh sách đơn hàng và cho phép người dùng tìm kiếm qua API /api/v1/orders

Sau khi AI thực hiện xong, bạn lưu tập tin thay đổi và xuất bản lên máy chủ. Mặc định, trang sẽ liệt kê toàn bộ đơn hàng, mới nhất hiển thị trước, kèm trạng thái và tổng tiền của từng đơn.

Danh sách đơn hàng ở màn hình tra cứu đơn hàng
Danh sách đơn hàng mặc định — mỗi đơn hiển thị mã đơn, thời gian đặt, trạng thái, số sản phẩm và tổng tiền.

Nhập mã đơn hàng hoặc tên sản phẩm vào ô tìm kiếm, kết hợp chọn trạng thái nếu cần, danh sách sẽ được lọc lại đúng theo điều kiện tìm kiếm.

Kết quả tìm kiếm ở màn hình tra cứu đơn hàng
Nhập mã đơn hàng (ví dụ 10) vào ô tìm kiếm, danh sách chỉ còn hiển thị đúng đơn hàng khớp kết quả.

Vậy là chúng ta đã hoàn thành một chương rất dài — dài nhất từ đầu sách đến giờ. Từ một website chỉ có giao diện và dữ liệu giả lập, bạn đã lần lượt ghép dữ liệu thật cho toàn bộ hành trình mua hàng: trang chủ hiển thị đúng sản phẩm từ danh mục "banh", màn hình chi tiết sản phẩm với giá thay đổi theo từng kích thước, giỏ hàng cập nhật số lượng theo thời gian thực, thực đơn phân trang và tải thêm, thanh toán với nhiều phương thức khác nhau (COD, chuyển khoản/QR, cổng thanh toán), cho đến trang xác nhận và tra cứu đơn hàng. Không còn một dòng dữ liệu giả nào trong localStorage — tất cả đều đi qua API thật, được lưu trên máy chủ EzyPlatform của chính bạn.

Với những gì đã có, website tiệm bánh này hoàn toàn đủ điều kiện để đưa vào kinh doanh thật — bạn có thể tự tin mang đi khoe với bạn bè, đối tác, hay thậm chí bắt đầu nhận đơn hàng đầu tiên ngay hôm nay. Và đây cũng chính là lúc bạn thấy rõ lợi ích đã nói ở đầu chương: vì các hàm ezyfunctions chạy và trả HTML render sẵn ở phía máy chủ, trình duyệt không hề giữ bất kỳ API key hay chuỗi kết nối cơ sở dữ liệu nào — khác hẳn với việc gọi thẳng đến một dịch vụ dữ liệu ngoài từ phía client. Nhờ vậy, bạn có thể chia sẻ đường dẫn website hay mở DevTools cho ai đó xem thoải mái mà không lo lộ khoá bí mật của hệ thống.

📌 Tóm tắt chương

  • EzyPlatform cung cấp sẵn ezyfunctions (render HTML sẵn ở server, tốt cho SEO) và API (dùng cho trang không cần SEO) — trình duyệt không bao giờ giữ key hay chuỗi kết nối cơ sở dữ liệu như khi gọi thẳng dịch vụ dữ liệu ngoài.
  • Phải cấu hình nền tảng phía máy chủ trước (quốc gia, tỉnh/thành, ngân hàng, tiền tệ, cửa hàng, chi nhánh, kho) rồi mới khởi tạo sản phẩm mẫu — bước chuẩn bị bắt buộc trước khi ghép dữ liệu thật.
  • Dùng MCP Server để AI tự tải schema ezyfunction và tài liệu Swagger, sau đó lần lượt ghép API thật cho từng màn hình: trang chủ, chi tiết sản phẩm, giỏ hàng, thực đơn, thanh toán, chi tiết đơn hàng và tra cứu đơn hàng.
  • Mỗi tình huống nghiệp vụ (giá theo kích thước, từng phương thức thanh toán COD/QR/cổng thanh toán) cần map đúng API riêng, tránh dùng chung một API cho nhiều trường hợp khác nhau.
  • Kết quả: website tiệm bánh vận hành hoàn toàn bằng dữ liệu thật trên máy chủ của chính bạn, không còn phụ thuộc localStorage, sẵn sàng đưa vào kinh doanh.
Chương trước: để AI Assistant thao tác trực tiếp với dữ liệu thật qua MCP Server. ← Đọc Chương 9
Chương tiếp theo: để hệ thống tự vận hành thay vì làm thủ công lặp đi lặp lại. Đọc Chương 11 →