| name | cron-pull-template |
| category | backend |
| version | 1.0.0 |
| priority | P3 |
| auto_load | false |
| triggers | ["creating a new scheduled data-sync / \"pull\" cron route","a section depends on external data but has no refresh cron","adding an entry to vercel.json crons"] |
| description | Apply this skill WHEN scaffolding a new cron "pull" route that syncs external/derived data into
Supabase on a schedule (Vercel cron). Encodes the Unite-Hub cron invariants: CRON_SECRET auth,
FOUNDER_USER_ID actor, overlap safety, idempotent upsert, last-sync timestamp, and failure
surfacing. Generic `cron-scheduler` covers scheduling; this covers the PULL handler body. P3.
|
| context | fork |
Cron Pull Template
The Default Being Overridden
Left unchecked, LLMs default to:
- Cron handlers with no auth (anyone can trigger them)
- Non-idempotent inserts that duplicate rows on re-run
- Silent failures — a broken pull looks identical to "no new data"
This skill overrides those with: authenticated, idempotent, observable pulls.
ABSOLUTE RULES (Never Violate)
NEVER ship a cron route without the CRON_SECRET Bearer guard.
NEVER use a session/getUser() in a cron — there is no session; use FOUNDER_USER_ID.
ALWAYS upsert idempotently (on a natural key) so a re-run cannot duplicate data.
ALWAYS record a last-sync timestamp and surface failures (do not swallow).
Canonical handler shape
import { NextResponse } from 'next/server'
import { createServiceClient } from '@/lib/supabase/service'
export const dynamic = 'force-dynamic'
export const maxDuration = 300
export async function GET(request: Request) {
const authHeader = request.headers.get('authorization')
if (authHeader !== `Bearer ${process.env.CRON_SECRET?.trim()}`) {
return NextResponse.({ : }, { : })
}
founderId = process..
(!founderId) .({ : }, { : })
supabase = ()
{
rows = ()
mapped = rows.( ({ ...r, : founderId }))
{ error } = supabase
.()
.(mapped, { : })
(error) error
supabase.().({
: founderId, : , : mapped., : ().(),
})
.({ : , : mapped., : })
} (e) {
supabase.().({
: founderId, : , : (e), : ().(),
})
.({ : , : (e) }, { : })
}
}