Konversi frontend web StairsLife (HTML/CSS/JS SPA) ke Flutter mobile app (iOS & Android), terhubung ke backend NestJS yang sama (TIDAK diubah).
Marketplace freelance: mahasiswa (freelancer) ⇄ bisnis (klien) + panel admin.
Desain mengikuti versi website + folder Flutter awal: indigo #6366F1,
teal, amber, rose, font Inter, Material 3. (Catatan: warna ungu #6C5DD3 di
brief lama TIDAK dipakai karena website asli & folder Flutter pakai indigo.)
lib/
├── main.dart / app.dart # Entry + MaterialApp.router
├── core/
│ ├── constants/api_constants.dart # Base URL + semua endpoint
│ ├── errors/app_exception.dart # Sealed exception (ApiException, SessionExpired, dll)
│ ├── network/
│ │ ├── api_client.dart # Dio wrapper + unwrap envelope {success,data,message}
│ │ ├── token_interceptor.dart # JWT attach + auto-refresh 401 (field `token`)
│ │ ├── socket_client.dart # Socket.io wrapper (namespaced)
│ │ └── network_providers.dart # secureStorageProvider, apiClientProvider
│ ├── storage/secure_storage.dart # flutter_secure_storage (sl_token, sl_refresh_token, sl_user)
│ ├── router/app_router.dart # GoRouter + redirect guard by role
│ └── theme/ # Design tokens
├── features/
│ ├── auth/ # login, register, verify-email, reset-password
│ ├── projects/ # browse, detail, post — data layer + providers
│ ├── applications/ # apply, my applications, project applicants (business)
│ ├── contracts/ # detail, deliverable review/complete
│ ├── deliverables/ # upload (file_picker → /upload/file)
│ ├── payments/ # history + Xendit WebView
│ ├── chat/ # list + room (Socket.io /chat)
│ ├── notifications/# list (Socket.io /notifications)
│ ├── wallet/ # saldo + bank + withdrawal data
│ ├── verification/ # KTM submit (image_picker → /upload/image)
│ ├── reviews/ # submit review
│ ├── disputes/ # list + new dispute
│ ├── profile/ # settings + verification status
│ ├── admin/ # 7 panel: overview/users/verif/dispute/proyek/penarikan/pengumuman
│ ├── student_dashboard/ # 5 tab — semua data backend nyata
│ └── business_dashboard/ # 5 tab — semua data backend nyata
└── shared/widgets/ # AppButton, AppCard, AppTextField, StatusBadge, dll
State management: Riverpod (AsyncNotifierProvider untuk data fetch,
FutureProvider.family untuk detail). DI lewat Provider.
cd StairsLifeAppTes
flutter pub get
flutter runEdit lib/core/constants/api_constants.dart:
// Production (default):
static const String baseUrl = 'https://stairslifebackendweb-production.up.railway.app/api/v1';
static const String wsUrl = 'https://stairslifebackendweb-production.up.railway.app';
// Android emulator (backend lokal):
// static const String baseUrl = 'http://10.0.2.2:3000/api/v1';
// static const String wsUrl = 'http://10.0.2.2:3000';
// iOS simulator / desktop:
// static const String baseUrl = 'http://localhost:3000/api/v1';
// static const String wsUrl = 'http://localhost:3000';- Response envelope:
{ success, data, message, timestamp }→ ApiClient ambildata - Error:
{ success:false, statusCode, message, timestamp }(messageString / array) - Auth: login/register balikin
{ user, token, refresh_token }(fieldtoken, bukanaccess_token) - Auto-refresh: 401 →
POST /auth/refresh { refresh_token }→ retry request - WebSocket:
/chat(eventjoin_room/send_message/new_message, camelCasecontractId),/notifications(eventnew_notification/unread_count), auth viahandshake.auth.token - Xendit:
POST /payments/invoice→ bukainvoice_urldi WebView (webview_flutter) - Enum exact: role
mahasiswa|bisnis|admin, tierpemula|menengah|mahir, project_status pakaiinProgress, payment adasplit_settled, contractpending_review
| Fitur | Status |
|---|---|
| Auth (login/register/verify/reset/logout + guard) | ✅ |
| Browse / detail / post project | ✅ |
| Lamaran (apply, my apps, kelola pelamar, approve→kontrak) | ✅ |
| Student dashboard (5 tab real data) | ✅ |
| Business dashboard (5 tab real data) | ✅ |
| Contract detail + deliverable upload/review + complete | ✅ |
| Pembayaran Xendit (invoice → WebView) + riwayat | ✅ |
| Chat realtime + notifikasi realtime (Socket.io) | ✅ |
| Verifikasi KTM (image_picker upload) | ✅ |
| Review, dispute (list + buka) | ✅ |
| Admin: overview/users/verif/dispute/proyek/penarikan/pengumuman | ✅ |
| Settings + theme + logout | ✅ |
flutter_riverpod · go_router · dio · socket_io_client · flutter_secure_storage · image_picker · file_picker · webview_flutter · connectivity_plus · permission_handler · google_fonts · cached_network_image · shimmer · intl · timeago
Backend NestJS tidak diubah — hanya dijadikan acuan kontrak API.