simplify: backend derives lifetime from day totals, app stops sending it

- backend daily PUT: no longer $set lifetime (app's local counter is unreliable after APK wipe)
- backend history GET: derives lifetime as sum of all days' totals, returns it at response level
- app: stops sending lifetime in chunks; reads it from history response
- app: refresh button on consumption pane + 'Şimdi yükle' on log pane (manual cache flush)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
TCFDONMEZ
2026-10-09 21:41:15 +03:00
co-authored by Claude
parent 8b25799d55
commit 06265bacc9
8 changed files with 144 additions and 27 deletions
+4 -4
View File
@@ -9,11 +9,12 @@ export const dynamic = "force-dynamic";
/**
* Upsert on (installationId, date), incrementally. The car sends a 2-minute delta chunk
* (not a cumulative total), so each PUT adds to the day's running totals rather than
* overwriting them. Lifetime is a snapshot — the latest one wins, so it is $set not $inc.
* overwriting them. The app does NOT send lifetime — the backend derives it as the sum of
* all days' totals when history is read, so an APK wipe that zeroes the local counter can
* never corrupt the cloud's lifetime.
*
* $setOnInsert must not touch `day` at all: $inc on `day.km` and $setOnInsert on `day`
* conflict in MongoDB ("Updating the path 'day' would create a conflict at 'day'").
* On an insert, $inc treats a missing field as 0 and adds to it, so no seed is needed.
* conflict in MongoDB. On an insert, $inc treats a missing field as 0 and adds to it.
*/
export async function PUT(request: Request) {
const denied = requireIngest(request);
@@ -24,7 +25,6 @@ export async function PUT(request: Request) {
const collection = await consumptionCollection();
const updatedAt = new Date();
const $set: Record<string, unknown> = { updatedAt };
if (record.lifetime) $set.lifetime = record.lifetime;
if (record.sohPercent !== undefined) $set.sohPercent = record.sohPercent;
await collection.updateOne(
{ installationId: record.installationId, date: record.date },
@@ -27,6 +27,17 @@ export async function GET(request: Request, context: { params: Promise<{ install
.sort({ date: -1 })
.limit(400)
.toArray();
return NextResponse.json({ records });
// Lifetime = sum of every day's totals. Derived, never stored, so a corrupted or
// stale lifetime field in any single document cannot poison the total.
const lifetime = records.reduce(
(sum, r) => ({
km: sum.km + (r.day?.km ?? 0),
kwh: sum.kwh + (r.day?.kwh ?? 0),
hours: sum.hours + (r.day?.hours ?? 0),
socDrop: sum.socDrop + (r.day?.socDrop ?? 0),
}),
{ km: 0, kwh: 0, hours: 0, socDrop: 0 },
);
return NextResponse.json({ records, lifetime });
});
}