diff --git a/ios/fastlane/report.xml b/ios/fastlane/report.xml index b93922a..58f0bb5 100644 --- a/ios/fastlane/report.xml +++ b/ios/fastlane/report.xml @@ -5,22 +5,22 @@ - + - + - + - + diff --git a/worker/src/components/dashboard/dashboard-shell.tsx b/worker/src/components/dashboard/dashboard-shell.tsx index 5ebb6bc..cda9f7d 100644 --- a/worker/src/components/dashboard/dashboard-shell.tsx +++ b/worker/src/components/dashboard/dashboard-shell.tsx @@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -type WindowKey = "24h" | "7d" | "30d"; +type WindowKey = "24h" | "7d"; type PacketTypeEntry = { key: string; @@ -91,7 +91,6 @@ type DashboardResponse = { const WINDOW_OPTIONS: Array<{ key: WindowKey; label: string }> = [ { key: "24h", label: "24h" }, { key: "7d", label: "7 days" }, - { key: "30d", label: "30 days" }, ]; const PACKET_TYPE_INFO: Record = { diff --git a/worker/worker/index.ts b/worker/worker/index.ts index 0d316e4..f91f43c 100644 --- a/worker/worker/index.ts +++ b/worker/worker/index.ts @@ -4,6 +4,7 @@ import { extractCfGeo, jsonHeaders, loadDashboardSummary, + purgeOldReports, validateIngestPayload, type Env, type IngestPayload, @@ -82,6 +83,9 @@ async function handleIngest(request: Request, env: Env): Promise { const result = await env.DB.prepare(REPORT_INSERT_SQL).bind(...values).run(); const changes = Number((result.meta as { changes?: number }).changes ?? 0); + // Purge reports older than 7 days (best-effort, don't block response) + void purgeOldReports(env).catch(() => {}); + return Response.json( { ok: true, @@ -107,7 +111,7 @@ async function handleDashboard(request: Request, env: Env): Promise { const url = new URL(request.url); const windowParam = url.searchParams.get("window"); const summary = await loadDashboardSummary(env, windowParam); - const cacheTtl = windowParam === "7d" || windowParam === "30d" ? 86400 : 60; + const cacheTtl = windowParam === "7d" ? 86400 : 60; return Response.json( { generatedAt: new Date().toISOString(), diff --git a/worker/worker/stats.ts b/worker/worker/stats.ts index 331bfbe..aa11bd6 100644 --- a/worker/worker/stats.ts +++ b/worker/worker/stats.ts @@ -85,13 +85,10 @@ const WINDOW_OPTIONS = { durationMs: 7 * 24 * 60 * 60 * 1000, bucket: "day", }, - "30d": { - label: "Last 30 days", - durationMs: 30 * 24 * 60 * 60 * 1000, - bucket: "day", - }, } as const; +const RETENTION_MS = 7 * 24 * 60 * 60 * 1000; + export const jsonHeaders = { "content-type": "application/json; charset=utf-8", } as const; @@ -269,8 +266,7 @@ export function buildWindowFilter( ): WindowFilter { const windowKey = requestedWindow === "24h" || - requestedWindow === "7d" || - requestedWindow === "30d" + requestedWindow === "7d" ? requestedWindow : "24h"; const option = WINDOW_OPTIONS[windowKey]; @@ -282,6 +278,19 @@ export function buildWindowFilter( }; } +export async function purgeOldReports( + env: Env, + now: Date = new Date(), +): Promise { + const cutoff = new Date(now.getTime() - RETENTION_MS).toISOString(); + const result = await env.DB.prepare( + "DELETE FROM reports WHERE window_end < ?", + ) + .bind(cutoff) + .run(); + return Number((result.meta as { changes?: number }).changes ?? 0); +} + export async function loadDashboardSummary( env: Env, requestedWindow: string | null,