Files
alpenwerk-hr/app/api/cron/apply-pending-changes/route.ts
Maximilian Stubhan e958bb5c6b
Some checks failed
CI / Lint, Typen, Tests, Build (push) Failing after 5m51s
CI / Integrationstests (echtes Postgres) (push) Failing after 5m15s
Stop pretending Vercel is an option
It was never used. The repository lives on a self-hosted Gitea, which
Vercel's git integration cannot connect to at all — so the documented
route amounted to "mirror to GitHub first", and nobody did.

vercel.json is gone, and with it the branch in next.config.ts that
switched off `output: "standalone"` when the VERCEL variable was
present. That branch was the only functional trace; everything else was
documentation and comments describing a second deployment path that did
not exist.

DEPLOYMENT.md loses its "two supported ways" framing and the whole
Vercel section — about fifty lines. Several statements next to it were
stale for a different reason and are corrected in the same pass: the
outbound-firewall table still listed Supabase's pooler (the database is
a container now, nothing leaves the server), the prerequisites still
demanded an existing Supabase project, and the .env table still asked
for a pooler connection string instead of the two new passwords.

The nightly job is described as what it is — a container in
docker-compose.yml — rather than as a replacement for Vercel Cron.

Migrations keep their references: two comments from July mention Vercel
Cron, and they describe what was true when they were written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 11:02:40 +02:00

30 lines
1.4 KiB
TypeScript

import { NextResponse, type NextRequest } from "next/server";
import { asSystem } from "@/lib/db";
import { callFunction } from "@/lib/db/rpc";
// Applies effective-dated changes (Versetzung/Beförderung/Karenz/Reorg/Daten
// ändern with a future "Wirksam ab" date) once their date has arrived — see
// apply_due_pending_changes() in supabase/migrations.
//
// Gerufen wird das vom `cron`-Dienst aus docker-compose.yml, täglich um 03:00.
// Nicht im Namen einer HR-Person: es gibt keine angemeldete Sitzung, deshalb
// weist sich der Aufruf mit einem gemeinsamen Geheimnis aus (CRON_SECRET).
export async function GET(request: NextRequest) {
const authHeader = request.headers.get("authorization");
if (!process.env.CRON_SECRET || authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "Nicht autorisiert." }, { status: 401 });
}
// Kein privilegierter Zugang mehr: derselbe Datenbankbenutzer ohne
// BYPASSRLS wie überall. apply_due_pending_changes ist SECURITY DEFINER
// und prüft selbst, was sie tut — der Dienstschlüssel, der RLS aushebelte,
// ist damit entfallen.
try {
const applied = await asSystem((tx) => callFunction(tx, "apply_due_pending_changes"));
return NextResponse.json({ applied });
} catch (err) {
console.error("apply_due_pending_changes failed:", err);
return NextResponse.json({ error: "Interner Fehler." }, { status: 500 });
}
}