feat: add SpamShield router for spam detection and call analysis
- Create tRPC router with checkNumber, classifySMS, classifyCall endpoints - Add protected procedures for rule CRUD, feedback submission, and stats - Implement service layer with phone number normalization and audit logging - Add ML engine with BERT stub, feature extraction, and rule engine - Implement reputation API module with circuit breaker and caching - Write comprehensive tests (34 tests) for all layers - Wire spamshield router into app root router
This commit is contained in:
75
web/src/server/api/routers/spamshield.ts
Normal file
75
web/src/server/api/routers/spamshield.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { wrap } from "@typeschema/valibot";
|
||||
import { createTRPCRouter, publicProcedure, protectedProcedure } from "../utils";
|
||||
import {
|
||||
CheckNumberSchema,
|
||||
ClassifySMSSchema,
|
||||
ClassifyCallSchema,
|
||||
CreateRuleSchema,
|
||||
DeleteRuleSchema,
|
||||
FeedbackSchema,
|
||||
StatsFilterSchema,
|
||||
} from "../schemas/spamshield";
|
||||
import * as spamshieldService from "~/server/services/spamshield.service";
|
||||
|
||||
export const spamshieldRouter = createTRPCRouter({
|
||||
checkNumber: publicProcedure
|
||||
.input(wrap(CheckNumberSchema))
|
||||
.query(async ({ input }) => {
|
||||
return spamshieldService.checkNumberReputation(input.phoneNumber);
|
||||
}),
|
||||
|
||||
classifySMS: publicProcedure
|
||||
.input(wrap(ClassifySMSSchema))
|
||||
.query(async ({ input }) => {
|
||||
return spamshieldService.classifySMS(input.text);
|
||||
}),
|
||||
|
||||
classifyCall: publicProcedure
|
||||
.input(wrap(ClassifyCallSchema))
|
||||
.query(async ({ input }) => {
|
||||
return spamshieldService.classifyCall(
|
||||
input.callerNumber,
|
||||
input.duration,
|
||||
input.timeOfDay,
|
||||
);
|
||||
}),
|
||||
|
||||
getRules: protectedProcedure.query(async ({ ctx }) => {
|
||||
return spamshieldService.getRules(ctx.user.id);
|
||||
}),
|
||||
|
||||
createRule: protectedProcedure
|
||||
.input(wrap(CreateRuleSchema))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return spamshieldService.createRule(
|
||||
ctx.user.id,
|
||||
input.ruleType,
|
||||
input.pattern,
|
||||
input.action,
|
||||
input.priority,
|
||||
);
|
||||
}),
|
||||
|
||||
deleteRule: protectedProcedure
|
||||
.input(wrap(DeleteRuleSchema))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return spamshieldService.deleteRule(ctx.user.id, input.ruleId);
|
||||
}),
|
||||
|
||||
submitFeedback: protectedProcedure
|
||||
.input(wrap(FeedbackSchema))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
return spamshieldService.submitFeedback(
|
||||
ctx.user.id,
|
||||
input.phoneNumber,
|
||||
input.isSpam,
|
||||
input.feedbackType,
|
||||
);
|
||||
}),
|
||||
|
||||
getStats: protectedProcedure
|
||||
.input(wrap(StatsFilterSchema))
|
||||
.query(async ({ ctx, input }) => {
|
||||
return spamshieldService.getStats(ctx.user.id, input.period);
|
||||
}),
|
||||
});
|
||||
Reference in New Issue
Block a user