Files
Nora da488b2cb0 feat(time-tracking): add cron route for time-tracking smartsheet sync (cycle 8)
Mirrors the /api/water-log/smartsheet-sync route so time entries
eventually reach the customer's Smartsheet workbook even when the
worker loses connectivity between clock-out and the realtime push.

- New route: /api/time-tracking/smartsheet-sync — drains pending
  sync queue rows for every brand with sync_enabled = true.
- Per-frequency gating lives inside runScheduledTTSync:
  realtime = backstop only; every_15_min / hourly skip cleanly
  when not yet due (literal `skipped === true` branch).
- Auth: Bearer $SMARTSHEET_CRON_SECRET (falls back to $CRON_SECRET).
- Optional body { brandId? } for 'Retry now' admin button.
- Schedule: */15 * * * * in vercel.json (same cadence as water-log).

Co-authored-by: cyc8-bot <bot@routecomm>
2026-07-03 19:26:18 -06:00

69 lines
2.1 KiB
JSON

{
"framework": "nextjs",
"buildCommand": "npm run build",
"devCommand": "npm run dev",
"installCommand": "npm install",
"regions": ["iad1"],
"crons": [
{
"path": "/api/wholesale/webhooks/dispatch",
"schedule": "*/12 * * * *"
},
{
"path": "/api/wholesale/notifications/send",
"schedule": "*/5 * * * *"
},
{
"path": "/api/wholesale/notifications/pickup-reminder",
"schedule": "0 8 * * *"
},
{
"path": "/api/square/process-queue",
"schedule": "*/2 * * * *"
},
{
"path": "/api/water-log/smartsheet-sync",
"schedule": "*/15 * * * *"
},
{
"path": "/api/time-tracking/smartsheet-sync",
"schedule": "*/15 * * * *"
},
{
"path": "/api/email-automation/abandoned-cart",
"schedule": "0 */6 * * *"
},
{
"path": "/api/email-automation/welcome-sequence",
"schedule": "0 */6 * * *"
},
{
"path": "/api/cron/send-scheduled",
"schedule": "0 9 * * *"
}
],
"headers": [
{
"source": "/api/(.*)",
"headers": [
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "X-XSS-Protection", "value": "1; mode=block" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
]
},
{
"source": "/(.*)",
"headers": [
{ "key": "X-DNS-Prefetch-Control", "value": "on" },
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload" },
{ "key": "X-Permitted-Cross-Domain-Policies", "value": "none" },
{ "key": "Content-Security-Policy", "value": "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://*.supabase.co https://*.resend.com https://*.stripe.com" }
]
}
],
"rewrites": [
{ "source": "/api/stripe/webhook", "destination": "/api/stripe/webhook" },
{ "source": "/api/resend/webhook", "destination": "/api/resend/webhook" }
]
}