跳到正文
DEV Community· omar rifaie·· 3 小時前AI 評分48

我如何為 Haven 復康教練建構後端:贏得 Best Use of Tiger Data 獎

How I Built the Backend for Haven, a Rehab Coach That Won Best Use of Tiger Data

AI 導讀

作者為乳癌手術後復康教練 Haven 建構後端,並以 Tiger Cloud 儲存及處理手臂活動時間序列數據,贏得 Best Use of Tiger Data 獎。系統使用即時連續彙總支援治療師儀錶板,並由 Gemini 根據計算所得的統計數據撰寫患者摘要和治療師報告,不查看影片,也不判斷安全標記。

正文

This is a submission for the MLH x DEV Writing Challenge

What I Built

Haven is a post-mastectomy rehab coach that lives at home with the patient. After breast cancer surgery, most shoulder rehab happens alone, and between visits a physical therapist can't see how high the arm got, whether it hurt, or whether a limit was crossed. In one randomized trial, 85.7% of patients on an early, tailored exercise program regained full shoulder strength within six months, compared with 17.9% on usual care (Min et al., JAMA Surgery, 2024). Haven is built to bring that kind of guidance home.

A laptop camera and a wearable armband guide each exercise, keep the patient inside the limits their PT set, and give the PT a clear picture of recovery. I built Haven with Mohamed Abdelmaksoud, who led the ESP32 armband hardware and firmware, and Mario Sinclair, who led the in-browser computer vision and dashboard. I focused on the backend: a Node.js, Express, and TypeScript API deployed as a single Vercel function, the data layer on Tiger Cloud, the Gemini written reports, and Auth0 sign-in.

The biggest lesson was that health tech runs on trust. Patients need to trust their feedback, clinicians need to trust that their limits reach the patient, and everyone needs to trust the AI. So deterministic code raises every safety flag, and Gemini only writes the wording.

Demo

Partner Technologies

Tiger Data (TimescaleDB on Tiger Cloud)

Haven is time series data at heart. The armband streams arm angle at 20 Hz, and every rep and every minute of daily arm use has a timestamp. That is roughly 20 rows a second per patient, so the schema had to handle growth from day one.

Hypertables and the columnstore. Reps, daily use, and the raw band stream are all hypertables. The band stream is the bulk of the data, so it moves to the columnstore after a day, segmented by patient so each patient's history stays contiguous, which is exactly how the dashboard reads it.

select create_hypertable('band_samples', by_range('t', interval '1 day'));

alter table band_samples set (
  timescaledb.enable_columnstore = true,
  timescaledb.segmentby = 'patient_id',
  timescaledb.orderby = 't desc'
);
call add_columnstore_policy('band_samples', after => interval '1 day');

reps and daily_use use seven day chunks, and daily_use moves to the columnstore after a week.

Continuous aggregates in real-time mode. The dashboard never scans raw reps. It reads rom_daily, a continuous aggregate that rolls every rep up by patient, exercise, arm, and the patient's local day:

create materialized view rom_daily
with (timescaledb.continuous, timescaledb.materialized_only = false) as
select
  patient_id,
  exercise_id,
  side,
  time_bucket(interval '1 day', performed_at, 'America/New_York') as day,
  max(peak_deg) as best_peak_deg,
  avg(peak_deg) as mean_peak_deg,
  count(*) as reps,
  sum(case when over_ceiling then 1 else 0 end) as reps_over_ceiling,
  sum(case when shoulder_hike or trunk_lean or elbow_bend then 1 else 0 end) as reps_with_compensation,
  avg(abs(peak_deg - imu_peak_deg)) as camera_band_gap_deg
from reps
where kind = 'exercise'
group by patient_id, exercise_id, side, time_bucket(interval '1 day', performed_at, 'America/New_York')
with no data;

select add_continuous_aggregate_policy('rom_daily',
  start_offset => interval '90 days',
  end_offset => interval '1 hour',
  schedule_interval => interval '15 minutes');

Setting materialized_only = false is what makes it real-time: the aggregate merges in rows newer than the last refresh, so a session shows up on the dashboard the moment it is saved. A second aggregate, daily_use_daily, does the same for at-home arm use.

Using Tiger Data meant the PT's dashboard stays fast as data grows, without me building a separate analytics pipeline.

Also used

  • Gemini writes the patient summary and the PT report from computed stats. It never sees video and never decides a flag. The server extracts every number from its text and checks it against the source data, sends the draft back once if anything is unsupported, and shows the PT anything still unverified. Gemini text to speech also recorded our voice coach clips.
  • Auth0 handles sign-in. Clinicians come from an allowlist, patients are linked to their care team by verified email, and the server takes limits from the PT's plan rather than from the request, so an edited request can't hide a limit break.

Hackathon Experience

We built Haven at SwampHacks XII, hosted by the University of Florida, with 483 hackers and 141 projects submitted. It was a weekend of hardware and software coming together: soldering and 3D printing on one side, API and database work on the other. What I'll remember most is the moment the camera, the armband, and the dashboard all worked together right before demo time, and then hearing Tiger Data had picked Haven for the Best Use of Tiger Data prize.

來源:DEV Community · dev.to