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.
§0Ekosistem dokumen
Semua dokumen di bawah harus dibaca sebelum mulai. Urutan membaca: dari atas ke bawah.
| # | Dokumen | Siapa yang baca | Kapan dibaca |
|---|---|---|---|
| 1 | Brand Strategy 02-brand/ | Designer + PM | Sebelum mulai desain apapun |
| 2 | Voice & Tone Guide 02-brand/ | Designer + Dev (copy) | Sebelum menulis copy di screen |
| 3 | Design System v2 03-design-system/ | Designer + Dev | Sebelum implement komponen apapun |
| 4 | Feature Flows & Wireframe 04-ia-wireframe/ | Designer + Dev | Untuk memahami flow setiap fitur |
| 5 | MASA E2E Complete 05-hifi/ | Designer + Dev | Referensi visual utama per layar |
| 6 | Copy Deck 06-handoff/ | Dev (backend + frontend) | Saat implement string resources |
| 7 | Analytics Event Spec 06-handoff/ | Dev (Firebase) | Saat implement tiap screen |
| 8 | Acceptance Criteria 06-handoff/ | Dev + QA + PM | Saat sprint planning + QA |
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 Name | Value | Usage |
|---|---|---|
| --blue-500 | #1B77A6 | Primary action, active nav, info state, trust primary |
| --blue-700 | #005E8C | Button hover, deep blue text, payment CTA |
| --blue-50 | #EAF3F9 | NOW zone background, info card bg, active chip bg |
| --amber-600 | #D97224 | FAB Sedekah, warm CTA, Sedekah Subuh, campaign banner |
| --amber-100 | #FFE5CC | Sedekah card bg, amber accent bg |
| --green-500 | #2D6A4F | Success state, habit tracker, impact, verified badge, LazisMu |
| --green-700 | #1B4332 | Deep green text, verified hover |
| --green-100 | #D0EBDA | Success bg, habit card bg, verified badge bg |
| --gold-600 | #B8924D | Authority badge, LazisMu trust, "by LabMu", kuitansi frame |
| --gold-100 | #F0E4C8 | Gold card bg, Pesan Hari Ini bg, authority surface |
| --err-700 | #8E2A2A | Error state, destructive action, P0 bug indicator |
| --err-100 | #FCE4E4 | Error card bg, danger surface |
| --ink-0 | #14110E | Primary text, headlines, primary button bg |
| --ink-2 | #3A332B | Body text, secondary headline |
| --ink-3 | #6E665B | Subtitle, placeholder, muted text |
| --ink-4 | #9A9286 | Caption, disabled text, overline |
| --paper-0 | #FFFCF5 | Card surface, modal background |
| --paper-1 | #FBF8F2 | App background (root) |
| --paper-2 | #F4EFE4 | Section background, secondary surface |
| --line | #E5DDCD | Dividers, card borders, input borders |
§2Typography Tokens
| Style Name | Font / Size / Weight | Usage |
|---|---|---|
| Display L | Inter 52px / W800 / LS -3.2% | Splash only |
| Display M | Inter 40px / W700 / LS -2.5% | Section hero title |
| H1 Page | Inter 28px / W700 / LS -1.8% | Screen title (AppBar large) |
| H2 Section | Inter 22px / W700 / LS -1.4% | Card hero, section header |
| H3 Card | Inter 17px / W700 / LS -1.0% | Card title, list item title |
| Body L | Inter 16px / W400 / LH 1.6 | Article body, description |
| Body M | Inter 14px / W400 / LH 1.6 | Standard body, form labels |
| Body S | Inter 12px / W400 / LH 1.5 | Caption, timestamp, meta |
| Label L | Inter 14px / W600 / LS -0.5% | Button text, CTA |
| Label S | Inter 11px / W600 / LS +1% | Badge, tag, status chip |
| Overline | JetBrains Mono 10px / W600 / LS +10% | Section label, card tag, category |
| Hero Serif | Newsreader Italic 22px+ / W400-500 | Pesan Hari Ini, manifesto, tagline ONLY |
§3Spacing + Radius Tokens
| Spacing Token | Value | Usage |
|---|---|---|
| --sp-1 | 4px | Icon margin, tight gap |
| --sp-2 | 8px | Small gap, chip padding |
| --sp-3 | 12px | Medium gap |
| --sp-4 | 16px | Card padding, standard gap |
| --sp-6 | 24px | Section gap, content spacing |
| --sp-8 | 32px | Section padding, large gap |
| --sp-12 | 48px | Page padding, hero spacing |
| Radius Token | Value | Usage |
|---|---|---|
| --r-xs | 4px | Input, small chip, badge |
| --r-s | 8px | Card, button, dropdown |
| --r-m | 12px | Modal, bottom sheet |
| --r-l | 16px | Hero card, banner, FAB bg |
| --r-xl | 24px | Bottom sheet radius-top |
| --r-full | 9999px | Pill chip, FAB, rounded button |
35 kategori komponen. Semua sudah didefinisikan di Design System v2. Status: semua Done untuk Sprint 1.
§1Foundation
§2Navigation
§3Actions
§4Inputs
§5Feedback
§6Trust System (MASA-specific)
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-500bukan#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)
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)
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
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
| Aspek | Di Figma | Di Flutter | Catatan |
|---|---|---|---|
| Font rendering | Antialiased, subpixel | Sedikit berbeda per platform | Inter cocok di keduanya — minimal diff |
| Shadow | Drop shadow langsung | BoxShadow di BoxDecoration | Gunakan nilai dari EL-1 sampai EL-4 |
| Border radius | Corner radius per corner | BorderRadius.circular() | Gunakan nilai token --r-s, --r-m dll |
| Auto layout | Hug / Fill / Fixed | Row/Column + Expanded/Flexible | Fill = Expanded, Hug = intrinsic size |
| Overflow text | Auto / Clip / Scroll | overflow: TextOverflow.ellipsis | Selalu set maxLines di list items |
| Gradient | Linear gradient angle | LinearGradient(begin, end, colors) | Convert angle ke alignment |
| Image placeholder | Rectangle + icon | CachedNetworkImage + placeholder widget | Gunakan skeleton saat loading |
§2Touch target rule
InkWell atau GestureDetector dengan behavior: HitTestBehavior.opaque dan set constraints: BoxConstraints(minWidth: 44, minHeight: 44) jika visual element lebih kecil.Semua yang diperlukan untuk memulai implementasi MASA Flutter app — dari setup hingga arsitektur folder.
§1Prerequsites
§2Folder structure yang direkomendasikan
ThemeData lengkap siap paste. Implement di lib/core/theme/masa_theme.dart.
Mapping setiap komponen di Design System v2 ke Flutter widget. Lengkap dengan package yang dibutuhkan.
| DS v2 Component | Flutter Widget | Key Props | Package |
|---|---|---|---|
| Primary Button | ElevatedButton / FilledButton | minimumSize: Size(0,44), shape: StadiumBorder | material |
| Ghost Button | OutlinedButton | side: BorderSide(color: paper3) | material |
| Text Button | TextButton | padding: EdgeInsets.zero untuk link style | material |
| Slide to Confirm | Custom widget | GestureDetector + AnimatedPositioned + haptic | custom |
| FAB Sedekah | FloatingActionButton | backgroundColor: amber600, shape: CircleBorder | material |
| Text Field | TextFormField | validator, obscureText, inputFormatters | material |
| Search Field | SearchBar (Flutter 3.10+) | leading: Icon(Icons.search_rounded) | material3 |
| OTP Input | pinput package | length: 6, defaultPinTheme | pinput: ^5.0 |
| Toggle | Switch | activeColor: blue500, trackColor | material |
| Checkbox | Checkbox | activeColor: blue700, shape: RoundedRectangleBorder | material |
| Radio | RadioListTile | activeColor: blue700 | material |
| Bottom Navigation | NavigationBar (M3) | destinations: [], selectedIndex, animationDuration | material3 |
| Top App Bar | AppBar / SliverAppBar | centerTitle: true, surfaceTintColor: transparent | material |
| Card | Card atau Container + BoxDecoration | elevation, shape: RoundedRectangleBorder | material |
| Bottom Sheet | showModalBottomSheet() | isScrollControlled: true, shape: RoundedRectangleBorder(xl radius) | material |
| Dialog | AlertDialog | shape: RoundedRectangleBorder(rM), actionsAlignment: end | material |
| Toast / Snackbar | ScaffoldMessenger.showSnackBar() | behavior: SnackBarBehavior.floating, margin, shape | material |
| Skeleton Loader | Shimmer | Shimmer.fromColors(baseColor, highlightColor, child) | shimmer: ^3.0 |
| Empty State | Custom widget | Column(icon, title, desc, CTA) | custom |
| Avatar | CircleAvatar | radius: 12/16/20/26/32, backgroundColor, backgroundImage | material |
| Badge | Badge (Flutter 3.7+) | label: Text, backgroundColor, alignment | material3 |
| Progress Bar | LinearProgressIndicator | value: 0.0-1.0, color, backgroundColor, minHeight: 6 | material |
| Tabs | TabBar + TabBarView | isScrollable, labelColor: blue500, indicator: UnderlineTabIndicator | material |
| Chip / Filter | FilterChip / ChoiceChip | selected, onSelected, backgroundColor, selectedColor | material |
| Image | CachedNetworkImage | placeholder: shimmer widget, errorWidget: error state | cached_network_image |
| e-KTAM Card | Custom widget | Gradient container + status badge + QR mode toggle | custom |
| Verification Badge | Custom widget | status enum + color mapping | custom |
| Transparency Card | Custom widget | 3-stat grid + organization identity | custom |
| Donation Card | Custom widget | CachedNetworkImage + LinearProgressIndicator + CTA | custom |
Semua endpoint yang dibutuhkan Flutter app dari Laravel backend. Diurutkan berdasarkan wave implementasi. Base URL: https://api.masa.muhammadiyah.or.id/v1
§0Authentication
| Endpoint | Method | Request Body | Response | Wave |
|---|---|---|---|---|
| /auth/login | POST | phone/email + password | access_token, user, segment | W0 |
| /auth/register | POST | name, phone, email, password | user_id, otp_sent | W0 |
| /auth/otp/verify | POST | phone, otp_code | access_token, user | W0 |
| /auth/otp/resend | POST | phone | otp_sent, expires_in | W0 |
| /auth/forgot-password | POST | phone/email | reset_token_sent | W0 |
| /auth/reset-password | POST | token, new_password | success | W0 |
| /auth/logout | POST | — | success | W0 |
§1User + Onboarding
| Endpoint | Method | Request | Response | Wave |
|---|---|---|---|---|
| /user/profile | GET | — | name, nbm, segment, ranting, ktam_status | W1 |
| /user/profile | PUT | name, photo_url | updated user | W1 |
| /user/segment | PUT | segment (kader/muslim/habit) | success, new_home_config | W1 |
| /user/notification-settings | GET | — | settings per category | W0 |
| /user/notification-settings | PUT | category, enabled | success | W0 |
| /user/quran-position | GET | — | surah_id, ayat_id, juz | W2 |
| /user/quran-position | PUT | surah_id, ayat_id | success | W2 |
§2Ibadah + Habit
| Endpoint | Method | Request | Response | Wave |
|---|---|---|---|---|
| /prayer-times | GET | ?city=yogyakarta&date=2026-06-12 | subuh, dzuhur, ashar, maghrib, isya, imsak | W2 |
| /quran/surahs | GET | — | list surah (id, name_ar, name_id, ayat_count) | W2 |
| /quran/surah/:id | GET | — | ayat list (ar, latin, translation) | W2 |
| /quran/tafsir/:surah/:ayat | GET | — | tafsir_tarjih text, source_ref | W2 |
| /duas | GET | ?category=pagi&time=subuh | doa list (ar, latin, translation, audio_url) | W2 |
| /habit/streak | GET | — | streak_quran, streak_sedekah, streak_salat | W2 |
§3Donasi + Transaksi
| Endpoint | Method | Request | Response | Wave |
|---|---|---|---|---|
| /donations/campaigns | GET | ?category=&page= | campaigns list + pagination | W3 |
| /donations/campaigns/:id | GET | — | detail + allocation_breakdown + organizer | W3 |
| /donations/create | POST | campaign_id, amount, payment_method | payment_url, transaction_id | W3 |
| /donations/:id/receipt | GET | — | receipt_pdf_url, receipt_number | W3 |
| /sedekah-subuh/setup | POST | amount, program, payment_method, is_recurring | subscription_id | W3 |
| /sedekah-subuh/cancel | POST | subscription_id | success | W3 |
| /zakat/calculate | POST | type, income/assets | nisab_met, amount_due, fatwa_ref | W3 |
| /iuran/pay | POST | month, payment_method | va_number | qris_url | error | W0 |
| /iuran/history | GET | — | list per month + status | W0 |
§4KTAM + Keanggotaan
| Endpoint | Method | Request | Response | Wave |
|---|---|---|---|---|
| /ktam/status | GET | — | status, nbm, valid_until, qr_token | W0 |
| /ktam/verify/:qr_token | GET | — | member name, nbm, status, ranting | W5 |
| /ranting/info | GET | — | name, pengurus, member_count, events, donations | W4 |
| /qurban/orders | POST | type, location, payment_scheme | order_id, payment_schedule | W4 |
| /qurban/orders/:id/status | GET | — | stage, photo_urls, certificate_url | W4 |
§5Konten
| Endpoint | Method | Request | Response | Wave |
|---|---|---|---|---|
| /news | GET | ?category=&page= | articles list (dari muhammadiyah.or.id) | W4 |
| /news/:id | GET | — | full article content | W4 |
| /videos | GET | ?category= | YouTube video list (dari channel Muhammadiyah) | W4 |
| /events | GET | ?ranting=&date= | events list per ranting | W4 |
| /events/:id/register | POST | — | ticket_id, qr_token | W4 |
| /chathpt/query | POST | query_text | answer, source_ref, suggested_action | W5 |
| /home/daily-message | GET | — | text, source, category | W1 |
{"status": "success|error", "data": {...}, "message": "...", "errors": {...}}Error response:
{"status": "error", "code": "VA_GENERATION_FAILED", "user_message": "...", "retryable": true}Urutan implementasi wajib diikuti. Bug fix dulu — tidak boleh mulai feature baru sebelum Wave 0 selesai.
§2Component Sprint (sebelum Wave 0)
Pattern state management yang direkomendasikan untuk MASA. Menggunakan Riverpod (atau BLoC jika tim sudah familiar).
§1Async State Pattern
§2User Segment State
(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