Implements comprehensive scheduled sync system using node-cron with full admin interface for configuration and monitoring. Features: - Configurable sync schedules with cron expressions - Enable/disable schedules without deletion - Manual trigger for testing - Status monitoring (last run, next run, success/failure) - Error tracking and display - Incremental and full sync support - Multiple concurrent schedules - Admin UI with schedule management Components: 1. Sync Scheduler Service (lib/services/sync-scheduler.ts) - node-cron integration for scheduling - Database-backed schedule configuration - Automatic initialization on startup - Prevents concurrent runs of same schedule - Calculates next run times - Tracks execution status and errors 2. Database Schema (sync_schedules table) - Schedule configuration storage - Execution history tracking - Last run status and errors - Next run calculation 3. API Endpoints - GET /api/sync/schedules - List all schedules - POST /api/sync/schedules - Create schedule - GET /api/sync/schedules/[id] - Get schedule - PATCH /api/sync/schedules/[id] - Update schedule - DELETE /api/sync/schedules/[id] - Delete schedule - POST /api/sync/schedules/[id]/trigger - Manual trigger 4. Admin UI (components/admin/SyncScheduler.tsx) - View all schedules with status - Create/edit/delete schedules - Enable/disable toggle - Manual trigger button - Cron expression presets - Real-time status updates - Error message display - Next run countdown 5. Default Schedules (created on first startup, disabled) - Daily Incremental: 2 AM daily (0 2 * * *) - Weekly Full: 3 AM Sunday (0 3 * * 0) Admin Interface: - New 'Schedules' tab in sync page - Schedule cards with status badges - Enable/disable with play/pause button - Manual trigger with clock button - Edit dialog with cron presets - Create dialog for new schedules - Real-time status (running, next run, last run) - Success/failure indicators - Error message alerts Cron Features: - Full cron expression support - Validation before saving - Common presets (daily, weekly, hourly) - Next run time calculation - Automatic schedule restart on config change Monitoring: - Last run timestamp - Next run countdown (e.g., 'in 2h 15m') - Success/failure status with icons - Error messages for failed syncs - Running indicator (animated badge) - Schedule validity check Dependencies: - node-cron: ^3.0.3 - @types/node-cron: ^3.0.11 UI Components: - Alert component added (components/ui/alert.tsx) - Integrated into sync page tabs - Responsive design Documentation: - Complete guide (docs/SCHEDULED_SYNCS.md) - Cron expression reference - Best practices - Troubleshooting guide - API reference - Database schema Use Cases: 1. Daily incremental sync for recent changes 2. Weekly full sync for data integrity 3. Custom schedules for specific needs 4. Off-peak hour automation 5. Backup for webhook failures Benefits: - No manual intervention required - Consistent data freshness - Flexible scheduling - Easy monitoring - Error tracking - Manual override available Next Steps: 1. Restart application to initialize scheduler 2. Navigate to Admin → Sync → Schedules tab 3. Enable default schedules or create custom ones 4. Monitor first runs for success 5. Adjust schedules as needed Files Added/Modified: - lib/services/sync-scheduler.ts (new) - app/api/sync/schedules/route.ts (new) - app/api/sync/schedules/[id]/route.ts (new) - app/api/sync/schedules/[id]/trigger/route.ts (new) - components/admin/SyncScheduler.tsx (new) - components/ui/alert.tsx (new) - app/admin/sync/page.tsx (modified - added Schedules tab) - docs/SCHEDULED_SYNCS.md (new) - package.json (node-cron added)
59 lines
1.5 KiB
TypeScript
59 lines
1.5 KiB
TypeScript
import * as React from "react"
|
|
import { cva, type VariantProps } from "class-variance-authority"
|
|
|
|
import { cn } from "@/lib/utils"
|
|
|
|
const alertVariants = cva(
|
|
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
|
|
{
|
|
variants: {
|
|
variant: {
|
|
default: "bg-background text-foreground",
|
|
destructive:
|
|
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
variant: "default",
|
|
},
|
|
}
|
|
)
|
|
|
|
const Alert = React.forwardRef<
|
|
HTMLDivElement,
|
|
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
|
>(({ className, variant, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
role="alert"
|
|
className={cn(alertVariants({ variant }), className)}
|
|
{...props}
|
|
/>
|
|
))
|
|
Alert.displayName = "Alert"
|
|
|
|
const AlertTitle = React.forwardRef<
|
|
HTMLParagraphElement,
|
|
React.HTMLAttributes<HTMLHeadingElement>
|
|
>(({ className, ...props }, ref) => (
|
|
<h5
|
|
ref={ref}
|
|
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
|
{...props}
|
|
/>
|
|
))
|
|
AlertTitle.displayName = "AlertTitle"
|
|
|
|
const AlertDescription = React.forwardRef<
|
|
HTMLParagraphElement,
|
|
React.HTMLAttributes<HTMLParagraphElement>
|
|
>(({ className, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn("text-sm [&_p]:leading-relaxed", className)}
|
|
{...props}
|
|
/>
|
|
))
|
|
AlertDescription.displayName = "AlertDescription"
|
|
|
|
export { Alert, AlertTitle, AlertDescription }
|