Overview
Designer
Designer + Developer Handoff

Satu dokumen untuk dua peran. Semua yang dibutuhkan untuk implementasi MASA dari desain ke production Flutter app — tanpa bolak-balik tanya ke desainer atau PM.

🎨 UI/UX Designer
Design Handoff
Token reference, component inventory, annotation guide, Figma → Flutter mapping, brand rules.
⚙️ Flutter Developer
Dev Handoff
ThemeData siap paste, widget mapping, API contract, wave implementation checklist.

§0Ekosistem dokumen

Semua dokumen di bawah harus dibaca sebelum mulai. Urutan membaca: dari atas ke bawah.

#DokumenSiapa yang bacaKapan dibaca
1Brand Strategy 02-brand/Designer + PMSebelum mulai desain apapun
2Voice & Tone Guide 02-brand/Designer + Dev (copy)Sebelum menulis copy di screen
3Design System v2 03-design-system/Designer + DevSebelum implement komponen apapun
4Feature Flows & Wireframe 04-ia-wireframe/Designer + DevUntuk memahami flow setiap fitur
5MASA E2E Complete 05-hifi/Designer + DevReferensi visual utama per layar
6Copy Deck 06-handoff/Dev (backend + frontend)Saat implement string resources
7Analytics Event Spec 06-handoff/Dev (Firebase)Saat implement tiap screen
8Acceptance Criteria 06-handoff/Dev + QA + PMSaat sprint planning + QA
Design Token Reference

Semua nilai token yang dipakai di MASA. Ini adalah sumber kebenaran tunggal — designer dan developer WAJIB pakai token ini, bukan hardcode nilai warna atau spacing.

§1Color Tokens

Token NameValueUsage
--blue-500#1B77A6Primary action, active nav, info state, trust primary
--blue-700#005E8CButton hover, deep blue text, payment CTA
--blue-50#EAF3F9NOW zone background, info card bg, active chip bg
--amber-600#D97224FAB Sedekah, warm CTA, Sedekah Subuh, campaign banner
--amber-100#FFE5CCSedekah card bg, amber accent bg
--green-500#2D6A4FSuccess state, habit tracker, impact, verified badge, LazisMu
--green-700#1B4332Deep green text, verified hover
--green-100#D0EBDASuccess bg, habit card bg, verified badge bg
--gold-600#B8924DAuthority badge, LazisMu trust, "by LabMu", kuitansi frame
--gold-100#F0E4C8Gold card bg, Pesan Hari Ini bg, authority surface
--err-700#8E2A2AError state, destructive action, P0 bug indicator
--err-100#FCE4E4Error card bg, danger surface
--ink-0#14110EPrimary text, headlines, primary button bg
--ink-2#3A332BBody text, secondary headline
--ink-3#6E665BSubtitle, placeholder, muted text
--ink-4#9A9286Caption, disabled text, overline
--paper-0#FFFCF5Card surface, modal background
--paper-1#FBF8F2App background (root)
--paper-2#F4EFE4Section background, secondary surface
--line#E5DDCDDividers, card borders, input borders

§2Typography Tokens

Style NameFont / Size / WeightUsage
Display LInter 52px / W800 / LS -3.2%Splash only
Display MInter 40px / W700 / LS -2.5%Section hero title
H1 PageInter 28px / W700 / LS -1.8%Screen title (AppBar large)
H2 SectionInter 22px / W700 / LS -1.4%Card hero, section header
H3 CardInter 17px / W700 / LS -1.0%Card title, list item title
Body LInter 16px / W400 / LH 1.6Article body, description
Body MInter 14px / W400 / LH 1.6Standard body, form labels
Body SInter 12px / W400 / LH 1.5Caption, timestamp, meta
Label LInter 14px / W600 / LS -0.5%Button text, CTA
Label SInter 11px / W600 / LS +1%Badge, tag, status chip
OverlineJetBrains Mono 10px / W600 / LS +10%Section label, card tag, category
Hero SerifNewsreader Italic 22px+ / W400-500Pesan Hari Ini, manifesto, tagline ONLY

§3Spacing + Radius Tokens

Spacing TokenValueUsage
--sp-14pxIcon margin, tight gap
--sp-28pxSmall gap, chip padding
--sp-312pxMedium gap
--sp-416pxCard padding, standard gap
--sp-624pxSection gap, content spacing
--sp-832pxSection padding, large gap
--sp-1248pxPage padding, hero spacing
Radius TokenValueUsage
--r-xs4pxInput, small chip, badge
--r-s8pxCard, button, dropdown
--r-m12pxModal, bottom sheet
--r-l16pxHero card, banner, FAB bg
--r-xl24pxBottom sheet radius-top
--r-full9999pxPill chip, FAB, rounded button
Component Inventory

35 kategori komponen. Semua sudah didefinisikan di Design System v2. Status: semua Done untuk Sprint 1.

§1Foundation

Color System
20 brand tokens · 4 semantic
Done
Typography
12 styles · Inter + Newsreader + Mono
Done
Spacing & Radius
10 spacing · 6 radius tokens
Done
Elevation & Shadow
5 levels (EL-0 to EL-4)
Done

§2Navigation

Top App Bar
Standard · Search · Large (homepage)
Done
Bottom Navigation
4 tabs + FAB center · Active state
Done
Tabs & Chips
Tab bar · Filter chip · Tag pill
Done

§3Actions

Button
8 variants × 3 sizes × 5 states
Done
Icon Button & FAB
36px icon btn · 44px FAB · Extended FAB
Done
Quick Action Grid
8-puck 4×2 grid · segmented ordering
Done
Slide to Confirm
Anti-accidental-tap · Sedekah + Qurban
Done

§4Inputs

Text Field
6 states · label · helper · error text
Done
Search Field
Default · Focus · With filter button
Done
Dropdown & Select
Single · Multi · Segmented · Currency
Done
Toggle / Checkbox / Radio
3 controls × on/off/disabled
Done
OTP Input
6-digit · Amount picker
Done

§5Feedback

Toast / Snackbar
Success · Error · Warning · Info
Done
Dialog
Confirmation · Destructive · Info
Done
Bottom Sheet
Action sheet · Form sheet · Detail
Done
Alert & Banner
4 semantic variants inline
Done

§6Trust System (MASA-specific)

Verification Badge
Verified · Pending · Rejected · Suspended
Done
Transparency Card
Donation breakdown · 3-stat grid
Done
Impact Card
Penerima manfaat + stats
Done
Audit Timeline
Done · Pending · Future steps
Done
e-KTAM Card
Aktif · Nunggak · QR Mode
Done
Donation Card
Full · Compact list · Urgent
Done
Annotation Guide

Cara menganotasi layar untuk developer agar tidak ada ambiguitas saat implement. Setiap layar yang di-handoff harus memiliki minimal 4 jenis anotasi.

🎨 1. Color Annotation

  • Selalu tulis token name, bukan hex value
  • Contoh: --blue-500 bukan #1B77A6
  • Untuk opacity: --ink-0 / 50%
  • Background overlay: --ink-0 / 40%

📐 2. Spacing Annotation

  • Gunakan token: sp-4 (16px)
  • Padding: tulis semua sisi p: sp-4 sp-6
  • Gap antar elemen: gap: sp-2
  • Edge case: tulis nilai px jika tidak ada token yang sesuai

📝 3. Copy Annotation

  • Tulis copy key dari Copy Deck: quran.impact
  • Dynamic copy: iuran.success: "{{month}} selesai"
  • Tandai copy yang berubah per segmen user
  • Tandai copy yang berubah per state (empty/error)

⚡ 4. Interaction Annotation

  • Tap → ke layar mana (tulis screen ID: P-07)
  • Scroll behavior (jika ada sticky element)
  • Animation type (bridge A = slide in from bottom)
  • State change (tap toggle → langsung update, tidak ada loading)

🔢 5. State Annotation

  • Tandai semua 6 state: loading / empty / error / success / disabled / offline
  • Error message text harus match Voice Guide
  • Loading state: skeleton atau spinner (pilih sesuai DS)
  • Empty state: perlu icon + title + desc + CTA

📏 6. Touch Target Annotation

  • Minimum 44×44px untuk semua tappable element
  • Tandai jika visual element lebih kecil dari touch area
  • FAB: 56px visual, 64px touch area
  • Icon button: 24px visual, 44×44px tap area (GestureDetector)
Brand Do/Don't

Rules cepat untuk decision harian. Bila ragu, kembali ke Brand Strategy dan Voice & Tone Guide yang lengkap.

§1Visual

Do ✓
  • Gunakan Inter untuk semua UI text
  • Newsreader hanya untuk Pesan Hari Ini, splash tagline, manifesto
  • FAB selalu amber di semua halaman utama
  • Verification badge HARUS tampil di semua campaign donasi
  • Background: --paper-0, --paper-1, --paper-2 saja
  • Gambar: foto nyata (orang, aktivitas) — bukan stock ilustrasi
Don't ✕
  • Gradient background yang agresif
  • Warna yang tidak ada di token (hardcode hex)
  • FAB diubah warna atau fungsinya
  • Ornamen Islam berat (arabesque, geometric heavy)
  • Gambar stock mosque yang generic
  • Drop shadow yang berlebihan (maksimal EL-2 untuk card)

§2Copy

Do ✓
  • Button: Verb + object + angka: "Bayar Iuran Rp 25.000"
  • Error: Apa yang salah + langkah selanjutnya
  • Pain → Insight → Guidance → Outcome formula
  • "Pembayaran Bertahap" untuk cicilan qurban
  • "Konsistensi-mu hari ke-X" untuk streak
Don't ✕
  • "Yuk gas" / "Segera!!!" / emoji berlebihan
  • "Paylater" untuk konteks ibadah
  • "Error 500" atau pesan teknis langsung ke user
  • "Selamat! 🎉🎉" untuk payment success
  • "Oops!" / "Maaf..." untuk empty/error states

§3Trust (wajib untuk semua screen donasi/transaksi)

5 pertanyaan trust yang harus dijawab di setiap screen transaksi:
1. Siapa yang bertanggung jawab? → nama lembaga + verification badge
2. Apakah sudah diverifikasi? → badge status
3. Bisakah ditelusuri? → audit timeline / tracking status
4. Apakah transparan? → breakdown alokasi dana
5. Apa dampak yang tercipta? → impact card / foto distribusi
Figma → Flutter Notes

Hal-hal yang perlu diperhatikan saat menerjemahkan desain Figma ke Flutter. Ini adalah "hilang dalam translasi" yang paling sering terjadi.

§1Yang berbeda antara Figma dan Flutter

AspekDi FigmaDi FlutterCatatan
Font renderingAntialiased, subpixelSedikit berbeda per platformInter cocok di keduanya — minimal diff
ShadowDrop shadow langsungBoxShadow di BoxDecorationGunakan nilai dari EL-1 sampai EL-4
Border radiusCorner radius per cornerBorderRadius.circular()Gunakan nilai token --r-s, --r-m dll
Auto layoutHug / Fill / FixedRow/Column + Expanded/FlexibleFill = Expanded, Hug = intrinsic size
Overflow textAuto / Clip / Scrolloverflow: TextOverflow.ellipsisSelalu set maxLines di list items
GradientLinear gradient angleLinearGradient(begin, end, colors)Convert angle ke alignment
Image placeholderRectangle + iconCachedNetworkImage + placeholder widgetGunakan skeleton saat loading

§2Touch target rule

Penting: Semua tappable element harus minimum 44×44px. Di Flutter, gunakan InkWell atau GestureDetector dengan behavior: HitTestBehavior.opaque dan set constraints: BoxConstraints(minWidth: 44, minHeight: 44) jika visual element lebih kecil.
Developer Getting Started

Semua yang diperlukan untuk memulai implementasi MASA Flutter app — dari setup hingga arsitektur folder.

§1Prerequsites

Flutter SDK ≥3.10 (untuk NavigationBar Material 3 + SearchBar)
Verified working: Flutter 3.19 · Dart 3.3
Firebase project setup: Analytics + Crashlytics + Auth + Firestore
google-services.json untuk Android · GoogleService-Info.plist untuk iOS
Fonts Inter + JetBrains Mono dari Google Fonts
pubspec.yaml: google_fonts: ^6.1.0 ATAU embed font assets langsung
Packages wajib: cached_network_image · dio · flutter_riverpod (atau bloc) · go_router · shimmer
Tambahkan ke pubspec.yaml sebelum mulai implement komponen

§2Folder structure yang direkomendasikan

// lib/ folder structure lib/ ├── core/ │ ├── theme/ // masa_theme.dart (ThemeData) │ ├── tokens/ // colors.dart, typography.dart, spacing.dart │ ├── router/ // app_router.dart (GoRouter) │ └── analytics/ // masa_analytics.dart (Firebase events) ├── shared/ │ ├── widgets/ // semua reusable widgets dari DS v2 │ │ ├── buttons/ // masa_button.dart, masa_fab.dart │ │ ├── cards/ // masa_card.dart, ktam_card.dart, donation_card.dart │ │ ├── trust/ // verification_badge.dart, transparency_card.dart │ │ ├── feedback/ // masa_toast.dart, masa_dialog.dart │ │ └── states/ // empty_state.dart, skeleton.dart, error_state.dart │ └── models/ // shared data models ├── features/ │ ├── home/ // beranda (3 varian segmen) │ ├── onboarding/ // splash + thesis + segment + permission │ ├── quran/ // reader + tafsir + bookmark + bridge_b │ ├── prayer/ // jadwal + notif + bridge_a │ ├── sedekah_subuh/ // fab entry + setup + recurring │ ├── donation/ // lazismu + zakat + qurban │ ├── ktam/ // e-ktam + iuran + ranting │ ├── content/ // berita + video + event + chathpt │ └── profile/ // profil + settings + notif └── main.dart
Flutter ThemeData

ThemeData lengkap siap paste. Implement di lib/core/theme/masa_theme.dart.

// lib/core/theme/masa_theme.dart import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; class MasaColors { // Brand primary static const blue500 = Color(0xFF1B77A6); static const blue700 = Color(0xFF005E8C); static const blue50 = Color(0xFFEAF3F9); static const blue100 = Color(0xFFCFE3EF); // Accent amber static const amber600 = Color(0xFFD97224); // FAB Sedekah static const amber100 = Color(0xFFFFE5CC); static const amber50 = Color(0xFFFFF8ED); // Trust green static const green500 = Color(0xFF2D6A4F); // success, habit, verified static const green700 = Color(0xFF1B4332); static const green100 = Color(0xFFD0EBDA); // Authority gold static const gold600 = Color(0xFFB8924D); // "by LabMu", kuitansi static const gold100 = Color(0xFFF0E4C8); static const gold50 = Color(0xFFFBF4E6); // Error static const error700 = Color(0xFF8E2A2A); static const error100 = Color(0xFFFCE4E4); // Ink (dark text scale) static const ink0 = Color(0xFF14110E); // primary text static const ink2 = Color(0xFF3A332B); // body text static const ink3 = Color(0xFF6E665B); // subtitle static const ink4 = Color(0xFF9A9286); // caption // Paper (background scale) static const paper0 = Color(0xFFFFFCF5); // card surface static const paper1 = Color(0xFFFBF8F2); // app background static const paper2 = Color(0xFFF4EFE4); // section background static const paper3 = Color(0xFFEAE2D0); // border, divider } class MasaSpacing { static const double sp1 = 4; static const double sp2 = 8; static const double sp3 = 12; static const double sp4 = 16; static const double sp5 = 20; static const double sp6 = 24; static const double sp8 = 32; static const double sp10 = 40; static const double sp12 = 48; static const double sp16 = 64; } class MasaRadius { static const xs = Radius.circular(4); static const s = Radius.circular(8); static const m = Radius.circular(12); static const l = Radius.circular(16); static const xl = Radius.circular(24); static BorderRadius get rXS => BorderRadius.circular(4); static BorderRadius get rS => BorderRadius.circular(8); static BorderRadius get rM => BorderRadius.circular(12); static BorderRadius get rL => BorderRadius.circular(16); static BorderRadius get rXL => BorderRadius.circular(24); static BorderRadius get rFull => BorderRadius.circular(9999); } final masaTheme = ThemeData( useMaterial3: true, colorScheme: ColorScheme( brightness: Brightness.light, primary: MasaColors.blue500, onPrimary: Colors.white, secondary: MasaColors.amber600, onSecondary: Colors.white, tertiary: MasaColors.green500, onTertiary: Colors.white, surface: MasaColors.paper0, onSurface: MasaColors.ink0, error: MasaColors.error700, onError: Colors.white, surfaceVariant: MasaColors.paper2, outline: MasaColors.paper3, ), scaffoldBackgroundColor: MasaColors.paper1, textTheme: GoogleFonts.interTextTheme().copyWith( displayLarge: GoogleFonts.inter(fontSize: 52, fontWeight: FontWeight.w800, letterSpacing: -1.66), headlineLarge: GoogleFonts.inter(fontSize: 28, fontWeight: FontWeight.w700, letterSpacing: -0.5), headlineMedium:GoogleFonts.inter(fontSize: 22, fontWeight: FontWeight.w700, letterSpacing: -0.3), titleLarge: GoogleFonts.inter(fontSize: 17, fontWeight: FontWeight.w700), bodyLarge: GoogleFonts.inter(fontSize: 16, height: 1.6), bodyMedium: GoogleFonts.inter(fontSize: 14, height: 1.6), bodySmall: GoogleFonts.inter(fontSize: 12, height: 1.5, color: MasaColors.ink3), labelLarge: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.w600), labelSmall: GoogleFonts.inter(fontSize: 11, fontWeight: FontWeight.w600, letterSpacing: 0.5), ), elevatedButtonTheme: ElevatedButtonThemeData( style: ElevatedButton.styleFrom( minimumSize: const Size(0, 44), shape: const StadiumBorder(), textStyle: GoogleFonts.inter(fontWeight: FontWeight.w600, fontSize: 14), ), ), inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: Colors.white, border: OutlineInputBorder( borderRadius: MasaRadius.rS, borderSide: const BorderSide(color: MasaColors.paper3), ), focusedBorder: OutlineInputBorder( borderRadius: MasaRadius.rS, borderSide: const BorderSide(color: MasaColors.blue500, width: 1.5), ), errorBorder: OutlineInputBorder( borderRadius: MasaRadius.rS, borderSide: const BorderSide(color: MasaColors.error700), ), contentPadding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), ), cardTheme: CardTheme( elevation: 0, shape: RoundedRectangleBorder( borderRadius: MasaRadius.rM, side: const BorderSide(color: MasaColors.paper3), ), color: MasaColors.paper0, margin: EdgeInsets.zero, ), navigationBarTheme: NavigationBarThemeData( backgroundColor: MasaColors.paper0, indicatorColor: MasaColors.ink0, labelTextStyle: MaterialStateProperty.all( GoogleFonts.inter(fontSize: 10, fontWeight: FontWeight.w500), ), ), dividerTheme: const DividerThemeData( color: MasaColors.paper3, thickness: 1, space: 0, ), );
Widget → Component Map

Mapping setiap komponen di Design System v2 ke Flutter widget. Lengkap dengan package yang dibutuhkan.

DS v2 ComponentFlutter WidgetKey PropsPackage
Primary ButtonElevatedButton / FilledButtonminimumSize: Size(0,44), shape: StadiumBordermaterial
Ghost ButtonOutlinedButtonside: BorderSide(color: paper3)material
Text ButtonTextButtonpadding: EdgeInsets.zero untuk link stylematerial
Slide to ConfirmCustom widgetGestureDetector + AnimatedPositioned + hapticcustom
FAB SedekahFloatingActionButtonbackgroundColor: amber600, shape: CircleBordermaterial
Text FieldTextFormFieldvalidator, obscureText, inputFormattersmaterial
Search FieldSearchBar (Flutter 3.10+)leading: Icon(Icons.search_rounded)material3
OTP Inputpinput packagelength: 6, defaultPinThemepinput: ^5.0
ToggleSwitchactiveColor: blue500, trackColormaterial
CheckboxCheckboxactiveColor: blue700, shape: RoundedRectangleBordermaterial
RadioRadioListTileactiveColor: blue700material
Bottom NavigationNavigationBar (M3)destinations: [], selectedIndex, animationDurationmaterial3
Top App BarAppBar / SliverAppBarcenterTitle: true, surfaceTintColor: transparentmaterial
CardCard atau Container + BoxDecorationelevation, shape: RoundedRectangleBordermaterial
Bottom SheetshowModalBottomSheet()isScrollControlled: true, shape: RoundedRectangleBorder(xl radius)material
DialogAlertDialogshape: RoundedRectangleBorder(rM), actionsAlignment: endmaterial
Toast / SnackbarScaffoldMessenger.showSnackBar()behavior: SnackBarBehavior.floating, margin, shapematerial
Skeleton LoaderShimmerShimmer.fromColors(baseColor, highlightColor, child)shimmer: ^3.0
Empty StateCustom widgetColumn(icon, title, desc, CTA)custom
AvatarCircleAvatarradius: 12/16/20/26/32, backgroundColor, backgroundImagematerial
BadgeBadge (Flutter 3.7+)label: Text, backgroundColor, alignmentmaterial3
Progress BarLinearProgressIndicatorvalue: 0.0-1.0, color, backgroundColor, minHeight: 6material
TabsTabBar + TabBarViewisScrollable, labelColor: blue500, indicator: UnderlineTabIndicatormaterial
Chip / FilterFilterChip / ChoiceChipselected, onSelected, backgroundColor, selectedColormaterial
ImageCachedNetworkImageplaceholder: shimmer widget, errorWidget: error statecached_network_image
e-KTAM CardCustom widgetGradient container + status badge + QR mode togglecustom
Verification BadgeCustom widgetstatus enum + color mappingcustom
Transparency CardCustom widget3-stat grid + organization identitycustom
Donation CardCustom widgetCachedNetworkImage + LinearProgressIndicator + CTAcustom
API Contract

Semua endpoint yang dibutuhkan Flutter app dari Laravel backend. Diurutkan berdasarkan wave implementasi. Base URL: https://api.masa.muhammadiyah.or.id/v1

§0Authentication

EndpointMethodRequest BodyResponseWave
/auth/loginPOSTphone/email + passwordaccess_token, user, segmentW0
/auth/registerPOSTname, phone, email, passworduser_id, otp_sentW0
/auth/otp/verifyPOSTphone, otp_codeaccess_token, userW0
/auth/otp/resendPOSTphoneotp_sent, expires_inW0
/auth/forgot-passwordPOSTphone/emailreset_token_sentW0
/auth/reset-passwordPOSTtoken, new_passwordsuccessW0
/auth/logoutPOSTsuccessW0

§1User + Onboarding

EndpointMethodRequestResponseWave
/user/profileGETname, nbm, segment, ranting, ktam_statusW1
/user/profilePUTname, photo_urlupdated userW1
/user/segmentPUTsegment (kader/muslim/habit)success, new_home_configW1
/user/notification-settingsGETsettings per categoryW0
/user/notification-settingsPUTcategory, enabledsuccessW0
/user/quran-positionGETsurah_id, ayat_id, juzW2
/user/quran-positionPUTsurah_id, ayat_idsuccessW2

§2Ibadah + Habit

EndpointMethodRequestResponseWave
/prayer-timesGET?city=yogyakarta&date=2026-06-12subuh, dzuhur, ashar, maghrib, isya, imsakW2
/quran/surahsGETlist surah (id, name_ar, name_id, ayat_count)W2
/quran/surah/:idGETayat list (ar, latin, translation)W2
/quran/tafsir/:surah/:ayatGETtafsir_tarjih text, source_refW2
/duasGET?category=pagi&time=subuhdoa list (ar, latin, translation, audio_url)W2
/habit/streakGETstreak_quran, streak_sedekah, streak_salatW2

§3Donasi + Transaksi

EndpointMethodRequestResponseWave
/donations/campaignsGET?category=&page=campaigns list + paginationW3
/donations/campaigns/:idGETdetail + allocation_breakdown + organizerW3
/donations/createPOSTcampaign_id, amount, payment_methodpayment_url, transaction_idW3
/donations/:id/receiptGETreceipt_pdf_url, receipt_numberW3
/sedekah-subuh/setupPOSTamount, program, payment_method, is_recurringsubscription_idW3
/sedekah-subuh/cancelPOSTsubscription_idsuccessW3
/zakat/calculatePOSTtype, income/assetsnisab_met, amount_due, fatwa_refW3
/iuran/payPOSTmonth, payment_methodva_number | qris_url | errorW0
/iuran/historyGETlist per month + statusW0

§4KTAM + Keanggotaan

EndpointMethodRequestResponseWave
/ktam/statusGETstatus, nbm, valid_until, qr_tokenW0
/ktam/verify/:qr_tokenGETmember name, nbm, status, rantingW5
/ranting/infoGETname, pengurus, member_count, events, donationsW4
/qurban/ordersPOSTtype, location, payment_schemeorder_id, payment_scheduleW4
/qurban/orders/:id/statusGETstage, photo_urls, certificate_urlW4

§5Konten

EndpointMethodRequestResponseWave
/newsGET?category=&page=articles list (dari muhammadiyah.or.id)W4
/news/:idGETfull article contentW4
/videosGET?category=YouTube video list (dari channel Muhammadiyah)W4
/eventsGET?ranting=&date=events list per rantingW4
/events/:id/registerPOSTticket_id, qr_tokenW4
/chathpt/queryPOSTquery_textanswer, source_ref, suggested_actionW5
/home/daily-messageGETtext, source, categoryW1
Response format standar semua endpoint:
{"status": "success|error", "data": {...}, "message": "...", "errors": {...}}
Error response: {"status": "error", "code": "VA_GENERATION_FAILED", "user_message": "...", "retryable": true}
Wave Implementation Plan

Urutan implementasi wajib diikuti. Bug fix dulu — tidak boleh mulai feature baru sebelum Wave 0 selesai.

Wave 0
Bug Kill — Iuran VA · Notifikasi · NBM Sync
Semua ⬛ CRIT di AC harus pass sebelum lanjut. Target: 2 minggu.
W0-01 · W0-02 · W0-03
Wave 1
Activation — Onboarding + Beranda
3-segment onboarding + homepage adaptif. Target activation ≥70%.
W1-01 · W1-02
Wave 2
Engagement — Habit Loop (Sholat + Qur'an + Doa)
Bridge A + Bridge B. Dead-end → connected journey.
W2-01 · W2-02 · W2-03
Wave 3
Trust + Retention — Sedekah Subuh · LazisMu · Zakat
Daily habit anchor + transparency trust system.
W3-01 · W3-02 · W3-03
Wave 4
Expand — Qurban · Ranting · Berita · Video · Event
Ecosystem features. Musiman + community.
W4-01 → W4-05
Wave 5
Polish — KTAM · Kiblat · KHGT · ChatHPT · Profil
Reskin + minor enhance. Tidak ada new arch.
W5-01 → W5-05

§2Component Sprint (sebelum Wave 0)

Rekomendasi: Sebelum Wave 0 dimulai, lakukan 1 sprint "Component Library Sprint" — implement semua komponen reusable dari DS v2 sebagai widget terpisah. Ini menghemat 30-40% waktu sprint berikutnya karena setiap screen tinggal compose dari komponen yang sudah jadi.
masa_button.dart — 8 variants + loading + disabled state
Dipakai di: semua 60+ screen
masa_text_field.dart — 6 states + label + helper
Dipakai di: Auth (4 screen) + Profil + Iuran + Zakat
masa_card.dart — 6 variants (standard/elevated/outlined/accent-blue/amber/green/gold)
Dipakai di: semua feature screens
masa_bottom_nav.dart — 4 tabs + FAB amber
Dipakai di: semua root screens
verification_badge.dart — 4 states
Dipakai di: semua donasi/event/org screens
skeleton_loader.dart — text/title/image/avatar variants
Dipakai di: semua network-dependent screens
empty_state.dart — 6 jenis empty state
Dipakai di: semua list screens
masa_toast.dart — 4 variants via ScaffoldMessenger
Dipakai di: semua payment/action screens
State Management Guide

Pattern state management yang direkomendasikan untuk MASA. Menggunakan Riverpod (atau BLoC jika tim sudah familiar).

§1Async State Pattern

// lib/shared/models/async_value.dart // Setiap network call menggunakan pattern ini // Provider example: lib/features/donation/providers/campaigns_provider.dart final campaignsProvider = AsyncNotifierProvider<CampaignsNotifier, List<Campaign>>( CampaignsNotifier.new, ); class CampaignsNotifier extends AsyncNotifier<List<Campaign>> { @override Future<List<Campaign>> build() async { return await ref.read(donationRepositoryProvider).getCampaigns(); } } // Widget usage — selalu handle 3 state: ref.watch(campaignsProvider).when( loading: () => CampaignListSkeleton(), // loading state error: (err, st) => MasaErrorState( // error state message: ApiError.fromException(err).userMessage, onRetry: () => ref.invalidate(campaignsProvider), ), data: (campaigns) => campaigns.isEmpty // empty + data state ? MasaEmptyState(type: EmptyStateType.donation) : CampaignList(campaigns: campaigns), );

§2User Segment State

// lib/features/home/providers/user_segment_provider.dart enum UserSegment { kader, muslim, habit } final userSegmentProvider = StateNotifierProvider<UserSegmentNotifier, UserSegment>( (ref) => UserSegmentNotifier(), ); // Di homepage — render varian yang tepat: switch (ref.watch(userSegmentProvider)) { case UserSegment.kader: return const KaderHomepage(); case UserSegment.muslim: return const MuslimHomepage(); case UserSegment.habit: return const HabitHomepage(); }
Catatan penting:
(1) Segment disimpan di SharedPreferences + server (PUT /user/segment) — harus sync keduanya.
(2) Saat onboarding, segment baru tersedia setelah user tap pilihan — langsung set ke provider dan SharedPreferences sebelum navigasi ke homepage.
(3) User bisa ubah segment di Settings — invalidate userSegmentProvider + PUT /user/segment + refresh homepage.

Akhir dokumen · Designer + Developer Handoff · MASA by LabMu · 12 Juni 2026

Index Handoff package complete · 6/6 pipeline ✓