POST /api/cron/expire-questions:
- Auth via Authorization: Bearer ${CRON_SECRET} (Vercel injecteert dit
automatisch wanneer de env-var op de project-omgeving staat); 401 als secret
niet matcht of niet is gezet (faal-veilig — geen open endpoint in dev)
- updateMany op claude_questions WHERE status='open' AND expires_at<now →
'expired'
- Bonus: zelfde route ruimt M10 login_pairings op (status='pending' AND
expires_at<now → 'cancelled'). Eén cron-job is goedkoper qua Vercel-budget
en houdt cleanup-strategie centraal — opvolg-actie uit M10 dat geparkeerd was.
Config:
- vercel.json: crons-entry { path: '/api/cron/expire-questions', schedule: '0 */6 * * *' } (4x/dag)
- lib/env.ts: CRON_SECRET als optional in Zod-schema
- .env.example: documentatie + openssl rand-tip
Tests __tests__/api/cron-expire-questions.test.ts (4 cases):
- 401 zonder Authorization-header
- 401 met verkeerde secret
- 401 als CRON_SECRET niet is gezet (faal-veilig)
- 200 met juiste secret: response { expired_questions, expired_pairings, ran_at }
+ beide updateMany WHERE/data correct
Quality gates: lint 0 errors, tsc clean, vitest 151/151.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
22 lines
852 B
TypeScript
22 lines
852 B
TypeScript
import { z } from 'zod'
|
|
|
|
const envSchema = z.object({
|
|
DATABASE_URL: z.string().min(1, 'DATABASE_URL is required'),
|
|
DIRECT_URL: z.string().optional(),
|
|
SESSION_SECRET: z.string().min(32, 'SESSION_SECRET must be at least 32 characters'),
|
|
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
// M11 (ST-1107) — gedeeld geheim tussen Vercel cron-trigger en
|
|
// /api/cron/expire-questions. In productie verplicht; lokaal dev mag missen
|
|
// (de cron-route geeft 401 als de header niet matcht).
|
|
CRON_SECRET: z.string().optional(),
|
|
})
|
|
|
|
const parsed = envSchema.safeParse(process.env)
|
|
|
|
if (!parsed.success) {
|
|
console.error('❌ Invalid environment variables:')
|
|
console.error(parsed.error.flatten().fieldErrors)
|
|
throw new Error('Invalid environment variables. Check .env.local.')
|
|
}
|
|
|
|
export const env = parsed.data
|