fix(privacy): store environment coordinates at 1 decimal instead of 2

The home location of the environment module was rounded to 2 decimals,
about 1 km, which places a home in a neighbourhood rather than the town the
schema comment promised. The weather archive it feeds is gridded at 9 to
25 km, so the extra precision bought nothing.

Every stored coordinate of the module now goes through the same 1-decimal
rounding (about 11 km north-south, 7 km east-west at 50° N): the home, the
travel periods, the geocoder's results, the per-day weather rows, and a
restore of a file written with finer values. Migration 0361 rounds the
existing users, travel periods and per-day rows; running it twice changes
nothing more. The answers keep their shape, plain numbers. The API
descriptions and the schema comment say 1 decimal now.
This commit is contained in:
Marc-André Bombeck committed 2026-09-27 10:37:37 +02:00
1 parent b8e78a78b3
commit f2e32afb24
12 files changed
+347 -46

No files matched your search

+7 -4
View File
@@ -60,6 +60,7 @@
*/
import type { Prisma, PrismaClient } from "@/generated/prisma/client";
import type { EnvironmentLocationSource } from "@/generated/prisma/client";
import { roundCoarse } from "@/lib/environment/open-meteo";
/** One day's environmental observation, at the location resolved for that day. */
export interface EnvironmentContextBackupEntry {
@@ -312,8 +313,10 @@ export async function restoreEnvironmentData(
// neither bound goes near a `Date`.
startDate: entry.startDate,
endDate: entry.endDate,
lat: entry.lat,
lon: entry.lon,
// A file written before v1.39.4 carries 2-decimal coordinates; they
// come back at today's privacy floor.
lat: roundCoarse(entry.lat),
lon: roundCoarse(entry.lon),
label: entry.label,
...(entry.createdAt ? { createdAt: new Date(entry.createdAt) } : {}),
...(entry.updatedAt ? { updatedAt: new Date(entry.updatedAt) } : {}),
@@ -326,8 +329,8 @@ export async function restoreEnvironmentData(
data: payload.environmentContexts.map((entry) => ({
userId: ownerId,
date: entry.date,
lat: entry.lat,
lon: entry.lon,
lat: roundCoarse(entry.lat),
lon: roundCoarse(entry.lon),
locationLabel: entry.locationLabel,
source: entry.source,
tempMin: entry.tempMin ?? null,