Sentinel
Proactive health companion that merges environmental risk (map + media + air/weather) with wearable context (sleep, stress, recovery) so people can act before they feel sick—not only after.
Team
| Name | LinkedIn Profile Link |
|---|---|
| Ngoc Viet Tien | https://www.linkedin.com/in/viettienngoc/ |
| Tran Thi Hong Hanh | https://www.linkedin.com/in/hanh-thi-hong-tran-0b886212a/ |
The problem
Health signals live in silos: news, air quality, and your watch rarely answer “Given what’s happening outside, how should I treat my body today?” Products default to reaction (symptoms, sick days). Prevention is vastly cheaper than treatment, but most apps show up only after the crash.
What we built
One narrative, six pillars—each is detailed again in Features & techniques (models and libraries).
| # | Feature | In one sentence |
|---|---|---|
| 1 | Sentinel Map | MapLibre view of incidents across France: disease-related signals from French RSS (LLM-extracted), WAQI air quality, OpenWeather temperature grid. |
| 2 | Ingest & DB | Cron jobs pull sources, normalize into Neon Postgres (incidents, biometrics, summaries, nudges, chat threads). |
| 3 | Thryve wearables 🚀 | Daily + epoch sync → rolling bio summary + rule-based flags (@acme/validators)—sleep, stress, recovery-style context, not diagnosis. |
| 4 | Companion assistant 🚀 | Mistral streaming chat with four tools (incidents, weather + live OpenWeather in France, Thryve context, Wrapped aggregates)—answers must follow tool output + Zod schemas. |
| 5 | Proactive nudges | After ingest, geo + dedupe + LLM structured decision → inbox + optional browser notifications when outside risk and inside readiness overlap. |
| 6 | Personalized Wrapped (Alan Play demo) | Synthetic employer-wellness dataset → deterministic aggregates → /wrapped story cards + optional Mistral narrative bundle; assistant exposes get_my_wrapped_context so chat and UI stay aligned. |
Features & techniques
| Feature | What users see | Models, APIs & techniques |
|---|---|---|
| Sentinel Map | Heatmap / markers: disease, pollution, pollen, weather-style incidents | MapLibre GL; Postgres via Drizzle; bbox filters shared with tools |
| RSS health ingest | New incidents from French media on the map | rss-parser + generateText (Mistral) + Output.object + newsIncidentExtractionSchema (Zod); dedupe rawRef |
| Environment grid | Per-city AQI + temperature incidents | WAQI + OpenWeather over FRANCE_ENV_GRID; heuristic severity; upsertIncidentByRawRef |
| Thryve ingest | Bio rows + rolling summary in DB | Thryve /v5/dailyDynamicValues & /v5/dynamicEpochValues; parsers + buildBioSummary + flags |
| Companion | Streaming chat, tool-backed replies, JSON UI | streamText, tool() ×4, stepCountIs(7), validateUIMessages, pipeJsonRender; IP-approx geo; conversation persist |
| Proactive nudges | In-app + optional browser notifications | Haversine ~220 km, severity gates, dedupe; generateText + proactiveNudgeDecisionSchema; rate limits |
| Wrapped | /wrapped cards, week/month, share |
Synthetic JSON, buildWrappedAggregates, generateText + wrappedStoryBundleSchema; Web Share / clipboard; assistant get_my_wrapped_context |
System overview
Data → ingest → Neon → models (batch generateText vs interactive streamText + tools) → Map, Assistant, Wrapped, notifications.
flowchart TB
subgraph sources["Data sources"]
RSS["French RSS feeds"]
WAQI["WAQI AQI"]
OWM["OpenWeather"]
TH["Thryve Web API"]
end
subgraph ingest["Ingest pipelines"]
IN1["RSS + Mistral structured extraction\n(Zod newsIncidentExtractionSchema)"]
IN2["France grid → WAQI + OWM\nheuristic severity → incidents"]
IN3["Thryve daily + epoch\nparse + rule-based bio summary"]
end
subgraph store["Persistence"]
DB[("Neon Postgres\nincidents · biometrics · summaries\nnudges · assistant threads")]
end
subgraph intelligence["Model use"]
M1["Mistral generateText + Output.object\nnews · nudges · wrapped stories"]
M2["Mistral streamText + tools\nassistant multi-step"]
end
subgraph surfaces["Product surfaces"]
MAP["Sentinel Map\nMapLibre"]
ASST["Companion\nstreaming + JSON render"]
WRAP["Wrapped\nstory cards"]
NUDGE["Inbox + browser notifications"]
end
RSS --> IN1
IN1 --> DB
WAQI --> IN2
OWM --> IN2
IN2 --> DB
TH --> IN3
IN3 --> DB
DB --> MAP
DB --> M2
M2 --> ASST
DB --> M1
M1 --> NUDGE
DB --> WRAP
M1 --> WRAP
Tech stack
| Layer | Technologies |
|---|---|
| Monorepo | Turborepo, pnpm, create-t3-turbo base |
| Web | Next.js App Router, React |
| API & types | tRPC, Zod |
| Database | PostgreSQL · Neon 🚀 · Drizzle |
| Auth | Better Auth |
| Map | MapLibre GL |
| AI | Mistral 🚀 · Vercel AI SDK (streamText, generateText + Output.object, json-render) |
| Wearables | Thryve Web API 🚀 |
| Hosting | Vercel (cron ingest + nudge evaluation) |
| Mobile (scaffold) | Expo |
Hackathon tracks
Wrapped is pillar 6 of Sentinel (employer-style recap + same assistant tools). The long standalone block duplicated the feature table; submission detail is summarized here and in Quick demo: Wrapped.
Are you submitting to a special track?
- [ ] Alan Play: Living Avatars
- [ ] Alan Play: Mo Studios
- [x] Alan Play: Personalized Wrapped — synthetic dataset,
/wrapped,get_my_wrapped_context(not live Alan production data). - [ ] Alan Play: Health App in a Prompt
- [x] Alan Precision — tool-grounded chat, structured
Output.objectpipelines, Zod + deterministic aggregates; no invented biometrics.
| Track | What we highlight |
|---|---|
| Personalized Wrapped | Narrative cards, team/league aggregates, chat Q&A via tool. |
| Precision | RSS / nudge / Wrapped schemas; validation and rule-based bio flags alongside the LLM. |
Quick demo: Wrapped
- Sign in (seeded personas:
pnpm -F @acme/nextjs seed:personas— seeapps/nextjs/scripts/seed-persona-users.ts; unmapped users get a stable synthetic member id). MISTRAL_API_KEYin repo root.env.- Open
/wrappedor use the app chrome linking to Wrapped. - Optional: regenerate synthetic data —
pnpm -F @acme/nextjs wrapped:gen-dataset
What we'd do next
- Prevention score / single briefing screen — Map risk + wearable readiness in one glance.
- Deep links — Incident on map → assistant with context; stronger notification CTAs.
- B2B view — Anonymized office/regional signals for HR / insurers.
- Mobile push — Expo + same nudge API.
- Voice — Speech-to-text into assistant.
Built With
- mistral
- neon
- nextjs
- postgresql
- react
- thryve
- vercel
Log in or sign up for Devpost to join the conversation.