0cce1c8170
Phase 1 of unified sync scheduler: - New Prisma model GisSyncRule: per-UAT or per-county sync frequency rules with priority, time windows, step selection (T/C/N/E) - CRUD API: /api/eterra/sync-rules (list, create, update, delete, bulk) - Global default frequency via KeyValueStore - /sync-management page with 3 tabs: - Reguli: table with filters, add dialog (UAT search + county select) - Status: stats cards, frequency distribution, coverage overview - Judete: quick county-level frequency assignment - Monitor page: link to sync management from eTerra actions section Rule resolution: UAT-specific > county default > global default. Scheduler engine (Phase 2) will read these rules to automate syncs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
73 lines
2.0 KiB
TypeScript
73 lines
2.0 KiB
TypeScript
/**
|
|
* GET /api/eterra/sync-rules/scheduler — Scheduler status
|
|
*
|
|
* Returns current scheduler state from KeyValueStore + computed stats.
|
|
*/
|
|
|
|
import { prisma } from "@/core/storage/prisma";
|
|
import { NextResponse } from "next/server";
|
|
|
|
export const runtime = "nodejs";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export async function GET() {
|
|
try {
|
|
// Get scheduler state from KV (will be populated by the scheduler in Phase 2)
|
|
const kvState = await prisma.keyValueStore.findUnique({
|
|
where: {
|
|
namespace_key: { namespace: "sync-management", key: "scheduler-state" },
|
|
},
|
|
});
|
|
|
|
// Compute rule stats
|
|
const [totalRules, activeRules, dueNow, withErrors] = await Promise.all([
|
|
prisma.gisSyncRule.count(),
|
|
prisma.gisSyncRule.count({ where: { enabled: true } }),
|
|
prisma.gisSyncRule.count({
|
|
where: { enabled: true, nextDueAt: { lte: new Date() } },
|
|
}),
|
|
prisma.gisSyncRule.count({
|
|
where: { lastSyncStatus: "error" },
|
|
}),
|
|
]);
|
|
|
|
// Frequency distribution
|
|
const freqDist = await prisma.gisSyncRule.groupBy({
|
|
by: ["frequency"],
|
|
where: { enabled: true },
|
|
_count: true,
|
|
});
|
|
|
|
// County coverage
|
|
const totalCounties = await prisma.gisUat.groupBy({
|
|
by: ["county"],
|
|
where: { county: { not: null } },
|
|
_count: true,
|
|
});
|
|
|
|
const countiesWithRules = await prisma.gisSyncRule.groupBy({
|
|
by: ["county"],
|
|
where: { county: { not: null } },
|
|
_count: true,
|
|
});
|
|
|
|
return NextResponse.json({
|
|
scheduler: kvState?.value ?? { status: "not-started" },
|
|
stats: {
|
|
totalRules,
|
|
activeRules,
|
|
dueNow,
|
|
withErrors,
|
|
frequencyDistribution: Object.fromEntries(
|
|
freqDist.map((f) => [f.frequency, f._count]),
|
|
),
|
|
totalCounties: totalCounties.length,
|
|
countiesWithRules: countiesWithRules.length,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
const msg = error instanceof Error ? error.message : "Eroare server";
|
|
return NextResponse.json({ error: msg }, { status: 500 });
|
|
}
|
|
}
|