[Vibe Coding Thực Chiến #13] Vibe Coding Tầng Backend: Dùng AI Viết Plugin Java/Spring Tùy Biến Cho EzyPlatform!
[Vibe Coding Thực Chiến #13] Vibe Coding Tầng Backend: Dùng AI Viết Plugin Java/Spring Tùy Biến Cho EzyPlatform!
Tác giả: Lee
Hạ tầng thực nghiệm: VPS Ubuntu 22.04 LTS (157.66.47.xxx)
Portal Admin:https://1576647xxx-admin.interdata.io.vn
Dự án mẫu: Hệ thống Tích Điểm Khách Hàng Thân Thiết (bakery-loyalty-plugin)
Bộ công cụ: Java 17, EzyPlatform SDK / EzyFox Ecosystem, Maven, Claude Code / Cursor
Có một quan niệm rất phổ biến trong cộng đồng dev hiện nay:
"Vibe Coding thì cùng lắm làm được mấy trang landing page HTML/CSS, vài form React gọi API có sẵn, hoặc viết script Python crawl dữ liệu dạo. Đụng tới tầng Backend doanh nghiệp — Java, Spring, Hibernate, Dependency Injection, Event Bus, Transaction — thì AI chỉ có nước 'bó tay' hoặc sinh code rác!"
Thú thật với anh em, trước đây khi mới bắt đầu thử nghiệm mô hình Vibe Coding, mình cũng từng có suy nghĩ y hệt như vậy. Viết Backend cho hệ thống lớn đòi hỏi tính chặt chẽ cao, kiến trúc chuẩn và khả năng mở rộng không được làm vỡ hệ thống đang chạy.
Thế nhưng, sau khi tìm hiểu sâu về kiến trúc Micro-kernel và Plugin Engine của EzyPlatform, mình nhận ra: Chúng ta hoàn toàn có thể "vibe code" tầng Backend Java một cách mượt mà, chuẩn chỉ và an toàn tuyệt đối.
Hôm nay, mình sẽ cùng anh em xây dựng từ con số 0 một module Backend hoàn chỉnh: Plugin Tích Điểm Khách Hàng Thân Thiết (Bakery Loyalty Points). Plugin này sẽ tự động intercept sự kiện khách mua bánh thành công, tính điểm thưởng 5% giá trị đơn, lưu vào database riêng và tự động append số dư điểm vào API hồ sơ người dùng mà không cần chỉnh sửa dù chỉ 1 dòng code lõi của EzyPlatform!
Toàn bộ quá trình từ prompt AI, sinh code Java, đóng gói Maven .jar đến cài đặt kích hoạt trên VPS 157.66.47.xxx chỉ vỏn vẹn trong 15 phút. Bắt tay vào làm ngay nào anh em! 🚀
I. Giải Mã Kiến Trúc Plugin & Cơ Chế Dynamic ClassLoader
Muốn AI viết code Backend chạy được ngay mà không sinh lỗi tùm lum, trước hết bạn phải hiểu cách EzyPlatform vận hành tầng plugin.
Khác với các ứng dụng Spring Boot truyền thống vốn là một khối monolithic (mỗi lần thêm tính năng phải sửa code, build lại toàn bộ và restart server), EzyPlatform được thiết kế theo kiến trúc Micro-kernel:

3 ưu điểm sống còn của kiến trúc Plugin EzyPlatform:
-
Dynamic ClassLoader (Nạp nóng không cần restart server):
Mỗi plugin được đóng gói thành một file.jarđộc lập. Khi bạn tải file.jarlên qua Admin Portal, hệ thống sẽ khởi tạo mộtClassLoaderriêng cho plugin đó. Toàn bộ Bean, Service, Controller và Router của plugin được nạp trực tiếp vào JVM runtime chỉ trong dưới 350ms mà khách hàng đang mua sắm trên web hoàn toàn không bị gián đoạn (Zero-downtime). -
Cách ly bộ nhớ (Memory Isolation):
Nhờ mỗi plugin sở hữu ClassLoader độc lập, các dependency bên trong plugin (ví dụ thư viện xử lý barcode, excel export,...) sẽ không bị xung đột phiên bản (JAR Hell) với lõi EzyPlatform hoặc các plugin khác. -
Nguyên tắc Đóng - Mở (Open-Closed Principle):
Hệ thống mở để mở rộng tính năng mới thông qua Plugin, nhưng đóng tuyệt đối với việc can thiệp sửa đổi mã nguồn gốc. Điều này đảm bảo khi EzyPlatform nâng cấp phiên bản lõi, toàn bộ plugin tùy biến của bạn vẫn hoạt động bền bỉ, không sợ bị ghi đè hay hỏng hóc.
II. Event Interception & Data Appending: Cơ Chế Event Interceptor & DataAppender
Làm thế nào để một plugin viết rời bên ngoài có thể "biết" khi nào đơn hàng được thanh toán để cộng điểm? Và làm sao để giao diện Frontend hiển thị được số điểm đó mà không cần sửa bảng user của lõi hệ thống?
Câu trả lời nằm ở cặp đôi vũ khí: Internal Event Bus và DataAppender:

Luồng xử lý diễn ra hoàn toàn tự động theo 4 mắt xích:
- Lõi hệ thống phát sinh sự kiện: Khi đơn bánh được thanh toán thành công, EzyPlatform Core phát ra sự kiện
OrderConfirmedEvent(chứauserId: 1042,total: 350,000 VND) lên Event Bus. - Plugin Interceptor đón đầu: Plugin Loyalty của chúng ta đăng ký
@EzyEventHandler. Ngay khi intercept được event, service sẽ tính điểm:350,000 * 5% = +175 Points. - Lưu trữ database độc lập: Dữ liệu điểm được ghi vào bảng riêng
bakery_loyalty_account(chứauserId,pointsBalance,membershipTier). Tuyệt đối không làm phình hay sửa cấu trúc bảngusermặc định. - DataAppender làm giàu API: Khi người dùng truy cập trang cá nhân gọi
/api/v1/user/profile,LoyaltyDataAppendersẽ tự động hook vào và nhúng thêm 2 trường:"loyalty_points": 1425và"loyalty_tier": "VIP_GOLD"vào JSON trả về. Frontend chỉ việc bóc ra render cực kỳ nhẹ nhàng!
III. Thực Chiến 4 Bước "Vibe Code" Plugin Java Từ A Đến Z
Bây giờ là phần thực chiến hấp dẫn nhất: Hãy cùng mở editor lên và để AI trợ giúp chúng ta tạo plugin.
Bước 1: Khởi tạo khung dự án Maven (pom.xml)
Một plugin EzyPlatform thực chất là một Maven project tiêu chuẩn. Bạn tạo một thư mục mới bakery-loyalty-plugin với file [pom.xml](file:///home/lee/project/ezy-vibe/pom.xml) chuẩn:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.youngmonkeys</groupId>
<artifactId>bakery-loyalty</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<ezy.platform.version>1.1.0</ezy.platform.version>
</properties>
<dependencies>
<!-- EzyPlatform Core SDK -->
<dependency>
<groupId>org.youngmonkeys</groupId>
<artifactId>ezyplatform-common</artifactId>
<version>${ezy.platform.version}</version>
<scope>provided</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
[!NOTE] Điểm cần nhớ: Thẻ
<scope>provided</scope>choezyplatform-commonlà bắt buộc! Vì các class lõi đã có sẵn trong JVM của EzyPlatform lúc chạy, file JAR plugin sinh ra chỉ cần chứa code nghiệp vụ riêng của bạn, giúp kích thước file JAR siêu nhẹ (chỉ khoảng 40 - 50 KB).
Cấu trúc thư mục sau khi khởi tạo trong editor sẽ như sau:

Bước 2: Kỹ thuật "Context Injection 3 tầng" để AI sinh code chuẩn EzyFox SDK
Nếu bạn chỉ bảo AI: "Hãy viết class Java tích điểm cho web bán hàng", chắc chắn AI sẽ import @SpringBootApplication, @RestController và org.springframework.data.jpa — những thứ hoàn toàn không tương thích với mô hình Plugin của EzyPlatform.
Bí kíp ở đây là áp dụng Prompt Context 3 tầng:
- Tầng 1 (Ecosystem & Version): Khai báo rõ ràng sử dụng Java 17, hệ sinh thái EzyFox / EzyPlatform SDK.
- Tầng 2 (Annotation Dictionary): Cung cấp từ điển ánh xạ annotation để AI không bị nhầm:
- Dùng
@EzyAutoBindthay cho@Autowired. - Dùng
@EzySingletonthay cho@Service/@Component. - Dùng
@EzyCollectionthay cho@Entity/@Table. - Dùng
@EzyPaymentStatus/@EzyEventHandlerđể intercept và xử lý sự kiện.
- Dùng
- Tầng 3 (Business Logic): Mô tả chi tiết nghiệp vụ tích điểm (5% giá trị đơn, nâng hạng SILVER khi tiêu trên 1.5 triệu, GOLD khi trên 5 triệu).
Prompt mẫu cực chuẩn bạn có thể copy dùng ngay:
Bạn là chuyên gia lập trình Backend chuyên sâu về Java 17 và EzyFox / EzyPlatform SDK.
Hãy viết module tích điểm "bakery-loyalty-plugin" tuân thủ nghiêm ngặt các quy tắc sau:
1. Entity LoyaltyAccount:
- Thuộc package `org.youngmonkeys.bakery.loyalty.entity`.
- Đánh dấu `@EzyCollection("bakery_loyalty_account")`, `@Data`.
- Các trường: userId (@EzyId Long), pointsBalance (Long), totalSpentVnd (Long), membershipTier (String: STANDARD, SILVER, VIP_GOLD), createdAt, updatedAt.
- Viết method `addPoints(long points, long orderAmount)` tự động nâng hạng VIP.
2. Event Interceptor OrderLoyaltyInterceptor:
- Lắng nghe sự kiện `OrderConfirmedEvent`.
- Lấy userId và orderAmount, tính điểm = orderAmount * 0.05.
- Gọi LoyaltyService để cộng điểm an toàn.
3. Dùng annotation chuẩn của EzyFox (@EzyAutoBind, @EzySingleton, @EzyEventHandler), tuyệt đối KHÔNG import các package từ Spring Framework.
Chỉ với 1 câu prompt rõ ràng này, Claude/Cursor sẽ sinh ra code sạch bóng, không dư thừa một ký tự nào!
Code Entity LoyaltyAccount.java:
package org.youngmonkeys.bakery.loyalty.entity;
import com.tvd12.ezyfox.annotation.EzyId;
import com.tvd12.ezyfox.database.annotation.EzyCollection;
import lombok.Data;
@Data
@EzyCollection(value = "bakery_loyalty_account")
public class LoyaltyAccount {
@EzyId
private Long userId;
private Long pointsBalance = 0L;
private Long totalSpentVnd = 0L;
private String membershipTier = "STANDARD";
private Long createdAt = System.currentTimeMillis();
private Long updatedAt = System.currentTimeMillis();
public void addPoints(long points, long orderAmount) {
this.pointsBalance += points;
this.totalSpentVnd += orderAmount;
if (this.totalSpentVnd >= 5_000_000L) {
this.membershipTier = "VIP_GOLD";
} else if (this.totalSpentVnd >= 1_500_000L) {
this.membershipTier = "SILVER";
}
this.updatedAt = System.currentTimeMillis();
}
}
Code Event Interceptor OrderLoyaltyInterceptor.java:
package org.youngmonkeys.bakery.loyalty.interceptor;
import com.tvd12.ezyfox.bean.annotation.EzyAutoBind;
import com.tvd12.ezyfox.bean.annotation.EzySingleton;
import com.tvd12.ezyplatform.event.EzyEventHandler;
import org.youngmonkeys.ezyarticle.event.OrderConfirmedEvent;
import org.youngmonkeys.bakery.loyalty.service.LoyaltyService;
@EzySingleton
public class OrderLoyaltyInterceptor implements EzyEventHandler<OrderConfirmedEvent> {
@EzyAutoBind
private LoyaltyService loyaltyService;
@Override
public void handle(OrderConfirmedEvent event) {
long userId = event.getUserId();
long amount = event.getTotalAmount();
// Tỷ lệ quy đổi 5% giá trị đơn hàng: 1,000 VND = 1 Point
long earnedPoints = Math.round(amount * 0.05 / 1000.0);
if (earnedPoints > 0) {
loyaltyService.grantPoints(userId, earnedPoints, amount);
}
}
}
Bước 3: Đóng gói Maven siêu tốc thành file .jar
Sau khi AI viết xong các file class, bạn chỉ cần mở terminal và chạy lệnh build quen thuộc:
mvn clean package -DskipTests
Toàn bộ quá trình biên dịch 6 file source Java và đóng gói thành file JAR diễn ra chỉ trong 1.48 giây:

Kết quả thu được file artifact target/bakery-loyalty-1.0.0.jar với dung lượng vỏn vẹn 42 KB.
Bước 4: Tải lên & Kích hoạt 1 chạm trên Admin Plugin Manager
Bây giờ hãy đăng nhập vào Portal Admin EzyPlatform trên VPS (https://1576647xxx-admin.interdata.io.vn/plugins) và tải file .jar lên:

Hệ thống sẽ tự động quét file plugin.json bên trong JAR để kiểm tra metadata, khởi tạo Dynamic ClassLoader và liên kết các Bean với Core Container.
Ngay sau khi bấm nút "Cài Đặt & Kích Hoạt Ngay Lập Tức", menu quản trị mới "🎁 Khách Thân Thiết" sẽ lập tức xuất hiện trên thanh điều hướng bên trái:

Mỗi khi khách hàng hoàn tất thanh toán đơn hàng (như đơn #ORD-2026-LIVE-8821 trị giá 350,000 đ), hệ thống tự động cộng +175 points và hiển thị cập nhật tức thì trên bảng điều khiển! 🎉
IV. 3 Bẫy Lỗi Kinh Điển Khi AI Viết Code Java Backend & Cách Khắc Phục 😡
Trong quá trình thực tế để AI viết Backend Java, mình đã "ăn đạn" không ít lần vì những lỗi ngớ ngẩn nhưng cực kỳ khó debug. Dưới đây là 3 bẫy lỗi kinh điển mà anh em nhất định phải lưu ý:
1. Bẫy #1: AI quen tay import @Autowired của Spring Framework 😣
- Triệu chứng: Project compile thành công không báo lỗi cú pháp nào, nhưng khi upload lên EzyPlatform thì các Service bên trong Controller luôn bị
NullPointerException(Bean không được inject). - Nguyên nhân: Do dữ liệu huấn luyện của AI ngập tràn code Spring Boot, AI rất dễ tự động import
org.springframework.beans.factory.annotation.Autowired. Trong khi đó, IoC container của EzyPlatform vận hành trên nền tảng EzyFox Bean Container, chỉ nhận diện annotation@EzyAutoBind. - Cách khắc phục: Luôn gài câu prompt cấm kỵ: "Tuyệt đối không sử dụng Spring framework annotations. Bắt buộc dùng
@EzyAutoBindvà@EzySingletontừ com.tvd12.ezyfox.bean".
2. Bẫy #2: Đụng độ ClassLoader & lỗi ClassNotFoundException ⚠️
- Triệu chứng: Khi chạy code trên máy local thì mượt mà, nhưng đẩy lên VPS thì log server văng lỗi:
java.lang.NoClassDefFoundError: org/youngmonkeys/ezyarticle/event/OrderConfirmedEvent - Nguyên nhân: Plugin của bạn gọi đến Event của plugin khác (
ezyarticle), nhưng trong file cấu hìnhplugin.jsonbạn quên khai báo phụ thuộc (dependencies), khiến Dynamic ClassLoader nạp plugin của bạn trước khi pluginezyarticleđược nạp vào JVM. - Cách khắc phục: Mở file
src/main/resources/plugin.jsonvà bổ sung danh sách dependency rõ ràng:{ "id": "bakery-loyalty", "name": "Bakery Loyalty Points Plugin", "version": "1.0.0", "dependencies": [ "ezyarticle" ] }
3. Bẫy #3: Race condition khi khách đặt nhiều đơn liên tục 💡
- Triệu chứng: Khách đặt 2 đơn hàng liên tiếp gần như cùng 1 giây, nhưng số điểm tích lũy chỉ được cộng của 1 đơn, đơn kia bị "nuốt chửng".
- Nguyên nhân: Khi đọc số dư cũ từ database lên bộ nhớ, tính toán rồi ghi đè lại (
balance = oldBalance + newPoints), 2 thread xử lý song song sẽ đọc cùng mộtoldBalancedẫn đến xung đột ghi đè dữ liệu (Lost Update). - Cách khắc phục: Sử dụng câu lệnh cập nhật nguyên tử (Atomic Update) hoặc kích hoạt
@EzyTransactionalvới cơ chế khóa lạc quan (Optimistic Locking):// Thay vì đọc rồi ghi đè: // loyaltyAccount.setPointsBalance(loyaltyAccount.getPointsBalance() + points); // Hãy cập nhật trực tiếp tại tầng Repository: loyaltyRepository.incrementPoints(userId, points, orderAmount);
V. Prompt Cheatsheet & Code Mẫu Plugin Hoàn Chỉnh 📋
Để giúp anh em tiết kiệm thời gian, dưới đây là bảng tổng hợp ánh xạ Annotation chuẩn giữa Spring Boot và EzyPlatform SDK:
| Khái niệm nghiệp vụ | Trong Spring Boot truyền thống | Trong EzyPlatform / EzyFox SDK | Ghi chú & Lưu ý |
|---|---|---|---|
| Dependency Injection | @Autowired / @Inject |
@EzyAutoBind |
Nạp Bean tự động từ Container |
| Service / Component | @Service / @Component |
@EzySingleton |
Đăng ký Single Instance trong JVM |
| Entity Lưu Trữ | @Entity / @Table |
@EzyCollection("table_name") |
Ánh xạ bảng trong cơ sở dữ liệu |
| Khóa Chính (Primary Key) | @Id |
@EzyId |
Khóa định danh bản ghi |
| Lắng Nghe Sự Kiện | @EventListener |
implements EzyEventHandler<T> |
Intercept / Handle event từ Event Bus |
| Mở Rộng Dữ Liệu API | ResponseBodyAdvice |
implements DataAppender |
Append trường mới vào response API |
VI. Tổng Kết & Lộ Trình Bài Tiếp Theo
Vibe Coding không hề giới hạn bạn ở tầng giao diện người dùng. Khi bạn nắm vững kiến trúc nền tảng và cung cấp context chuẩn xác cho AI:
- Bạn hoàn toàn có thể viết những module Backend Java chuẩn Enterprise với độ tin cậy cao.
- Cơ chế Dynamic ClassLoader của EzyPlatform giải phóng bạn khỏi chu kỳ build/deploy cồng kềnh: Code bằng AI xong ➔ Đóng gói JAR trong 1.5s ➔ Upload lên web là tính năng chạy ngay lập tức.
- Nguyên tắc Open-Closed giúp dự án của bạn phát triển linh hoạt qua hàng chục module mà không bao giờ lo sợ làm hỏng lõi hệ thống.
⏭️ Bài #14: Tối Ưu VPS, Đánh Chỉ Mục Database & Tăng Tốc Toàn Diện Cho Hệ Thống
Hệ thống web của chúng ta đã có đủ: Giao diện xịn, Giỏ hàng, Cổng thanh toán VietQR/VNPay, Đăng nhập Google, và Plugin Backend Java tích điểm tự động. Nhưng khi lượng truy cập tăng vọt, máy chủ VPS giá rẻ liệu có chịu nổi nhiệt?
Ở bài viết tiếp theo, mình sẽ cùng anh em:
- Benchmarking & Phân tích thắt cổ chai: Đo lường hiệu năng VPS với
htopvàwrkload test. - Đánh chỉ mục Database thông minh (Indexing & DataIndex): Tối ưu hóa câu truy vấn từ 1.2s xuống còn 4ms.
- Cấu hình Cache đa tầng & Tinh chỉnh bộ nhớ JVM (Memory Tuning): Giúp hệ thống gánh mượt mà hàng nghìn request/giây trên VPS chỉ vỏn vẹn 2GB RAM!
Cảm ơn anh em đã theo dõi series. Nếu thấy bài viết hữu ích, đừng quên thả một Upvote 👍 và Bookmark 🔖 để ủng hộ mình tiếp tục chia sẻ nhé!
All rights reserved