News App (BLoC + Clean Architecture) — Flutter Learning Project Lanjutan

Iterasi lanjutan dari news-app-mvvm dengan arsitektur Clean Architecture lengkap, BLoC + Cubit, Firebase OTP untuk reset password, Google Sign-In, dan compute() isolate untuk crop dan compress avatar di profile.

Role
Solo Flutter developer (learning project lanjutan)
Ownership
Solo builder: arsitektur Clean Architecture berlapis lengkap, integrasi Firebase OTP, Google Sign-In, Dio AuthInterceptor dengan refresh lock, image processing di Isolate, plus modul News Feed, Explore, Search, Bookmark, Article Detail, dan Profile.
Team
Solo learning project
Period
2026
Focus
Flutter, Flutter Developer, Mobile Developer

Overview

news-app adalah iterasi lanjutan dari news-app-mvvm yang mengeksplorasi Clean Architecture berlapis lengkap pada Flutter, dipasangkan dengan backend free-api-news yang sama. Fokus dari iterasi ini adalah masuk ke topik yang jarang ditemui di project tutorial: interceptor Dio dengan refresh token lock, BLoC plus Cubit untuk kebutuhan state yang berbeda, Firebase OTP sebagai lapisan verifikasi HP untuk reset password, Google Sign-In OAuth, serta image processing berat di Dart Isolate melalui compute() supaya UI tetap smooth saat upload avatar.

Problem

Setelah mengerti MVVM + Provider di iterasi pertama, masih ada banyak area Flutter yang belum tersentuh seperti interceptor dengan refresh lock, event traceability BLoC, OAuth Google, OTP via Firebase, dan image processing yang tidak membekukan UI. Mengerjakan semuanya di project yang sama memungkinkan setiap keputusan arsitektur saling mendukung, bukan sekadar menempel tutorial terpisah.

My Role & Ownership

Solo builder: arsitektur Clean Architecture berlapis lengkap, integrasi Firebase OTP, Google Sign-In, Dio AuthInterceptor dengan refresh lock, image processing di Isolate, plus modul News Feed, Explore, Search, Bookmark, Article Detail, dan Profile.

Technical Approach

Membangun Flutter app memakai Clean Architecture berlapis lengkap: Presentation (Pages, Widgets, BLoC/Cubit), Domain (Entities, UseCases, Repository contract), Data (Models, Repository impl, RemoteDatasource, LocalDatasource), dan Core (ApiClient Dio, AuthInterceptor, ErrorHandling, DI, theme, router). Return type di boundary domain-repository konsisten Either<Failure, T>.

BLoC dipakai untuk state global seperti AuthBloc, Cubit dipakai untuk state lokal per layar (feed, explore, search, bookmark, article detail, profile edit).

Auth stack mendalam: login email/password ke backend, Google Sign-In lewat official plugin, Firebase OTP untuk reset password (verifyPhoneNumber dan signInWithCredential, lalu menukar Firebase ID Token ke backend), plus auth interceptor dengan lock supaya refresh token race condition tidak terjadi saat beberapa request paralel kena

  1. Untuk update profile, image dari kamera atau galeri dipindah ke Isolate via compute() untuk crop square dan encode JPEG, sehingga Main Thread tetap responsif walau file asli besar.

Architecture Notes

Feature-first dengan lapisan tegas: Presentation (Pages, Widgets, BLoC/Cubit), Domain (Entities, UseCases, Repository contract), Data (Models, Repository impl, RemoteDatasource, LocalDatasource), dan Core (ApiClient, AuthInterceptor, Failure, DI, router, theme). Dependency rule: Presentation tidak pernah memanggil ApiClient langsung, semua lewat UseCase ke Repository interface.

External dependency dibungkus sesuai siapa yang mengonsumsinya. Dio dan SecureStorage dibungkus sebagai Datasource karena dipakai RepositoryImpl di Data layer, sedangkan Firebase OTP dan flutter_local_notifications dibungkus sebagai Service atau Repository khusus karena dipakai sebagai orkestrasi multi-sumber dari UseCase atau Repository.

Misalnya AuthRepositoryImpl berperan sebagai dirigen: menerima request dari UseCase, berkoordinasi dengan FirebaseOTPService untuk verifikasi HP, menukar credential ke backend lewat AuthRemoteDatasource, lalu menyimpannya via AuthLocalDatasource.

Trade-offs

Memilih BLoC untuk AuthBloc dan Cubit untuk state lokal per layar sebagai kompromi antara event traceability dan ringkasnya boilerplate, bukan full-BLoC di setiap layar. Memakai Firebase OTP alih-alih membangun SMS Gateway sendiri karena biaya dan manajemen bot spam terlalu mahal untuk project belajar; konsekuensinya ada ketergantungan ke layanan Google.

Bookmark optimistic update disimpan di SharedPreferences supaya terasa instan, trade-off-nya perlu logic rekonsiliasi ketika backend dan local tidak sinkron.

Compute() isolate dipakai spesifik untuk crop dan compress image; tidak dipakai untuk parse JSON ringan karena overhead Isolate tidak sebanding untuk payload kecil. UseCase layer dipertahankan walaupun banyak yang tipis karena tujuan utama iterasi ini adalah latihan Clean Architecture berlapis.

Results

  • Menunjukkan kemampuan meramu Clean Architecture Flutter dengan state management BLoC plus Cubit secara proporsional, menangani integrasi third-party yang umum ditemui di production (Firebase OTP, Google OAuth), dan memahami batas antara Main Thread dan Isolate ketika beban komputasi berat seperti decode image muncul di alur UI.

Links