fixing a ton of sloppy mess...

This commit is contained in:
Wowieee4
2026-05-17 18:40:03 +07:00
parent f970f1bac8
commit d2608e0188
37 changed files with 3099 additions and 1795 deletions
+39
View File
@@ -0,0 +1,39 @@
# Benchmark Evidence Template
This file is intentionally a template, not a fabricated result. Fill it after running benchmarks on the required machine/device.
## Flutter Device Benchmark
| Metric | Tool | Threshold | Result | Evidence File |
|---|---|---:|---:|---|
| Memory baseline | DevTools Memory | report MB | TBD | screenshot TBD |
| Memory leak check | DevTools Memory | no steady growth | TBD | screenshot TBD |
| Frame rate / jank | DevTools Performance | >= 90% frames < 16ms | TBD | screenshot TBD |
| CPU profile | DevTools CPU Profiler | top 3 operations documented | TBD | screenshot TBD |
| API latency | Dio logs | < 1500ms | TBD | log TBD |
| Cold start | `flutter run --profile --trace-startup` | < 3000ms | TBD | trace TBD |
| APK size | `flutter build apk --analyze-size` | < 50MB | TBD | report TBD |
## Backend Load Benchmark
| Metric | Tool | Threshold | Result | Evidence File |
|---|---|---:|---:|---|
| Throughput | k6/JMeter | >= 100 req/s | TBD | k6 summary TBD |
| p95 latency | k6/JMeter | < 500ms | TBD | k6 summary TBD |
| Error rate | k6/JMeter | < 1% | TBD | k6 summary TBD |
| Slow query | DB/Actuator logs | no query > 200ms | TBD | log TBD |
| JVM memory | Actuator metrics | no heap exhaustion | TBD | metrics TBD |
## Commands To Run
```powershell
cd "D:\CodeSpace\Final Project Gabungan - Broken Test\walkguide-mobile\walkguide_app"
flutter run --profile --trace-startup
flutter build apk --analyze-size
```
```bash
cd "walkguide-backend/demo/k6-tests"
./run-all-tests.sh smoke
./run-all-tests.sh load
```
+38
View File
@@ -0,0 +1,38 @@
# WalkGuide Design Pattern Documentation
## Builder - Creational
- Backend DTO/entity builders via Lombok `@Builder`.
- Files: `PairingStatusResponse.java`, `AgoraTokenResponse.java`, entity classes such as `PairingRelation.java`.
- Reason: response/entity construction has many optional fields, so builder calls are clearer than long constructors.
## Singleton / Service Locator - Creational
- Flutter registers app-wide services once with GetIt.
- File: `walkguide-mobile/walkguide_app/lib/app/injection_container.dart`.
- Examples: `TtsService`, `WebSocketService`, `CallService`, `YoloDetector`.
- Reason: resource-heavy services need one shared lifecycle.
## Facade - Structural
- Flutter service classes hide low-level plugins from UI.
- Files: `TtsService`, `HapticService`, `FcmService`, `CallService`, `WebSocketService`.
- Reason: screens call simple domain-oriented methods instead of plugin APIs directly.
## Repository - Structural
- Backend repositories abstract JPA persistence.
- Files: `UserRepository`, `PairingRelationRepository`, `LocationHistoryRepository`, etc.
- Reason: service layer works against repository contracts, not SQL.
## Observer - Behavioral
- Flutter BLoC/Cubit and ChangeNotifier notify screens on state changes.
- Backend WebSocket broker pushes location/SOS/notification updates to subscribers.
- Files: `AppCubit`, `WebSocketService`, `LocationBroadcaster`.
- Reason: real-time features need push updates without polling.
## Strategy - Behavioral
- Obstacle direction/distance analysis can vary independently from camera capture.
- File: `core/ai/obstacle_analyzer.dart`.
- Reason: detection interpretation is isolated so thresholds/rules can evolve.
## Chain of Responsibility - Behavioral
- Dio interceptors handle token injection, refresh, and error flow.
- File: `core/network/api_client.dart`.
- Reason: each request passes through consistent auth/error handling before reaching UI.
+29
View File
@@ -0,0 +1,29 @@
# WalkGuide Traceability Audit
## Use Case To Code
| Use Case | Flutter Entry | Backend Entry | Status |
|---|---|---|---|
| Register/Login | `features/auth/*` | `AuthController`, `AuthService` | Implemented |
| Pair Guardian/User | `features/pairing/pairing_screens.dart` | `PairingController`, `PairingService` | Implemented |
| Start/Stop WalkGuide | `features/walk_guide/walk_guide_screen.dart` | `POST /user/walkguide/start`, `POST /user/walkguide/stop` | Implemented |
| Obstacle Detection | `core/ai/*`, `walk_guide_screen.dart` | `POST /user/obstacle` | Partially implemented; real `.tflite` model file still required |
| Location Tracking | `LocationReporterService`, navigation/walk screens | `LocationService`, `LocationBroadcaster` | Implemented |
| SOS | `features/sos/sos_screen.dart` | `SosService`, `GuardianController` | Implemented |
| Notifications | `features/notifications/notification_screen.dart` | `NotificationService`, `FcmService` | Partially implemented; backend FCM is log-only without credentials |
| Guardian Dashboard | `guardian_dashboard_screen.dart` | `GuardianDashboardService` | Implemented |
| Call | `features/call/call_screen.dart`, `CallService` | `CallController`, `AgoraTokenService` | Partially implemented; Agora App ID/credential required for live call |
| Geofence | guardian dashboard screens | `GeofenceService` | Implemented |
## Design Deviations
- Flutter uses a pragmatic mix of BLoC/Cubit, ChangeNotifier, and StatefulWidget. This deviates from strict full-BLoC architecture but keeps feature screens small for the exam demo.
- Offline storage uses `SharedPreferences` queue instead of a full Drift database for cached entities. The dependency exists, but production-grade SQLite cache is not fully wired.
- Backend FCM service is log-only until Firebase Admin credentials are provided.
- Agora call flow is implemented at API and service level, but live RTC depends on a real Agora App ID.
## Remaining Evidence
- Export rendered OOAD diagrams from the PlantUML files in this folder.
- Run backend tests and archive JaCoCo/Surefire reports.
- Run Flutter benchmarks on a physical Android device and add screenshots/results.
+71
View File
@@ -0,0 +1,71 @@
@startuml
skinparam classAttributeIconSize 0
class User {
+Long id
+String email
+String role
+String uniqueUserId
+String displayName
+String fcmToken
}
class PairingRelation {
+Long id
+PairingStatus status
+LocalDateTime invitedAt
+LocalDateTime respondedAt
}
class LocationHistory
class ActivityLog
class ObstacleLog
class GuardianNotification
class SosEvent
class UserSettings
class AiConfig
class VoiceCommandConfig
class HardwareShortcut
class GeofenceConfig
class RefreshToken
User "1" -- "0..*" LocationHistory
User "1" -- "0..*" ActivityLog
User "1" -- "0..*" ObstacleLog
User "1" -- "0..*" SosEvent
User "1" -- "0..1" UserSettings
User "1" -- "0..*" RefreshToken
User "1" -- "0..*" PairingRelation : guardian
User "1" -- "0..*" PairingRelation : user
PairingRelation "1" -- "0..*" GuardianNotification
PairingRelation "1" -- "0..1" AiConfig
PairingRelation "1" -- "0..*" VoiceCommandConfig
PairingRelation "1" -- "0..*" HardwareShortcut
PairingRelation "1" -- "0..1" GeofenceConfig
class AuthController
class PairingController
class UserController
class GuardianController
class CallController
class AuthService
class PairingService
class LocationService
class NotificationService
class SosService
class AgoraTokenService
class FcmService
class LocationBroadcaster
AuthController --> AuthService
PairingController --> PairingService
UserController --> LocationService
UserController --> SosService
GuardianController --> NotificationService
GuardianController --> SosService
CallController --> AgoraTokenService
CallController --> FcmService
LocationService --> LocationBroadcaster
NotificationService --> LocationBroadcaster
SosService --> LocationBroadcaster
@enduml
+35
View File
@@ -0,0 +1,35 @@
@startuml
skinparam componentStyle rectangle
component "Flutter Mobile App" {
[Presentation Screens]
[ApiClient + Interceptors]
[TTS/STT/YOLO/Location Services]
[WebSocketService]
[CallService]
}
component "Spring Boot Backend" {
[Controllers]
[Services]
[Repositories]
[Security/JWT]
[WebSocket Broker]
}
database "PostgreSQL" as DB
cloud "Firebase FCM" as FCM
cloud "Agora RTC" as Agora
cloud "OpenStreetMap/OSRM" as Maps
[Presentation Screens] --> [ApiClient + Interceptors]
[ApiClient + Interceptors] --> [Controllers] : REST /api/v1
[WebSocketService] --> [WebSocket Broker] : STOMP /ws
[CallService] --> [Controllers] : /shared/call
[Controllers] --> [Services]
[Services] --> [Repositories]
[Repositories] --> DB
[Services] --> FCM
[CallService] --> Agora
[Presentation Screens] --> Maps
@enduml
+101
View File
@@ -0,0 +1,101 @@
@startuml
hide circle
skinparam linetype ortho
entity users {
* id : BIGSERIAL <<PK>>
--
email : VARCHAR
password : VARCHAR
role : VARCHAR
unique_user_id : CHAR(12)
display_name : VARCHAR
fcm_token : VARCHAR
created_at : TIMESTAMP
}
entity pairing_relations {
* id : BIGSERIAL <<PK>>
--
guardian_id : BIGINT <<FK>>
user_id : BIGINT <<FK>>
status : VARCHAR
invited_at : TIMESTAMP
responded_at : TIMESTAMP
}
entity activity_logs {
* id : BIGSERIAL <<PK>>
--
user_id : BIGINT <<FK>>
log_type : VARCHAR
description : TEXT
metadata : JSONB
created_at : TIMESTAMP
}
entity obstacle_logs {
* id : BIGSERIAL <<PK>>
--
user_id : BIGINT <<FK>>
label : VARCHAR
confidence : FLOAT
direction : VARCHAR
estimated_dist : VARCHAR
lat : DOUBLE
lng : DOUBLE
}
entity location_history {
* id : BIGSERIAL <<PK>>
--
user_id : BIGINT <<FK>>
lat : DOUBLE
lng : DOUBLE
accuracy : FLOAT
speed : FLOAT
heading : FLOAT
}
entity guardian_notifications {
* id : BIGSERIAL <<PK>>
--
guardian_id : BIGINT <<FK>>
user_id : BIGINT <<FK>>
notif_type : VARCHAR
content : TEXT
is_read : BOOLEAN
}
entity sos_events {
* id : BIGSERIAL <<PK>>
--
user_id : BIGINT <<FK>>
trigger_type : VARCHAR
lat : DOUBLE
lng : DOUBLE
status : VARCHAR
}
entity user_settings
entity ai_configs
entity voice_command_configs
entity hardware_shortcuts
entity geofence_configs
entity refresh_tokens
users ||--o{ pairing_relations : guardian_id
users ||--o{ pairing_relations : user_id
users ||--o{ activity_logs
users ||--o{ obstacle_logs
users ||--o{ location_history
users ||--o{ guardian_notifications : guardian_id
users ||--o{ guardian_notifications : user_id
users ||--o{ sos_events
users ||--o| user_settings
users ||--o{ refresh_tokens
pairing_relations ||--o| ai_configs
pairing_relations ||--o{ voice_command_configs
pairing_relations ||--o{ hardware_shortcuts
pairing_relations ||--o| geofence_configs
@enduml
+19
View File
@@ -0,0 +1,19 @@
@startuml
actor User
participant "Flutter LoginScreen" as UI
participant "ApiClient/Dio" as Dio
participant "AuthController" as Controller
participant "AuthService" as Service
database "PostgreSQL" as DB
User -> UI : enter email/password
UI -> Dio : POST /api/v1/auth/login
Dio -> Controller : LoginRequest
Controller -> Service : login(req)
Service -> DB : find user + refresh token
DB --> Service : user
Service --> Controller : AuthDataResponse
Controller --> Dio : ApiResponse<AuthDataResponse>
Dio --> UI : tokens + role
UI -> UI : save tokens and route by role
@enduml
+23
View File
@@ -0,0 +1,23 @@
@startuml
actor Guardian
actor User
participant "GuardianPairingScreen" as GUI
participant "PairingController" as Controller
participant "PairingService" as Service
database "PostgreSQL" as DB
participant "FcmService" as FCM
Guardian -> GUI : input uniqueUserId
GUI -> Controller : POST /shared/pairing/invite
Controller -> Service : inviteUser(guardianId, uniqueUserId)
Service -> DB : validate and create PENDING relation
Service -> FCM : notify user
Service --> Controller : PairingStatusResponse
Controller --> GUI : invite status
User -> Controller : POST /shared/pairing/respond
Controller -> Service : respondToPairing(userId, pairingId, accept)
Service -> DB : update ACTIVE/REJECTED
Service -> DB : seed default AI/voice/shortcut configs
Service -> FCM : notify guardian
@enduml
+22
View File
@@ -0,0 +1,22 @@
@startuml
actor User
actor Guardian
participant "SosScreen" as UI
participant "UserController" as UserController
participant "SosService" as SosService
database "PostgreSQL" as DB
participant "FcmService" as FCM
participant "LocationBroadcaster" as WS
participant "GuardianDashboard" as Dashboard
User -> UI : press SOS / voice command
UI -> UserController : POST /api/v1/user/sos
UserController -> SosService : triggerSos(userId, req)
SosService -> DB : save sos_events
SosService -> FCM : push high-priority SOS
SosService -> WS : /queue/sos/{guardianId}
WS -> Dashboard : realtime SOS alert
Guardian -> Dashboard : acknowledge
Dashboard -> SosService : PUT /guardian/sos/{id}/acknowledge
SosService -> DB : status ACKNOWLEDGED
@enduml
+7
View File
@@ -0,0 +1,7 @@
@startuml
[*] --> TRIGGERED : User sends SOS
TRIGGERED --> ACKNOWLEDGED : Guardian acknowledges
ACKNOWLEDGED --> RESOLVED : incident handled
TRIGGERED --> RESOLVED : auto/manual close
RESOLVED --> [*]
@enduml
+45
View File
@@ -0,0 +1,45 @@
@startuml
left to right direction
actor "User\n(Visually Impaired)" as User
actor "Guardian" as Guardian
actor "Firebase FCM" as FCM
actor "Agora RTC" as Agora
actor "OpenStreetMap/OSRM" as Map
rectangle "WalkGuide System" {
usecase "Register/Login" as UCAuth
usecase "Pair Guardian and User" as UCPair
usecase "Start WalkGuide" as UCWalk
usecase "Detect Obstacle" as UCDetect
usecase "Report Location" as UCLoc
usecase "Trigger SOS" as UCSos
usecase "Read Notifications" as UCNotif
usecase "Call Partner" as UCCall
usecase "Monitor Dashboard" as UCDash
usecase "Configure AI, TTS,\nVoice Commands, Geofence" as UCConfig
usecase "Acknowledge SOS" as UCAck
usecase "Navigate Route" as UCNav
}
User --> UCAuth
Guardian --> UCAuth
Guardian --> UCPair
User --> UCPair
User --> UCWalk
UCWalk --> UCDetect : <<include>>
UCWalk --> UCLoc : <<include>>
User --> UCSos
User --> UCNotif
User --> UCCall
Guardian --> UCCall
Guardian --> UCDash
Guardian --> UCConfig
Guardian --> UCAck
User --> UCNav
UCSos --> FCM
UCNotif --> FCM
UCCall --> Agora
UCCall --> FCM
UCNav --> Map
@enduml