Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
876c95d
Implement redesign follow-up fixes
elkimek May 15, 2026
02e364c
Polish redesign themes and performance
elkimek May 15, 2026
04b5c8c
Fix residual CLS on empty dashboard
elkimek May 15, 2026
2908df5
Update redesign experience
elkimek May 18, 2026
f53e081
Improve Lighthouse startup performance
elkimek May 18, 2026
1773b55
Fix empty-state Lighthouse LCP
elkimek May 18, 2026
93ccf4a
Resolve axe accessibility findings
elkimek May 18, 2026
bb7ee9d
Guard optional responsive E2E test
elkimek May 18, 2026
4ab85cc
Polish mobile touch targets
elkimek May 18, 2026
d76461b
Update guided tour for redesign
elkimek May 18, 2026
6a3dd7e
Run guided tour on first visit
elkimek May 18, 2026
ccb9fb4
Split empty and dashboard guided tours
elkimek May 18, 2026
b0b935d
Simplify empty dashboard state
elkimek May 18, 2026
f2d55be
Make empty onboarding chat first
elkimek May 18, 2026
a97ca7c
Address Greptile review findings
elkimek May 18, 2026
d56bb85
Address full-branch review findings
elkimek May 18, 2026
de1d0d7
Fix mobile theme browser chrome
elkimek May 18, 2026
99fcd0d
Add redesign changelog
elkimek May 18, 2026
2aecd6f
Fix onboarding lab import CTA
elkimek May 18, 2026
a76cf68
Adjust default dashboard widget order
elkimek May 18, 2026
46fb2f1
Show cycle widget by default for female profiles
elkimek May 18, 2026
b820048
Move cycle widget up for female profiles
elkimek May 18, 2026
7ede1fa
Fix CI after widget default changes
elkimek May 18, 2026
bea75f8
Guard service worker cache writes
elkimek May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,20 @@ WHOOP_CLIENT_ID=
# Apple Health is file-import — no credentials at all.

# ── CAMS atmosphere relay (powers the Sun Data Source `auto` mode) ──
# When set, the local /api/proxy?meteo=cams handler forwards browser
# requests to the maintainer-hosted (or self-run) getbased-uvdata
# instance, which fronts CAMS Atmospheric Composition Forecasts and
# merges Open-Meteo's hourly clouds/temp/UVI into a single response.
# The bearer is injected server-side so it never reaches the browser.
# The local /api/proxy?meteo=cams handler forwards browser requests to
# getbased-uvdata, which fronts CAMS Atmospheric Composition Forecasts
# and merges Open-Meteo's hourly clouds/temp/UVI into one response.
# By default it uses the maintainer-hosted instance:
# https://uvdata.getbased.health
# The hosted instance requires UVDATA_BEARER. The bearer is injected
# server-side, so it never reaches the browser.
#
# When unset, /api/proxy returns 503 and the app's auto-fallback chain
# moves on to Open-Meteo for clouds/temp/UVI — the user still gets data,
# just without the CAMS-quality ozone/aerosol fields (`ozoneDU` reads
# null, confidence drops from ~0.95 to ~0.65).
#
# UVDATA_UPSTREAM — base URL of the getbased-uvdata server.
# Production: https://uvdata.getbased.health
# Self-host: https://your-uvdata.example.com
# UVDATA_UPSTREAM — optional base URL override for the getbased-uvdata server.
# Leave blank for the hosted default above.
# Self-host example: https://your-uvdata.example.com
# UVDATA_BEARER — bearer token registered in the uvdata server's
# GETBASED_UVDATA_BEARER env. Treat like a credential.
# GETBASED_UVDATA_BEARER env. Required for the hosted
# default. Treat like a credential.

UVDATA_UPSTREAM=
UVDATA_BEARER=
Expand Down
32 changes: 23 additions & 9 deletions api/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

export const config = { runtime: 'edge' };

const DEFAULT_UVDATA_UPSTREAM = 'https://uvdata.getbased.health';

// Allowlisted provider URL prefixes — these always pass without further
// checks. User-configured endpoints (Custom API, decentralized Routstr
// nodes) are allowed too, but only over HTTPS with a non-private host.
Expand Down Expand Up @@ -510,20 +512,33 @@ async function handlePolarTokenRequest(payload, req) {
}
}

// CAMS atmosphere relay → getbased-uvdata (the maintainer-run instance
// behind UVDATA_UPSTREAM env). The proxy injects the bearer server-side
// so the token never reaches the browser. Hosted-only path; self-host
// users go straight via the `selfhost` Sun Data Source mode instead.
// CAMS atmosphere relay → getbased-uvdata. Defaults to the maintainer-run
// instance so Sun Data Source `auto` is genuinely CAMS-first out of the box.
// UVDATA_UPSTREAM can override the upstream, and UVDATA_BEARER is injected
// server-side when configured so the token never reaches the browser.
// Self-host users can also go straight via the `selfhost` Sun Data Source
// mode instead.
//
// env:
// UVDATA_UPSTREAM — base URL, e.g. https://uvdata.getbased.health
// UVDATA_UPSTREAM — optional base URL override, e.g. https://your-uvdata.example.com
// UVDATA_BEARER — token to send on Authorization header
async function handleCamsRelay(payload, req) {
const upstream = (typeof process !== 'undefined' && process.env?.UVDATA_UPSTREAM)
? process.env.UVDATA_UPSTREAM.replace(/\/+$/, '') : '';
const configuredUpstream = (typeof process !== 'undefined' && process.env?.UVDATA_UPSTREAM)
? process.env.UVDATA_UPSTREAM.replace(/\/+$/, '')
: '';
const upstream = configuredUpstream || DEFAULT_UVDATA_UPSTREAM;
const bearer = (typeof process !== 'undefined' && process.env?.UVDATA_BEARER) ? process.env.UVDATA_BEARER : '';
if (!upstream) {
return new Response(JSON.stringify({
error: 'CAMS relay not configured on this deploy. Set UVDATA_UPSTREAM env or use the self-host Sun Data Source mode.',
error: 'CAMS relay upstream is empty. Set UVDATA_UPSTREAM or switch Sun Data Source to Open-Meteo/manual.',
}), {
status: 503,
headers: { ...corsHeaders(req), 'Content-Type': 'application/json' },
});
}
if (!configuredUpstream && !bearer) {
return new Response(JSON.stringify({
error: 'CAMS hosted relay requires UVDATA_BEARER. Set UVDATA_BEARER for the hosted default, set UVDATA_UPSTREAM for your own relay, or switch Sun Data Source to Open-Meteo/manual.',
}), {
status: 503,
headers: { ...corsHeaders(req), 'Content-Type': 'application/json' },
Expand All @@ -542,7 +557,6 @@ async function handleCamsRelay(payload, req) {
if (time) qs.set('time', time);
const url = `${upstream}/uv?${qs.toString()}`;
const headers = { 'Accept': 'application/json' };
const bearer = (typeof process !== 'undefined' && process.env?.UVDATA_BEARER) ? process.env.UVDATA_BEARER : '';
if (bearer) headers['Authorization'] = `Bearer ${bearer}`;
try {
const res = await fetch(url, { headers });
Expand Down
Binary file modified dashboard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion data/recommendations.json

This file was deleted.

Loading