138 lines
4.4 KiB
Plaintext
138 lines
4.4 KiB
Plaintext
' ============================================================
|
||
' WALKGUIDE — DESIGN PATTERNS (GoF)
|
||
' Flutter × Spring Boot × In-Device AI
|
||
' Pattern 7 of 7: CHAIN OF RESPONSIBILITY (Behavioral)
|
||
' ============================================================
|
||
|
||
@startuml WalkGuide_07_ChainOfResponsibility
|
||
|
||
skinparam monochrome false
|
||
skinparam shadowing false
|
||
skinparam defaultFontName Arial
|
||
skinparam defaultFontSize 12
|
||
skinparam roundCorner 10
|
||
skinparam ArrowColor #555555
|
||
skinparam ArrowThickness 1.2
|
||
|
||
skinparam class {
|
||
BackgroundColor #FAFAFA
|
||
BorderColor #AAAAAA
|
||
HeaderBackgroundColor #E8E8E8
|
||
FontColor #222222
|
||
StereotypeFontColor #666666
|
||
AttributeFontColor #333333
|
||
}
|
||
|
||
skinparam package {
|
||
BackgroundColor #F5F5F5
|
||
BorderColor #888888
|
||
FontColor #333333
|
||
FontStyle bold
|
||
}
|
||
|
||
skinparam note {
|
||
BackgroundColor #FFFDE7
|
||
BorderColor #F9A825
|
||
FontColor #444444
|
||
FontSize 11
|
||
}
|
||
|
||
' ============================================================
|
||
' PATTERN 7 — CHAIN OF RESPONSIBILITY (Behavioral)
|
||
' ============================================================
|
||
|
||
package "⑦ Chain of Responsibility [Behavioral]" #FCE4EC {
|
||
|
||
' --- Flutter: Dio Interceptor Chain ---
|
||
abstract class "Interceptor\n<<Handler>>" as DioInterceptor {
|
||
+ onRequest(options, handler)
|
||
+ onResponse(response, handler)
|
||
+ onError(error, handler)
|
||
}
|
||
|
||
class "AuthInterceptor\n<<ConcreteHandler>>" as AuthInterceptor {
|
||
- _secureStorage : FlutterSecureStorage
|
||
+ onRequest(options, handler)
|
||
' Attach Bearer token ke setiap request
|
||
+ onError(error, handler)
|
||
' Jika 401: refresh token → retry request
|
||
}
|
||
|
||
class "ErrorInterceptor\n<<ConcreteHandler>>" as ErrorInterceptor {
|
||
+ onError(error, handler)
|
||
' Map HTTP error codes → Failure domain objects
|
||
' 401 → UnauthorizedFailure
|
||
' 404 → NotFoundFailure
|
||
' 500 → ServerFailure
|
||
}
|
||
|
||
class "LogInterceptor\n<<ConcreteHandler>>" as LogInterceptorFlutter {
|
||
+ onRequest(options, handler)
|
||
+ onResponse(response, handler)
|
||
+ onError(error, handler)
|
||
' Print request/response untuk debugging
|
||
}
|
||
|
||
class "ApiClient\n<<Dio>>" as ApiClient {
|
||
- _dio : Dio
|
||
+ get(url) : Response
|
||
+ post(url, data) : Response
|
||
+ put(url, data) : Response
|
||
' Interceptors dieksekusi berurutan
|
||
}
|
||
|
||
' --- Backend: Spring Security Filter Chain ---
|
||
abstract class "OncePerRequestFilter\n<<Handler>>" as SpringFilter {
|
||
+ {abstract} doFilterInternal(req, res, chain)
|
||
+ doFilter(req, res, chain)
|
||
}
|
||
|
||
class "JwtAuthFilter\n<<ConcreteHandler>>" as JwtAuthFilter {
|
||
- _jwtUtil : JwtUtil
|
||
- _userDetailsService : UserDetailsService
|
||
+ doFilterInternal(req, res, chain)
|
||
' Extract JWT → validate → set SecurityContext
|
||
' Jika invalid: 401 Unauthorized langsung
|
||
}
|
||
|
||
class "SecurityConfig\n<<Config/Handler>>" as SecurityConfigChain {
|
||
+ securityFilterChain(http) : SecurityFilterChain
|
||
' /auth/** → permitAll
|
||
' /api/v1/** → authenticated
|
||
' ROLE_GUARDIAN vs ROLE_USER routing
|
||
}
|
||
|
||
class "Controller\n<<Endpoint>>" as ControllerChain {
|
||
+ handleRequest(request) : ResponseEntity
|
||
' Request tiba hanya jika lolos semua filter
|
||
}
|
||
|
||
DioInterceptor <|-- AuthInterceptor : extends
|
||
DioInterceptor <|-- ErrorInterceptor : extends
|
||
DioInterceptor <|-- LogInterceptorFlutter : extends
|
||
|
||
ApiClient --> AuthInterceptor : chain[0]
|
||
AuthInterceptor --> ErrorInterceptor : passes to\nchain[1]
|
||
ErrorInterceptor --> LogInterceptorFlutter : passes to\nchain[2]
|
||
|
||
SpringFilter <|-- JwtAuthFilter : extends
|
||
JwtAuthFilter --> SecurityConfigChain : passes to
|
||
SecurityConfigChain --> ControllerChain : passes to\n(if authorized)
|
||
}
|
||
|
||
note bottom of ApiClient
|
||
Flutter — Dio interceptor chain:
|
||
HTTP Request → AuthInterceptor → ErrorInterceptor → LogInterceptor → Response
|
||
Setiap handler bisa: proses, modifikasi, atau blok request.
|
||
AuthInterceptor otomatis refresh JWT jika expired (401).
|
||
end note
|
||
|
||
note bottom of JwtAuthFilter
|
||
Backend — Spring Security filter chain:
|
||
HTTP Request → JwtAuthFilter → SecurityConfig → Controller
|
||
JwtAuthFilter extract & validasi Bearer token setiap request.
|
||
Jika invalid → langsung 401 tanpa lanjut ke controller.
|
||
end note
|
||
|
||
@enduml
|