Skip to content

Feedback Technical Architecture

neil warner edited this page Oct 12, 2026 · 2 revisions

๐Ÿ› ๏ธ Feedback Technical Architecture & Telemetry Pipelines

Target Audience: Core Engineers & System Architects
Related Non-Technical Guide: User Feedback & Private Prayer Triage
Private Triage Repository: njwandroid/selahfeedback


๐Ÿ—๏ธ Architecture & Data Flow Overview

graph TD
    A[Client UI EmojiFeedbackDialog] -->|User Tap / BetterFeedback| B(FeedbackService Dart)
    B -->|Upload PNG Asset| C[GitHub Contents API PUT<br/>/contents/feedback_assets/fileName.png]
    C -->|Commit SHA & URL| B
    B -->|Create Issue POST| D[GitHub Issues API<br/>/repos/njwandroid/selahfeedback/issues]
    B -->|Firestore REST POST| E[(Cloud Firestore user_feedback)]
    B -->|Doorbell.io REST POST| F[Doorbell.io Webhook / Email]
    G[Firebase Remote Config] -->|github_feedback_token| B
    H[api.ipify.org] -->|public_ip discovery| B
Loading

๐Ÿ”’ Security & Dynamic Token Management

  1. Zero Plaintext Secrets in Repository:

    • The GitHub Personal Access Token is stored in Firebase Remote Config under key github_feedback_token.
    • On app startup, RemoteConfigService fetches and activates the parameter dynamically.
    • The token resides in volatile memory and encrypted cache โ€” never in git history or client source files.
  2. Automated Screenshot Asset Upload:

    • Endpoint: PUT https://api.github.com/repos/njwandroid/selahfeedback/contents/feedback_assets/{fileName}
    • Headers:
      • Authorization: Bearer <github_feedback_token>
      • Accept: application/vnd.github.v3+json
      • User-Agent: Selah-Scripture-Audio-Meditation/0.3.1
    • Payload:
      {
        "message": "chore(feedback): upload screenshot asset {fileName}",
        "content": "<base64_encoded_png_bytes>",
        "branch": "main"
      }
    • Markdown Image Embedding: The issue body embeds the uploaded asset using session-authenticated GitHub blob links:
      ![User Feedback Screenshot](https://github.com/njwandroid/selahfeedback/blob/main/feedback_assets/{fileName}?raw=true)
      ๐Ÿ”— [View Screenshot in Repository](https://github.com/njwandroid/selahfeedback/blob/main/feedback_assets/{fileName})
      Note: We intentionally avoid raw.githubusercontent.com URLs because GitHub private repositories return HTTP 404 for unauthenticated raw requests.
  3. Client IP & Device Context:

    • Discovery Service: AppDeviceInfoService.getClientContext()
    • Public IP: Discovered via https://api.ipify.org?format=json with a 2-second connection timeout, falling back gracefully to 'unavailable' (or '127.0.0.1' during unit test fixtures).
    • Hardware Profiling: Attaches platform, app_version, device_model, and nps to every reflection note.
  4. Multi-Channel Fanout & Fallbacks:

    • Firestore REST: Written to projects/selahwordapp/databases/(default)/documents/user_feedback for analytics querying.
    • Doorbell.io: Gracefully bypassed if DOORBELL_APP_ID is not supplied in the environment.
    • GitHub Issues: Primary triage channel with automatic labeling (user-feedback, happy/neutral/sad, screenshot, platform:web/platform:ios/platform:android).

๐Ÿงช Automated Testing & Verification Baseline

  • Unit Test: test/unit/github_feedback_test.dart
    • Asserts HTTP PUT screenshot upload payload with base64 validation.
    • Asserts issue creation payload, label arrays, and IP telemetry injection.
    • Asserts markdown embedding format.
  • Coverage: 87/87 tests passing green (100%); flutter analyze: 0 warnings.

Clone this wiki locally