From a6d7e1d87fdedace6060f5e90c3f3bf51ce9cdce Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Thu, 26 Mar 2026 22:46:50 +0200 Subject: [PATCH] fix(wds): auto-initialize queue with default cities on first access The /wds page was showing 0 cities because the KeyValueStore was empty until the scheduler ran for the first time. Now the GET endpoint initializes the queue with the 9 default cities on first access. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/api/eterra/weekend-sync/route.ts | 78 +++++++++++++++--------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/src/app/api/eterra/weekend-sync/route.ts b/src/app/api/eterra/weekend-sync/route.ts index 29e04b5..02a8c98 100644 --- a/src/app/api/eterra/weekend-sync/route.ts +++ b/src/app/api/eterra/weekend-sync/route.ts @@ -26,22 +26,58 @@ type WeekendSyncState = { completedCycles: number; }; +const FRESH_STEPS: Record = { + sync_terenuri: "pending", + sync_cladiri: "pending", + import_nogeom: "pending", + enrich: "pending", +}; + +const DEFAULT_CITIES: Omit[] = [ + { siruta: "54975", name: "Cluj-Napoca", county: "Cluj", priority: 1 }, + { siruta: "32394", name: "Bistri\u021Ba", county: "Bistri\u021Ba-N\u0103s\u0103ud", priority: 1 }, + { siruta: "114319", name: "T\u00E2rgu Mure\u0219", county: "Mure\u0219", priority: 2 }, + { siruta: "139704", name: "Zal\u0103u", county: "S\u0103laj", priority: 2 }, + { siruta: "26564", name: "Oradea", county: "Bihor", priority: 2 }, + { siruta: "9262", name: "Arad", county: "Arad", priority: 2 }, + { siruta: "155243", name: "Timi\u0219oara", county: "Timi\u0219", priority: 2 }, + { siruta: "143450", name: "Sibiu", county: "Sibiu", priority: 2 }, + { siruta: "40198", name: "Bra\u0219ov", county: "Bra\u0219ov", priority: 2 }, +]; + +/** Initialize state with default cities if not present in DB */ +async function getOrCreateState(): Promise { + const row = await prisma.keyValueStore.findUnique({ + where: { namespace_key: { namespace: KV_NAMESPACE, key: KV_KEY } }, + }); + if (row?.value && typeof row.value === "object") { + return row.value as unknown as WeekendSyncState; + } + // First access — initialize with defaults + const state: WeekendSyncState = { + cities: DEFAULT_CITIES.map((c) => ({ ...c, steps: { ...FRESH_STEPS } })), + totalSessions: 0, + completedCycles: 0, + }; + await prisma.keyValueStore.upsert({ + where: { namespace_key: { namespace: KV_NAMESPACE, key: KV_KEY } }, + update: { value: state as unknown as Prisma.InputJsonValue }, + create: { + namespace: KV_NAMESPACE, + key: KV_KEY, + value: state as unknown as Prisma.InputJsonValue, + }, + }); + return state; +} + /** * GET /api/eterra/weekend-sync * Returns the current queue state. */ export async function GET() { // Auth handled by middleware (route is not excluded) - const row = await prisma.keyValueStore.findUnique({ - where: { namespace_key: { namespace: KV_NAMESPACE, key: KV_KEY } }, - }); - - if (!row?.value) { - return NextResponse.json({ state: null }); - } - - // Enrich with DB feature counts per city - const state = row.value as unknown as WeekendSyncState; + const state = await getOrCreateState(); const sirutas = state.cities.map((c) => c.siruta); const counts = await prisma.gisFeature.groupBy({ @@ -99,21 +135,7 @@ export async function POST(request: Request) { priority?: number; }; - // Load current state - const row = await prisma.keyValueStore.findUnique({ - where: { namespace_key: { namespace: KV_NAMESPACE, key: KV_KEY } }, - }); - - const state: WeekendSyncState = row?.value - ? (row.value as unknown as WeekendSyncState) - : { cities: [], totalSessions: 0, completedCycles: 0 }; - - const freshSteps: Record = { - sync_terenuri: "pending", - sync_cladiri: "pending", - import_nogeom: "pending", - enrich: "pending", - }; + const state = await getOrCreateState(); switch (body.action) { case "add": { @@ -134,7 +156,7 @@ export async function POST(request: Request) { name: body.name, county: body.county ?? "", priority: body.priority ?? 3, - steps: { ...freshSteps }, + steps: { ...FRESH_STEPS }, }); break; } @@ -145,14 +167,14 @@ export async function POST(request: Request) { case "reset": { const city = state.cities.find((c) => c.siruta === body.siruta); if (city) { - city.steps = { ...freshSteps }; + city.steps = { ...FRESH_STEPS }; city.errorMessage = undefined; } break; } case "reset_all": { for (const city of state.cities) { - city.steps = { ...freshSteps }; + city.steps = { ...FRESH_STEPS }; city.errorMessage = undefined; } state.completedCycles = 0;