Android (Java, minSdk 21), Gradle Groovy DSL. Kiến trúc MVVM + Repository 1 tầng data. Giao tiếp Backend Spring Boot qua Retrofit, JWT lưu bằng
SessionManager.
- Thống nhất cách code cho cả nhóm
- Tách bạch UI - Xử lý - Gọi data, dễ quản lý, test và bảo trì
- Chuẩn hóa kiến trúc
- Hiển trị layout và bắt sự kiện, dữ liệu
- Gửi và nhận dữ liệu để render từ ViewModel
- Điều phối luồng: nhận event từ UI và gọi xử lý ở mức độ dữ liệu (Repository)
- Đồng thời xử dụng Resource để Loading/Success/Error
- Xử lý dữ liệu: Gọi Retrofit, đọc/lưu token qua SessionManager
- Mapping: RequestDomain → RequestDTO, DTO → DomainModel (qua
Mapper). - Chuẩn hóa lỗi (HTTP/IO/parse) -> trả Resource
- Chuyển đổi RequestDomain -> RequestDTO, DTO -> DomainModel
- P/S: Tránh rò rĩ kiểu dữ liệu lên UI, dễ unit test(Thực tế)
- Lưu/đọc token
- Được
Interceptordùng để gắnAuthorization: Bearer <token>.
- Retrofit + OkHttp + Interceptor
- Khai báo Api và gắn token vào request được gửi đi
Activity/Fragment (UI + nhận event)
→ ViewModel (điều phối; post Resource.Loading)
→ data/repository/*Repository (class cụ thể - chỉ 1 layer data)
→ mapper: DomainReq → DTOReq (nếu có body)
→ remote/api (Retrofit qua ApiClient + Interceptor JWT)
→ HTTP → Spring Boot: Controller → Service → JPA → PostgreSQL
← JSON (status + body)
← mapper: DTORsp → DomainModel
← ViewModel nhận Resource.Success/Error(domain data)
← UI observe → render (progress / adapter.submitList / error)
LÀM
- UI chỉ thao tác UI; ViewModel chỉ điều phối.
RepositoryImplchịu trách nhiệm dữ liệu: Retrofit, token, mapping, lỗi.Mappertách riêng để test tốt; không để DTO xuất hiện ở UI.Interceptorgắn token tự động; bật logging ở build debug.
KHÔNG LÀM
- Adapter không gọi API / không chuyển domain → list phức tạp (chỉ bind).
- Không pass Context lung tung vào repository/mapper.
- Không dùng DTO ở UI; không lưu token trong ViewModel.
LoginFragmentbắt click →AuthViewModel.login(u, p).AuthViewModelpostLoading→ gọiauthRepository.login(LoginRequestDomain).AuthRepository→AuthApi.login()(Retrofit).- Backend trả
200 {token,...}hoặc401. - Lưu token vào
SessionManager, map DTO → Domain, trảSuccess. AuthViewModelpostSuccess→ UI điều hướng;Error→ UI hiển thị thông báo.
BlogListFragment.onViewCreated()→BlogViewModel.load(page,size).BlogViewModelpostLoading→blogRepository.getBlogs(page,size).BlogRepositorygọiBlogApi.getBlogs(...)(Interceptor tự gắnBearer <token>).- Map
List<BlogDto> → List<Blog>→Success. - UI nhận
Success→adapter.submitList(list).
main→ code ổn định (chỉ merge khi review xong).-
develop→ nhánh tổng hợp code nhóm.
feature/<tên-chức-năng>→ mỗi thành viên code trên nhánh riêng.
feat:– thêm tính năng mới.fix:– sửa bug.docs:– cập nhật tài liệu/README.refactor:– chỉnh code không đổi chức năng.test:– thêm hoặc sửa test.
- Pull code mới nhất từ
developtrước khi code:git checkout develop git pull origin develop
- Tạo nhánh mới kèm tên feat và check out: git checkout -b feat/aut
- Commit và push git add . git commit -m "feat(auth): register & login with bcrypt and jwt" git push origin feat/auth
- Tạo Pull Request từ feat/.. -> develop
- Review code nếu ổn thì merge
- Sau khi release, mearge develop -> main
📌 Notes
Mọi thành viên không push trực tiếp vào main.
Nếu gặp vấn đề môi trường → tham khảo [ChatGPT Setup Guide] hoặc trao đổi trong nhóm.