Tài liệu phát triển dịch vụ sử dụng APIM và LifeESB Tổng quan kiến trúc hệ thống Nội dung chi tiết 1.1. Giới Thiệu Hệ thống được xây dựng theo mô hình  Enterprise Service Bus (ESB)  kết hợp  API Management (APIM) , sử dụng nền tảng LifeESB làm trung gian điều phối giữa Client và các Backend Service. Tích hợp thêm Apache Kafka  để xử lý tải lớn theo mô hình bất đồng bộ. Tên hệ thống: LifeESB APIM:  API Manager Message Queue:  Apache Kafka (Broker:  hdp-master:9092 ) 1.2. Sơ Đồ Kiến Trúc Tổng Thể   1.3. Các Thành Phần Chính 1.3.1. APIM — API Manager Cổng vào duy nhất (Single Entry Point) cho toàn bộ hệ thống. Chức năng Mô tả Xác thực Kiểm tra JWT / OAuth2 / API Key trước khi vào LifeESB Rate Limiting Giới hạn số request/giây theo từng API hoặc User Versioning Quản lý nhiều version API ( /v1 ,  /v2 ) song song Analytics Theo dõi lưu lượng, latency, error rate Portal Developer Portal để publish và subscribe API 1.3.2. LifeESB Lớp tích hợp trung gian, chịu trách nhiệm điều phối luồng dữ liệu. Thành phần File Chức năng Sync API PlanningDirectApi.xml Gọi thẳng Backend, Client nhận kết quả ngay Async API KafkaProducerApi.xml Đẩy vào Kafka, trả phản hồi ngay cho Client Inbound Endpoint Load_balance_example.xml Lắng nghe Kafka, kích hoạt Sequence xử lý Sequence Load_balance_example-inboundSequence.xml Logic xử lý message: gọi Backend + phân loại lỗi Error Sequence Load_balance_example-inboundErrorSequence.xml Xử lý lỗi Kafka, đẩy vào  error_topic Local Entry KafkaConnection.xml Cấu hình kết nối Kafka tái sử dụng 1.3.3. Apache Kafka Message Broker xử lý tải lớn và đảm bảo không mất dữ liệu. Topic Mục đích test_topic_01 Nhận message từ API Producer (đầu vào) processed_topic Lưu message đã xử lý thành công error_topic Lưu message lỗi để review thủ công 1.3.4. Backend Service REST API xử lý nghiệp vụ thực tế. Thông tin Giá trị Base URL http://192.168.0.133:8080 Endpoint chính POST /api/v1/plannings Xác thực JWT Bearer Token Framework Spring Boot 1.4. Hai Mô Hình Dịch Vụ 1.4.1. Đồng Bộ — Synchronous (Direct API) Client gọi và  chờ kết quả  từ Backend. Client → APIM → LifeESB (PlanningDirectApi) │ ▼ Backend API [chờ response] │ ▼ LifeESB → Client [trả kết quả thực] Đặc điểm: Client biết ngay kết quả thành công hay thất bại Backend bị quá tải → Client bị block, timeout Phù hợp: nghiệp vụ cần xác nhận ngay, lượng request vừa phải Endpoint:   POST /plannings-direct 1.4.2. Bất Đồng Bộ — Asynchronous (Kafka) Client gửi và  nhận phản hồi ngay  (không chờ Backend xử lý xong). Đặc điểm: Client không bị block dù Backend chậm hoặc quá tải Kafka buffer message, đảm bảo không mất dữ liệu Phù hợp: tải lớn, xử lý nền, không cần kết quả ngay Endpoint:   POST /kafka-producer 1.5. So Sánh Hai Mô Hình Tiêu chí Đồng bộ ( /plannings-direct ) Bất đồng bộ ( /kafka-producer ) Client chờ ✅ Chờ kết quả thực ❌ Nhận  success  ngay lập tức Khả năng chịu tải Thấp hơn (Backend block) Cao (Kafka buffer) Độ trễ Phụ thuộc Backend Gần như bằng 0 (phía Client) Đảm bảo dữ liệu Ghi ngay hoặc lỗi ngay Kafka lưu, retry nếu fail Xử lý lỗi faultSequence  → trả ngay error_topic  → review sau Phù hợp Tải vừa, cần confirm Tải lớn, xử lý nền Timeout 15 giây Không (Kafka giữ message) 1.6. Nguyên Tắc Kiến Trúc Single Entry Point : Mọi request đi qua APIM, không gọi thẳng LifeESB từ ngoài. Stateless Mediator : LifeESB không lưu trạng thái — toàn bộ state trong Kafka hoặc Backend DB. Error Isolation : Lỗi phải được bắt trong Sequence, không để lỗi raw thoát ra ngoài. Dead Letter Pattern : Message lỗi luôn được chuyển vào  error_topic , không bao giờ bị drop. Observability : Mọi bước xử lý đều có  log level="custom"  để trace theo luồng. 1.7. Môi Trường Triển Khai Thành phần Host / Port Ghi chú LifeESB 192.168.0.167:8290 HTTP endpoint LifeESB Management 192.168.0.167:9201 Deploy CAR file Kafka Broker hdp-master:9092 PLAINTEXT Backend API 192.168.0.133:8080 Spring Boot 📸  [Ảnh minh họa] — LifeESB Dashboard sau khi deploy   📸  [Ảnh minh họa] — Kafka UI / Kafka Manager hiển thị các topic Chương 1: Setup môi trường Chương này hướng dẫn chuẩn bị môi trường phát triển cho dự án, bao gồm cài đặt công cụ cần thiết, cấu hình biến môi trường, thiết lập IDE và kiểm tra kết nối đến các dịch vụ phụ trợ (DB, cache, message broker…). Sau khi hoàn thành, lập trình viên có thể chạy dự án ở môi trường local. Hướng dẫn setup môi trường và start project 1. Mục tiêu Hướng dẫn developer: Cài đặt môi trường chạy project Cấu hình biến môi trường Khởi động project Spring Boot Kiểm tra project chạy thành công 2. Yêu cầu hệ thống 2.1. Phần mềm cần cài đặt Công cụ Phiên bản khuyến nghị Java JDK 17 (bắt buộc) Maven 3.8+ Git Mới nhất IDE IntelliJ IDEA 2023+ PostgreSQL 14 hoặc 15 DB Tool DBeaver / PgAdmin 2.2. Kiểm tra cài đặt Mở terminal: java -version Kết quả mong muốn: java version "17.0.x" Kiểm tra Maven: mvn -v 3. Clone source code link driver: https://drive.google.com/file/d/1Ytzo-_uYqhhD8Pa4HUmCEjwPatoCnfPe/view?usp=sharing  4. Cấu hình biến môi trường Project sử dụng file: application.properties 4.1. Các biến môi trường cơ bản Ví dụ file: application.properties server: port: 8080 spring: datasource: url: jdbc:postgresql://localhost:5432/lifetex username: lifetex pass #spring.application.name=demo #server.port=8080 # ## ===== Oracle datasource ===== #spring.datasource.url=jdbc:oracle:thin:@//192.168.0.111:1111/ORCLPDB1 #spring.datasource.username=test #spring.datasource.password=test #spring.datasource.driver-class-name=oracle.jdbc.OracleDriver # ## ===== JPA ===== #spring.jpa.hibernate.ddl-auto=none #spring.jpa.show-sql=true #spring.jpa.properties.hibernate.format_sql=true #spring.jpa.database-platform=org.hibernate.dialect.OracleDialect # ## ===== Hikari pool (optional) ===== #spring.datasource.hikari.maximum-pool-size=10 #spring.datasource.hikari.minimum-idle=2 #spring.datasource.hikari.connection-timeout=30000 # #management.endpoints.web.exposure.include=health,info 4.2. Cách chỉnh sửa biến môi trường Cách 1: Sửa trực tiếp trong file application.properties Ví dụ đổi DB: spring: datasource: url: jdbc:postgresql://localhost:5432/test_db username: test password: test123 Cách 2: Dùng biến môi trường hệ điều hành Ví dụ trong application.properties : spring: datasource: url: ${DB_URL} username: ${DB_USER} password: ${DB_PASS} Trên Windows (PowerShell) $env:DB_URL = "jdbc:postgresql://localhost:5432/lifetex" $env:DB_USER = "lifetex" $env:DB_PASS = "123456" Trên Linux/Mac export DB_URL=jdbc:postgresql://localhost:5432/lifetex export DB_USER=lifetex export DB_PASS=123456 5. Chọn profile chạy Spring Boot thường dùng profile: dev staging prod Ví dụ chạy với profile dev . Cách cấu hình profile Cách 1: Trong biến môi trường Windows: $env:SPRING_PROFILES_ACTIVE = "dev" Linux/Mac: export SPRING_PROFILES_ACTIVE=dev Cách 2: Trong IDE VM options: -Dspring.profiles.active =dev 6. Build project Trong thư mục project: mvn clean install Nếu build thành công sẽ thấy: BUILD SUCCESS 7. Start project Chạy trong IDE Trong IntelliJ: Mở project Mở file: DemoApplication.java Nhấn nút Run 8. Kiểm tra project chạy thành công Sau khi start, kiểm tra log: Started DemoApplication in 5 . 123 seconds Mở trình duyệt: http: //localhost:8080 Hoặc gọi API: http://localhost:8080/api/v1/health Chương 2: Hướng dẫn phát triển (Developer) Chương này mô tả cấu trúc source code, quy ước coding, cách tạo module mới, cách viết API/UI, quy trình commit/branch, và cách chạy/debug dự án trong quá trình phát triển. Mục tiêu giúp developer hiểu kiến trúc và đóng góp code đúng chuẩn. Luồng Xử Lý Dịch Vụ API Tích Hợp Kafka (Kafka API Processing Flow) 1.1. Mục Tiêu Tài liệu này mô tả luồng xử lý chuẩn của dịch vụ  Loadbalance_kafka  trên nền tảng  WSO2 Micro Integrator (WSO2 MI) , từ khi Client gửi request đến khi dữ liệu được xử lý và phản hồi về. Mục tiêu: Thống nhất cách hiểu kiến trúc giữa các thành viên Đảm bảo đúng luồng dữ liệu qua từng lớp Kafka Dễ dàng trace lỗi và mở rộng sau này 1.2. Phạm Vi Áp Dụng Dự án:  Loadbalance_kafka  (WSO2 MI v4.4.0) Ngôn ngữ: Synapse XML (WSO2 Mediation) Các component: API, Inbound Endpoint, Sequence, Local Entry Kafka Connector:  mi-inbound-kafka  v2.0.6,  mi-connector-kafka  v3.3.10 1.3. Tổng Quan Luồng Xử Lý Client (HTTP POST) ↓ KafkaProducerApi (/kafka-producer) ↓ kafkaTransport.init (KafkaConnection) ↓ Kafka Topic: test_topic_01 ↓ Inbound Endpoint (KafkaMessageConsumer) ↓ inboundSequence (Load_balance_example-inboundSequence) ↓ Backend API (POST http://192.168.0.133:8080/api/v1/plannings) ↓ payloadFactory (Đóng gói lại kết quả) ↓ Kafka Topic: processed_topic 📸  [Ảnh minh họa]  — Chụp màn hình sơ đồ luồng WSO2 MI Studio hoặc Kafka Manager 1.4. Các Bước Xử Lý Chi Tiết Bước 1. Client Gửi Request Client gọi API qua HTTP: http POST http://:8290/kafka-producer Content-Type: application/json Authorization: Bearer { "field1": "value1", "field2": "value2" } Quy định: Phương thức bắt buộc:  POST Content-Type:  application/json Payload là JSON tuỳ ý — không bị validate tại lớp này 📸  [Ảnh minh họa]  — Ảnh chụp Postman/Curl gửi request thành công Bước 2. KafkaProducerApi Nhận Request File:   KafkaProducerApi.xml   API nhận request và bắt đầu luồng xử lý  inSequence . xml < api context = " /kafka-producer " name = " KafkaProducerApi " > < resource methods = " POST " > < inSequence > < log level = " custom " > < property name = " API_NAME " value = " KafkaProducerApi " /> < property name = " STATUS " value = " Processing incoming message... " /> < property name = " PAYLOAD " expression = " json-eval($) " /> ... < faultSequence > Log ghi nhận: API_NAME : Tên API xác định nguồn log STATUS : Trạng thái hiện tại của luồng PAYLOAD : Toàn bộ JSON body của request 📸  [Ảnh minh họa]  — Ảnh log WSO2 MI Console hoặc file log khi request vào Bước 3. Khởi Tạo Kết Nối Kafka (kafkaTransport.init) File:   KafkaProducerApi.xml  (trong  inSequence )   xml < kafkaTransport.init > < name >KafkaConnection < bootstrapServers >hdp-master:9092 < keySerializerClass >org.apache.kafka.common.serialization.StringSerializer < valueSerializerClass >org.apache.kafka.common.serialization.StringSerializer < acks >all < requestTimeout >10000 < maxBlock >5000 Giải thích từng trường: Trường Giá trị Mô tả name KafkaConnection Tên kết nối dùng để Sequence tham chiếu ( configKey ). bootstrapServers hdp-master:9092 Địa chỉ Kafka Broker. keySerializerClass StringSerializer Class serialize Key của message (kiểu chuỗi). valueSerializerClass StringSerializer Class serialize Value của message (kiểu chuỗi). acks all Broker phải xác nhận ghi đủ trên mọi replica mới coi là thành công. requestTimeout 10000 Timeout cho mỗi request gửi lên Kafka (ms). maxBlock 5000 Thời gian tối đa chờ nếu buffer đầy hoặc Kafka chưa sẵn sàng (ms). Bước 4. Publish Message vào Kafka File:   KafkaProducerApi.xml   xml < kafkaTransport.publishMessages > < topic >test_topic_01 Giải thích: topic :  test_topic_01  — Topic nhận dữ liệu đầu vào. Nội dung message là toàn bộ  payload  nhận từ Client. Không có key, partition cụ thể → Kafka tự điều phối vào các partition. Bước 5. Trả Response Cho Client (Producer) xml < payloadFactory media-type = " json " > < format >{"success": "true", "message": "Hồ sơ đã được gửi thành công"} < respond /> Sau khi publish xong, API trả ngay về Client mà không chờ xử lý phía Consumer. Response thành công: json { " success " : " true " , " message " : " Hồ sơ đã được gửi thành công " } Response thất bại (faultSequence): json { " status " : " Failed " , " error " : " " } Bước 6. Inbound Endpoint Lắng Nghe Kafka File:   Load_balance_example.xml   Đây là thành phần chạy ngầm liên tục, tự động poll message từ Kafka. xml < inboundEndpoint name = " Load_balance_example " class = " org.wso2.carbon.inbound.kafka.KafkaMessageConsumer " sequence = " Load_balance_example-inboundSequence " onError = " Load_balance_example-inboundErrorSequence " > Toàn bộ tham số cấu hình: Tham số Giá trị Mô tả interval 100 Khoảng cách giữa 2 lần poll (ms). sequential false false  = đa luồng, tận dụng tối đa CPU. coordination true Tránh consume trùng khi chạy cluster nhiều node. suspend false false  = khởi động ngay, không dừng. bootstrap.servers hdp-master:9092 Địa chỉ Kafka Broker kết nối đến. topic.name test_topic_01 Topic mà Inbound Endpoint theo dõi. group.id group1 Tên Consumer Group. Nhiều node cùng group sẽ chia partition. contentType application/json Định dạng nội dung message nhận về. poll.timeout 5000 Thời gian chờ khi không có dữ liệu (ms). key.deserializer StringDeserializer Class giải mã Key của message. value.deserializer StringDeserializer Class giải mã Value của message. avro.use.logical.type.converters false Không dùng Avro logical type. enable.auto.commit true Tự commit offset sau khi đọc xong. auto.commit.interval.ms 5000 Chu kỳ tự commit offset (ms). auto.offset.reset latest Bắt đầu đọc từ message mới nhất nếu không có offset cũ. exclude.internal.topics true Bỏ qua các topic nội bộ của Kafka. check.crcs true Kiểm tra tính toàn vẹn dữ liệu (CRC). partition.assignment.strategy RangeAssignor Chiến lược phân chia partition cho consumer. max.poll.interval.ms 300000 Thời gian tối đa xử lý một đợt poll (5 phút). max.poll.records 500 Số message tối đa lấy về mỗi đợt poll. fetch.max.wait.ms 500 Thời gian chờ tối đa fetch từ broker nếu chưa đủ data (ms). receive.buffer.bytes 65536 Kích thước buffer nhận dữ liệu TCP (64KB). send.buffer.bytes 131072 Kích thước buffer gửi dữ liệu TCP (128KB). request.timeout.ms 305000 Timeout cho mỗi request gửi đến Broker (ms). reconnect.backoff.ms 50 Thời gian chờ trước khi kết nối lại sau lỗi (ms). retry.backoff.ms 100 Thời gian chờ trước khi thử lại request thất bại (ms). connections.max.idle.ms 540000 Đóng kết nối nếu idle quá thời gian này (9 phút). security.protocol PLAINTEXT Giao thức bảo mật (tắt mã hóa). metrics.num.samples 2 Số mẫu dùng để tính metrics. metrics.recording.level INFO Mức độ ghi metrics. metrics.sample.window.ms 30000 Cửa sổ thời gian lấy mẫu metrics (30 giây). Bước 7. Sequence Xử Lý Message Nhận Được File:   Load_balance_example-inboundSequence.xml   7.1. Lấy Payload từ Kafka xml < property name = " PAYLOAD " expression = " json-eval($) " /> < log level = " custom " > < property name = " STATUS " value = " [KafkaConsumer] Message du lieu nhan duoc " /> < property name = " TOPIC " value = " test_topic_01 " /> < property name = " PAYLOAD " expression = " get-property('PAYLOAD') " /> Các property được tạo: Property Giá trị / Expression Mô tả PAYLOAD json-eval($) Nội dung JSON toàn bộ của message từ Kafka. 7.2. Gọi Backend API xml < header name = " Authorization " scope = " transport " value = " Bearer eyJhbGciOiJIUzI1NiJ9... " /> < property name = " Content-Type " value = " application/json " scope = " transport " /> < call > < endpoint > < address uri = " http://192.168.0.133:8080/api/v1/plannings " > < suspendOnFailure > < initialDuration >1000 < progressionFactor >1.0 < maximumDuration >60000 Thông tin endpoint: Trường Giá trị Mô tả uri http://192.168.0.133:8080/api/v1/plannings URL Backend API nhận dữ liệu. Authorization Bearer Token xác thực gửi kèm header. Content-Type application/json Định dạng body gửi đến Backend. initialDuration 1000 Chờ 1 giây trước khi retry khi lỗi (ms). progressionFactor 1.0 Hệ số tăng thời gian retry (1.0 = không tăng). maximumDuration 60000 Thời gian chờ tối đa khi retry (60 giây). 7.3. Lưu Response từ Backend xml < property name = " API_RESPONSE " expression = " json-eval($) " scope = " default " /> < property name = " HTTP_STATUS " expression = " $axis2:HTTP_SC " scope = " default " /> Các property lưu kết quả: Property Expression Mô tả API_RESPONSE json-eval($) Toàn bộ JSON response từ Backend API. HTTP_STATUS $axis2:HTTP_SC Mã HTTP status code (200, 500...) của Backend. RESPONSE_SIZE fn:string-length(...) Độ dài chuỗi JSON của response (dùng để log). 7.4. Đóng Gói Lại Dữ Liệu (payloadFactory) xml < payloadFactory media-type = " json " template-type = " default " > < format >{ "eventType": "transaction", "source": "bank-transactions", "data": ${payload} } Cấu trúc JSON đầu ra: Trường Giá trị Kiểu Mô tả eventType transaction String  (cố định) Phân loại sự kiện. source bank-transactions String  (cố định) Nguồn gốc dữ liệu. data ${payload} Object  (JSON động) Toàn bộ message gốc nhận từ Kafka. 7.5. Publish Kết Quả vào Topic Phản Hồi xml < kafkaTransport.publishMessages configKey = " KafkaConnection " > < topic >processed_topic < partitionNo >0 < forwardExistingHeaders >None < customHeaders >[] Các trường publish: Trường Giá trị Mô tả configKey KafkaConnection Tham chiếu đến Local Entry kết nối Kafka. topic processed_topic Topic nhận kết quả đã xử lý. partitionNo 0 Partition cố định (0 = partition đầu tiên). forwardExistingHeaders None Không chuyển tiếp header gốc. customHeaders [] Không thêm header tuỳ chỉnh. Bước 8. Local Entry - Cấu Hình Kết Nối Kafka Tái Sử Dụng File:   KafkaConnection.xml   xml < localEntry key = " KafkaConnection " > < kafkaTransport.init > < connectionType >KAFKA < bootstrapServers >hdp-master:9092 < keySerializerClass >...StringSerializer < valueSerializerClass >...StringSerializer < poolingEnabled >false < name >KafkaConnection Giải thích: Trường Giá trị Mô tả key KafkaConnection Tên Local Entry dùng để gọi qua  configKey . connectionType KAFKA Loại kết nối. bootstrapServers hdp-master:9092 Kafka Broker. poolingEnabled false Không dùng connection pool. Bước 9. Xử Lý Lỗi (Error Sequence) File:   Load_balance_example-inboundErrorSequence.xml   xml < sequence name = " Load_balance_example-inboundErrorSequence " > < log category = " INFO " logMessageID = " false " logFullPayload = " false " > < message >Lỗi khi lắng nghe lấy dữ liệu từ kafka Khi Inbound Endpoint bị lỗi (không parse được message, mất kết nối...), WSO2 MI sẽ kích hoạt sequence lỗi này. ⚠️  Ghi chú : Hiện tại sequence lỗi chỉ log thông báo. Cần bổ sung logic retry hoặc dead-letter queue cho production. 1.5. Luồng Phát Triển & Deploy Dev Code XML → Build CAR → Deploy lên WSO2 MI Bước 10. Build Project bash mvn clean install Output: File  Loadbalance_kafka_1.0.0.car  trong thư mục  target/ . Bước 11. Deploy lên WSO2 MI Server Tự động qua Maven: bash mvn deploy Hoặc copy file  .car  vào thư mục  /repository/deployment/server/carbonapps/ . Cấu hình server deploy (trong  pom.xml ):   Trường Giá trị Mô tả serverUrl http://192.168.0.167:9201 địa chỉ WSO2 MI Management API. userName adminvp Tài khoản admin MI. serverType mi Loại server WSO2. operation deploy Hành động thực hiện. 📸  [Ảnh minh họa]  — Ảnh chụp Deploy thành công trong WSO2 MI Dashboard 1.6. Sơ Đồ Tổng Thể API Lifecycle Client POST Request ↓ KafkaProducerApi (context: /kafka-producer) ↓ kafkaTransport.init (KafkaConnection Local Entry) ↓ Publish → Kafka: test_topic_01 ↓ ↓ (response lại Client ngay) ↓ {"success": "true", ...} ↓ Inbound Endpoint (poll interval: 100ms) ↓ inboundSequence ↓ Call Backend: POST /api/v1/plannings ↓ payloadFactory: {eventType, source, data} ↓ Publish → Kafka: processed_topic ↓ (error path) inboundErrorSequence → Log lỗi 1.7. Phụ Lục: Cấu Hình Build ( pom.xml ) Tham số Giá trị Mô tả artifactId Loadbalance_kafka Tên artifact Maven. groupId com.microintegrator.projects Group package. version 1.0.0 Phiên bản hiện tại. project.runtime.version 4.4.0 Phiên bản WSO2 MI. dockerfile.base.image wso2/wso2mi:4.4.0 Docker base image. dockerfile.name loadbalance_kafka:1.0.0 Tên Docker image output. mi-inbound-kafka 2.0.6 Phiên bản connector nhận message từ Kafka. mi-connector-kafka 3.3.10 Phiên bản connector gửi message lên Kafka. mi-connector-http 0.1.14 Phiên bản connector gọi HTTP. 1.Cấu trúc dự án 1.1. Mục tiêu chương Chương này quy định cấu trúc dự án chuẩn và phạm vi quản lý artifact giữa Core Team và các đơn vị Partner , nhằm: Đảm bảo tính ổn định của hệ thống tích hợp Tránh xung đột cấu hình và artifact giữa các đơn vị phát triển Chuẩn hóa cách tổ chức integration artifact trong toàn dự án Tăng khả năng bảo trì, mở rộng và triển khai hệ thống 1.2. Khái niệm và phạm vi áp dụng Tài liệu này được áp dụng cho: Tất cả các dự án sử dụng nền tảng WSO2 Micro Integrator Core Team : Đội phát triển lõi, chịu trách nhiệm quản lý hạ tầng, cấu hình hệ thống và các thành phần dùng chung Partner Team : Các đơn vị đối tác, chịu trách nhiệm phát triển các luồng nghiệp vụ cụ thể 1.3. Cấu trúc dự án chuẩn Cấu trúc dự án được tổ chức theo tiêu chuẩn nhằm phân tách rõ ràng giữa cấu hình hệ thống, tài nguyên tích hợp và logic nghiệp vụ, đảm bảo tính nhất quán và khả năng mở rộng trong quá trình phát triển. Ý Nghĩa Từng thư mục * Root level .mvn , mvnw , pom.xml  Project build bằng Maven pom.xml → quản lý dependency, plugin build WSO2 .mvn → config Maven wrapper + deployment/  Cấu hình runtime & deploy deployment.toml → config server (port, datasource, kafka...) docker/ → chạy container (nếu có) libs/ → thêm JAR custom (Kafka client, connector...) + docs/ Tài liệu project (thiết kế, API spec...)  * Source chính + src/main/java  Nếu có custom Java (hiện tại bạn chưa dùng) + src/main/wso2mi Đây là toàn bộ logic integration + artifacts/ + apis/  API nhận request từ client KafkaProducerApi.xml → API nhận request → đẩy vào Kafka (producer) PlanningDirectApi.xml → API gọi trực tiếp backend (không qua Kafka) + inbound-endpoints/ Kafka Consumer (cực kỳ quan trọng) Load_balance_example.xml → Lắng nghe Kafka topic → Khi có message → trigger sequence xử lý Đây chính là chỗ  load balancing bằng Kafka + sequences/  Logic xử lý nghiệp vụ Load_balance_example-inboundSequence.xml → Xử lý message lấy từ Kafka → gọi backend Load_balance_example-inboundErrorSequence.xml → xử lý lỗi khi fail + endpoints/  Định nghĩa backend service Ví dụ: HTTP endpoint REST API backend + local-entries/ Config dùng chung KafkaConnection.xml → cấu hình Kafka broker (host, port, topic...) + message-stores/  Lưu message (queue trung gian)  Dùng khi: retry đảm bảo không mất dữ liệu + message-processors/  Xử lý message từ store  Ví dụ: retry gửi lại xử lý batch + proxy-services/  Proxy service (SOAP/HTTP)  Thường dùng khi: wrap service cũ expose service trung gian + data-services/  Kết nối database  Tạo API CRUD trực tiếp DB + data-sources/  Cấu hình kết nối DB + tasks/  Job chạy định kỳ (cron job) + templates/  Template tái sử dụng  Giúp: tránh lặp code sequence / endpoint + resources/  Tài nguyên bổ trợ conf/ → config runtime (properties) connectors/ → Kafka connector JAR api-definitions/ → Swagger/OpenAPI metadata/ → metadata của artifact 1.4. Quy định chính 1.4.1. Phân quyền quản lý artifact Khu vực Đơn vị quản lý Quyền chỉnh sửa deployment/** Core Team Partner không được phép chỉnh sửa artifacts/local-entries/** Core Team Partner không được phép chỉnh sửa resources/conf/** Core Team Partner không được phép chỉnh sửa resources/connectors/** Core Team Partner không được phép chỉnh sửa artifacts/apis/** Core Team + Partner Được phép phát triển artifacts/sequences/** Core Team + Partner Được phép phát triển artifacts/inbound-endpoints/** Core Team + Partner Được phép phát triển artifacts/endpoints/** Core Team + Partner Được phép phát triển 1.4.2. Quy định bắt buộc Partner không được phép chỉnh sửa trực tiếp các khu vực sau: deployment/** artifacts/local-entries/** resources/conf/** resources/connectors/** Mọi thay đổi liên quan đến các khu vực trên phải tuân theo quy trình kiểm soát của Core Team, bao gồm: Tạo yêu cầu thay đổi (Core Change Request) Được Core Team xem xét và đánh giá Được Core Team phê duyệt và thực hiện thay đổi 1.5. Cách thực hiện / Quy trình 1.5.1. Quy trình thay đổi artifact dùng chung Bước 1: Partner xác định nhu cầu thay đổi đối với các khu vực do Core Team quản lý. Bước 2: Tạo ticket trên hệ thống quản lý công việc (Jira, Redmine hoặc YouTrack) với tiêu đề: [CORE CHANGE REQUEST] Ví dụ: [CORE CHANGE REQUEST] Thêm Kafka topic mới vào KafkaConnection local-entry Luồng xử lý Partner tạo ticket → Core Team review → Cập nhật trạng thái → Core thực hiện → Partner cập nhật code Trạng thái ticket Trạng thái Ý nghĩa Open Ticket được tạo mới Under Review Core Team đang đánh giá Approved Được chấp thuận thực hiện Rejected Bị từ chối (kèm lý do) Implemented Core Team đã hoàn thành thay đổi Merged Đã merge vào nhánh develop Bước 3: Core Team thực hiện đánh giá dựa trên các tiêu chí: Phạm vi ảnh hưởng đến các luồng hiện tại Rủi ro liên quan đến cấu hình (ví dụ: Kafka, endpoint, connection) Tính cần thiết và mức độ ảnh hưởng đến hệ thống Bước 4: Nếu thay đổi được chấp thuận: Core Team thực hiện cập nhật Merge vào nhánh develop Bước 5: Partner cập nhật code mới và tiếp tục phát triển. 1.6. Ví dụ minh họa 1.6.1. Trường hợp hợp lệ Tình huống: Bổ sung xử lý lỗi cho inbound sequence Kafka artifacts/sequences/Load_balance_example-inboundSequence.xml artifacts/sequences/Load_balance_example-inboundErrorSequence.xml → Được phép chỉnh sửa trực tiếp và tạo Pull Request. Tình huống: Thêm API mới để nhận dữ liệu artifacts/apis/PlanningDirectApi.xml → Được phép tạo mới hoặc chỉnh sửa, sau đó tạo Pull Request để Core Team review. 1.6.2. Trường hợp không hợp lệ Tình huống: Thêm Kafka topic vào cấu hình kết nối artifacts/local-entries/KafkaConnection.xml → Không được phép chỉnh sửa trực tiếp. Phải thực hiện theo quy trình: Tạo ticket: [CORE CHANGE REQUEST] Thêm topic planning_topic vào KafkaConnection Chờ Core Team phê duyệt Core Team thực hiện thay đổi và merge Tình huống: Thay đổi cấu hình Kafka bootstrap server deployment/deployment.toml resources/conf/config.properties → Không được phép chỉnh sửa trực tiếp. Phải tạo Core Change Request. 1.7. Checklist áp dụng Trước khi commit hoặc tạo Pull Request, cần đảm bảo: Artifact nằm trong các thư mục được phép chỉnh sửa ( artifacts/apis/ , artifacts/sequences/ , artifacts/inbound-endpoints/ , artifacts/endpoints/ ) Không chỉnh sửa artifacts/local-entries/** Không chỉnh sửa deployment/** Không chỉnh sửa resources/conf/** Không chỉnh sửa resources/connectors/** Pull Request đã được Core Team review (nếu ảnh hưởng đến luồng chung) Đã kiểm thử luồng Kafka producer/consumer sau khi thay đổi (nếu có) Tài liệu này thuộc phạm vi quản lý của Core Team. Mọi thay đổi nội dung phải được Core Team phê duyệt. 2. API Design & Response Standard 2.1. Mục Tiêu Chương Chương này quy định cấu trúc chuẩn của mỗi integration flow và trách nhiệm của từng artifact layer nhằm: Tách biệt rõ ràng các tầng xử lý trong luồng tích hợp Giảm phụ thuộc giữa các thành phần artifact Dễ bảo trì, mở rộng và kiểm thử từng layer độc lập Đảm bảo tính nhất quán giữa các flow trong toàn hệ thống 2.2. Khái Niệm / Phạm Vi Áp Dụng Quy tắc này áp dụng cho: Tất cả các integration flow trong thư mục  artifacts/** Cả  Core Team  và  Partner Team Tất cả các luồng tích hợp mới được phát triển Cấu Trúc Artifact Chuẩn Mỗi integration flow gồm các thành phần sau: Ý Nghĩa Từng Artifact Layer Layer Artifact Vai trò Ví dụ API Layer apis/*.xml Nhận request từ client và trả response KafkaProducerApi.xml , PlanningDirectApi.xml Mediation Layer sequences/*-inboundSequence.xml Xử lý logic, điều phối luồng Load_balance_example-inboundSequence.xml Error Layer sequences/*-inboundErrorSequence.xml Xử lý và cô lập lỗi Load_balance_example-inboundErrorSequence.xml Consumer Layer inbound-endpoints/*.xml Nhận message từ Kafka topic Load_balance_example.xml Connection Layer local-entries/*.xml Cấu hình kết nối dùng chung KafkaConnection.xml Endpoint Layer endpoints/*.xml Định nghĩa backend endpoint Backend API address 2.3. Quy Định Chính Trách Nhiệm Từng Layer API Layer ( apis/ ) Nhận request HTTP từ client (hoặc từ WSO2 APIM Gateway) Gọi backend trực tiếp hoặc publish message lên Kafka Trả response chuẩn về client Không chứa logic nghiệp vụ phức tạp Mediation Layer ( sequences/*-inboundSequence.xml ) Xử lý message nhận từ Kafka consumer Điều phối lời gọi đến backend API Phân loại kết quả theo HTTP status code (2xx / 4xx / 5xx) Publish kết quả vào  processed_topic  hoặc  error_topic Không  xử lý lỗi kỹ thuật (dành cho Error Layer) Error Layer ( sequences/*-inboundErrorSequence.xml ) Bắt lỗi kỹ thuật khi consume message từ Kafka Log đầy đủ thông tin:  ERROR_CODE ,  ERROR_MESSAGE ,  ORIGINAL_PAYLOAD Đóng gói và publish message lỗi vào  error_topic Không  retry — chỉ ghi nhận và chuyển sang error topic Consumer Layer ( inbound-endpoints/ ) Kết nối đến Kafka broker và subscribe topic Khai báo  sequence  (luồng thành công) và  onError  (luồng lỗi) Không  chứa logic xử lý Connection Layer ( local-entries/ ) Lưu thông tin kết nối Kafka dùng chung toàn hệ thống Chỉ Core Team được phép chỉnh sửa Quy Tắc Bắt Buộc   API Layer không được chứa logic nghiệp vụ phức tạp Mọi response trả về client phải theo cấu trúc JSON chuẩn Error sequence phải luôn publish message vào  error_topic Mediation sequence phải phân loại HTTP status (2xx / 4xx / 5xx) Cấu Trúc Response Chuẩn Thành công: { "success": true, "message": "Hồ sơ đã được gửi thành công" } Thành công kèm data: { "eventType": "transaction", "source": "", "data": { ... } }   Lỗi từ API Layer: { "success": false, "httpStatus": "400", "error": { ... } }   Lỗi kỹ thuật (Error Sequence ghi vào  error_topic ): { "errorSource": "Load_balance_example-inboundEndpoint", "sourceTopic": "test_topic_01", "errorType": "KAFKA_CONSUME_ERROR", "errorCode": "...", "errorMessage": "...", "originalPayload": { ... }, "timestamp": "..." }   2.4. Cách Thực Hiện / Quy Trình Quy Trình Phát Triển Một Integration Flow Mới Bước 1: Khai báo Connection (nếu chưa có) Tạo hoặc tái sử dụng  local-entries/KafkaConnection.xml . Chỉ Core Team thực hiện bước này. Bước 2: Tạo Inbound Endpoint Tạo file  inbound-endpoints/.xml : Khai báo Kafka broker, topic, group ID Trỏ  sequence  đến inbound sequence Trỏ  onError đến error sequence Bước 3: Tạo Error Sequence Tạo file  sequences/-inboundErrorSequence.xml : Log đầy đủ  ERROR_CODE ,  ERROR_MESSAGE ,  ORIGINAL_PAYLOAD Build payload lỗi chuẩn Publish vào  error_topic Bước 4: Tạo Inbound Sequence Tạo file  sequences/-inboundSequence.xml : Log message nhận được Set header xác thực Gọi backend API ( ) Phân loại theo HTTP status: 200 / 201  → publish vào  processed_topic 4xx  → đóng gói lỗi dữ liệu → publish vào  error_topic 5xx  → đóng gói lỗi backend → publish vào  error_topic Bước 5: Tạo API (nếu cần điểm vào HTTP) Tạo file  apis/Api.xml : Khai báo context path và method Set header, gọi backend hoặc publish Kafka Trả response chuẩn theo HTTP status   2.5. Ví Dụ Minh Họa Ví Dụ Đúng — Inbound Sequence phân loại HTTP Status { "eventType": "transaction", "source": "Load_balance_example-inboundSequence", "data": ${payload} } processed_topic error_topic Đúng vì: Phân loại rõ 2xx (thành công) và lỗi Kết quả thành công đi vào  processed_topic Lỗi được tách riêng vào  error_topic Sequence không xử lý lỗi kỹ thuật (để cho Error Sequence) Ví Dụ Đúng — Error Sequence đóng gói lỗi chuẩn { "errorSource": "Load_balance_example-inboundEndpoint", "sourceTopic": "test_topic_01", "errorType": "KAFKA_CONSUME_ERROR", "errorCode": "$1", "errorMessage":"$2", "originalPayload": $3 } error_topic    Ví Dụ Sai — Không phân loại HTTP Status
Sai vì: Không kiểm tra HTTP status code từ backend Lỗi 4xx / 5xx không được phân loại, không vào  error_topic Không log trạng thái xử lý  Ví Dụ Sai — API trả về raw data không theo chuẩn {"data": "ok"} Sai vì: Response không nhất quán với chuẩn  success / error toàn hệ thống 2.6. Checklist Áp Dụng Trước khi commit integration flow mới:  Có đủ:  inbound-endpoint ,  inboundSequence ,  inboundErrorSequence  Inbound Sequence có phân loại HTTP status (2xx / 4xx / 5xx)  Thành công publish vào  processed_topic  Lỗi publish vào  error_topic  Error Sequence log đầy đủ:  ERROR_CODE ,  ERROR_MESSAGE ,  ORIGINAL_PAYLOAD  Error Sequence đóng gói payload lỗi theo cấu trúc chuẩn  API Layer trả response theo cấu trúc JSON chuẩn ( success ,  error )  Không hardcode thông tin kết nối trong Sequence (dùng  local-entries )  PR đã được Core Team review Tài liệu này thuộc phạm vi quản lý của  Core Team  — mọi thay đổi phải được Core Team phê duyệt. 3.Cơ chế xác thực (JWT/Bearer) 3.1. Mục Tiêu Chương Chương này quy định chuẩn xác thực và nguyên tắc thiết kế bảo mật nhằm: Đảm bảo cơ chế xác thực thống nhất giữa các integration flow và đơn vị phát triển Giúp artifact dễ đọc, dễ hiểu và dễ bảo trì Giảm lỗi phát sinh do xử lý token không đúng chuẩn Tăng hiệu quả review và kiểm soát chất lượng artifact Đảm bảo toàn bộ luồng từ Client → APIM → MI → Backend đều có xác thực nhất quán Tích hợp đúng với WSO2 Identity Server (IS) làm trung tâm cấp và xác thực token 3.2. Khái Niệm / Phạm Vi Áp Dụng Quy định này áp dụng cho: Toàn bộ artifact xử lý hoặc chuyển tiếp request qua xác thực Core Team  và  Partner Team Tất cả các API, Sequence, Inbound Endpoint trong  artifacts/** Cấu hình APIM và IS do Core Team quản lý Kiến Trúc Xác Thực Tổng Thể Ba Tầng Xác Thực Tầng Thành phần Vai trò xác thực Cấp token WSO2 Identity Server (IS) OAuth2 Authorization Server, cấp JWT/Access Token Validate token WSO2 API Manager (APIM) Xác thực token tại Gateway trước khi route vào MI Forward token WSO2 Micro Integrator (MI) Set  Authorization: Bearer  header khi gọi backend 3.3. Quy Định Chính 3.3.1. Quy Tắc Đặt Tên Artifact Các artifact liên quan xác thực phải đặt tên theo quy ước thống nhất: Thành phần Quy tắc đặt tên Ví dụ REST API Api.xml KafkaProducerApi.xml , PlanningDirectApi.xml Inbound Sequence -inboundSequence.xml Load_balance_example-inboundSequence.xml Error Sequence -inboundErrorSequence.xml Load_balance_example-inboundErrorSequence.xml Inbound Endpoint .xml Load_balance_example.xml Connection Entry Connection.xml KafkaConnection.xml Backend Endpoint Endpoint.xml PlanningBackendEndpoint.xml 3.3.2. Quy Tắc Đặt Property Trong Sequence Dùng tên property nhất quán khi xử lý token/header: 3.3.3. Quy Định Về Logging Xác Thực Không được bỏ qua bước log khi xử lý request:
Phải log đầy đủ các bước:   3.3.4. Quy Định Về Token / Header Xác Thực Token dùng để gọi backend phải được set từ  local-entries hoặc  config.properties  —  không hardcode trong Sequence :
3.4. Nguyên Lý Tách Biệt Trách Nhiệm (Separation of Concerns) Tương đương nguyên lý  SOLID  áp dụng trong hệ thống WSO2: 3.4.1. S — Mỗi Artifact Một Trách Nhiệm Mỗi artifact chỉ được thực hiện một nhiệm vụ: Artifact Chỉ được làm apis/ Nhận HTTP request, set header auth, gọi backend/Kafka, trả response sequences/*-inboundSequence.xml Điều phối luồng message từ Kafka đến backend sequences/*-inboundErrorSequence.xml Ghi nhận lỗi và publish vào  error_topic inbound-endpoints/ Kết nối Kafka, subscribe topic local-entries/ Lưu thông tin kết nối và cấu hình dùng chung Sai  — Error logic nằm trong inbound sequence: ... error_topic Đúng  — Error sequence riêng biệt: 3.4.2. O — Mở Rộng Không Sửa Artifact Cũ Khi thêm topic/luồng mới, tạo artifact mới — không sửa sequence của luồng khác: 3.4.3. L — Consumer Tuân Thủ Contract Sequence Inbound Endpoint phải trỏ đúng sequence và error sequence đã khai báo: 3.4.4. I — Tách Riêng Local Entry Theo Chức Năng Không nhét tất cả cấu hình vào một local entry: ... ...   3.4.5. D — Phụ Thuộc Config, Không Hardcode Sequence phụ thuộc vào  local-entries và  config.properties — không hardcode URL hay token:
3.5. Luồng Xác Thực Chuẩn Trong Hệ Thống 3.5.1. Luồng Chuẩn Từ Client Đến Backend Client → [1] Lấy token từ WSO2 IS (/oauth2/token) → [2] Gọi API qua WSO2 APIM với Bearer token → [3] APIM validate token với WSO2 IS (introspect / JWT verify) → [4] APIM route request vào WSO2 MI → [5] MI set header Authorization khi gọi backend → [6] Backend (Spring Boot) validate JWT 3.5.2. Luồng Kafka Consumer Không Đi Qua APIM Kafka Topic (test_topic_01) → [1] MI Inbound Endpoint consume message → [2] MI Inbound Sequence xử lý → [3] MI set header Authorization: Bearer → [4] MI gọi Backend API → [5] Backend validate JWT → [6] Kết quả: published_topic hoặc error_topic Luồng Kafka consumer bypass APIM Gateway — token phải được quản lý thủ công trong MI (lấy từ IS hoặc dùng service account token). 3.5.3. Không Được Phép
3.5.4. Luồng Token Trong Kafka Consumer (Chuẩn)
1000 2.0 60000
3.6. Cấu Hình Xác Thực WSO2 APIM & IS 3.6.1. WSO2 IS — Key Manager WSO2 IS đóng vai trò  Key Manager  cho APIM: Chức năng Endpoint WSO2 IS Lấy Access Token POST /oauth2/token Introspect Token POST /oauth2/introspect Lấy Public Key (JWKS) GET /oauth2/jwks Revoke Token POST /oauth2/revoke Lấy token từ IS (client_credentials): POST https://:9443/oauth2/token Content-Type: application/x-www-form-urlencoded Authorization: Basic grant_type=client_credentials&scope=   3.6.2. WSO2 APIM — API Gateway Security Mọi API publish lên APIM phải cấu hình: Thuộc tính Giá trị chuẩn Security Type OAuth2 hoặc API Key Token Validation IS Introspection / JWT verify Throttling Theo chính sách dự án CORS Cấu hình theo môi trường 3.6.3. JWT Claims Chuẩn Của Hệ Thống Token JWT cấp bởi WSO2 IS phải chứa: { "sub": "admin", "role": "ADMIN", "iat": 1771917707, "exp": 1772004107, "iss": "https://:9443/oauth2/token", "aud": "...client_id...", "scope": "..." } 3.7. Cách Thực Hiện / Quy Trình Quy Trình Thêm Xác Thực Cho Luồng Mới Bước 1:  Đăng ký OAuth2 Application trong WSO2 IS Tạo Service Provider Lấy  clientId  và  clientSecret Bước 2:  Cấu hình token trong  backend.auth.token= backend.planning.url=http://192.168.0.133:8080/api/v1/plannings Bước 3:  Trong Sequence, đọc token từ config
Bước 4:  Publish API lên APIM với OAuth2 Security Import OpenAPI spec từ  resources/api-definitions/ Enable Security:  OAuth2 Set Key Manager:  WSO2 IS Bước 5:  Test luồng xác thực end-to-end Lấy token từ IS Gọi API qua APIM với Bearer token Verify log trong MI:  STATUS ,  HTTP_STATUS ,  PAYLOAD 3.8. Ví Dụ Minh Họa Ví Dụ Sai — Sequence Không Có Authorization Header
Sai vì: Không set  Authorization: Bearer  header Không log request/response Backend sẽ reject với 401 Unauthorized Không xử lý HTTP status response Ví Dụ Sai — Hardcode Token Trong Sequence
Sai vì: Token hardcode sẽ hết hạn, phải sửa code mỗi lần Lộ thông tin xác thực trong source code Không thể thay đổi theo môi trường (dev / staging / prod) Ví Dụ Đúng — Sequence Xác Thực Và Gọi Backend Chuẩn
1000 2.0 60000
processed_topic error_topic   [Chỗ này thêm ảnh: WSO2 MI log viewer — hiển thị STATUS, HTTP_STATUS sau khi gọi backend thành công] Ví Dụ Đúng — API APIM Với OAuth2 Security # resources/api-definitions/KafkaProducerApi.yaml openapi: 3.0.0 info: title: Kafka Producer API version: 1.0.0 paths: /kafka-producer: post: summary: Publish message lên Kafka security: - OAuth2: [] # Bắt buộc xác thực OAuth2 tại APIM requestBody: required: true content: application/json: schema: type: object responses: '200': description: Thành công components: securitySchemes: OAuth2: type: oauth2 flows: clientCredentials: tokenUrl: https://:9443/oauth2/token scopes: {}   3.9. Checklist Áp Dụng Trước khi commit hoặc tạo PR: Naming  API artifact:  Api.xml  Inbound Sequence:  -inboundSequence.xml  Error Sequence:  -inboundErrorSequence.xml  Connection Entry:  Connection.xml Token & Xác Thực  Không hardcode Bearer token trong Sequence  Token lấy từ config.properties  hoặc  local-entries  Mọi lời gọi backend đều có  Authorization: Bearer  header  API publish lên APIM đã bật OAuth2 Security  Key Manager trỏ đúng về WSO2 IS Logging  Sequence log  STATUS ,  PAYLOAD  khi nhận request  Sequence log  HTTP_STATUS ,  API_RESPONSE  sau khi gọi backend  Error Sequence log  ERROR_CODE ,  ERROR_MESSAGE ,  ORIGINAL_PAYLOAD Separation of Concerns  API Layer không chứa logic điều phối phức tạp  Error handling nằm trong Error Sequence riêng  Kết nối Kafka trong  local-entries , không khai báo lại trong Sequence  URL backend lấy từ config, không hardcode Architecture  Inbound Endpoint trỏ đúng  sequence  và  onError  Luồng thành công publish vào  processed_topic  Luồng lỗi publish vào  error_topic  Không có luồng nào bỏ qua xác thực với backend 3.10. Cấu Trúc Chuẩn Của Một Sequence Xử Lý Nghiệp Vụ 3.10.1. Mục Tiêu Quy định cấu trúc thống nhất của một  inboundSequence  nhằm: Dễ đọc và dễ review Tách rõ:  nhận dữ liệu → xác thực → gọi backend → phân loại kết quả Tránh thiếu log hoặc thiếu xử lý HTTP status Chuẩn hóa cách publish kết quả vào Kafka topic 3.10.2. Cấu Trúc Bắt Buộc Một  inboundSequence phải theo thứ tự: 1. Lưu payload gốc vào property 2. Log thông tin message nhận được 3. Set Authorization header (Bearer token) 4. Gọi backend API () 5. Lưu HTTP status và response 6. Log phản hồi backend 7. Phân loại theo HTTP status (filter) - 2xx → publish vào processed_topic - 4xx → đóng gói lỗi dữ liệu → publish vào error_topic - 5xx → đóng gói lỗi backend → publish vào error_topic   3.10.3. Quy Định Chi Tiết Từng Bước 1. Lưu payload:   2. Log input:   3. Set header xác thực (từ config, không hardcode):
  4. Gọi backend:
1000 2.0 60000
  5–6. Lưu và log phản hồi:   7. Phân loại kết quả:   3.10.4. Ví Dụ Sequence Sai Sai vì:  Không có Bearer token, không log, không phân loại HTTP status, không publish kết quả. 3.10.5. Checklist Review Sequence Khi review một inboundSequence :  Có lưu  PAYLOAD  vào property trước khi xử lý  Có log thông tin nhận message  Có set  Authorization: Bearer  header (từ config, không hardcode)  Có log HTTP status sau khi gọi backend  Có phân loại HTTP status: 2xx / 4xx / 5xx  2xx →  processed_topic  4xx và 5xx →  error_topic  Không xử lý lỗi kỹ thuật trong sequence này (để cho Error Sequence) Tài liệu này thuộc phạm vi quản lý của  Core Team  — mọi thay đổi phải được Core Team phê duyệt. 4. Logging & Audit trong Sequence 4.1. Mục tiêu chương Chương này quy định cách kiểm soát các thay đổi liên quan đến cấu trúc dữ liệu nhằm: Tránh mất dữ liệu hoặc lỗi hệ thống Đảm bảo tương thích giữa các module Ngăn xung đột schema khi nhiều đơn vị cùng phát triển Bảo vệ các field và bảng dữ liệu chuẩn của hệ thống 4.2. Khái niệm / phạm vi áp dụng Quy định này áp dụng cho: Tất cả các entity trong hệ thống Tất cả các bảng database Core Team và Partner Team Mọi thay đổi liên quan đến: Các loại thay đổi cần kiểm soát Thêm field mới Xóa field Sửa field Đổi kiểu dữ liệu Thay đổi quan hệ entity Thêm/xóa bảng database 4.3. Quy định chính 4.3.1. Không được tự ý thay đổi các field chuẩn Các field chuẩn hệ thống: id created_at created_by updated_at updated_by deleted / status tenant_id (nếu có) Quy định bắt buộc Không được: Xóa field chuẩn Đổi kiểu dữ liệu Đổi tên field Thay đổi ý nghĩa nghiệp vụ của field Các field này được coi là system fields và được dùng chung cho: Audit Logging Multi-tenant Phân quyền Tích hợp hệ thống 4.3.2. Thêm field mới trong module Partner chỉ được phép thêm field khi: Phục vụ nghiệp vụ của module Không trùng với dữ liệu core Không phá vỡ cấu trúc hiện tại Có migration script Có mô tả trong Pull Request Được Core Team review 4.3.3. Các thay đổi bắt buộc xin phép Core Team Các thay đổi sau không được tự ý thực hiện: Đổi kiểu dữ liệu field Xóa field Đổi tên field Thay đổi quan hệ entity Thêm field liên quan: user role permission tenant audit Tất cả các trường hợp trên phải qua: Data Model Change Request 4.4. Cách thực hiện / quy trình Trường hợp 1: Thêm field trong module Bước 1: Cập nhật entity trong: modules//entity/** Bước 2: Tạo migration script: V__add__to_.sql Bước 3: Tạo Pull Request, trong PR phải có: Mô tả field mới Lý do nghiệp vụ Migration script Bước 4: Core Team review: Không trùng core data Không phá vỡ hệ thống Bước 5: Merge vào develop Trường hợp 2: Thay đổi field hoặc quan hệ entity Bước 1: Tạo ticket: các phần mềm quản lý công việc liên quan (Jira / Redmine / YouTrack) hoặc nội bộ [DATA MODEL CHANGE REQUEST] Bước 2: Cung cấp thông tin: Entity bị ảnh hưởng Field thay đổi Kiểu dữ liệu cũ và mới Migration script Lý do thay đổi Bước 3: Core Team review: Đánh giá ảnh hưởng hệ thống Kiểm tra backward compatibility Bước 4: Nếu được duyệt: Core Team thực hiện thay đổi Merge vào develop 4.5. Ví dụ minh họa Trường hợp hợp lệ Partner thêm field vào entity module: @Column(name = "PRIORITY") private Integer priority; Và có migration: ALTER TABLE PLANNING ADD PRIORITY INT; → Được phép. Trường hợp không hợp lệ Partner sửa: @Column(name = "CREATED_AT") private String createdAt; → Đổi kiểu dữ liệu từ timestamp sang string. → Không được phép. Phải tạo: [DATA MODEL CHANGE REQUEST] Trường hợp cần xin phép Partner muốn: Xóa field status Đổi tên description → detail Thêm quan hệ với bảng user_account 4.6. Checklist áp dụng Trước khi commit hoặc tạo PR: Có thay đổi field chuẩn không? Nếu có → phải tạo Data Model Change Request Có đổi kiểu dữ liệu field không? Nếu có → phải xin phép Core Team Có migration script chưa? Field mới có trùng dữ liệu core không? PR đã mô tả rõ thay đổi chưa? 5.Git Workflow & Pull Request 5.1. Mục tiêu chương Chương này quy định chuẩn commit và quy trình merge code nhằm: Đảm bảo lịch sử thay đổi rõ ràng, dễ truy vết Giảm xung đột giữa các nhóm phát triển Đảm bảo chất lượng code trước khi đưa vào nhánh chính Chuẩn hóa quy trình phát triển giữa Core Team và Partner 5.2. Khái niệm / phạm vi áp dụng Quy định này áp dụng cho: Tất cả repository của dự án Core Team và Partner Team Mọi commit và Pull Request (PR) Quy trình phát triển tuân theo: Chuẩn format commit Chiến lược branch Điều kiện merge bắt buộc 5.3. Quy định chính 5.3.1. Format commit Tất cả commit phải theo format: : Trong đó: : loại thay đổi : mô tả ngắn gọn nội dung thay đổi Ví dụ commit hợp lệ feat: add planning API fix: validate file upload refactor: optimize planning service docs: update API guideline test: add unit test for planning service chore: update dependency versions Type hợp lệ Type Ý nghĩa feat Thêm chức năng mới fix Sửa lỗi refactor Tối ưu, không đổi logic docs Cập nhật tài liệu test Thêm hoặc sửa test chore Thay đổi cấu hình, build, dependency 5.3.2. Branch strategy Hệ thống sử dụng mô hình branch chuẩn: Branch Mục đích main Bản stable, dùng cho production develop Bản tích hợp, nơi merge các feature feature/* Phát triển chức năng mới fix/* Sửa lỗi Quy tắc làm việc với branch Không commit trực tiếp vào main Không commit trực tiếp vào develop Mọi thay đổi phải qua Pull Request Branch phải được đặt tên đúng quy tắc Ví dụ tên branch hợp lệ feature/planning-create-api feature/document-upload fix/login-null-pointer fix/planning-date-validation 5.3.3. Điều kiện merge Pull Request Pull Request chỉ được merge khi đáp ứng đầy đủ các điều kiện: Build thành công Không sửa: common/** config/** Không sửa shared entity Có review từ Core Team 5.4. Cách thực hiện / quy trình Quy trình phát triển tính năng Bước 1: Tạo branch từ develop git checkout develop git pull git checkout -b feature/planning-create-api Bước 2: Thực hiện commit theo chuẩn git commit -m "feat: add planning create API" Bước 3: Push branch lên remote git push origin feature/planning-create-api Bước 4: Tạo Pull Request vào develop Bước 5: Core Team review Bước 6: Nếu đạt yêu cầu → merge vào develop Quy trình sửa lỗi Bước 1: Tạo branch fix git checkout develop git checkout -b fix/planning-null-error Bước 2: Commit git commit -m "fix: handle null planning name" Bước 3: Tạo PR và chờ review 5.5. Ví dụ minh họa Trường hợp commit sai Sai vì: Không theo format chuẩn Không có type Trường hợp commit đúng fix: handle null planning name Trường hợp merge sai Partner: Commit trực tiếp vào develop Không tạo PR Không có review → Vi phạm quy trình. Trường hợp merge đúng Tạo branch feature/planning-api Commit theo chuẩn Tạo PR vào develop Core Team review Build pass Merge 5.6. Checklist áp dụng Trước khi tạo Pull Request: Commit đúng format : Branch đúng quy tắc feature/* hoặc fix/* Không commit trực tiếp vào main hoặc develop Build thành công Không sửa: common/** config/** shared entity PR đã được Core Team review 6.Checklist kiểm tra trước khi merge 6.1. Mục tiêu chương Chương này quy định checklist bắt buộc trước khi merge code nhằm: Đảm bảo chất lượng code trước khi tích hợp Tránh vi phạm các quy định về kiến trúc và dữ liệu Giảm rủi ro lỗi khi build hoặc triển khai Chuẩn hóa quy trình review giữa Core Team và Partner 6.2. Khái niệm / phạm vi áp dụng Checklist này áp dụng cho: Tất cả Pull Request (PR) Core Team và Partner Team Mọi module trong hệ thống Checklist được dùng trong: Code review Kiểm tra trước khi merge vào develop Kiểm tra trước khi release 6.3. Quy định chính Pull Request chỉ được phép merge khi đáp ứng đầy đủ các điều kiện sau: Code nằm trong khu vực được phép: modules/** Không sửa các khu vực bị cấm: common/** config/** Không sửa shared entity trong: common/entity/** Nếu có thay đổi database: Phải có migration script API phải đúng chuẩn: /api/v1/ Response phải dùng: ApiResponse  7.Build phải thành công 6.4. Cách thực hiện / quy trình Quy trình kiểm tra trước khi merge Bước 1: Dev hoàn thành feature hoặc fix bug Bước 2: Tạo Pull Request vào develop Bước 3: Dev tự kiểm tra checklist Bước 4: Core Team review theo checklist Bước 5: Nếu đạt yêu cầu → merge Nếu không đạt: PR bị reject Dev phải sửa lại theo checklist 6.5. Ví dụ minh họa Trường hợp hợp lệ PR: Chỉ sửa code trong: modules/planning/** Có migration: V20260210__add_priority_to_planning.sql API: /api/v1/planning Build thành công → Được merge. Trường hợp không hợp lệ PR: Sửa file: common/entity/UserEntity.java → Vi phạm quy định shared entity. → PR bị từ chối. Trường hợp bị từ chối do thiếu migration PR: Thêm field trong entity: private Integer priority; Không có migration SQL → PR bị reject. 6.6. Checklist áp dụng Dev phải tick đủ các mục sau trước khi merge: [ ] Code nằm trong modules/** [ ] Không sửa common/** [ ] Không sửa config/** [ ] Không sửa shared entity [ ] Có migration nếu thay đổi DB [ ] API đúng chuẩn /api/v1/ [ ] Response dùng ApiResponse [ ] Build thành công Core Team chỉ merge khi checklist đạt đầy đủ. 7.Quy trình phối hợp & quản lý thay đổi các nhóm 7.1. Mục tiêu chương Chương này quy định cách phối hợp giữa nhiều đơn vị phát triển nhằm: Tránh xung đột giữa FE, BE và Database Đảm bảo tích hợp ổn định Giữ tính tương thích giữa các module Kiểm soát các thay đổi ảnh hưởng hệ thống 7.2. Khái niệm / phạm vi áp dụng Áp dụng khi: Có nhiều đơn vị cùng phát triển FE và BE tách source Nhiều FE dùng chung BE BE tách thành nhiều service Mọi thay đổi liên quan: API contract Entity/Database Auth Domain/CORS đều phải thông qua Core Team. 7.3. Quy định chính Nguyên tắc chung Dùng contract-first (OpenAPI là nguồn chuẩn) Mọi thay đổi API hoặc DB phải được kiểm soát Mọi thay đổi breaking phải qua Core Team Trường hợp FE và BE khác source, dùng chung DB Rủi ro: Sai contract API Response làm FE vỡ Migration xung đột Quy định: BE thay đổi API/DB phải update OpenAPI Mọi thay đổi DB phải có migration Staging dùng DB chung Quy trình: FE tạo ticket: API CONTRACT ISSUE BE/Core xác nhận Fix backward compatible hoặc tạo API v2 Trường hợp FE và BE dùng DB riêng khi dev Quy định: Có DB baseline chung Staging dùng DB chung Quy trình: Nếu staging lỗi → so version migration Không cho merge nếu thiếu migration Trường hợp nhiều FE dùng chung một BE Quy định: Dùng IdP chung (WSO2/Keycloak) Mỗi FE là một OAuth client riêng Gọi API bằng JWT Quy trình: FE đăng ký client_id Core cấu hình redirectUri, scope Core cấp quyền Trường hợp FE chung source, BE nhiều service Quy định: FE cấu hình baseURL theo service Auth dùng token chung CORS do Core Team quản lý Quy trình: Thêm service → tạo Integration Checklist Core cấu hình CORS và token audience Trường hợp thay đổi response làm FE vỡ Quy định: Chỉ được thêm field (non-breaking) Không đổi kiểu dữ liệu Không rename field Breaking change phải tạo /api/v2 Quy trình: Tạo BREAKING CHANGE REQUEST Core duyệt Thông báo FE Trường hợp xung đột entity/model Quy định: Entity dùng chung → coi là shared model Phải qua Data Model Change Request Quy trình: Partner đề xuất field + migration Core review Approve hoặc yêu cầu sửa Trường hợp migration xung đột Quy định: Không sửa migration đã merge Tạo migration mới để fix forward Quy trình: Rebase Tạo migration mới Test staging Trường hợp seed/master data bị sửa Quy định: Seed core do Core Team quản lý Partner chỉ được đề xuất Quy trình: Tạo MASTER DATA REQUEST Core duyệt và triển khai 7.4. Quy trình triển khai tính năng nhiều tầng Tạo ticket Feature Chốt API contract (OpenAPI) Chốt entity/migration BE implement FE integrate Test staging Release 7.5.Ví dụ minh họa 1. bảng mô tả các môi trường hệ thống: Env FE URL BE URL DB Auth dev http://localhost:4200 http://localhost:8080 local mock staging https://staging.app.vn https://staging.api.vn shared WSO2 thật prod https://app.vn https://api.vn prod WSO2 thật 8. Prompt Template cho AI Agent tạo API trên LifeESB 8.1. Vai trò và Nhiệm vụ (System Prompt) Copy đoạn văn bản sau đưa cho AI: Vai trò:  Bạn là một Chuyên gia Kiến trúc Tích hợp (Integration Architect) hệ thống WSO2 Micro Integrator (MI) 4.4.0. Nhiệm vụ của bạn là đọc các bản đặc tả API (Use Cases) từ người dùng và tự động sinh ra mã nguồn XML chuẩn xác, có thể chạy được ngay của WSO2 MI. Tiêu chuẩn Thiết kế (Bắt buộc tuân thủ 100%): Kiến trúc REST:  Mọi API phải được bọc trong thẻ  . Các Use Case bên trong được chia thành các thẻ  . Phân tách Endpoint:  Cấm hardcode URL trực tiếp vào  . Mọi URL gọi xuống backend phải được định dạng trong một file   độc lập. Cấu hình Môi trường:  Trong file  , thuộc tính  uri-template  của   BẮT BUỘC phải dùng định dạng System Properties:  $SYSTEM:TEN_BIEN_CUA_DICH_VU . Xử lý Dữ liệu mặc định là XML:  Payload đi qua hệ thống mặc định là XML. Trừ khi được yêu cầu đổi sang JSON, còn lại không tự ý dùng DataMapper hay  . Trích xuất thông tin:  Trong  inSequence  của API, phải có các property sử dụng  XPath  để lấy các trường quan trọng từ payload XML đầu vào (như  requestId ,  procedureCode ,  registrationId ...). Ghi Log (Observability):  Ngay sau khi vào  inSequence  và trích xuất property, phải có thẻ   để in ra Console thông tin request (bao gồm Use Case ID đang chạy và các biến vừa lấy). Xử lý Ngoại lệ:  Mọi   bắt buộc phải có   để bẫy lỗi và trả response. Đầu ra (Output Mode): Chỉ in ra kết quả là các khối mã XML rõ ràng kèm tên file (comment ở dòng đầu), không giải thích dài dòng trừ khi người dùng hỏi. 8.2. Kiến thức Nền tảng (Few-Shot Examples) Cung cấp cho AI đoạn mã mẫu sau làm chuẩn mực (Golden Template): Dưới đây là Mẫu Code Tiêu Chuẩn bạn phải học theo: Mẫu 1: File API định tuyến (ReceivingAPI.xml)   Mẫu 2: File Endpoint độc lập (BackendReceivingCreateEndpoint.xml)   2000 1.0 3000 8.3. Cách thức làm việc (User Workflow) Sau khi lưu 2 đoạn trên làm cấu hình cho Bot (System Instructions), bạn chỉ cần làm việc với nó qua các bước đơn giản mỗi lệnh: Ví dụ một đoạn Chat bạn nhập vào: Prompt: "Đây là tài liệu Use Case UC-26: [dán phần text tài liệu UC-26 Định tuyến thông điệp vào đây]. Yêu cầu: Generates file RoutingAPI.xml với context '/api/v1/routing' và các file Endpoints tương ứng. Chú ý sử dụng Switch mediator để rẽ nhánh procedureCode." Kết quả hoàn hảo bot trả về:  Bot sẽ lập tức sinh ra 1 file API có Switch mediator dùng XPath  //procedureCode/text()  cực chuẩn xác và 2-3 file cấu hình Endpoint  $SYSTEM:  cho nó. Comment Ctrl+Alt+M 9. Prompt Template cho AI Agent tạo Test Case API LifeESB Bản Prompt này được tối ưu để hướng dẫn AI sinh ra các kịch bản kiểm thử (Test Cases), cURL commands, và Postman Collection dựa trên tài liệu đặc tả API và file mã nguồn WSO2 MI. 9.1. Vai trò và Nhiệm vụ (System Prompt) Copy đoạn văn bản sau đưa cho AI: Vai trò:  Bạn là một QA / API Testing Engineer cấp cao chuyên về nền tảng tích hợp WSO2 Micro Integrator (MI). Nhiệm vụ của bạn là đọc các bản đặc tả Use Case và đoạn mã XML API của WSO2, từ đó sinh ra bộ Test Case hoàn chỉnh để kiểm thử API hoạt động đúng nghiệp vụ. Tiêu chuẩn Thiết kế Test Case (Bắt buộc tuân thủ 100%): Dữ liệu Mặc định là XML:  Mặc dù đặc tả có thể mô tả bằng JSON, nhưng Client giao tiếp với MI qua định dạng XML. Tất cả các Test Case payload ( Body ) BẮT BUỘC phải viết dưới dạng chuỗi XML hợp lệ. Cấu trúc Test Case:  Mỗi Use Case phải có ít nhất 2 nhóm Test Case gốc: Happy Path (Thành công):  Dữ liệu chuẩn, mô phỏng luồng đi trót lọt ( HTTP 200/202 ). Negative Path (Báo lỗi):  Dữ liệu cố tình làm sai (VD: thiếu dòng/sai XML, logic sai như thiếu chữ ký...) để kiểm thử khối   hoặc logic Validate của backend. Cú pháp Đầu ra (Output Format):  Mỗi Test Case phải trình bày rõ ràng 4 phần: Tên Test Case:  (VD: TC01 - Tiếp nhận đăng ký thành công) Endpoint & Method:  (VD:  POST http://localhost:8290/api/v1/receiving/registrations ) Headers:  Định nghĩa rõ  Content-Type: application/xml  (hoặc  application/json  nếu có yêu cầu dị biệt). Request Body (XML):  Cấu trúc XML chuẩn xác theo nghiệp vụ. Postman/cURL Script:  Cung cấp câu lệnh  cURL  tương ứng cho nhóm Happy Path để người dùng dễ dàng dán vào Terminal hoặc Import vào Postman test nhanh. Tập trung vào Giao diện (Integration Edge):  Bạn chỉ test lớp Integration (Gateway/MI). Hãy chú ý truyền đúng các Param/Path Variable/Body mà WSO2  inSequence  đang cần dùng (như  requestId ,  procedureCode ). 9.2. Kiến thức Nền tảng (Few-Shot Examples) Cung cấp cho AI ví dụ Test Case chuẩn mực sau: Dưới đây là Mẫu Test Case Tiêu Chuẩn bạn phải học theo: Use Case Mẫu:  UC-22 Tiếp nhận hồ sơ mới (Nhận XML Ingestion) TC01: Happy Path - Đăng ký hồ sơ thành công (Dữ liệu XML chuẩn mực) Method:   POST URL:   http://localhost:8290/api/v1/receiving/registrations Headers:   Content-Type: application/xml   Accept: application/xml Body Raw (XML): REQ_20250228001 HQ01 DN001 INV Base-64-Encoded-Content ... Expected Result:  Nhận về HTTP Status  200 OK (Hoặc 202 tuỳ backend) với form Output Payload do Backend nhả ra qua WSO2 MI. cURL để Test nhanh TC01: bash curl -X POST -H 'Content-Type: application/xml' -H 'Accept: application/xml' -d 'REQ_20250228001HQ01DN001INVBase-64-Encoded-Content...' http://localhost:8290/api/v1/receiving/registrations TC02: Negative Path - Payload XML bị khuyết cấu trúc nghiêm trọng (Lỗi Missing Mandatory Field) Mô tả: Gửi cố tình xoá cụm   để xem khối WSO2 Fault Sequence hoặc Backend có bẫy được không. Body Raw (XML): REQ_20250228_ERR02 Expected Result:  Nhận về chuỗi XML mô tả lỗi, HTTP Code dạng  400 Bad Request  hoặc  500 . 9.3. Cách thức làm việc (User Workflow) Sau khi nhập 2 khối trên vào System Context, quy trình bạn ra lệnh sẽ như sau: Ví dụ một đoạn Chat bạn nhập vào: Prompt: "Tôi vừa viết xong WSO2 API cho UC-23 (Sửa hồ sơ  /{registrationId}/amend ). Đây là nguyên văn tài liệu: [Dán tài liệu UC-23]. Yêu cầu sinh Test Case cho API này theo định dạng XML. Context API gốc chày trên máy tôi là port 8290." Kết quả hoàn hảo bot trả về: Bot sẽ sinh ra các bộ câu hỏi kiểm thử: HTTP Body (XML) sửa hồ sơ, Path params  id kèm cURL Script. Bạn chỉ việc Copy ném vào Postman là bắn test luôn không phải typing mỏi tay định dạng từng dấu ngoặc. Chương 3: Triển khai hệ thống (Deploy) Chương này hướng dẫn quy trình build và triển khai ứng dụng Java (Spring Boot) lên các môi trường dev/staging/production. Bao gồm chuẩn bị hạ tầng, build artifact (JAR), cấu hình biến môi trường, chạy ứng dụng dạng service hoặc Docker container, cấu hình reverse proxy (Nginx), database migration và kiểm tra sau triển khai. Mục tiêu đảm bảo ứng dụng chạy ổn định, có thể giám sát và rollback khi cần. Hướng dẫn chi tiết 1. Yêu cầu hạ tầng Server tối thiểu CPU: ≥ 2 core RAM: ≥ 4 GB (prod ≥ 8 GB) Disk: ≥ 20 GB OS: Linux (Ubuntu 20.04+ / CentOS 7+) Java: OpenJDK 17 (khuyến nghị LTS) Cài Java: sudo apt update sudo apt install openjdk-17-jdk -y java -version 2. Build ứng dụng Build bằng Maven mvn clean package -DskipTests Artifact tạo ra: target/app.jar   Chương 4: Kiểm thử đơn vị (Unit Test) Chương này hướng dẫn cách viết unit test cho API trong ứng dụng Java Spring Boot. Nội dung bao gồm cấu trúc test chuẩn, cách mock dependency, kiểm tra validate input, xác thực (authentication/authorization), ghi log, xử lý exception và kiểm tra logic service. Mục tiêu đảm bảo mỗi API hoạt động đúng, an toàn và ổn định trước khi tích hợp hoặc triển khai. Nội dung chi tiết   1. Nguyên tắc Unit Test API Mỗi API cần test các nhóm case cơ bản: Validate input Auth / permission Business logic Repository interaction Exception handling Logging HTTP status & response 2. Ví dụ API mẫu Controller: @RestController @RequestMapping("/users") @RequiredArgsConstructor public class UserController { private final UserService userService; @PostMapping public ResponseEntity create ( @Valid @RequestBody CreateUserRequest req) { return ResponseEntity.ok(userService.create(req)); } } DTO: @Data public class CreateUserRequest { @NotBlank private String username; @Email private String email; } Service: @Service @RequiredArgsConstructor public class UserService { private final UserRepository repo; public UserResponse create (CreateUserRequest req) { User u = new User (req.getUsername(), req.getEmail()); repo.save(u); return new UserResponse (u.getId(), u.getUsername()); } } 3. Cấu trúc test chuẩn Dependency: < dependency > < groupId >org.springframework.boot < artifactId >spring-boot-starter-test < scope >test Controller test dùng: @WebMvcTest MockMvc @MockBean 4. Test Validate Input Case cần có: thiếu field bắt buộc email sai format request null @WebMvcTest(UserController.class) class UserControllerValidationTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test void create_shouldFail_whenUsernameBlank () throws Exception { String json = """ {"username":"","email":"a@test.com"} """ ; mockMvc.perform(post( "/users" ) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isBadRequest()); } @Test void create_shouldFail_whenEmailInvalid () throws Exception { String json = """ {"username":"john","email":"invalid"} """ ; mockMvc.perform(post( "/users" ) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isBadRequest()); } } 5. Test Auth / Permission Giả sử API cần login: @WithMockUser @Test void create_shouldSuccess_whenAuthenticated () throws Exception { when (userService.create(any())) .thenReturn( new UserResponse ( 1L , "john" )); String json = """ {"username":"john","email":"a@test.com"} """ ; mockMvc.perform(post( "/users" ) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isOk()); } Test chưa login: @Test void create_shouldUnauthorized_whenNoAuth () throws Exception { String json = """ {"username":"john","email":"a@test.com"} """ ; mockMvc.perform(post( "/users" ) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isUnauthorized()); } 6. Test Business Logic (Service) @ExtendWith(MockitoExtension.class) class UserServiceTest { @Mock private UserRepository repo; @InjectMocks private UserService service; @Test void create_shouldSaveUser () { CreateUserRequest req = new CreateUserRequest (); req.setUsername( "john" ); req.setEmail( "a@test.com" ); when (repo.save(any())).thenAnswer(i -> i.getArgument( 0 )); UserResponse res = service.create(req); assertEquals( "john" , res.getUsername()); verify(repo).save(any()); } } 7. Test Exception Handling Giả sử email trùng: when (repo.save(any())) .thenThrow( new DataIntegrityViolationException ( "dup" )); Test: @Test void create_shouldThrow_whenDuplicateEmail () { CreateUserRequest req = new CreateUserRequest (); req.setUsername( "john" ); req.setEmail( "a@test.com" ); when (repo.save(any())) .thenThrow( new RuntimeException ( "duplicate" )); assertThrows(RuntimeException.class, () -> service.create(req)); } 8. Test Logging Giả sử service có log: log.info( "Create user {}" , req.getUsername()); Test log: @ExtendWith(MockitoExtension.class) class UserServiceLogTest { @Mock private UserRepository repo; @InjectMocks private UserService service; @Test void create_shouldLog () { CreateUserRequest req = new CreateUserRequest (); req.setUsername( "john" ); req.setEmail( "a@test.com" ); when (repo.save(any())).thenAnswer(i -> i.getArgument( 0 )); service.create(req); verify(repo).save(any()); } } (Thực tế có thể dùng LogCaptor) 9. Test HTTP Response @Test @WithMockUser void create_shouldReturnBody () throws Exception { when (userService.create(any())) .thenReturn( new UserResponse ( 1L , "john" )); String json = """ {"username":"john","email":"a@test.com"} """ ; mockMvc.perform(post( "/users" ) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isOk()) .andExpect(jsonPath( "$.username" ).value( "john" )); } 10. Danh sách Case chuẩn cho mỗi API Mỗi API cần tối thiểu: Validate thiếu field format sai null body Auth chưa login sai role đúng role Business flow thành công dữ liệu biên điều kiện đặc biệt Repository save OK not found duplicate Exception DB lỗi logic lỗi external lỗi Response status code body schema Log log khi success log khi error   11. Checklist Unit Test API Test validate Test auth Test service Mock repo Test exception Test response Verify interaction No DB thật No network Chương 5: Đóng gói & phát hành (Packaging) Chương này hướng dẫn cách đóng gói dự án thành artifact phát hành (jar, docker image, bundle web…), đặt version, ghi changelog, ký số (nếu có) và lưu trữ trên repository. Kết quả là gói cài đặt sẵn sàng để triển khai hoặc phân phối.