# Mapping Class per Design Pattern — WalkGuide

> Dokumen ini memetakan setiap class dari **Class Diagram WalkGuide** ke design pattern yang menggunakannya, beserta peran class tersebut dalam pattern dan justifikasi pemilihannya.

---

## Daftar Isi

1. [Matriks Ringkasan](#1-matriks-ringkasan)
2. [Builder Pattern](#2-builder-pattern--creational)
3. [Singleton Pattern](#3-singleton-pattern--creational)
4. [Facade Pattern](#4-facade-pattern--structural)
5. [Repository / Proxy Pattern](#5-repository--proxy-pattern--structural)
6. [Observer Pattern](#6-observer-pattern--behavioral)
7. [Strategy Pattern](#7-strategy-pattern--behavioral)
8. [Chain of Responsibility Pattern](#8-chain-of-responsibility-pattern--behavioral)

---

## 1. Matriks Ringkasan

| Pattern | Kategori | Class Utama (dari Class Diagram) |
|---------|----------|----------------------------------|
| Builder | Creational | `User`, `AuthService`, `FcmService`, `AuthDataResponse` |
| Singleton | Creational | `TtsService`, `SttService`, `YoloDetector`, `WebSocketService`, `AgoraService`, `HapticService` |
| Facade | Structural | `VoiceCommandHandler`, `GuardianDashboardService`, `GuardianController`, `VoiceCommandConfig` |
| Repository (Proxy) | Structural | `WalkGuideRepositoryImpl`, `ActivityLogRepositoryImpl`, `LocationRepositoryImpl`, `ObstacleLogRepository`, `ActivityLogRepository` |
| Observer | Behavioral | `WalkGuideBloc`, `SosBloc`, `WebSocketService`, `LocationBroadcaster`, `GuardianNotificationRepository` |
| Strategy | Behavioral | `ObstacleAnalyzer`, `AiConfig`, `AiConfigService`, `TtsService`, `HapticService` |
| Chain of Responsibility | Behavioral | `ApiClient`, `AuthInterceptor`, `ErrorInterceptor`, `JwtAuthFilter`, `SecurityConfig`, `JwtUtil`, `CustomUserDetailsService` |

---

## 2. Builder Pattern — Creational

### Justifikasi

Entitas `User` memiliki **8 field** — tidak semua selalu terisi. Field `uniqueUserId` hanya ada untuk `ROLE_USER`, `fcmToken` di-update setiap login, dan `displayName` bersifat opsional. Tanpa Builder, constructor membutuhkan 8 parameter yang rawan salah urutan dan sulit dibaca. `FcmService` membangun payload Firebase `Message` secara kondisional (beberapa field hanya ada saat SOS, yang lain hanya saat notifikasi biasa) — Builder sangat cocok untuk kasus ini.

### Class yang Terlibat

| Class | Layer | Peran dalam Pattern | Lokasi di Class Diagram |
|-------|-------|---------------------|-------------------------|
| `User` | Backend — Entity | **Product** — objek yang dibangun step-by-step via `@Builder` Lombok | Entity block |
| `AuthService` | Backend — Service | **Director/Client** — memanggil `User.builder()...build()` saat register | Service block |
| `FcmService` | Backend — Service | **Client** — memanggil `Message.builder()` Firebase untuk bangun payload FCM | Service block |
| `AuthDataResponse` | Backend — DTO | **Product 2** — response token dibangun via `AuthDataResponse.builder()` | DTO block |
| `RefreshToken` | Backend — Entity | **Product 3** — dibuat via builder saat generate refresh token | Entity block |

### Relasi Antar Class

```
AuthService ──uses──► User.builder()
                          .email()
                          .password()
                          .displayName()
                          .uniqueUserId()
                          .role()
                          .build()
                              │
                              ▼
                           User (Entity tersimpan ke UserRepository)

FcmService ──uses──► Message.builder()
                          .setToken()
                          .setNotification()
                          .putData("type", "SOS_ALERT")
                          .setAndroidConfig()
                          .build()
                              │
                              ▼
                       FirebaseMessage (dikirim via FCM)
```

---

## 3. Singleton Pattern — Creational

### Justifikasi

WalkGuide memiliki beberapa **resource-heavy services** yang harus ada tepat satu instance:
- `YoloDetector` memuat model `.tflite` ±6 MB ke memori — jika dibuat ulang setiap buka layar akan terjadi memory leak dan delay 2–3 detik.
- `WebSocketService` mempertahankan satu koneksi STOMP ke backend — multiple instance menyebabkan event diterima dobel.
- `TtsService` mengelola engine TTS — dua instance berbicara bersamaan akan saling menimpa.
- `AgoraService` mengelola RTC engine — satu per sesi, tidak boleh duplikat.

Semua di-register via `GetIt` service locator sebagai singleton agar seluruh widget tree mendapat instance yang sama.

### Class yang Terlibat

| Class | Layer | Peran dalam Pattern | Lokasi di Class Diagram |
|-------|-------|---------------------|-------------------------|
| `TtsService` | Flutter — Service | **Singleton** — satu TTS engine untuk seluruh app | Services block |
| `SttService` | Flutter — Service | **Singleton** — satu STT listener always-on | Services block |
| `YoloDetector` | Flutter — AI | **Singleton** — satu model inference engine (6 MB) | AI block |
| `WebSocketService` | Flutter — Service | **Singleton** — satu koneksi STOMP ke backend | Services block |
| `AgoraService` | Flutter — Service | **Singleton** — satu RTC engine untuk VoIP call | Services block |
| `HapticService` | Flutter — Service | **Singleton** — satu haptic controller | Services block |
| `GetIt` (injection_container) | Flutter — DI | **ServiceLocator** — mengelola lifecycle semua singleton | Bootstrap |

### Relasi Antar Class

```
injection_container.dart
        │
        ├─ sl.registerSingleton<TtsService>(TtsService())
        ├─ sl.registerSingleton<SttService>(SttService())
        ├─ sl.registerSingleton<YoloDetector>(YoloDetector())
        ├─ sl.registerSingleton<WebSocketService>(WebSocketService())
        ├─ sl.registerSingleton<AgoraService>(AgoraService())
        └─ sl.registerSingleton<HapticService>(HapticService())

WalkGuideBloc ──sl<YoloDetector>()──► YoloDetector (instance sama)
WalkGuideBloc ──sl<TtsService>()───► TtsService   (instance sama)
VoiceCommandHandler ──sl<TtsService>()──► TtsService (instance sama, bukan baru)
```

---

## 4. Facade Pattern — Structural

### Justifikasi

Memproses satu perintah suara `"Send SOS"` membutuhkan koordinasi: `SttService`, command matcher, `SosBloc`, GPS, `TtsService` feedback, dan `GoRouter` navigasi — 6 subsystem berbeda. Tanpa Facade, setiap Widget harus inject dan tahu semua 6 dependency tersebut. `VoiceCommandHandler` menyederhanakan ini menjadi satu panggilan `processText(string)`.

Di backend, `GuardianController` membutuhkan data dari 5 repository berbeda untuk render dashboard Guardian. `GuardianDashboardService` menjadi Facade yang mengagregasi semuanya, sehingga controller cukup memanggil satu method.

### Class yang Terlibat

| Class | Layer | Peran dalam Pattern | Lokasi di Class Diagram |
|-------|-------|---------------------|-------------------------|
| `VoiceCommandHandler` | Flutter — Service | **Facade** — menyembunyikan koordinasi 6 subsystem voice | Services block |
| `WalkGuideBloc` | Flutter — BLoC | **Client** — hanya tahu `processText()`, tidak tahu subsystem | BLoC block |
| `TtsService` | Flutter — Service | **Subsystem** — salah satu dari yang dikoordinasikan | Services block |
| `SttService` | Flutter — Service | **Subsystem** — salah satu dari yang dikoordinasikan | Services block |
| `VoiceCommandConfig` | Backend — Entity | **Data** — konfigurasi perintah suara yang dibaca Facade | Entity block |
| `VoiceCommandKey` | Backend — Enum | **Enum** — key identifier 14 perintah suara | Enum block |
| `GuardianDashboardService` | Backend — Service | **Facade** — mengagregasi data dari 5 repository | Service block |
| `GuardianController` | Backend — Controller | **Client** — cukup panggil `getGuardianHomeData()` | Controller block |
| `LocationHistoryRepository` | Backend — Repository | **Subsystem** — data lokasi terakhir User | Repository block |
| `SosEventRepository` | Backend — Repository | **Subsystem** — data SOS aktif User | Repository block |
| `ActivityLogRepository` | Backend — Repository | **Subsystem** — log aktivitas User | Repository block |
| `GuardianNotificationRepository` | Backend — Repository | **Subsystem** — jumlah notif belum dibaca | Repository block |
| `PairingRelationRepository` | Backend — Repository | **Subsystem** — ambil userId yang dipasangkan ke Guardian | Repository block |

### Relasi Antar Class

```
Widget ──processText("send sos")──► VoiceCommandHandler (Facade)
                                          │
                          ┌───────────────┼───────────────┐
                          ▼               ▼               ▼
                      SttService      SosBloc         TtsService
                      (stop listen) (TriggerSos)  (speak feedback)

GuardianController ──getGuardianHomeData()──► GuardianDashboardService (Facade)
                                                      │
                              ┌───────────────────────┼───────────────────────┐
                              ▼                       ▼                       ▼
                   LocationHistoryRepo        SosEventRepo          ActivityLogRepo
                   (last location)           (active SOS)          (recent activity)
```

---

## 5. Repository / Proxy Pattern — Structural

### Justifikasi

WalkGuide harus berjalan **offline-first** — tunanetra sering berada di area tanpa sinyal. Log obstacle, activity log, dan update lokasi harus tetap tersimpan lokal (SQLite/Drift) saat offline, kemudian di-sync ke backend saat koneksi kembali. `WalkGuideBloc` tidak boleh tahu apakah data berasal dari API atau SQLite — keputusan ini ada di Repository Implementation yang bertindak sebagai Proxy.

### Class yang Terlibat

| Class | Layer | Peran dalam Pattern | Lokasi di Class Diagram |
|-------|-------|---------------------|-------------------------|
| `WalkGuideRepository` (interface) | Flutter — Domain | **Subject Interface** — kontrak yang dipakai BLoC | Domain layer |
| `WalkGuideRepositoryImpl` | Flutter — Data | **Proxy** — memutuskan API vs SQLite | Data layer |
| `ActivityLogRepository` (interface) | Flutter — Domain | **Subject Interface** | Domain layer |
| `ActivityLogRepositoryImpl` | Flutter — Data | **Proxy** | Data layer |
| `ObstacleLogRepository` | Backend — Repository | **Real Subject** — JPA repository backend | Repository block |
| `ActivityLogRepository` (JPA) | Backend — Repository | **Real Subject** — JPA repository backend | Repository block |
| `LocationHistoryRepository` | Backend — Repository | **Real Subject** — JPA repository backend | Repository block |
| `ObstacleLog` | Backend — Entity | **Data** — entitas yang disimpan/diambil | Entity block |
| `ActivityLog` | Backend — Entity | **Data** — entitas yang disimpan/diambil | Entity block |
| `LocationHistory` | Backend — Entity | **Data** — riwayat lokasi User | Entity block |

### Relasi Antar Class

```
WalkGuideBloc
    │
    │ depends on interface only
    ▼
WalkGuideRepository (interface)
    │ implements
    ▼
WalkGuideRepositoryImpl (Proxy)
    │
    ├─ if (isOnline) ──► REST API  ──► ObstacleLogRepository (JPA)
    │                                       │
    │                                       ▼
    │                                  ObstacleLog (Entity)
    │
    └─ else ────────► SQLite/Drift ──► Local cache
                      (Drift ORM)
```

---

## 6. Observer Pattern — Behavioral

### Justifikasi

Saat YOLO mendeteksi obstacle, puluhan komponen perlu bereaksi: overlay bounding box, TTS feedback, haptic, backend log, dan debug panel. Menghubungkan semua ini secara langsung akan menciptakan tight coupling. BLoC pattern adalah implementasi Observer murni — `WalkGuideBloc` sebagai Subject, widget sebagai Observer. Ketika state baru di-emit, semua subscriber otomatis bereaksi tanpa BLoC perlu tahu siapa saja Observer-nya.

Untuk Guardian, `WebSocketService` adalah Observer terhadap backend STOMP — Guardian menerima update lokasi User real-time tanpa polling.

### Class yang Terlibat

| Class | Layer | Peran dalam Pattern | Lokasi di Class Diagram |
|-------|-------|---------------------|-------------------------|
| `WalkGuideBloc` | Flutter — BLoC | **Concrete Subject** — emit state saat obstacle terdeteksi | BLoC block |
| `SosBloc` | Flutter — BLoC | **Concrete Subject** — emit state saat SOS triggered | BLoC block |
| `BlocBuilder` (widget) | Flutter — UI | **Observer** — rebuild UI saat state berubah | Widget layer |
| `BlocListener` (widget) | Flutter — UI | **Observer** — side effects tanpa rebuild UI | Widget layer |
| `WebSocketService` | Flutter — Service | **Subject** — Stream lokasi, SOS, notifikasi | Services block |
| `LocationBroadcaster` | Backend — Component | **Publisher** — push event ke STOMP topics | Backend block |
| `GuardianNotificationRepository` | Backend — Repository | **Data Store** — notifikasi yang perlu di-broadcast | Repository block |
| `SosEventRepository` | Backend — Repository | **Data Store** — SOS event yang di-broadcast ke Guardian | Repository block |
| `ActivityLogService` | Backend — Service | **Publisher** — broadcast activity log via LocationBroadcaster | Service block |

### Relasi Antar Class

```
YoloDetector ──detect()──► DetectionResult
                                │
                          WalkGuideBloc (Subject)
                          emit(ObstacleDetected)
                                │
                ┌───────────────┼───────────────┐
                ▼               ▼               ▼
          BlocBuilder      BlocListener    BlocConsumer
          (UI rebuild)    (side effects)    (both)
          overlay bbox    SnackBar error   combined

Backend STOMP push:
LocationBroadcaster ──/topic/location/{userId}──► WebSocketService (Subject)
                                                         │
                                           ┌─────────────┼─────────────┐
                                           ▼             ▼             ▼
                                    GuardianMap    GuardianDash   NotifScreen
                                    (live marker)   (SOS alert)  (new notif)
```

---

## 7. Strategy Pattern — Behavioral

### Justifikasi

Guardian perlu mengkonfigurasi **cara WalkGuide memperingatkan** User tentang obstacle. Ada tiga mode: TTS saja (cocok untuk lingkungan tenang), TTS + haptic (default untuk sebagian besar situasi), haptic saja (lingkungan bising seperti pasar atau stasiun). Logika ini bisa berubah kapan saja dari dashboard Guardian tanpa restart app. Strategy Pattern memungkinkan penggantian algoritma alert di runtime tanpa mengubah `ObstacleAnalyzer` sedikit pun.

### Class yang Terlibat

| Class | Layer | Peran dalam Pattern | Lokasi di Class Diagram |
|-------|-------|---------------------|-------------------------|
| `ObstacleAlertStrategy` (interface) | Flutter — AI | **Strategy Interface** — kontrak `alert(result)` | Domain/AI layer |
| `TtsOnlyStrategy` | Flutter — AI | **Concrete Strategy 1** — hanya TTS | Strategy layer |
| `TtsWithHapticStrategy` | Flutter — AI | **Concrete Strategy 2** — TTS + haptic | Strategy layer |
| `HapticOnlyStrategy` | Flutter — AI | **Concrete Strategy 3** — hanya haptic | Strategy layer |
| `ObstacleAnalyzer` | Flutter — AI | **Context** — menyimpan dan mendelegasikan ke strategy | AI block |
| `AiConfig` | Backend — Entity | **Config Source** — menyimpan `alertMode` yang dipilih Guardian | Entity block |
| `AiConfigService` | Backend — Service | **Config Manager** — update config dan kirim FCM ke User | Service block |
| `AiConfigRepository` | Backend — Repository | **Persistence** — simpan/ambil konfigurasi AI | Repository block |
| `TtsService` | Flutter — Service | **Subsystem** — dipakai oleh TtsOnly dan TtsWithHaptic | Services block |
| `HapticService` | Flutter — Service | **Subsystem** — dipakai oleh TtsWithHaptic dan HapticOnly | Services block |
| `FcmService` | Backend — Service | **Notifier** — kirim FCM ke User saat config berubah | Service block |

### Relasi Antar Class

```
Guardian PUT /guardian/ai-config
    │
    ▼
AiConfigService ──updateConfig()──► AiConfig (simpan alertMode)
    │
    └──► FcmService.sendToUser() ──► FCM ke User: "ai_config_updated"
                                              │
                                    Flutter terima FCM
                                              │
                                    switch (config.alertMode)
                                    ┌─────────┼──────────┐
                                    ▼         ▼          ▼
                               TtsOnly  TtsHaptic  HapticOnly
                               Strategy  Strategy   Strategy
                                    │
                          ObstacleAnalyzer.setStrategy(new)
                                    │
                          _strategy.alert(detectionResult)
```

---

## 8. Chain of Responsibility Pattern — Behavioral

### Justifikasi

Setiap HTTP request dari Flutter perlu melewati beberapa proses berurutan: (1) menambahkan JWT, (2) auto-refresh jika expired, (3) error mapping terpusat, (4) logging. Tanpa Chain of Responsibility, setiap Repository harus menulis ulang logika ini. Di backend, setiap request perlu (1) divalidasi JWT, (2) dicek role-nya sebelum mencapai controller bisnis. Chain memungkinkan setiap handler fokus pada tanggung jawabnya sendiri dan meneruskan ke handler berikutnya.

### Class yang Terlibat

| Class | Layer | Peran dalam Pattern | Lokasi di Class Diagram |
|-------|-------|---------------------|-------------------------|
| `Interceptor` (abstract Dio) | Flutter — Network | **Abstract Handler** | Network layer |
| `AuthInterceptor` | Flutter — Network | **Concrete Handler 1** — inject token, auto-refresh | Network layer |
| `ErrorInterceptor` | Flutter — Network | **Concrete Handler 2** — map HTTP error ke Failure | Network layer |
| `LogInterceptor` | Flutter — Network | **Concrete Handler 3** — logging request/response | Network layer |
| `ApiClient` | Flutter — Network | **Chain Builder** — mengatur urutan dan membangun chain | Network layer |
| `OncePerRequestFilter` (Spring) | Backend — Security | **Abstract Handler** | Security block |
| `JwtAuthFilter` | Backend — Security | **Concrete Handler 1** — validasi JWT, set SecurityContext | Security block |
| `SecurityConfig` | Backend — Security | **Concrete Handler 2** — RBAC routing per URL pattern | Security block |
| `JwtUtil` | Backend — Security | **Component** — dipakai JwtAuthFilter untuk decode/validate | Security block |
| `CustomUserDetailsService` | Backend — Security | **Component** — dipakai JwtAuthFilter untuk load user dari DB | Security block |
| `UserRepository` | Backend — Repository | **Data Source** — dipakai CustomUserDetailsService | Repository block |
| `GlobalExceptionHandler` | Backend — Exception | **Error Handler** — menangkap exception dari seluruh chain | Exception block |

### Relasi Antar Class

```
Flutter HTTP Request
    │
    ▼
[Chain[0]] AuthInterceptor ──onRequest()──► inject "Bearer {token}" ──► next()
    │
    ▼
[Chain[1]] ErrorInterceptor ──onRequest()──► pass-through ──► next()
    │
    ▼
[Chain[2]] LogInterceptor ──onRequest()──► log URL + body ──► next()
    │
    ▼  (HTTP over network)
    │
[Backend] JwtAuthFilter ──doFilterInternal()──► validate JWT ──► chain.doFilter()
    │
    ▼
[Backend] SecurityConfig ──securityFilterChain()──► cek role ──► pass
    │
    ▼
[Backend] Controller ──handleRequest()──► proses bisnis
    │
    ▼
[Backend] GlobalExceptionHandler ──► tangkap exception jika ada
    │
    ▼  (HTTP Response)
    │
[Chain[2]] LogInterceptor.onResponse() ──► log response
    │
    ▼
[Chain[1]] ErrorInterceptor.onResponse() ──► map error jika 4xx/5xx
    │
    ▼
[Chain[0]] AuthInterceptor.onError() ──► jika 401: refresh token + retry
    │
    ▼
Repository / BLoC menerima Either<Failure, Data>
```

---

## Ringkasan Jumlah Class per Pattern

| Pattern | Jumlah Class Terlibat | Layer |
|---------|----------------------|-------|
| Builder | 5 class | Backend |
| Singleton | 7 class | Flutter |
| Facade | 13 class | Flutter + Backend |
| Repository/Proxy | 10 class | Flutter + Backend |
| Observer | 9 class | Flutter + Backend |
| Strategy | 11 class | Flutter + Backend |
| Chain of Responsibility | 12 class | Flutter + Backend |
| **Total unik** | **±40 class** | **Full Stack** |

> Semua class di atas dapat ditelusuri langsung di **Class Diagram WalkGuide** (file PDF yang dilampirkan).