معماری اپلیکیشن Mobile
اپلیکیشن از معماری Feature-first با جریان داده یکطرفه و جداسازی Presentation و Data استفاده میکند. Domain Layer فقط برای منطق کسبوکاری واقعی، Invariant یا مدل مستقل از Transport ساخته میشود؛ Feature ساده با Use Case و Interface نمایشی پیچیده نمیشود.
جریان داده
User Event
-> ViewModel / Notifier
-> Repository Contract
-> Repository Implementation
-> Remote Service / Local Service
-> Immutable State
-> View
View فقط State را نمایش و Event را ارسال میکند. ViewModel رفتار Presentation و Coordination را مدیریت میکند. Repository منبع حقیقت Feature است و انتخاب Remote، Cache یا ترکیب آنها را در یک مرز Testable نگه میدارد.
ساختار هدف
lib/
├── l10n/
└── src/
├── app/ # Bootstrap، Router و Theme
├── core/ # Primitive پایدار و بدون دانش Feature
└── features/
└── <feature>/
├── domain/ # در صورت منطق واقعی
├── data/ # Repository و Service
└── presentation/ # View، State و ViewModel
نام Feature از مستند محصول و API میآید. Folder خالی، utils عمومی، Service Locator موازی یا abstraction بدون Consumer واقعی ساخته نمیشود.
Dependency Rule
- Presentation به Contract Repository وابسته است و مستقیم API یا Storage را صدا نمیزند.
- Data میتواند Domain Model را Map کند ولی Domain از Flutter، Dio، Database و Plugin مستقل است.
- Feature دیگر به Internal این Feature Deep Import نمیکند.
coreاز Feature مستقل است و Business Rule را برای reuse در خود نمیکشد.
State و DI
Riverpod مالک State و Dependency Injection است. Providerها کوچک و Feature-scoped هستند، Rebuild با Selector محدود میشود و Global Mutable State خارج از Provider Graph مجاز نیست. State باید Immutable و حالت Loading، Data، Empty، Error و Offline روشن داشته باشد.
امنیت
- Refresh Token فقط از طریق Keychain یا Android Keystore و
flutter_secure_storageنگهداری میشود. - Access Token فقط در Memory است و Token، OTP، Authorization Header یا PII Log نمیشوند.
dart-define، Source و Asset محل Secret نیستند؛ Mobile یک Public Client است.- Validation Client برای UX است و تصمیم Authorization فقط در Backend انجام میشود.
- Deep Link و Notification Input غیرقابل اعتماد و نیازمند Parse و Permission Check هستند.
- Certificate Pinning، Analytics، Crash SDK و WebView بدون Threat Model و ADR اضافه نمیشوند.
شبکه ضعیف و Offline
- Queryهای لازم میتوانند آخرین پاسخ موفق را با TTL و نسخه Schema مشخص Cache کنند.
- Command Offline فقط با تایید Product، Idempotency و Conflict Policy Queue میشود.
- Retry خودکار فقط برای عملیات Safe یا Idempotent، محدود و با Backoff و Jitter است.
- Push فقط Signal همگامسازی است و منبع حقیقت داده نیست.
- با تغییر Building، Cache، Request و State Tenant قبلی Cancel یا Invalidate میشوند.
آزمون
Service و Repository با Fake محدود، ViewModel با Unit Test و View با Widget Test از دید کاربر پوشش داده میشوند. Flowهای Authentication، Tenant Switch، Offline Queue و Deep Link به Integration Test نیاز دارند.