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,44 @@
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json turbo.json ./
COPY packages/api/package.json ./packages/api/
COPY packages/db/package.json ./packages/db/
COPY packages/types/package.json ./packages/types/
COPY packages/core/package.json ./packages/core/ 2>/dev/null || true
COPY packages/jobs/package.json ./packages/jobs/
COPY packages/shared-notifications/package.json ./packages/shared-notifications/
COPY services/darkwatch/package.json ./services/darkwatch/
COPY services/spamshield/package.json ./services/spamshield/
COPY services/voiceprint/package.json ./services/voiceprint/
RUN npm ci
COPY tsconfig.json ./
COPY packages/types/tsconfig.json ./packages/types/
COPY packages/db/tsconfig.json ./packages/db/
COPY services/spamshield/tsconfig.json ./services/spamshield/
COPY services/spamshield/ ./services/spamshield/
COPY packages/types/ ./packages/types/
COPY packages/db/ ./packages/db/
RUN npm run build --workspace=@shieldai/types --workspace=@shieldai/db --workspace=@shieldai/spamshield
FROM node:20-alpine AS runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 shieldai
COPY --from=builder --chown=shieldai:nodejs /app/services/spamshield/dist ./dist
COPY --from=builder --chown=shieldai:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=shieldai:nodejs /app/services/spamshield/package.json ./package.json
COPY --from=builder --chown=shieldai:nodejs /app/packages/db ./packages/db
USER shieldai
EXPOSE 3002
CMD ["node", "dist/index.js"]

View File

@@ -0,0 +1,22 @@
{
"name": "@shieldai/spamshield",
"version": "0.1.0",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsx watch src/index.ts",
"lint": "eslint src/",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@shieldai/db": "0.1.0",
"@prisma/client": "^6.2.0",
"libphonenumber-js": "^1.10.50"
},
"devDependencies": {
"typescript": "^5.3.3",
"tsx": "^4.19.0",
"eslint": "^8.56.0"
}
}

View File

@@ -0,0 +1,22 @@
export const spamRateLimits = {
BASIC: 100,
PLUS: 500,
PREMIUM: 2000,
} as const;
export const spamFeatureFlags = {
enableHiyaIntegration: true,
enableTruecallerIntegration: true,
enableSMSClassification: true,
enableCallAnalysis: true,
enableFeedbackLoop: true,
} as const;
export const spamConfig = {
maxPhoneNumberLength: 20,
minPhoneNumberLength: 10,
defaultConfidenceThreshold: 0.7,
maxMetadataSize: 1024 * 10, // 10KB
circuitBreakerThreshold: 5,
circuitBreakerTimeout: 60000,
} as const;

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"baseUrl": "./src",
"paths": {
"@shieldai/db": ["../../packages/db/src/index.ts"],
"@shieldai/db/*": ["../../packages/db/src/*"]
}
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist"]
}