Consolidation pass: HR-only access, effective-dated mutations, data integrity guards, test suite
Reworks the app from a two-role (hr_admin/manager) model to a single HR-only role gated by profiles.is_active, fixes transfer/promote/karenz/ reorg RPCs to actually defer future-dated changes via a new pending_org_changes table instead of writing them immediately (applied by a daily Vercel Cron route), makes reorg undo append-only instead of deleting history, adds Karenz-return and history-date integrity guards, deprecates the salary column, and adds explicit schema grants + perf indexes needed to run against a fresh (non-hosted) Postgres instance. Adds vitest unit + integration test suites (the latter against a real local Supabase instance) covering all of the above, plus lint/typecheck/ build wiring (`npm run check`).
This commit is contained in:
@@ -67,36 +67,36 @@ export default async function DashboardPage() {
|
||||
upcomingReturnsRes,
|
||||
historyRes,
|
||||
] = await Promise.all([
|
||||
supabase.from("employees_directory").select("id", { count: "exact", head: true }).in("status", ["Aktiv", "Karenz"]),
|
||||
supabase.from("employees_directory").select("id", { count: "exact", head: true }).eq("status", "Karenz"),
|
||||
supabase.from("employees").select("id", { count: "exact", head: true }).in("status", ["Aktiv", "Karenz"]),
|
||||
supabase.from("employees").select("id", { count: "exact", head: true }).eq("status", "Karenz"),
|
||||
supabase
|
||||
.from("employees_directory")
|
||||
.from("employees")
|
||||
.select("id", { count: "exact", head: true })
|
||||
.gte("entry_date", yearStart)
|
||||
.lte("entry_date", yearEnd),
|
||||
supabase
|
||||
.from("employees_directory")
|
||||
.from("employees")
|
||||
.select("id", { count: "exact", head: true })
|
||||
.gte("exit_date", yearStart)
|
||||
.lte("exit_date", yearEnd),
|
||||
supabase.from("positions").select("id", { count: "exact", head: true }).eq("status", "open"),
|
||||
supabase.from("employees_directory").select("weekly_hours").in("status", ["Aktiv", "Karenz"]),
|
||||
supabase.from("employees").select("weekly_hours").in("status", ["Aktiv", "Karenz"]),
|
||||
supabase.from("divisions").select("id, name"),
|
||||
supabase.from("employees_directory").select("division_id").in("status", ["Aktiv", "Karenz"]),
|
||||
supabase.from("employees").select("division_id").in("status", ["Aktiv", "Karenz"]),
|
||||
supabase
|
||||
.from("employees_directory")
|
||||
.from("employees")
|
||||
.select("id, first_name, last_name, entry_date")
|
||||
.eq("status", "Geplant")
|
||||
.gte("entry_date", todayIso)
|
||||
.lte("entry_date", in60Iso),
|
||||
supabase
|
||||
.from("employees_directory")
|
||||
.from("employees")
|
||||
.select("id, first_name, last_name, exit_date")
|
||||
.not("exit_date", "is", null)
|
||||
.gte("exit_date", todayIso)
|
||||
.lte("exit_date", in60Iso),
|
||||
supabase
|
||||
.from("employees_directory")
|
||||
.from("employees")
|
||||
.select("id, first_name, last_name, karenz_return_date")
|
||||
.eq("status", "Karenz")
|
||||
.not("karenz_return_date", "is", null)
|
||||
@@ -148,7 +148,7 @@ export default async function DashboardPage() {
|
||||
|
||||
const historyEmployeeIds = Array.from(new Set((historyRes.data ?? []).map((h) => h.employee_id)));
|
||||
const historyEmployeesRes = historyEmployeeIds.length
|
||||
? await supabase.from("employees_directory").select("id, first_name, last_name").in("id", historyEmployeeIds)
|
||||
? await supabase.from("employees").select("id, first_name, last_name").in("id", historyEmployeeIds)
|
||||
: { data: [] as { id: string; first_name: string; last_name: string }[] };
|
||||
const employeeNameById = new Map((historyEmployeesRes.data ?? []).map((e) => [e.id, `${e.first_name} ${e.last_name}`]));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user