Add tier-based scan scheduler and webhook triggers (FRE-4498)

- ScanScheduler: tier-based scheduling (BASIC=24h, PLUS=6h, PREMIUM=1h)
- WebhookHandler: HMAC-verified webhook ingestion with SCAN_TRIGGER support
- API routes: /scheduler and /webhooks endpoints under /api/v1/darkwatch
- Jobs: scheduled scan checker + webhook retry processor via BullMQ
- Schema: ScanSchedule, WebhookEvent models; ScanJob.scheduledBy field
- Types: ScheduleStatus, WebhookEventType, WebhookTriggerInput
- Tests: scheduler lifecycle + webhook signature/processing tests

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-30 10:57:56 -04:00
parent 76d431e1ec
commit 9fb5379b7a
43 changed files with 7819 additions and 93 deletions

View File

@@ -0,0 +1,35 @@
import { z } from 'zod';
import { SubscriptionTier } from '../config/billing.config';
export const SubscriptionModel = z.object({
id: z.string(),
userId: z.string(),
stripeSubscriptionId: z.string(),
stripeCustomerId: z.string(),
tier: z.nativeEnum(SubscriptionTier),
status: z.enum(['active', 'canceled', 'in_trial', 'past_due', 'unpaid', 'incomplete']),
currentPeriodStart: z.date(),
currentPeriodEnd: z.date(),
cancelAtPeriodEnd: z.boolean().default(false),
createdAt: z.date(),
updatedAt: z.date(),
});
export type Subscription = z.infer<typeof SubscriptionModel>;
export const SubscriptionCreateSchema = z.object({
userId: z.string(),
tier: z.nativeEnum(SubscriptionTier),
stripeCustomerId: z.string(),
stripeSubscriptionId: z.string(),
currentPeriodStart: z.date(),
currentPeriodEnd: z.date(),
});
export const SubscriptionUpdateSchema = z.object({
tier: z.nativeEnum(SubscriptionTier).optional(),
status: z.enum(['active', 'canceled', 'in_trial', 'past_due', 'unpaid', 'incomplete']).optional(),
cancelAtPeriodEnd: z.boolean().optional(),
currentPeriodStart: z.date().optional(),
currentPeriodEnd: z.date().optional(),
});