diff --git a/MOTORSIGNAL_CLOUD_ARCHITECTURE.md b/MOTORSIGNAL_CLOUD_ARCHITECTURE.md new file mode 100644 index 0000000..6335cf0 --- /dev/null +++ b/MOTORSIGNAL_CLOUD_ARCHITECTURE.md @@ -0,0 +1,639 @@ +# MotorSignal Cloud Architecture + +**Status:** Planning baseline +**Date:** 2026-09-01 +**Backend direction:** Firebase Authentication + Firebase cloud services, integrated with the existing local-first Flutter application + +## Purpose + +Define the cloud architecture required for MotorSignal accounts, ride backup, synchronization, profiles, friends, planned rides, trips, and group rides. + +This document intentionally favors an **offline-first** architecture. Local data remains the immediate source for recording and ride operation; cloud services provide identity, backup, synchronization, collaboration, and cross-device continuity. + +--- + +# Architectural Goals + +1. Recording must work without internet access. +2. Cloud synchronization must be resilient to intermittent connectivity. +3. A user's data must be isolated from other users by security rules. +4. Synchronization must be idempotent and safe to retry. +5. Reinstalling the app must not require recreating a user's ride history. +6. Cloud functionality must support both Free and Pro entitlements. +7. The data model must support future social/group-riding features without a major rewrite. +8. Sensitive location information must receive stronger privacy treatment than ordinary profile information. +9. Account deletion must have a defined, testable data-deletion path. +10. Raw high-volume telemetry should not automatically be treated like ordinary profile documents. + +--- + +# High-Level Architecture + +```text + MotorSignal Flutter App + │ + ┌────────────────────┴────────────────────┐ + │ │ + Local Database Cloud Services + / Local Files / Firebase + │ │ + │ ┌──────────┼──────────┐ + │ │ │ │ + │ Auth Firestore Storage + │ │ │ │ + └──────────────┬───────────────┴──────────┴──────────┘ + │ + Sync Engine + │ + Entitlement + │ + Pro / Free +``` + +--- + +# Identity + +Firebase Authentication provides the account identity. + +The internal account identifier should remain stable even if a user changes: + +- Display name. +- Username. +- Profile photo. +- Optional public location. + +Google sign-in should remain compatible with the existing application authentication flow. + +The Firebase user ID should be treated as an internal identifier, not a public username. + +--- + +# Proposed Data Model + +The exact collection structure can be refined during implementation, but the logical model should include: + +```text +users/{userId} + +users/{userId}/motorcycles/{motorcycleId} +users/{userId}/rides/{rideId} +users/{userId}/trips/{tripId} +users/{userId}/events/{eventId} +users/{userId}/friends/{friendId} +``` + +Potential future top-level collaborative resources: + +```text +groupRides/{groupRideId} +publicRoutes/{routeId} +``` + +These should only be introduced when query patterns and security requirements justify them. + +--- + +# User Document + +Conceptual fields: + +```text +id +username +displayName +profilePhotoUrl +bio +location +createdAt +updatedAt +privacySettings +preferences +``` + +Do not store sensitive secrets in the user document. + +Avoid storing a complete ride history or large telemetry payload directly inside the user document. + +--- + +# Motorcycle Document + +Conceptual fields: + +```text +id +ownerId +year +make +model +nickname +photoUrl +photoSource +photoAttribution +createdAt +updatedAt +privacy +``` + +The motorcycle should have a stable ID independent of its displayed name. + +--- + +# Ride Document + +Conceptual metadata: + +```text +id +ownerId +motorcycleId +tripId? +groupRideId? +startedAt +endedAt +duration +distance +summaryStatistics +routeReference? +telemetryReference? +createdAt +updatedAt +syncState +visibility +``` + +High-volume telemetry should not be duplicated unnecessarily across multiple Firestore documents. + +Where appropriate, use compressed/structured files in Firebase Storage and keep searchable summary metadata in Firestore. + +--- + +# Trip Document + +Conceptual fields: + +```text +id +ownerId +name +startDate +endDate +description +routeReferences +waypoints +participants +createdAt +updatedAt +visibility +``` + +Trips may contain multiple daily routes and completed rides. + +--- + +# Event Document + +For meetups and planned events: + +```text +id +ownerId +name +description +startAt +location +attendees +linkedGroupRideId? +createdAt +updatedAt +visibility +``` + +An event does not automatically imply live location sharing. + +--- + +# Friend Relationship + +Friend relationships should have explicit state. + +```text +PENDING +ACCEPTED +DECLINED +BLOCKED +``` + +Friendship should not automatically grant access to private ride data. + +Visibility remains controlled by the owner's privacy settings. + +--- + +# Group Ride + +A group ride should be a shared activity context while each rider retains ownership of their own ride record. + +Conceptually: + +```text +Group Ride + ├── Organizer + ├── Participants + ├── Route + ├── Meeting Point + ├── Schedule + ├── Live Ride State + └── Completed Ride References +``` + +A rider's individual telemetry remains associated with that rider and motorcycle. + +--- + +# Local-First Sync + +The app should never require a successful cloud write before considering a ride locally saved. + +### Write flow + +```text +User records ride + ↓ +Save locally + ↓ +Mark PENDING_UPLOAD + ↓ +Continue normal app operation + ↓ +Connectivity available + ↓ +Sync engine uploads + ↓ +Server acknowledgement + ↓ +Mark SYNCED +``` + +### Offline flow + +```text +No internet + ↓ +Record normally + ↓ +Queue cloud operation + ↓ +Internet returns + ↓ +Retry automatically +``` + +--- + +# Sync States + +Recommended common state model: + +```text +LOCAL_ONLY +PENDING_UPLOAD +SYNCED +PENDING_DELETE +CONFLICT +SYNC_FAILED +``` + +The implementation may combine or rename states, but synchronization must be observable and debuggable. + +--- + +# Idempotency + +Cloud writes must be safe to retry. + +Do not create a new ride document every time an upload request is retried. + +Use stable application-generated IDs so: + +```text +same ride ID + repeated upload = same logical ride +``` + +not: + +```text +same ride + repeated upload = duplicate rides +``` + +--- + +# Conflict Handling + +Conflicts should be rare but must be explicitly designed. + +Potential strategy: + +- Server metadata determines whether an object changed. +- Immutable ride telemetry should generally not be merged field-by-field. +- User-editable metadata can use last-write-wins or explicit conflict resolution where appropriate. +- Never silently overwrite a user's ride data without a defined policy. + +For example, if two devices edit a motorcycle nickname, last-write-wins may be acceptable. + +If two devices produce different telemetry for the same ride ID, preserve enough information to diagnose the conflict rather than silently destroying one copy. + +--- + +# Cloud Storage + +Use Firebase Storage for large binary objects where appropriate: + +- Ride telemetry files. +- Exported reports if cloud retention is required. +- Profile photos. +- Motorcycle photos where user-uploaded. +- Future ride media. + +Keep Firestore documents focused on metadata, indexes, relationships, and summaries. + +--- + +# Security Model + +Every user-owned resource must enforce ownership server-side. + +Conceptually: + +```text +request.auth.uid == resource.ownerId +``` + +or an equivalent rule based on the final data model. + +Never rely solely on Flutter UI restrictions to protect data. + +A hidden button is not a security boundary. + +--- + +# Social Security + +Friendship and group participation must not automatically permit access to all account data. + +Examples: + +- Being a friend does not expose private ride history. +- Joining a group ride does not expose a user's historical rides. +- Live location is only available during explicitly authorized group activity. +- Public profile data is distinct from private account data. + +--- + +# Location Privacy + +Ride telemetry and GPS tracks can reveal a user's home, workplace, and routine. + +The platform should support: + +- Private rides. +- Friends-only rides. +- Public rides. +- Optional location sharing. +- Home/start/end location obfuscation for shared rides. +- No continuous background social tracking merely because a user has an account. + +Live group location must require explicit participation/consent and should automatically stop at the end of the group ride. + +--- + +# Cloud Entitlements + +Cloud usage must be controlled through the centralized entitlement system. + +Example capabilities: + +```text +canCloudBackup +canUnlimitedCloudHistory +canMultiDeviceRestore +``` + +The client may use these capabilities for UX, but backend rules must also enforce limits and ownership where practical. + +Do not trust a client-provided `isPro=true` field as proof of payment. + +--- + +# Subscription / Account Separation + +A user account should continue to exist even if a Pro subscription expires. + +Conceptually: + +```text +Firebase Account + │ + ├── Profile + ├── Garage + ├── Rides + └── Entitlement + │ + ┌──────┴──────┐ + │ │ + Free Pro Monthly/Lifetime +``` + +Billing provider state determines the paid entitlement. The account owns the data. + +--- + +# Expired Pro Data Policy + +The final product policy must be defined before launch. + +Recommended direction: + +- Do not silently delete historical rides when Pro expires. +- Preserve account and existing data. +- Restrict creation/synchronization of additional premium-only data if the user exceeds Free limits. +- Allow upgrade to restore full Pro functionality. + +The exact storage allowance and retention policy must be finalized after Firebase cost modeling and legal review. + +--- + +# Backup / Restore + +Backup should be automatic where the user's entitlement allows it. + +Restore should be explicit and understandable. + +New device flow: + +```text +Install MotorSignal + ↓ +Sign in + ↓ +Authenticate + ↓ +Discover cloud account + ↓ +Download motorcycle/profile metadata + ↓ +Download ride metadata + ↓ +Download required ride data + ↓ +Rebuild local database + ↓ +Ready +``` + +The restore process should be resumable if interrupted. + +--- + +# Account Deletion + +Account deletion must be a real backend workflow. + +It should address: + +- Firebase Authentication identity. +- User profile. +- Motorcycles. +- Rides. +- Telemetry files. +- Profile photos. +- Social relationships. +- Trips/events owned by the user. +- Group ride participation data where legally/technically appropriate. + +Do not simply delete the authentication record while leaving user data orphaned indefinitely. + +--- + +# Data Export + +Provide an account-level export capability where required/appropriate. + +Potential export contents: + +- Profile information. +- Motorcycle data. +- Ride metadata. +- Ride telemetry. +- Routes. +- Trip data. + +The existing CSV/PDF ride exports are not necessarily sufficient to satisfy an account-level data export requirement. + +--- + +# Observability + +Cloud synchronization should provide enough logging to diagnose: + +- Authentication failures. +- Upload failures. +- Download failures. +- Permission-denied errors. +- Duplicate prevention failures. +- Conflict events. +- Storage failures. +- Billing/entitlement synchronization problems. + +Do not log raw sensitive telemetry or credentials unnecessarily. + +--- + +# Testing Matrix + +### Authentication + +- [ ] Fresh account. +- [ ] Existing account. +- [ ] Sign out. +- [ ] Sign in again. +- [ ] Multiple devices. +- [ ] Account deletion. + +### Offline + +- [ ] Record without internet. +- [ ] Save ride locally. +- [ ] Restore connectivity. +- [ ] Automatic upload. +- [ ] Retry after failure. + +### Sync + +- [ ] New motorcycle sync. +- [ ] Ride sync. +- [ ] Ride update. +- [ ] Ride deletion. +- [ ] Duplicate upload prevention. +- [ ] Conflict behavior. + +### Restore + +- [ ] Reinstall. +- [ ] New device. +- [ ] Large ride history. +- [ ] Interrupted restore. +- [ ] Partial network failure. + +### Security + +- [ ] User A cannot read User B's private rides. +- [ ] User A cannot write User B's data. +- [ ] Friend access respects privacy. +- [ ] Group membership does not grant historical access. +- [ ] Client cannot self-grant Pro entitlement. + +--- + +# Implementation Order + +1. Audit existing Firebase/auth implementation. +2. Document current local Room/database models. +3. Define cloud DTOs and stable IDs. +4. Define Firestore/Storage collections. +5. Write security rules before exposing new data. +6. Implement profile document. +7. Implement motorcycle synchronization. +8. Implement ride metadata synchronization. +9. Implement telemetry/blob synchronization. +10. Implement retry queue. +11. Implement conflict/error handling. +12. Implement backup status UI. +13. Implement restore. +14. Add account deletion/data export. +15. Connect cloud capability checks to entitlement manager. +16. Test Free/Pro storage behavior. +17. Add friends/social resources. +18. Add planned rides/trips. +19. Add group rides and explicit live-location sessions. + +--- + +# Design Rule + +The cloud system must make MotorSignal more reliable, not more fragile. + +The critical riding path should remain: + +```text +Sensors → Local Recording → Local Database → Ride Processing +``` + +Cloud synchronization should be downstream: + +```text +Local Ride → Sync Queue → Cloud Backup +``` + +A cloud outage must not prevent a rider from recording a ride.