Kiến trúc Hệ thống Tasco SuperApp & Mini App
Tài liệu này trình bày chi tiết kiến trúc của nền tảng ứng dụng di động Tasco, bao gồm sự kết hợp giữa mô hình SuperApp (Host Container) và các Mini-apps (Plug-ins), cấu trúc phân lớp Clean Architecture và các quy tắc phát triển ràng buộc.
1. Tổng quan Kiến trúc SuperApp & Mini App
Hệ sinh thái ứng dụng của Tasco hoạt động theo mô hình Pluggable Architecture (Kiến trúc cắm ghép). Trong đó:
- Host Shell (
apps/shell): Đóng vai trò là Container chính (Shell App). Shell quản lý các tính năng hệ thống dùng chung như Bootstrap, quản lý Flavor/Environment, xác thực tập trung, thanh điều hướng gốc, cấu hình đẩy thông báo (Push Notification), và tích hợp hệ thống định tuyến chính. - Mini-apps (
apps/mini_app,mini_apps/*): Là các module độc lập chứa logic nghiệp vụ đặc thù (ví dụ: Bảo hiểm xe, Bảo hiểm sức khỏe, v.v.). Mỗi Mini-app được phát triển và kiểm thử độc lập như một package riêng. Khi chạy production, Mini-app được nhúng vào Shell thông qua hợp đồng giao tiếp chuẩn hóa.
2. Hợp đồng Module Slot (tasco_module)
Hợp đồng cho phép Shell nhúng và giao tiếp với Mini-app được định nghĩa thông qua package tasco_module:
ModuleSlot: Định nghĩa siêu dữ liệu và các hành vi vòng đời của Mini-app:abstract class ModuleSlot {String get moduleId;String get routePrefix;List<String> get notificationTypes;Future<void> init({required AppEnv env, required Interceptor hostInterceptor});List<RouteBase> routes();Future<void> onNotification(ModuleNotification notification);void dispose();}ModuleManager: Quản lý tập hợp cácModuleSlotđã đăng ký, tự động gộp các route và điều phối sự kiện notification đến đúng module đích.
Quy tắc Plug-in: Việc thêm hoặc gỡ bỏ một Mini-app chỉ diễn ra tại điểm khởi tạo (bootstrap.dart) thông qua ModuleManager.register(). Nhà phát triển không bao giờ sửa đổi thủ công hệ thống Router hay Shell để tích hợp module mới.
3. Kiến trúc Phân lớp (Clean Architecture)
Tất cả các thành phần trong SuperApp và Mini-apps đều phải tuân thủ nghiêm ngặt mô hình phân lớp Clean Architecture:
Các lớp và vai trò:
- Lớp Domain (
domain/): Chỉ chứa các quy tắc nghiệp vụ thuần túy. Gồm các thực thể (Entities), Use Cases và giao diện kho dữ liệu trừu tượng (abstractRepository). Lớp này không phụ thuộc vào bất kỳ thư viện ngoài nào (trừ Dart core). - Lớp Data (
data/): Thực thi việc truy xuất và xử lý dữ liệu. GồmRepositoryImpl, các nguồn dữ liệuDataSource(gọi API qua Dio hoặc lưu cache qua SQLite/SharedPreferences) và các lớp ánh xạ dữ liệu (Data Transfer Objects / Models). - Lớp Presentation (
features/): Gồm giao diện người dùng (Pages, Widgets) và bộ quản lý trạng thái (CubithoặcBloc).
Quy tắc ràng buộc Clean Architecture:
- Giao diện người dùng (UI) không bao giờ gọi trực tiếp Repository hoặc DataSource. Mọi tương tác phải đi qua
UseCase. CubitvàUseCasechỉ giao tiếp với abstractRepository, không bao giờ giao tiếp trực tiếp với lớp thực thiRepositoryImplhoặc cácDataSource.
4. Quản lý Trạng thái (State Management)
Hệ thống chuẩn hóa sử dụng Flutter BLoC / Cubit kết hợp với thư viện equatable để so sánh trạng thái tối ưu:
- Sử dụng Cubit cho các luồng xử lý trạng thái giao diện đơn giản.
- Sử dụng BLoC cho các luồng nghiệp vụ phức tạp, bất đồng bộ và nhiều sự kiện xen kẽ.
- Sử dụng enum
LoadingStatus(initial | loading | success | failure) nằm trongtasco_utilsđể quản lý trạng thái tải bất đồng bộ thay vì khai báo các biến Boolean rời rạc.
5. Dependency Injection (DI) & Networking
Quản lý Dependency Injection
Hệ thống sử dụng thư viện get_it và đăng ký thủ công theo từng Module đăng ký (di.dart).
Thứ tự đăng ký bắt buộc phải tuân theo thứ tự phân lớp từ dưới lên trên:
- Local/Core services (
SharedPreferences,SecureStorage, v.v.) - API Clients (Dio)
- Remote/Local DataSources
- Repositories
- Use Cases
- Cubits/Blocs
Đa dịch vụ mạng (Multi-service Network)
Mỗi backend service sử dụng một URL cơ sở (baseURL) riêng biệt và được đăng ký dưới dạng một Dio client có tên định danh trong api_module.dart:
// Truy xuất Dio client theo tên định danh
final ticketDio = getIt<Dio>(instanceName: DiKey.ticketDio);
Hệ thống tích hợp sẵn các Interceptor dùng chung quan trọng:
AuthInterceptor: Tự động đính kèm token xác thựcBearervà xử lý tự động làm mới token (Refresh Token) khi nhận mã lỗi401.ErrorInterceptor: Đồng bộ hóa định dạng lỗi trả về và kết nối trực tiếp vớiLoadingManagertoàn cục để hiển thị thông báo lỗi.
6. Quy tắc Phụ thuộc Một chiều (Dependency Rules)
Để tránh hiện tượng mã nguồn đan xen vòng lặp (circular dependency) làm gãy hệ thống, quy tắc phụ thuộc một chiều sau đây là bắt buộc:
- Các package nền tảng (
tasco_utils,tasco_core,tasco_ui_kit) không bao giờ được phép import hoặc phụ thuộc ngược lại vàoshellhoặc bất kỳ Mini-app nào. - Mini-apps giao tiếp với nhau duy nhất thông qua định tuyến đường dẫn (deep link/routing) hoặc lưu trữ dùng chung, tuyệt đối không được import chéo mã nguồn của nhau.