@startuml WalkGuide_Component_Diagram
title Component Diagram — WalkGuide System (v2.0)

skinparam componentStyle rectangle
skinparam backgroundColor #FAFAFA
skinparam component {
  BackgroundColor #EEF2FF
  BorderColor #6366F1
  FontColor #1E1B4B
  FontSize 11
}
skinparam package {
  BackgroundColor #F0F4FF
  BorderColor #818CF8
  FontColor #1E1B4B
  FontSize 12
  FontStyle bold
}
skinparam interface {
  BackgroundColor #DBEAFE
  BorderColor #3B82F6
}
skinparam database {
  BackgroundColor #FEF3C7
  BorderColor #D97706
}
skinparam cloud {
  BackgroundColor #F0FDF4
  BorderColor #16A34A
}
skinparam arrow {
  Color #4B5563
  FontSize 9
  FontColor #374151
}
skinparam note {
  BackgroundColor #FFFBEB
  BorderColor #F59E0B
  FontSize 9
}

' ─────────────────────────────────────────────
' MOBILE DEVICE — Flutter App
' ─────────────────────────────────────────────
package "Mobile Device (Flutter App)" as FLUTTER #E8EAF6 {

  package "Presentation Layer" as PRESENTATION {
    [ServerConnectScreen] as SCS
    [SplashScreen] as SS
    [LoginScreen] as LS
    [RegisterScreen] as RS

    package "User Screens" as US_SCREENS {
      [WalkGuideScreen] as WGS
      [SosScreen] as SOSS
      [ActivityLogScreen] as ALS
      [NotificationScreen] as NS
      [NavigationModeScreen] as NMS
      [UserSettingsScreen] as USS
      [CallScreen] as CS
      [ManualScreen] as MS
      [UserPairingScreen] as UPS
    }

    package "Guardian Screens" as GS_SCREENS {
      [GuardianDashboardScreen] as GDS
      [GuardianMapScreen] as GMS
      [GuardianActivityLogScreen] as GALS
      [GuardianSendNotifScreen] as GSNS
      [GuardianAiConfigScreen] as GACS
      [GuardianVoiceCmdScreen] as GVCS
      [GuardianShortcutScreen] as GSHS
      [GuardianGeofenceScreen] as GGFS
      [GuardianPairingScreen] as GPS
      [IncomingCallScreen] as ICS
    }
  }

  package "Application Layer (BLoC / Cubit)" as BLOC_LAYER {
    [AuthBloc] as AuthBloc
    [PairingBloc] as PairingBloc
    [WalkGuideBloc] as WGBloc
    [SosBloc] as SosBloc
    [LocationBloc] as LocBloc
    [NotificationBloc] as NotifBloc
    [ActivityLogBloc] as ActLogBloc
    [VoiceCommandBloc] as VCBloc
    [ServerConnectBloc] as SCBloc
    [CallBloc] as CallBloc
    [GuardianDashboardBloc] as GDBloc
  }

  package "Domain Layer" as DOMAIN {
    package "Use Cases" as USECASES {
      [LoginUseCase] as LoginUC
      [RegisterUseCase] as RegUC
      [LogoutUseCase] as LogoutUC
      [InviteUserUseCase] as InviteUC
      [RespondPairingUseCase] as RespUC
      [UnpairUseCase] as UnpairUC
      [StartSessionUseCase] as StartUC
      [StopSessionUseCase] as StopUC
      [LogObstacleUseCase] as LogObsUC
      [TriggerSosUseCase] as TrigSosUC
      [UpdateLocationUseCase] as UpdLocUC
    }
    package "Repository Interfaces" as REPO_INTF {
      interface "IAuthRepository" as IAuthRepo
      interface "IPairingRepository" as IPairRepo
      interface "IWalkGuideRepository" as IWGRepo
      interface "IActivityLogRepository" as IActRepo
      interface "ISosRepository" as ISosRepo
      interface "ILocationRepository" as ILocRepo
      interface "INotificationRepository" as INotifRepo
      interface "IAiConfigRepository" as IAIRepo
    }
  }

  package "Data Layer" as DATA {
    package "Repository Implementations" as REPO_IMPL {
      [AuthRepositoryImpl] as AuthRepoImpl
      [PairingRepositoryImpl] as PairRepoImpl
      [WalkGuideRepositoryImpl] as WGRepoImpl
      [ActivityLogRepositoryImpl] as ActRepoImpl
      [SosRepositoryImpl] as SosRepoImpl
      [LocationRepositoryImpl] as LocRepoImpl
      [NotificationRepositoryImpl] as NotifRepoImpl
      [AiConfigRepositoryImpl] as AIRepoImpl
    }

    package "Remote Data Sources" as REMOTE_DS {
      [AuthRemoteDataSource] as AuthDS
      [WalkGuideRemoteDataSource] as WGDS
      [ActivityLogRemoteDataSource] as ActDS
      [SosRemoteDataSource] as SosDS
      [LocationRemoteDataSource] as LocDS
      [NotificationRemoteDataSource] as NotifDS
      [GuardianRemoteDataSource] as GrdDS
    }

    package "Local Data Sources (Drift/SQLite)" as LOCAL_DS {
      [SecureStorageService] as SecStore
      [LocalDatabase (Drift)] as DriftDB
      [SharedPreferencesService] as SharedPref
    }

    package "Core Services (Singletons)" as CORE_SVC {
      [TtsService\n(flutter_tts)] as TTS
      [SttService\n(speech_to_text)] as STT
      [VoiceCommandHandler] as VCH
      [HapticService\n(vibration)] as HAP
      [HardwareShortcutListener] as HSL
      [FcmService\n(firebase_messaging)] as FCMSvc
      [WebSocketService\n(stomp_dart_client)] as WSSvc
      [AgoraService\n(agora_rtc_engine)] as AgoraSvc
    }

    package "AI Engine (On-Device)" as AI_ENGINE {
      [ModelLoader\n(tflite_flutter)] as ModelLoader
      [YoloDetector\n(YOLOv8n)] as YOLO
      [ObstacleAnalyzer] as ObsAnalyzer
    }

    [ApiClient\n(Dio + Interceptors)] as DioClient
  }
}

' ─────────────────────────────────────────────
' BACKEND SERVER — Spring Boot
' ─────────────────────────────────────────────
package "Backend Server (Spring Boot @ 202.46.28.160:8080)" as BACKEND #E8F5E9 {

  package "Security & Config" as SEC_CFG {
    [SecurityConfig\n(CORS, CSRF, RBAC)] as SecConfig
    [JwtAuthFilter\n(OncePerRequestFilter)] as JWTFilter
    [JwtUtil\n(JJWT)] as JWTUtil
    [CustomUserDetailsService] as CUDS
    [WebSocketConfig\n(STOMP)] as WSConfig
    [GlobalExceptionHandler\n(@ControllerAdvice)] as GEH
    [SwaggerConfig\n(Springdoc OpenAPI)] as SwagConfig
  }

  package "Controller Layer" as CTRL {
    [AuthController\n/api/v1/auth] as AuthCtrl
    [PairingController\n/api/v1/shared/pairing] as PairCtrl
    [GuardianController\n/api/v1/guardian] as GrdCtrl
    [UserController\n/api/v1/user] as UserCtrl
    [CallController\n/api/v1/shared/call] as CallCtrl
  }

  package "Service Layer" as SVC {
    [AuthService] as AuthSvc
    [PairingService] as PairSvc
    [ActivityLogService] as ActLogSvc
    [LocationService\n(+ Haversine)] as LocSvc
    [ObstacleLogService] as ObsLogSvc
    [NotificationService] as NotifSvc
    [SosService] as SosSvc
    [AiConfigService] as AICfgSvc
    [VoiceCommandService] as VCSvc
    [HardwareShortcutService] as HWSvc
    [GeofenceService\n(Haversine)] as GeoSvc
    [UserSettingsService] as UserSetSvc
    [FcmService\n(Firebase Admin)] as FcmBackSvc
    [AgoraTokenService] as AgoraSvcBE
    [GuardianDashboardService] as GDSvc
  }

  package "WebSocket Broadcaster" as WS_BROADCAST {
    [LocationBroadcaster\n(SimpMessagingTemplate)] as LocBcast
  }

  package "Repository Layer (Spring Data JPA)" as REPO {
    [UserRepository] as UserRepo
    [PairingRelationRepository] as PairRepo
    [ActivityLogRepository] as ActRepo
    [ObstacleLogRepository] as ObsRepo
    [LocationHistoryRepository] as LocRepo
    [GuardianNotificationRepository] as NotifRepo
    [SosEventRepository] as SosRepo
    [UserSettingsRepository] as UserSetRepo
    [AiConfigRepository] as AIRepo
    [VoiceCommandConfigRepository] as VCRepo
    [HardwareShortcutRepository] as HWRepo
    [GeofenceConfigRepository] as GeoRepo
    [RefreshTokenRepository] as RTRepo
  }

  package "Domain / Entity" as ENTITY {
    [User] as UEnt
    [PairingRelation] as PRel
    [ActivityLog] as ActEnt
    [ObstacleLog] as ObsEnt
    [LocationHistory] as LocEnt
    [GuardianNotification] as NotifEnt
    [SosEvent] as SosEnt
    [UserSettings] as UserSetEnt
    [AiConfig] as AICfgEnt
    [VoiceCommandConfig] as VCEnt
    [HardwareShortcut] as HWEnt
    [GeofenceConfig] as GeoEnt
    [RefreshToken] as RTEnt
  }
}

' ─────────────────────────────────────────────
' EXTERNAL SERVICES
' ─────────────────────────────────────────────
package "External Services" as EXTERNAL #FFF8E1 {
  cloud "Firebase (FCM)\nPush Notifications" as FCM
  cloud "Agora RTC\nVoIP Audio Call" as AGORA
  cloud "OpenStreetMap\n(flutter_map tiles)" as OSM
}

database "PostgreSQL\n202.46.28.160:2002\n(University Server)\nFlyway Migrations V1-V16" as PGDB

' ─────────────────────────────────────────────
' PRESENTATION → BLOC
' ─────────────────────────────────────────────
SCS --> SCBloc
SS --> AuthBloc
LS --> AuthBloc
RS --> AuthBloc
WGS --> WGBloc
WGS --> VCBloc
SOSS --> SosBloc
ALS --> ActLogBloc
NS --> NotifBloc
NMS --> LocBloc
USS --> AuthBloc
CS --> CallBloc
UPS --> PairingBloc
GDS --> GDBloc
GMS --> LocBloc
GALS --> ActLogBloc
GSNS --> NotifBloc
GACS --> AIRepoImpl
GVCS --> VCBloc
GSHS --> VCBloc
GGFS --> GDBloc
GPS --> PairingBloc
ICS --> CallBloc

' ─────────────────────────────────────────────
' BLOC → USE CASES
' ─────────────────────────────────────────────
AuthBloc --> LoginUC
AuthBloc --> RegUC
AuthBloc --> LogoutUC
PairingBloc --> InviteUC
PairingBloc --> RespUC
PairingBloc --> UnpairUC
WGBloc --> StartUC
WGBloc --> StopUC
WGBloc --> LogObsUC
SosBloc --> TrigSosUC
LocBloc --> UpdLocUC
CallBloc --> AgoraSvc
VCBloc --> VCH

' ─────────────────────────────────────────────
' USE CASES → REPOSITORY INTERFACES
' ─────────────────────────────────────────────
LoginUC --> IAuthRepo
RegUC --> IAuthRepo
LogoutUC --> IAuthRepo
InviteUC --> IPairRepo
RespUC --> IPairRepo
UnpairUC --> IPairRepo
StartUC --> IWGRepo
StopUC --> IWGRepo
LogObsUC --> IWGRepo
TrigSosUC --> ISosRepo
UpdLocUC --> ILocRepo

' ─────────────────────────────────────────────
' INTERFACES → IMPLEMENTATIONS
' ─────────────────────────────────────────────
IAuthRepo <|.. AuthRepoImpl
IPairRepo <|.. PairRepoImpl
IWGRepo <|.. WGRepoImpl
IActRepo <|.. ActRepoImpl
ISosRepo <|.. SosRepoImpl
ILocRepo <|.. LocRepoImpl
INotifRepo <|.. NotifRepoImpl
IAIRepo <|.. AIRepoImpl

' ─────────────────────────────────────────────
' REPO IMPL → DATA SOURCES
' ─────────────────────────────────────────────
AuthRepoImpl --> AuthDS
AuthRepoImpl --> SecStore
PairRepoImpl --> GrdDS
WGRepoImpl --> WGDS
WGRepoImpl --> DriftDB
ActRepoImpl --> ActDS
SosRepoImpl --> SosDS
LocRepoImpl --> LocDS
NotifRepoImpl --> NotifDS
NotifRepoImpl --> DriftDB
AIRepoImpl --> GrdDS

' ─────────────────────────────────────────────
' REMOTE DATA SOURCES → DioClient
' ─────────────────────────────────────────────
AuthDS --> DioClient
WGDS --> DioClient
ActDS --> DioClient
SosDS --> DioClient
LocDS --> DioClient
NotifDS --> DioClient
GrdDS --> DioClient

' ─────────────────────────────────────────────
' CORE SERVICES INTERCONNECT
' ─────────────────────────────────────────────
WGBloc --> YOLO
WGBloc --> TTS
WGBloc --> HAP
YOLO --> ModelLoader
YOLO --> ObsAnalyzer
ObsAnalyzer --> TTS
ObsAnalyzer --> HAP
VCH --> STT
VCH --> DriftDB
HSL --> DriftDB
FCMSvc --> DriftDB

SharedPref --> DioClient : baseUrl

' ─────────────────────────────────────────────
' DioClient → Backend REST API
' ─────────────────────────────────────────────
DioClient -down-> AuthCtrl : "POST /api/v1/auth/register\nPOST /api/v1/auth/login\nPOST /api/v1/auth/refresh\nPOST /api/v1/auth/logout\nPUT  /api/v1/auth/fcm-token\nGET  /api/v1/auth/ping"
DioClient -down-> PairCtrl : "POST /shared/pairing/invite\nPOST /shared/pairing/respond\nDELETE /shared/pairing/unpair\nGET /shared/pairing/status"
DioClient -down-> UserCtrl : "GET /user/profile\nPOST /user/location\nPOST /user/obstacle\nPOST /user/sos\nGET /user/notifications\nPOST /user/walkguide/start\nPOST /user/walkguide/stop"
DioClient -down-> GrdCtrl : "GET /guardian/dashboard\nGET /guardian/user-location\nPOST /guardian/notifications/send\nPUT /guardian/ai-config\nPUT /guardian/geofence"
DioClient -down-> CallCtrl : "POST /shared/call/token\nPOST /shared/call/notify"

' WebSocket STOMP
WSSvc -down-> WSConfig : "ws://host:8080/ws\n(STOMP)\n/topic/location/{userId}\n/queue/sos/{guardianId}\n/queue/notif/{userId}"

' ─────────────────────────────────────────────
' BACKEND SECURITY FLOW
' ─────────────────────────────────────────────
JWTFilter --> JWTUtil : validate token
JWTFilter --> CUDS : load user
JWTFilter -up-> SecConfig : filter chain
SecConfig -right-> JWTFilter

' ─────────────────────────────────────────────
' CONTROLLERS → SERVICES
' ─────────────────────────────────────────────
AuthCtrl --> AuthSvc
PairCtrl --> PairSvc
GrdCtrl --> GDSvc
GrdCtrl --> LocSvc
GrdCtrl --> ActLogSvc
GrdCtrl --> ObsLogSvc
GrdCtrl --> NotifSvc
GrdCtrl --> SosSvc
GrdCtrl --> AICfgSvc
GrdCtrl --> VCSvc
GrdCtrl --> HWSvc
GrdCtrl --> GeoSvc
UserCtrl --> AuthSvc
UserCtrl --> LocSvc
UserCtrl --> ObsLogSvc
UserCtrl --> SosSvc
UserCtrl --> ActLogSvc
UserCtrl --> NotifSvc
UserCtrl --> UserSetSvc
UserCtrl --> VCSvc
UserCtrl --> HWSvc
UserCtrl --> AICfgSvc
CallCtrl --> AgoraSvcBE

' ─────────────────────────────────────────────
' SERVICES CROSS-DEPENDENCIES
' ─────────────────────────────────────────────
AuthSvc --> PairSvc : seed defaults on register
PairSvc --> VCSvc : seedDefaults()
PairSvc --> HWSvc : seedDefaults()
PairSvc --> AICfgSvc : create config on pair
PairSvc --> FcmBackSvc : send FCM invite/response
NotifSvc --> FcmBackSvc : send FCM notification
SosSvc --> FcmBackSvc : send FCM SOS high-priority
AICfgSvc --> FcmBackSvc : notify settings updated
LocSvc --> GeoSvc : checkGeofence()
LocSvc --> LocBcast : broadcastLocation()
LocSvc --> ActLogSvc : log LOCATION_UPDATE
NotifSvc --> LocBcast : broadcastNotification()
SosSvc --> LocBcast : broadcastSos()
SosSvc --> ActLogSvc : log SOS_TRIGGERED
ActLogSvc --> LocBcast : broadcast to Guardian
GDSvc --> LocSvc
GDSvc --> ActLogSvc
GDSvc --> NotifSvc
GDSvc --> SosSvc

' ─────────────────────────────────────────────
' SERVICES → REPOSITORIES
' ─────────────────────────────────────────────
AuthSvc --> UserRepo
AuthSvc --> RTRepo
AuthSvc --> ActLogSvc
PairSvc --> PairRepo
PairSvc --> UserRepo
ActLogSvc --> ActRepo
LocSvc --> LocRepo
LocSvc --> PairRepo
ObsLogSvc --> ObsRepo
ObsLogSvc --> ActLogSvc
NotifSvc --> NotifRepo
NotifSvc --> PairRepo
SosSvc --> SosRepo
SosSvc --> PairRepo
AICfgSvc --> AIRepo
VCSvc --> VCRepo
HWSvc --> HWRepo
GeoSvc --> GeoRepo
UserSetSvc --> UserSetRepo
FcmBackSvc --> UserRepo
AgoraSvcBE --> UserRepo

' ─────────────────────────────────────────────
' REPOSITORIES → ENTITIES (JPA/Hibernate)
' ─────────────────────────────────────────────
UserRepo --> UEnt
PairRepo --> PRel
ActRepo --> ActEnt
ObsRepo --> ObsEnt
LocRepo --> LocEnt
NotifRepo --> NotifEnt
SosRepo --> SosEnt
UserSetRepo --> UserSetEnt
AIRepo --> AICfgEnt
VCRepo --> VCEnt
HWRepo --> HWEnt
GeoRepo --> GeoEnt
RTRepo --> RTEnt

' ─────────────────────────────────────────────
' ENTITIES → DATABASE
' ─────────────────────────────────────────────
UEnt --> PGDB : JPA/Hibernate
PRel --> PGDB
ActEnt --> PGDB
ObsEnt --> PGDB
LocEnt --> PGDB
NotifEnt --> PGDB
SosEnt --> PGDB
UserSetEnt --> PGDB
AICfgEnt --> PGDB
VCEnt --> PGDB
HWEnt --> PGDB
GeoEnt --> PGDB
RTEnt --> PGDB

' ─────────────────────────────────────────────
' EXTERNAL SERVICES
' ─────────────────────────────────────────────
FcmBackSvc -right-> FCM : "Firebase Admin SDK\nFirebaseMessaging.send()"
AgoraSvcBE -right-> AGORA : "Generate RTC Token\n(server-side Agora SDK)"
AgoraSvc --> AGORA : "agora_rtc_engine\nJoin Channel (audio-only)"
FCMSvc --> FCM : "firebase_messaging\nReceive push"
GMS --> OSM : "flutter_map\nOpenStreetMap tiles"

note top of PGDB
  Tables (Flyway V1–V16):
  users, pairing_relations,
  activity_logs, obstacle_logs,
  location_history, guardian_notifications,
  sos_events, user_settings, ai_configs,
  voice_command_configs, hardware_shortcuts,
  geofence_configs, refresh_tokens
end note

note right of AI_ENGINE
  On-Device AI (No server call):
  YOLOv8n .tflite (640×640)
  → detect obstacles
  → direction: LEFT/CENTER/RIGHT
  → TTS + Haptic alert
  NNAPI delegate (Android AI accel.)
end note

note left of SharedPref
  Dynamic Server URL:
  User inputs "http://202.46.28.160:8080"
  Saved to SharedPreferences
  No hardcoded BASE_URL in APK
end note

note bottom of WSSvc
  WebSocket STOMP:
  /topic/location/{userId} → Guardian map real-time
  /queue/sos/{guardianId}  → SOS alert instant
  /queue/notif/{userId}    → Notification push
end note

@enduml
