Skip to main content

๐Ÿ“ Architecture Overview

Distributed, Event-Driven, GPU-Accelerated

:::tip TL;DR

  • Client (Flutter) requests an upload path, then uploads one video file โ†’ Firebase Storage
  • A Cloud Function triggers on upload, creates/updates a job, and dispatches it to RunPod serverless GPU workers
  • GPU workers run the Python AI pipeline, write results back to Storage, and a result trigger marks the Firestore job complete
  • The app gets real-time updates via Firestore listeners โ€” no polling :::

AceSense is built on a modern cloud-native architecture designed for scalability, reliability, and cost-efficiency. This document provides a comprehensive overview of the system design.


๐ŸŽฏ Design Principlesโ€‹

:::info Core Principles

  1. Event-Driven: All processing is triggered by events (uploads, completions)
  2. Stateless Compute: Each uploaded video job is processed independently
  3. Horizontal Scaling: GPU instances scale based on demand
  4. Fail-Safe: Failed processing can be retried without side effects
  5. Cost-Optimized: Pay only for actual GPU usage on RunPod :::

๐Ÿ—๏ธ High-Level Architectureโ€‹


๐Ÿ“Š Data Flowโ€‹

Video Upload Flowโ€‹


๐Ÿ”ง Component Deep Diveโ€‹

Client Applicationsโ€‹

ComponentTechnologyResponsibility
UI LayerFlutter WidgetsScreen rendering, user interaction
State LayerProviderApp state, business logic
Service LayerDartFirebase SDK, REST calls
Data LayerDart ModelsType-safe data structures
CameraPlatform ChannelsNative camera access

Firebase Servicesโ€‹

See firebase-functions/overview.md for the complete function list, trigger types, and the GDPR-flow (export / delete) details.

GPU Processing Pipelineโ€‹

The pipeline uses a Stage Strategy Pattern: four abstract base stages (BallTracker, SurfaceDetector, EventDetector, PhysicsModel) defined in src/pipeline/stage_base.py, with concrete implementations under src/stages/. The checked-in config is games/tennis/config.yaml, and the entry point is process_video(sport="tennis", ...) in src/pipeline/game_processor.py. See GPU Backend for implementation detail.

Status (2026-05-05): Phase 6 output generation is ported. The modular pipeline emits: events_timeline.json, ball_trajectory_3d.json, annotated video, PDF report, per-shot directories, trimmed match video, and insights.json (AI insight engine โ€” ranked insight candidates with text and implication). MediaPipe pose sequences, ML shot classification probabilities, and swing motion analysis require a GPU environment; they are absent in CPU-only runs but emitted as per-shot data when running on GPU.

Phase 6 output artifactsโ€‹

ArtifactDescription
events_timeline.jsonOrdered list of match events (shots, bounces, serves, point ends) with frame indices and metadata
ball_trajectory_3d.jsonBall position in 3D court space per frame, derived via homography from 2D detections
Annotated videoSource video with overlaid court keypoints, ball track, player bounding boxes, and event labels
PDF report8-page editorial match report (Match Pass cover + 7 body pages) built by src/export/report_generator.py
Per-shot directoriesOne sub-directory per detected shot containing trimmed clip, pose data, and shot-level JSON
Trimmed match videoMatch-length video with dead time removed
insights.jsonAI insight engine output โ€” ranked candidates with featured (top insight) and secondary list, each with text, implication, level (2=comparison, 3=implication), and score

๐Ÿ“ฌ User Feedback Pipelineโ€‹

Out-of-band channel for users to flag bugs, request features, or rate docs pages. App feedback writes directly to Firestore; docs feedback posts to the admin-gated docs server, which writes with Admin SDK. It does not touch the GPU pipeline, RunPod, or the jobs collection.

Flowโ€‹

Collections & schemasโ€‹

CollectionProducerKey fields
feedback/{id}Flutter FirestoreService.submitFeedback()text (string, 1-10000), email, uid, createdAt
docs_feedback/{id}docsServer /__/feedbackhelpful (bool), optional note (string โ‰ค 2000), path, createdAt, userEmail

Cloud Functionsโ€‹

Both are v2 onDocumentCreated triggers in acesense-auth-function/feedback/index.ts, re-exported from index.ts.

FunctionTriggerBehavior
onFeedbackCreatedfeedback/{id} onCreateAlways alerts (skips silently when text is empty). Email contains text, user email, UID, Firestore deeplink.
onDocsFeedbackCreateddocs_feedback/{id} onCreateAlerts on ๐Ÿ‘Ž always; alerts on ๐Ÿ‘ only when a note is attached, to avoid inbox spam.

Both build a brand-styled HTML + plaintext email and call the shared enqueueEmail() helper, which writes to mail/{id} โ€” picked up by the Trigger Email from Firestore extension and dispatched via SMTP (Resend, verified acesense.io) to admin@acesense.io.

Firestore rulesโ€‹

feedback/ is admin-read and authenticated-create. docs_feedback/ is admin-read and server-created only; the Docusaurus widget posts to /__/feedback, and docsServer verifies the admin session before writing with Admin SDK. Update and delete are denied so feedback can't be tampered with after submission.

match /feedback/{id} {
allow read: if isAdmin();
allow create: if request.auth != null
&& request.resource.data.text is string
&& request.resource.data.text.size() > 0
&& request.resource.data.text.size() <= 10000;
allow update, delete: if false;
}

match /docs_feedback/{id} {
allow read: if isAdmin();
allow create, update, delete: if false;
}

Source filesโ€‹

  • acesense-auth-function/feedback/index.ts โ€” both Cloud Functions
  • acesense-auth-function/index.ts โ€” re-exports
  • acesense-frontend/firestore.rules โ€” feedback/ + docs_feedback/ rule blocks
  • acesense-frontend/lib/services/firestore_service.dart โ€” submitFeedback() (writes to feedback/)
  • acesense-docs/functions/index.js โ€” verifies docs admin sessions and writes docs_feedback/
  • acesense-docs/website/src/components/DocFeedback.tsx โ€” posts to /__/feedback

๐Ÿ” Security Architectureโ€‹

LayerMechanismDetails
TransportTLS 1.3All traffic encrypted
AuthenticationFirebase AuthGoogle OAuth 2.0
AuthorizationSecurity RulesDocument-level access control
StorageGCS EncryptionAES-256 at rest
SecretsSecret ManagerAPI keys, credentials

๐Ÿ“ˆ Scalabilityโ€‹

Auto-Scaling Configurationโ€‹

MetricScale Up ThresholdScale Down Threshold
Queue Depth> 10 pending jobs< 2 pending jobs
Processing Time> 5 min averageN/A
GPU Utilization> 80%< 20% for 10 min
Max Workers101 (always-on)

๐Ÿ”— Integration Pointsโ€‹

SystemIntegrationProtocol
RunPodJob dispatch & statusREST API
FirebaseAuth, Storage, FirestoreSDK
FCMPush notificationsFirebase SDK
AnalyticsUsage trackingFirebase Analytics
api.acesense.ioPublic REST + MCP surfaceHTTPS rewrite โ†’ apiServer / mcpServer Cloud Functions

Public API surface (api.acesense.io)โ€‹

The acesense-api-hosting repository owns a Firebase Hosting site (target api, site acesense-prod-api) that fronts api.acesense.io. It carries no application code โ€” firebase.json rewrites traffic to two Cloud Functions defined in acesense-auth-function:

  • https://api.acesense.io/v1/** โ†’ apiServer (Express, europe-west1); Firebase Hosting preserves the /v1 prefix for Express routing.
  • https://api.acesense.io/mcp โ†’ mcpServer (europe-west1); Model Context Protocol endpoint consumed by external agents.
  • API keys are minted in the Admin panel (/admin-api-keys), stored in Firestore, and scoped per user.

See architecture/api-reference.md for full request/response schemas.


๐ŸŽฏ Next Stepsโ€‹