Flutter, Laravel, GoLang, dan AI sebagai Pair Programmer (Part 1)

ilustrasi AI
Bagian 1

Flutter, Laravel, GoLang, dan AI sebagai Pair Programmer

Studi Kasus : Pembuatan Maintenance Management System

Membangun aplikasi dari nol bisa menjadi proses yang panjang dan melelahkan. Kami memilih pendekatan berbeda: menggunakan Claude Code sebagai AI pair-programming partner untuk mempercepat siklus development tanpa mengorbankan kualitas arsitektur.

Mengapa Flutter dan BLoC?

Pilihan teknologi bukan keputusan yang diambil secara sembarangan. Flutter dipilih karena beberapa alasan pragmatis:

  • Cross-platform — satu codebase untuk Android dan iOS. Tim teknisi di lapangan menggunakan berbagai macam perangkat, dan kami tidak ingin membangun dua aplikasi terpisah.
  • Performa native — Flutter mengompilasi ke kode native, bukan web view. Ini penting untuk pengalaman yang responsif, terutama saat membuka kamera dan mengupload foto di area dengan sinyal terbatas.
  • Widget system yang kaya — Material Design out-of-the-box, membuat kami bisa fokus ke logika bisnis alih-alih membangun komponen UI dari nol.

Untuk state management, kami memilih BLoC (Business Logic Component) karena memberikan pemisahan yang jelas antara UI dan logika bisnis, mudah di-test secara unit, dan menggunakan pattern event-driven yang predictable.

Layer Teknologi Fungsi
FrameworkFlutterUI cross-platform
State Managementflutter_blocBLoC pattern
HTTP ClientDioAPI calls + interceptors
Routinggo_routerDeclarative navigation
DIget_itService locator
Imageimage_pickerKamera & galeri
Testingbloc_test + mocktailUnit & widget testing

Clean Architecture: Fondasi yang Tidak Bisa Ditawar

Sejak awal, kami menerapkan Clean Architecture dengan tiga layer yang tegas. Ini bukan over-engineering — ini adalah investasi jangka panjang. Ketika API berubah, hanya data layer yang perlu dimodifikasi. Ketika UI di-redesign, domain layer tidak tersentuh. Ketika bisnis rule bertambah, presentation layer tetap bersih.

lib/ ├── app/ ── theme, router, DI, entry point ├── core/ ── constants, errors, network, utils ├── shared/widgets/ ── 11 reusable components └── features/ ├── auth/ │ ├── data/ ── models, datasources, repo impl │ ├── domain/ ── entities, repositories, usecases │ └── presentation/ ── bloc, pages, widgets ├── dashboard/ ── (same structure) ├── task/ ── (same structure) └── report/ ── (same structure)

Setiap feature module mengikuti pola yang sama: data → domain ← presentation. Domain layer menjadi pusat — murni Dart, tanpa dependency ke Flutter atau package pihak ketiga. Ini membuatnya sangat mudah di-test.

Claude Code sebagai Partner Development

Inilah bagian yang membedakan project ini dari pendekatan konvensional. Kami tidak hanya menggunakan AI untuk generate code potongan demi potongan. Kami merancang seluruh workflow development agar bisa dieksekusi oleh Claude Code secara sistematis.

Langkah 1: Menyiapkan Konteks Project

Sebelum satu baris kode Flutter pun ditulis, kami membuat file CLAUDE.md — sebuah dokumen yang berisi seluruh konteks project: tech stack, arsitektur, design system, konvensi bahasa (kode dalam bahasa Inggris, UI dalam bahasa Indonesia), dan business rules. File ini menjadi “otak” yang dibaca Claude Code sebelum mengeksekusi apapun.

maintenance-mobile/
├── CLAUDE.md                        # Project context
└── .claude/
    ├── context/
    │   └── api-spec.md              # API specification
    ├── rules/
    │   ├── 01-code-style.md         # Dart/Flutter conventions
    │   ├── 02-testing-conventions.md # Test patterns & coverage
    │   └── 03-security-requirements.md # Token, network, upload
    └── tasks/
        ├── 00-task-index.md         # Execution order
        ├── 01-project-setup.md      # Foundation
        ├── 02-shared-widgets.md     # Reusable components
        ├── 03-auth-feature.md       # Login flow
        ├── 04-dashboard-feature.md  # Home page
        ├── 05-task-list-feature.md  # Search, filter, sort
        ├── 06-task-detail-feature.md # Detail + actions
        ├── 07-report-form-feature.md # Report + photo upload
        └── 08-integration-polish.md # Wiring & polish

Langkah 2: Rules sebagai Guardrails

Tiga file rules berfungsi sebagai guardrails — memastikan Claude Code menghasilkan output yang konsisten, aman, dan bisa di-maintain:

📐 Code Style Guidelines

Naming conventions (PascalCase untuk BLoC events, camelCase untuk variabel), import ordering, dependency direction, BLoC patterns (event past-tense, state sealed class), dan aturan string externalization — semua label UI harus dari AppStrings, tidak boleh hardcoded.

🧪 Testing Conventions

Minimum coverage per layer (domain: 100%, BLoC: 95%, widget: 80%). Pattern AAA (Arrange-Act-Assert). Mocking dengan mocktail. Setiap BLoC harus di-test menggunakan blocTest untuk setiap event × state transition — termasuk edge cases seperti empty list dan network failure.

🔒 Security Requirements

Token JWT disimpan dengan flutter_secure_storage. Interceptor otomatis menangani 401 (redirect ke login). Validasi input di client-side sebelum dikirim ke API. Foto divalidasi MIME type dan ukuran (maks 5MB). Tidak ada data sensitif yang pernah muncul di log.

Langkah 3: Task Files — Blueprint untuk Eksekusi

Setiap task file bukan sekadar todo list. Ini adalah blueprint lengkap yang berisi: objective, API endpoints yang digunakan, entity dan model yang harus dibuat (termasuk contoh kode), BLoC events dan states, mockup UI dalam ASCII art, daftar unit test yang harus ditulis, dan acceptance criteria yang harus dipenuhi.

Dengan struktur ini, menjalankan satu task dengan Claude Code menjadi sangat straightforward:

claude "Read and execute .claude/tasks/03-auth-feature.md.
Follow rules in .claude/rules/ and reference CLAUDE.md.
After completing, run flutter analyze and flutter test."

Claude Code membaca task, memahami konteks dari CLAUDE.md, mengikuti aturan dari rules, dan menghasilkan seluruh feature — lengkap dengan test. Ini bukan magic — ini hasil dari persiapan konteks yang detail.

Anatomi Satu Feature: Task Detail

Mari kita bedah satu feature untuk melihat bagaimana semua elemen bekerja bersama. Task Detail adalah halaman yang menampilkan informasi lengkap sebuah tugas dengan action buttons yang berubah berdasarkan status.

API yang Digunakan

ActionMethodEndpoint
Lihat detailGET/tasks/:id
Ambil tugasPOST/tasks/:id/take
Update statusPATCH/tasks/:id/status
Kirim laporanPOST/reports
Upload fotoPOST/reports/:id/photos

Tiga Kondisi, Tiga Tampilan

Halaman detail tugas memiliki action button yang berubah sesuai status:

Status 1 Menunggu
Tombol “Ambil Tugas”
Status 2 Dikerjakan
“Tambah Laporan” + “Selesaikan”
Status 3 Selesai
Read-only, tanpa tombol

Setiap transisi status memiliki confirmation dialog — mencegah teknisi tidak sengaja menyelesaikan tugas yang belum benar-benar selesai. Dan setiap aksi memberi feedback berupa SnackBar dalam bahasa Indonesia: “Tugas berhasil diambil”, “Tugas berhasil diselesaikan”.

BLoC yang Mengorkestrasi

BLoC untuk fitur ini mengelola state yang cukup kompleks. Selain state standar (loading, success, error), ada state khusus untuk action loading — ketika teknisi menekan “Ambil Tugas”, UI tetap menampilkan detail task sambil menunjukkan loading indicator di tombol. Ini memberikan pengalaman yang mulus tanpa flash putih yang mengganggu.

Event: TaskTaken(taskId)
  → emit TaskActionLoading(detail, "Mengambil tugas...")
  → call POST /tasks/:id/take
  → re-fetch detail
  → emit TaskActionSuccess(updatedDetail, "Tugas berhasil diambil")
  
Event: TaskCompleted(taskId)
  → emit TaskActionLoading(detail, "Menyelesaikan tugas...")
  → call PATCH /tasks/:id/status {"status": "done"}
  → re-fetch detail
  → emit TaskActionSuccess(updatedDetail, "Tugas berhasil diselesaikan")

Reusable Widget Library

Sebelum membangun satu halaman pun, kami membangun library widget yang reusable. Ini investasi waktu di awal yang menghemat sangat banyak waktu di kemudian hari. Sebelas widget yang menjadi building blocks seluruh aplikasi:

Widget
AppButton
4 varian: primary, secondary, outline, danger. Support loading state.
Widget
AppTextField
Input dengan label, validasi, toggle password, error state.
Widget
StatusBadge
Badge warna otomatis: Menunggu, Sedang Dikerjakan, Selesai.
Widget
PriorityBadge
Menampilkan level prioritas dengan warna dari API.
Widget
TaskCard
Kartu tugas kompak: judul, status, prioritas, due date.
Widget
PhotoPickerWidget
Multi-photo picker dengan validasi ukuran dan tipe file.
Widget
SearchBarWidget
Input pencarian dengan debounce 300ms dan tombol clear.
Widget
EmptyStateWidget
Tampilan kosong: ikon, judul, subtitle — semuanya dalam bahasa Indonesia.

Setiap widget menerima data dan konfigurasi melalui constructor — tidak ada hardcoded value. Warna dari AppColors, teks dari AppStrings. Ini membuat widget bisa digunakan di konteks manapun tanpa modifikasi.

Dual-Language Convention

Salah satu keputusan desain yang menarik: kode ditulis dalam bahasa Inggris, tetapi semua yang dilihat pengguna dalam bahasa Indonesia. Ini bukan sekadar preferensi — ini best practice. Kode dalam bahasa Inggris membuatnya universal dan bisa di-maintain oleh developer manapun. UI dalam bahasa Indonesia membuatnya aksesibel bagi teknisi di lapangan.

// Code in English
class LoginSubmitted extends AuthEvent {
  final String email;
  final String password;
}
 
// Labels in Indonesian (from AppStrings)
class AppStrings {
  static const loginTitle = 'Masuk';
  static const emailRequired = 'Email wajib diisi';
  static const passwordMinLength = 'Kata sandi minimal 6 karakter';
  static const taskTakenSuccess = 'Tugas berhasil diambil';
}

Testing: Bukan Afterthought

Testing bukan sesuatu yang kami tambahkan di akhir. Setiap task file sudah mendefinisikan test apa saja yang harus ditulis — dari model serialization, repository success/failure paths, BLoC state transitions, hingga widget rendering.

100% Domain Layer Coverage
95% BLoC Coverage
90% Repository Coverage
80% Widget Coverage

Setiap BLoC di-test untuk setiap kombinasi event dan outcome: sukses, gagal, network error, empty data, dan edge cases. Menggunakan blocTest dari package bloc_test dan mocktail untuk mocking — tanpa exception.

Apa yang Kami Pelajari

Menggunakan AI sebagai pair-programming partner mengubah cara kami berpikir tentang development. Beberapa insight:

  1. Investasi terbesar ada di persiapan, bukan eksekusi. Membuat CLAUDE.md, rules, dan task files memakan waktu. Tapi begitu semua konteks siap, eksekusi menjadi jauh lebih cepat dan konsisten.
  2. AI bekerja paling baik dengan batasan yang jelas. Rules file bukan formalitas — ini yang membedakan output berkualitas dari spaghetti code. Tanpa guardrails, AI bisa menghasilkan kode yang “bekerja” tapi tidak bisa di-maintain.
  3. Task decomposition adalah skill yang underrated. Memecah project menjadi 8 task yang sequential dengan dependency yang jelas membuat seluruh pembangunan bisa dilakukan secara incremental — setiap task menghasilkan output yang bisa diverifikasi secara independen.
  4. API spec adalah kontrak. Ketika API spec berubah (dan itu terjadi di project ini), kami hanya perlu mengupdate context file dan task file yang terdampak — bukan menyusuri seluruh codebase.

Bagian 2

Admin Dashboard : CMS Untuk mengelola data user, teknisi, tugas dan laporan.


Maintenance Mobile App — Dibangun dengan Flutter, BLoC, dan Claude Code

Artikel ini mendokumentasikan proses nyata pembuatan aplikasi dari perencanaan hingga development.

Flutter BLoC Clean Architecture Claude Code Mobile Development Maintenance Indonesia

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *