4.0 KiB
09 — Fraud Controls & Audit Trail
Status: Not Started Depends On: 08 — Sales Agent Controls
Goal
A dedicated, immutable audit log plus automated anomaly detection over everything built in steps
01–08. Covers mainPlan.md §18
(logAuditEvent, checkLicenseCompliance, generateComplianceReport) and the fraud-relevant piece
of §15 (sendRouteDeviationAlert) and §12 (return-without-prior-sale detection).
Background / Context
Every prior step in this plan references "logged" or "flagged" behavior (override logs, loading discrepancies, reconciliation variances) — this step is where that logging actually becomes a queryable, immutable audit trail instead of scattered per-feature notes.
Data Model Changes
Audit Log Entry
UserId, Action, EntityType, EntityId, OldValue/NewValue (JSON snapshot), CreatedAt,
SourceIp/RequestId if available. Append-only — no update or delete path exposed anywhere.
Anomaly Flag
Type (ReturnWithoutSale, RouteDeviation, HighVarianceRate, CashShortfall), EntityType/
EntityId, RaisedAt, Status (Open, Reviewed, Dismissed).
Return Approval Record
Reuses the approveReturn flow from 18_returns_claims.md — this step
adds the automated pre-check (ReturnWithoutSale) that runs before a human approver sees it.
API Endpoints
| Function reference | Endpoint intent |
|---|---|
logAuditEvent(userId, action, entityType, entityId) (§18) |
Internal — called by every mutating service, not directly exposed |
checkLicenseCompliance(entityId, licenseType) (§18) |
GET /api/compliance/{entityType}/{entityId}/license-check |
generateComplianceReport(period) (§18) |
GET /api/compliance/report?period=... |
sendRouteDeviationAlert(routeId, salesRepId) (§15) |
Not implemented. The underlying data now exists — POST /api/routes/{id}/visits/check-in (11_route_sales_management.md) computes and stores IsDeviationFlagged on each RouteVisitLog row (Haversine distance vs. the store's registered lat/long) — but nothing reads that flag to raise an alert/anomaly flag yet. |
| — | GET /api/audit-log?entityType=...&entityId=... |
| — | GET /api/anomaly-flags?status=Open |
Automated Checks & Flags
- Returns without a matching prior sale (
ReturnWithoutSale). - Sales/deliveries outside the geofenced route (
RouteDeviation) — the GPS check-in/out data this depends on now exists (11_route_sales_management.md'sRouteVisitLog.IsDeviationFlagged), but no anomaly flag or alert reads it yet. - Agents with consistently high variance rates across closed rides (
HighVarianceRate) — readsVariance Recordhistory from 07_ride_reconciliation.md. - Cash collected below invoiced amount (
CashShortfall) — readsPayment Recordfrom 06_sale_ride.md.
Business Rules
- Every state-changing action across every feature must call
logAuditEvent— this is the one cross-cutting requirement every other numbered step inherits once this lands. - Return approval requires supervisor sign-off before stock is credited back (18_returns_claims.md), regardless of whether an anomaly flag fired.
Fraud / Control Considerations
- Anomaly reports are surfaced to area managers on a scheduled basis — batch job or on-demand endpoint, not real-time push, in v1.
Open Questions
- Should
logAuditEventbe wired in as a cross-cutting concern (e.g. an EFSaveChangesinterceptor) rather than an explicit call in every service, to guarantee nothing is missed? - What licenses does
checkLicenseComplianceactually need to validate for this business — is regulated goods handling in scope at all, or is this function speculative until a real requirement shows up?
Implementation Notes
Fill this section in during planning discussion before writing any code.