Vectra is a Fitness Coach Client Management System that combines coach account management, client tracking, plan creation, and AI-powered form analysis in a single workspace. It uses a React + Vite frontend, a FastAPI backend, MediaPipe-based pose analysis, Azure Blob Storage for media and generated PDFs, Azure Database for PostgreSQL for persistence, and Azure Queue Storage with a worker for async form-analysis processing.
The current release supports a broader coaching workflow while still shipping squat analysis first under the generalized FormAnalysis domain.
The current frontend uses a desktop-first coach workspace model with a KPI-only dashboard, client-owned operational workflows, and a Slate + Electric Blue visual system with lucide-react icons.
- Lets coaches sign up and sign in with email + password
- Lets coaches create and manage their own client roster
- Lets coaches update client profile data and current goal
- Lets coaches upload and review weekly/monthly client progress photos on a timeline
- Lets coaches create weekly or monthly nutrition plans
- Lets coaches create weekly or monthly workout plans
- Lets coaches download nutrition and workout plans as PDF
- Lets coaches upload client squat videos for async form analysis
- Generates annotated frames, rule-based findings, corrective cues, and coach feedback notes
- Lets coaches review client-specific analysis history and download analysis reports as PDF
- Gives coaches a hover-expanding side navigation rail and a calmer, sport-oriented UI palette
- Real coach signup/signin via
/auth/signupand/auth/signin - Coach-owned clients only; clients do not sign in yet
- Dashboard is a KPI and navigation surface only; uploads and dense review workflows live inside client workspaces
- Client profile editing
- Current-goal tracking
- Progress-photo timeline inside the client
Profiletab - Client detail workspace split into:
ProfileNutritionWorkoutForm Analysis
Recent Analysisremains a cross-client library for reopening past analyses inside the relevant client workspace
- React + Vite + TypeScript SPA
- Shared hover-expanding side navigation via
vectra-ui/src/components/SideNav.tsx - Shared UI tokens in
vectra-ui/src/theme.ts lucide-reacticons for navigation, KPI cards, actions, tabs, empty states, and status surfaces- Slate + Electric Blue palette:
- slate/navy structure
- electric-blue primary actions and active states
- ice-blue muted surfaces
- gradients used sparingly for page/nav/brand depth
- Nutrition plans are managed in a dedicated client
Nutritiontab - Workout plans are managed in a dedicated client
Workouttab - Nutrition and workout plans are stored as separate versioned snapshots
- Each plan supports:
weeklymonthly
- Each plan can be exported as PDF
- Client-specific form analysis is managed in the client
Form Analysistab - Async queue-driven analysis lifecycle:
queuedrunningcompletedfailed
- Generalized backend naming now uses form analyses
- Squat is the currently implemented analysis type
- Deadlift is a planned extension point, not implemented yet
- React
- TypeScript
- Vite
- lucide-react
- FastAPI
- Python
- OpenCV
- MediaPipe Pose Landmarker
- Azure Blob Storage for:
- uploaded videos
- extracted frames
- annotated frames
- client progress photos
- nutrition plan PDFs
- workout plan PDFs
- Azure Database for PostgreSQL Flexible Server for:
- users
- coaches
- clients
- client goals
- progress photo metadata
- nutrition plans
- workout plans
- form analyses
- Azure Queue Storage for async analysis dispatch
- Azure Container Apps Job or local worker for queue-driven processing
- Poison queue handling through
analysis-jobs-poisonfor terminal failures
MobilityDetectionSystem/
├── mobility-ai-service/
│ ├── analyzers/
│ ├── config/
│ ├── repositories/
│ ├── services/
│ ├── shared/
│ ├── tests/
│ ├── app.py
│ ├── queue_worker.py
│ ├── Dockerfile.worker
│ └── local.settings.json
├── vectra-ui/
│ ├── src/
│ └── package.json
├── Specs/
│ ├── BLOB_STORAGE_IMPLEMENTATION.md
│ ├── POSTGRES_IMPLEMENTATION.md
│ ├── QUEUE_STORAGE_IMPLEMENTATION.md
│ ├── UI_PLAN.md
│ ├── UI_PLAN1.md
│ ├── UI_PLAN2.md
│ └── WORKER_ARCHITECTURE.md
└── README.md
userscoachesclientsclient_goalsclient_progress_photos
nutrition_plansworkout_plans
form_analyses
form_analyses replaces the older business meaning of jobs while preserving the async worker model and historical backfill compatibility.
- Coach signs up or signs in from the frontend.
- Backend returns a bearer token plus coach profile data.
- Frontend stores the token and uses it for protected client, plan, and analysis requests.
- Coach creates a client.
- Coach updates profile and current goal.
- Coach uploads weekly/monthly progress photos with a capture date and optional caption.
- Coach creates weekly/monthly nutrition plans in the
Nutritiontab. - Coach creates weekly/monthly workout plans in the
Workouttab. - Backend stores progress-photo metadata and each plan as historical snapshots in Postgres.
- Coach can review prior progress photos and download a PDF version of any saved plan.
- Coach selects a client in the frontend.
- Coach opens that client's
Form Analysistab. - Coach uploads a squat video for that client.
- Backend stores the uploaded video in Azure Blob Storage.
- Backend creates a
form_analysesrecord with statusqueued. - Backend pushes a queue message to Azure Queue Storage.
- Worker claims the analysis, marks it
running, and executes the squat pipeline. - Frames are extracted and uploaded to Blob Storage.
- Pose landmarks are analyzed and squat rules are applied.
- Annotated output frames are uploaded to Blob Storage.
- Backend stores the structured result JSON and marks the analysis
completedorfailed. - Frontend polls the analysis endpoint and renders the completed result in the client workspace.
app.pycreates form-analysis records and enqueues queue messages.services/job_service.pycurrently acts as the form-analysis lifecycle service.services/queue_job_processor.pyvalidates queue payloads, claims queued analyses, and orchestrates execution.services/job_runner.pyperforms the actual squat video processing work.queue_worker.pyis the local and container worker entrypoint.
Retry and poison queue behavior:
- The worker receives messages with a visibility timeout controlled by
ANALYSIS_JOB_VISIBILITY_TIMEOUT. - Retryable failures are left on the main queue and retried based on Azure Queue
dequeue_count. - Non-retryable failures go straight to
analysis-jobs-poison. - When
dequeue_countreachesANALYSIS_JOB_MAX_DEQUEUE_COUNT, the message is moved to the poison queue and the analysis is markedfailed.
The backend reads infra settings from environment variables. For local development, mobility-ai-service/local.settings.json is auto-loaded by the FastAPI app and the queue worker when those values are not already present in the environment.
AzureWebJobsStorageorBLOB_STORAGE_CONNECTION_STRINGQUEUE_STORAGE_CONNECTION_STRING(optional ifAzureWebJobsStorageis used)BLOB_UPLOADS_CONTAINERBLOB_FRAMES_CONTAINERBLOB_ANNOTATED_FRAMES_CONTAINERANALYSIS_JOBS_QUEUE_NAMEANALYSIS_JOBS_POISON_QUEUE_NAMEANALYSIS_JOB_VISIBILITY_TIMEOUTANALYSIS_JOB_MAX_DEQUEUE_COUNTPOSTGRES_HOSTPOSTGRES_PORTPOSTGRES_DBPOSTGRES_USERPOSTGRES_PASSWORDPOSTGRES_SSLMODE
AUTH_TOKEN_SECRETAUTH_TOKEN_EXPIRATION_HOURS
- uploads container from
BLOB_UPLOADS_CONTAINER - extracted frames container from
BLOB_FRAMES_CONTAINER - annotated frames container from
BLOB_ANNOTATED_FRAMES_CONTAINER client-progress-photosnutrition-plan-pdfsworkout-plan-pdfs
- Python 3.11 recommended
- Node.js 18+
- npm
From mobility-ai-service:
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtImportant note:
- The pose model asset is expected at
mobility-ai-service/models/pose_landmarker.task.
From mobility-ai-service:
source venv/bin/activate
uvicorn app:app --reloadBackend URL:
http://localhost:8000
From mobility-ai-service:
Run once:
source venv/bin/activate
python3 queue_worker.pyRun in a simple local loop:
source venv/bin/activate
while true; do python3 queue_worker.py || true; sleep 5; doneFrom vectra-ui:
npm install
npm run devFrontend URL:
http://localhost:5173
- Create a coach account from the login screen.
- Create a client from the
Clientstab. - Open that client and add profile info, current goal, and progress photos in
Profile. - Create nutrition plans from the client
Nutritiontab. - Create workout plans from the client
Workouttab. - Upload and review squat video analyses from the client
Form Analysistab. - Use
Dashboardfor KPI summaries and navigation shortcuts.
GET /
POST /auth/signupPOST /auth/signinGET /auth/me
Legacy compatibility:
POST /login
GET /clientsPOST /clientsGET /clients/{client_id}PUT /clients/{client_id}POST /clients/{client_id}/goalsGET /clients/{client_id}/progress-photosPOST /clients/{client_id}/progress-photosGET /client-progress-photos/{blob_name}
GET /clients/{client_id}/nutrition-plansPOST /clients/{client_id}/nutrition-plansGET /nutrition-plans/{plan_id}GET /nutrition-plans/{plan_id}/pdf
GET /clients/{client_id}/workout-plansPOST /clients/{client_id}/workout-plansGET /workout-plans/{plan_id}GET /workout-plans/{plan_id}/pdf
POST /clients/{client_id}/form-analysesGET /clients/{client_id}/form-analysesGET /form-analysesGET /form-analyses/{analysis_id}PUT /form-analyses/{analysis_id}/feedbackGET /form-analyses/{analysis_id}/pdfGET /frames/{filename}
Legacy compatibility:
POST /jobs/squatGET /jobsGET /jobs/{job_id}
- Frontend auth now uses bearer tokens.
- Protected endpoints expect
Authorization: Bearer <token>. - PDF download endpoints also support
?token=<token>so browser-open download links work from the SPA. - Progress photo image URLs also support
?token=<token>so authenticated image previews can load inside the SPA.
cd mobility-ai-service
./venv/bin/python -m unittest tests.test_side_view_squat_logic tests.test_login_service tests.test_job_servicecd vectra-ui
npm run lint
npm run buildlocal.settings.jsonis for local development only.- For Azure deployment, configure the same keys as backend/container environment variables.
Dockerfile.workerbuilds the worker image that startsqueue_worker.py.- Do not rely on checked-in local secrets for production.
The repository currently has separate workflows for backend and frontend deployment.
Workflow:
.github/workflows/deploy-vectra-api.yml
Behavior:
- Runs on
pushtomainwhen files undermobility-ai-service/**change. - Can also be started manually with
workflow_dispatch. - Builds and pushes two Docker images to Azure Container Registry:
vectra-apivectra-worker
- Tags each image with both the Git SHA and
latest.
Workflow:
.github/workflows/azure-static-web-apps-black-desert-0265d2900.yml
Behavior:
- Runs only for changes under
vectra-ui/**or the frontend workflow file. - On pull requests to
main, it validates the frontend only:npm cinpm run lintnpm run build
- On
pushtomain, it deploys the production Azure Static Web App. - Pull requests do not deploy Static Web App preview or production environments.
- Merging a PR to
maincauses a single frontend production deployment from the resultingpushevent.
- Squat is the only currently implemented analysis type.
- The backend naming is moving from
jobstoform analyses; some service names still usejobfor compatibility and lower-risk migration. - Progress-photo timeline is now available in the client
Profiletab with upload, timeline grouping, and image preview support. - Nutrition and workout planning are separate client workspace tabs.
- Client-specific form analysis is the primary analysis workflow;
Recent Analysisis secondary cross-client browsing. - Dashboard is intentionally KPI/navigation-only.
- Async processing remains queue-driven and does not rely on DB polling or Azure Functions.