feat: tambah endpoint stale-villages untuk deteksi desa tidak aktif

This commit is contained in:
2026-05-28 14:14:35 +08:00
parent 3272ecaef3
commit 619cc9a403

View File

@@ -1510,6 +1510,66 @@ const MonitoringServer = new Elysia({ prefix: "/api/monitoring" })
}
)
.get("/stale-villages", async ({ query, set }) => {
const VALID_DAYS = [7, 14, 30];
const days = VALID_DAYS.includes(Number(query.days)) ? Number(query.days) : 7;
try {
const data = await prisma.$queryRaw`
SELECT
v."id",
v."name",
MAX(ul."createdAt") AS "lastActivity"
FROM "Village" v
LEFT JOIN "User" u ON u."idVillage" = v."id" AND u."idUserRole" != 'developer'
LEFT JOIN "UserLog" ul ON ul."idUser" = u."id"
WHERE v."isDummy" = false AND v."isActive" = true
GROUP BY v."id", v."name"
HAVING MAX(ul."createdAt") < NOW() - (${days} * INTERVAL '1 day')
OR MAX(ul."createdAt") IS NULL
ORDER BY "lastActivity" ASC NULLS FIRST
` as any[];
const result = data.map((v: any) => ({
id: v.id,
name: v.name,
lastActivity: v.lastActivity ?? null,
daysSince: v.lastActivity
? Math.floor((Date.now() - new Date(v.lastActivity).getTime()) / (1000 * 60 * 60 * 24))
: null,
}));
return {
success: true,
message: "Berhasil mendapatkan data",
data: {
count: result.length,
days,
villages: result,
},
};
} catch (error) {
console.error("[stale-villages] error:", error);
set.status = 500;
return {
success: false,
message: "Terjadi kesalahan pada server",
data: null,
};
}
},
{
query: t.Object({
days: t.Optional(t.String({ description: "Threshold hari tidak aktif: 7, 14, atau 30 (default: 7)" })),
}),
detail: {
summary: "Stale Villages",
description: "Mendapatkan daftar desa aktif yang tidak ada aktivitas dalam X hari terakhir (atau belum pernah ada aktivitas sama sekali).",
tags: ["villages"],
},
}
)
// ─── API KEY MANAGEMENT ──────────────────────────────────────────────────
.get("/api-keys", async ({ set }) => {