From c7bf4ac55f6a194e58cce8624c5feec59edfff67 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 23 Jun 2026 19:24:16 +0000 Subject: [PATCH 1/8] =?UTF-8?q?docs:=20mark=20Loss=20Prevention=20LIVE,=20?= =?UTF-8?q?update=20rule=20count=2020=E2=86=9224=20(closes=20#129)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README: architecture block updated to 24 rules with LP (4) subsection - README: Loss Prevention status PLANNED → LIVE in modules line - README: content overview updated to 18 retail + 6 generic, playbooks 3→4 - README: MITRE ATT&CK table gains TLS-001 row + 4 LP rule rows - README: folder structure reflects tls_downgrade_pos.kql, all LP rules, lp-incident-response playbook, deploy_all.py, test_lp_rules.py - README: Quick Start updated to reference deploy_all.py - ROADMAP: rule count 19→24, pytest count 221→315, playbooks 8→9 - ROADMAP: portal modules 4→5, Detection Rules table 19→24 - ROADMAP: Loss Prevention module items all marked complete [x] --- README.md | 45 ++++++++++++++++++++++++++++++++++++--------- ROADMAP.md | 20 +++++++++++--------- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 6c55d99..ae5cb27 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ RetailShield closes that gap. │ ▼ ┌─────────────────────────────────────────────────────────────────┐ -│ 2. DETECTION — 20 KQL rules mapped to MITRE ATT&CK │ +│ 2. DETECTION — 24 KQL rules mapped to MITRE ATT&CK │ │ │ │ Retail-specific (14): gift-card fraud · POS void/refund · │ │ credential stuffing · MFA fatigue · phishing · ransomware · │ @@ -95,6 +95,9 @@ RetailShield closes that gap. │ anomaly · privileged role abuse · after-hours · impossible │ │ travel · TLS downgrade (PCI) │ │ │ +│ Loss Prevention (4): void/refund abuse · gift card fraud · │ +│ sweethearting · after-hours POS transaction │ +│ │ │ Generic SOC (6): brute force · bulk file access · C2 beacon · │ │ DNS exfil · RDP lateral movement · suspicious PowerShell │ └─────────────────────────────────────────────────────────────────┘ @@ -119,7 +122,7 @@ RetailShield closes that gap. └─────────────────────────────────────────────────────────────────┘ MODULES: [Threat Detection: LIVE] [Compliance Centre: LIVE] [Vulnerability Scanner: LIVE] - [Loss Prevention: PLANNED] [ChainShield: PLANNED] + [Loss Prevention: LIVE] [ChainShield: PLANNED] Validated in a controlled lab · published methodology (DOI 10.5281/zenodo.20608262) · avg ~22 min MTTD A Sentinel-native content pack — not a standalone SIEM. @@ -131,8 +134,8 @@ A Sentinel-native content pack — not a standalone SIEM. | Content type | Count | Description | |---|---|---| -| **KQL Analytics Rules** | 13 retail + 6 generic | Scheduled analytics rules covering POS fraud, ransomware, exfiltration, identity abuse, supply chain, voice fraud | -| **Logic App Playbooks** | 3 | Triage & classify, threat-intel enrichment (AbuseIPDB / VirusTotal), containment (block IP / disable account / isolate host) | +| **KQL Analytics Rules** | 18 retail + 6 generic | Scheduled analytics rules covering POS fraud, ransomware, exfiltration, identity abuse, supply chain, voice fraud, and loss prevention | +| **Logic App Playbooks** | 4 | Triage & classify, threat-intel enrichment (AbuseIPDB / VirusTotal), containment (block IP / disable account / isolate host), LP incident response | | **Sentinel Workbook** | 1 | Live incident feed, TTP heatmap, analyst KPIs | | **Watchlists** | 5 | RetailIOCWatchlist, RetailApprovedSenders, AbuseIPDBWatchlist, RetailSupplierAccounts, RetailServiceAccounts | | **Hunting Queries** | Planned | Proactive threat hunting queries for retail TTPs | @@ -158,6 +161,16 @@ A Sentinel-native content pack — not a standalone SIEM. | Initial Access | T1195 | Supply Chain Compromise | `retail/supply_chain_anomaly.kql` | notify_soc | | Initial Access | T1199 / T1078 | Trusted Relationship / Valid Accounts | `retail/supplier_impossible_travel.kql` | notify_soc | | Persistence | T1098 / T1078 | Account Manipulation / Valid Accounts | `retail/privileged_role_addition.kql` | notify_soc | +| Credential Access / Collection | T1557 | Adversary-in-the-Middle | `retail/tls_downgrade_pos.kql` | notify_soc | + +### Loss Prevention rules + +| Tactic | Technique ID | Technique Name | Detection Rule | Playbook | +|---|---|---|---|---| +| Impact | T1657 | Financial Theft | `retail/lp-pos-void-refund-abuse.kql` | lp-incident-response | +| Impact | T1657 | Financial Theft | `retail/lp-gift-card-rapid-redemption.kql` | lp-incident-response | +| Impact | T1657 | Financial Theft | `retail/lp-sweethearting.kql` | lp-incident-response | +| Impact | T1657 | Financial Theft | `retail/lp-after-hours-pos-transaction.kql` | lp-incident-response | ### Generic rules @@ -194,7 +207,12 @@ RetailShield/ │ │ ├── ransomware_indicator.kql # RS-RAN-001 — T1486 — Critical │ │ ├── supply_chain_anomaly.kql # RS-SUP-001 — T1195 — High │ │ ├── supplier_impossible_travel.kql # RS-SUP-002 — T1199 — Medium -│ │ └── privileged_role_addition.kql # RS-PRA-001 — T1098 — High +│ │ ├── privileged_role_addition.kql # RS-PRA-001 — T1098 — High +│ │ ├── tls_downgrade_pos.kql # RS-TLS-001 — T1557 — High +│ │ ├── lp-pos-void-refund-abuse.kql # LP-001 — T1657 — High +│ │ ├── lp-gift-card-rapid-redemption.kql # LP-002 — T1657 — High +│ │ ├── lp-sweethearting.kql # LP-003 — T1657 — High +│ │ └── lp-after-hours-pos-transaction.kql # LP-004 — T1657 — High │ ├── generic/ # General-purpose SOC rules │ │ ├── brute-force-login.kql # GEN-001 — T1110 │ │ ├── bulk-file-access.kql # GEN-002 — T1005 @@ -212,6 +230,8 @@ RetailShield/ │ ├── containment/ │ │ ├── workflow.json # Block IP / Disable account / Isolate host │ │ └── README.md +│ ├── lp-incident-response/ +│ │ └── workflow.json # LP incident triage, manager notification, HR/CCTV escalation │ └── DEPLOYMENT.md # Step-by-step Logic App deployment guide │ ├── sentinel/ @@ -232,11 +252,13 @@ RetailShield/ │ ├── validate_kql.py # KQL rule static validator (used by CI) │ ├── validate_logicapps.py # Logic App JSON validator (used by CI) │ ├── retail_log_generator.py # Sample retail log generator for testing -│ └── cve_scanner.py # CVE scanner utility +│ ├── cve_scanner.py # CVE scanner utility +│ └── deploy_all.py # One-command deployment to Sentinel workspace │ ├── tests/ │ ├── detection-rules/ -│ │ └── test_kql_rules.py +│ │ ├── test_kql_rules.py +│ │ └── test_lp_rules.py # 94 tests covering all 4 LP detection rules │ └── playbooks/ │ └── test_playbook_schema.py │ @@ -268,9 +290,14 @@ git checkout dev ### 2. Deploy KQL analytics rules to Sentinel -Rules are deployed manually through the Microsoft Sentinel Analytics blade. There is no automated deployment script at this time. +Rules can be deployed via the included script (requires `az login` and ARM rule templates in `sentinel/analytics-rules/`): + +```bash +pip install azure-identity azure-mgmt-securityinsight +python scripts/deploy_all.py --workspace --resource-group --dry-run +``` -For each `.kql` file in `detection-rules/retail/` (and optionally `detection-rules/generic/`): +Or deploy manually through the Microsoft Sentinel Analytics blade. For each `.kql` file in `detection-rules/retail/` (and optionally `detection-rules/generic/`): 1. In the Azure Portal, open your Sentinel workspace → **Analytics** → **+ Create** → **Scheduled query rule** 2. Set the rule name and description using the `// Rule ID` and `// Title` comments at the top of the file diff --git a/ROADMAP.md b/ROADMAP.md index fa0a2e3..90ce487 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -11,10 +11,11 @@ Research paper: [DOI 10.5281/zenodo.20608262](https://doi.org/10.5281/zenodo.206 The foundation: a working SOC platform purpose-built for UK retail, with published research validating the detection capability. ### Detection engineering -- [x] 19 production-ready KQL detection rules covering the full MITRE ATT&CK kill chain -- [x] 8 Logic App playbooks for automated incident response +- [x] 24 production-ready KQL detection rules covering the full MITRE ATT&CK kill chain +- [x] 9 Logic App playbooks for automated incident response - [x] Sentinel analytics-rule JSON wrappers for one-click deployment -- [x] 221 automated pytest tests validating rule syntax and MITRE mapping +- [x] 315 automated pytest tests validating rule syntax and MITRE mapping +- [x] One-command deployment script (`scripts/deploy_all.py`) for Sentinel workspace ### Compliance automation - [x] ICO 72-hour breach notification countdown with auto-generated draft reports @@ -23,11 +24,12 @@ The foundation: a working SOC platform purpose-built for UK retail, with publish - [x] Submission history tracking ### Platform -- [x] Responsive portal dashboard (Landing → Login → Portal → 4 modules) +- [x] Responsive portal dashboard (Landing → Login → Portal → 5 modules) - [x] Threat Detection module: live incident feed, MITRE heatmap, attack timeline, AI-generated incident reports - [x] Vulnerability Scanner: SVG risk gauge, phased scan progress, OWASP Top 10 findings - [x] Compliance Centre: live countdown timers, regulatory accordion, submission log -- [x] Detection Rules: 19-rule table with search/filter, full MITRE ATT&CK coverage matrix +- [x] Detection Rules: 24-rule table with search/filter, full MITRE ATT&CK coverage matrix +- [x] Loss Prevention module: store risk leaderboard, incident detail panel, void/refund/gift card/sweethearting signals - [x] Fully responsive at 375px, 768px, 1024px, and 1440px viewport widths - [x] SIMULATE ATTACK feature populating all modules with realistic incident data @@ -42,10 +44,10 @@ The foundation: a working SOC platform purpose-built for UK retail, with publish Expanding coverage to retail-specific financial crime and supply chain risk, and connecting the platform to live Sentinel data. ### Loss Prevention module -- [ ] POS transaction anomaly detection (void abuse, refund fraud, sweethearting patterns) -- [ ] Gift card abuse tracking (bulk activation, rapid redemption sequences) -- [ ] Store risk scoring dashboard with trend analysis -- [ ] Integration with retail EPOS event logs +- [x] POS transaction anomaly detection (void abuse, refund fraud, sweethearting patterns) +- [x] Gift card abuse tracking (bulk activation, rapid redemption sequences) +- [x] Store risk scoring dashboard with trend analysis +- [x] Integration with retail EPOS event logs ### ChainShield — Supply chain security module - [ ] Third-party supplier compromise detection From ffc67bfb8e0b4bda8b81ee380f6eac0dd0ae1196 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 23 Jun 2026 20:38:58 +0100 Subject: [PATCH 2/8] Update data.js --- frontend/src/lib/data.js | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/frontend/src/lib/data.js b/frontend/src/lib/data.js index fd52a86..551901f 100644 --- a/frontend/src/lib/data.js +++ b/frontend/src/lib/data.js @@ -744,6 +744,129 @@ export const LP_STORE_RISK = [ { storeId: 'Store-011', storeName: 'Lakeside', riskScore: 28, openIncidents: 0, highestSignal: null, lastIncident: null, trend: 'stable'}, { storeId: 'Store-055', storeName: 'Arndale', riskScore: 21, openIncidents: 0, highestSignal: null, lastIncident: null, trend: 'down' }, ]; +export const LP_ATTACK_SIM_EVENTS = [ + { + id: 'LP-SIM-001', + title: 'Void Abuse Spike — Till Override Bypass', + severity: 'Critical', + tactic: 'Impact', + technique: 'T1657', + status: 'Active', + detectedAt: null, + mttd: 1, + ruleId: 'LP-001', + detectionSignal: 'HighValueVoidNoOverride', + storeId: 'Store-044', + operatorId: 'EMP-7732', + terminalId: 'POS-044-02', + transactionCount: 6, + totalValueGBP: 1840.00, + hasManagerOverride: false, + riskScore: 97, + description: 'Simulated: EMP-7732 processed 6 high-value void transactions totalling £1,840 at Store-044 with no manager override. Matches known till manipulation pattern.', + timeline: [ + { time: '+0:00', event: 'First high-value void — £310 — no manager override at POS-044-02' }, + { time: '+0:04', event: 'Third void — running total exceeds £500 critical threshold' }, + { time: '+0:08', event: 'Sixth void — total reaches £1,840' }, + { time: '+0:08', event: 'Critical alert — HighValueVoidNoOverride, RiskScore 97' }, + ], + affectedEntities: ['EMP-7732', 'POS-044-02', 'Store-044 refund ledger'], + autoDefence: ['Operator account suspended immediately', 'Manager PIN enforcement activated', 'LP team escalated'], + recommendations: ['Same-day investigation and reconciliation', 'Review 7-day void history for EMP-7732', 'Preserve CCTV footage'], + estimatedLossGBP: 1840.00, + }, + { + id: 'LP-SIM-002', + title: 'Organised Gift Card Fraud — 14 Cards in 25 Minutes', + severity: 'Critical', + tactic: 'Impact', + technique: 'T1657', + status: 'Active', + detectedAt: null, + mttd: 2, + ruleId: 'LP-002', + detectionSignal: 'RapidCrossChannelRedemption', + storeId: 'Store-012', + operatorId: 'EMP-5521', + terminalId: 'POS-012-01', + activationCount: 14, + totalValueGBP: 700.00, + minutesSinceActivation: 12, + riskScore: 96, + description: 'Simulated: 14 gift cards activated at Store-012 and redeemed online within 12 minutes of activation. Consistent with organised retail gift card fraud ring.', + timeline: [ + { time: '+0:00', event: '14 gift cards activated at Store-012 POS-012-01 by EMP-5521' }, + { time: '+0:12', event: 'All 14 cards redeemed via online channel — 12 minutes post-activation' }, + { time: '+0:12', event: 'RapidCrossChannelRedemption fired — Critical, RiskScore 96' }, + { time: '+0:13', event: 'Cards suspended; fraud team alerted' }, + ], + affectedEntities: ['EMP-5521', 'POS-012-01', '14 gift card accounts', 'Online redemption API'], + autoDefence: ['Affected cards frozen', 'Online channel velocity cap applied', 'Fraud team alerted'], + recommendations: ['Coordinate with online fraud team to trace redemption session', 'Investigate whether EMP-5521 acted alone', 'Consider law enforcement referral'], + estimatedLossGBP: 700.00, + }, + { + id: 'LP-SIM-003', + title: 'Sweethearting — 47% Discount to Repeat Customer Over 5 Days', + severity: 'High', + tactic: 'Impact', + technique: 'T1657', + status: 'Investigating', + detectedAt: null, + mttd: 18, + ruleId: 'LP-003', + detectionSignal: 'RepeatHighDiscountRelationship', + storeId: 'Store-029', + operatorId: 'EMP-4482', + loyaltyCardId: 'LC-20019447', + transactionCount: 11, + avgDiscountRate: 0.47, + totalDiscountGBP: 421.60, + avgBasketGBP: 34.22, + riskScore: 82, + description: 'Simulated: Cashier EMP-4482 served loyalty customer LC-20019447 eleven times in 5 days with an average discount of 47% — well above the 30% threshold. No loyalty entitlement found.', + timeline: [ + { time: 'Day 1', event: 'First transaction — 51% discount applied by EMP-4482' }, + { time: 'Days 2–4', event: '10 further transactions — discounts between 41% and 53%' }, + { time: 'Day 5', event: '5-day rolling analysis triggers RepeatHighDiscountRelationship' }, + { time: 'Day 5 +18min', event: 'LP manager notified; HR review scheduled' }, + ], + affectedEntities: ['EMP-4482', 'LC-20019447', 'Store-029 discount ledger'], + autoDefence: ['Discount cap applied to EMP-4482 terminal', 'LP manager alerted', 'Transaction history exported for HR'], + recommendations: ['Full 30-day discount audit for EMP-4482', 'Cross-check LC-20019447 loyalty entitlement', 'Review CCTV to confirm scanning compliance'], + estimatedLossGBP: 421.60, + }, + { + id: 'LP-SIM-004', + title: 'After-Hours Ghost Transaction — 03:17 AM — Store-061', + severity: 'Critical', + tactic: 'Impact', + technique: 'T1657', + status: 'Active', + detectedAt: null, + mttd: 1, + ruleId: 'LP-004', + detectionSignal: 'GhostEmployeeAfterHours', + storeId: 'Store-061', + operatorId: 'EMP-1147', + terminalId: 'POS-061-01', + transactionCount: 7, + totalValueGBP: 934.25, + hourOfDay: 3, + riskScore: 95, + description: 'Simulated: EMP-1147 processed 7 transactions totalling £934.25 at 03:17 AM with no active shift record. Potential ghost employee or credential-sharing incident.', + timeline: [ + { time: '03:11', event: 'EMP-1147 logs into POS-061-01 — no shift record found' }, + { time: '03:17', event: '7 transactions processed totalling £934.25' }, + { time: '03:17', event: 'GhostEmployeeAfterHours alert — Critical, RiskScore 95' }, + { time: '03:18', event: 'Terminal locked remotely; security dispatched' }, + ], + affectedEntities: ['EMP-1147', 'POS-061-01', 'Store-061 till'], + autoDefence: ['Terminal remotely locked', 'Security team dispatched', 'EMP-1147 credential suspended'], + recommendations: ['Contact on-site security and review CCTV immediately', 'Verify badge access records for EMP-1147', 'Consider law enforcement notification if entry confirmed'], + estimatedLossGBP: 934.25, + }, +]; export const SUBMISSION_HISTORY = [ { id: 'SUB-001', date: '2026-05-22T10:30:00Z', incident: 'INC-2801', regulation: 'UK GDPR', authority: 'ICO', status: 'Submitted', refNo: 'ICO-2026-051822' }, From d48e216d9ae524f492a6768c979ca70d20454bc5 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 23 Jun 2026 20:39:52 +0100 Subject: [PATCH 3/8] Update App.jsx --- frontend/src/App.jsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 269e1ba..547d7b9 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { BASELINE_INCIDENTS } from './lib/data.js'; +import { BASELINE_INCIDENTS, LP_INCIDENTS } from './lib/data.js'; import Landing from './pages/Landing.jsx'; import Login from './pages/Login.jsx'; import Portal from './pages/Portal.jsx'; @@ -10,8 +10,9 @@ import DetectionRules from './modules/DetectionRules.jsx'; import LossPrevention from './modules/LossPrevention.jsx'; export default function App() { - const [route, setRoute] = useState('landing'); - const [incidents, setIncidents] = useState([...BASELINE_INCIDENTS]); + const [route, setRoute] = useState('landing'); + const [incidents, setIncidents] = useState([...BASELINE_INCIDENTS]); + const [lpIncidents, setLpIncidents] = useState([...LP_INCIDENTS]); const nav = (page) => { setRoute(page); @@ -28,7 +29,7 @@ export default function App() { case 'vuln': return nav('portal')} />; case 'compliance': return nav('portal')} />; case 'rules': return nav('portal')} />; - case 'lp': return nav('portal')} />; + case 'lp': return nav('portal')} lpIncidents={lpIncidents} setLpIncidents={setLpIncidents} />; default: return nav('portal')} onSignIn={() => nav('login')} />; } } From d080f0e7f8945905b379c0367cc1865c43d72677 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 23 Jun 2026 20:41:47 +0100 Subject: [PATCH 4/8] Update LossPrevention.jsx --- frontend/src/modules/LossPrevention.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/modules/LossPrevention.jsx b/frontend/src/modules/LossPrevention.jsx index a419d07..278ad4b 100644 --- a/frontend/src/modules/LossPrevention.jsx +++ b/frontend/src/modules/LossPrevention.jsx @@ -1,4 +1,4 @@ -import { useState, useMemo } from 'react'; +import { useState, useMemo, useCallback, useRef } from 'react'; import { ShoppingCart, AlertTriangle, TrendingUp, TrendingDown, Minus, X, Clock, User, Monitor, ChevronRight, From 076296ccfeec109f9836a3c6dc777058c837eac1 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 23 Jun 2026 20:42:38 +0100 Subject: [PATCH 5/8] Update LossPrevention.jsx --- frontend/src/modules/LossPrevention.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/modules/LossPrevention.jsx b/frontend/src/modules/LossPrevention.jsx index 278ad4b..31767da 100644 --- a/frontend/src/modules/LossPrevention.jsx +++ b/frontend/src/modules/LossPrevention.jsx @@ -2,7 +2,7 @@ import { useState, useMemo, useCallback, useRef } from 'react'; import { ShoppingCart, AlertTriangle, TrendingUp, TrendingDown, Minus, X, Clock, User, Monitor, ChevronRight, - PoundSterling, Store, BarChart2, + PoundSterling, Store, BarChart2,Zap, } from 'lucide-react'; import TopBar from '../components/TopBar.jsx'; import SeverityBadge from '../components/SeverityBadge.jsx'; From 5c5e9cdb0b6dd209f002e76de2fbe4b4f5495da8 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 23 Jun 2026 20:43:53 +0100 Subject: [PATCH 6/8] Update LossPrevention.jsx --- frontend/src/modules/LossPrevention.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/modules/LossPrevention.jsx b/frontend/src/modules/LossPrevention.jsx index 31767da..67a8f07 100644 --- a/frontend/src/modules/LossPrevention.jsx +++ b/frontend/src/modules/LossPrevention.jsx @@ -7,7 +7,7 @@ import { import TopBar from '../components/TopBar.jsx'; import SeverityBadge from '../components/SeverityBadge.jsx'; import StatCard from '../components/StatCard.jsx'; -import { LP_INCIDENTS, LP_STORE_RISK } from '../lib/data.js'; +import { LP_ATTACK_SIM_EVENTS, LP_STORE_RISK } from '../lib/data.js'; import { useBreakpoint } from '../lib/hooks.js'; const LP_COLOR = '#F97316'; From c002103f8950515a2ebbdb7271288c1fa3500322 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 23 Jun 2026 20:57:50 +0100 Subject: [PATCH 7/8] Update LossPrevention.jsx --- frontend/src/modules/LossPrevention.jsx | 29 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/frontend/src/modules/LossPrevention.jsx b/frontend/src/modules/LossPrevention.jsx index 67a8f07..74ea02d 100644 --- a/frontend/src/modules/LossPrevention.jsx +++ b/frontend/src/modules/LossPrevention.jsx @@ -225,14 +225,29 @@ export default function LossPrevention({ nav, onBack }) {
{/* Page header */} -
-
- -
-
-

Loss Prevention

-

Financial fraud detection, void/refund abuse, and store risk scoring

+
+
+
+ +
+
+

Loss Prevention

+

Financial fraud detection, void/refund abuse, and store risk scoring

+
+
{/* KPI cards */} From 81b51cc3a4ad718356ce697e72fd7cc4e08c7a32 Mon Sep 17 00:00:00 2001 From: Tanvir Farhad Date: Tue, 23 Jun 2026 21:03:00 +0100 Subject: [PATCH 8/8] Update LossPrevention.jsx --- frontend/src/modules/LossPrevention.jsx | 32 ++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/frontend/src/modules/LossPrevention.jsx b/frontend/src/modules/LossPrevention.jsx index 74ea02d..18e22dc 100644 --- a/frontend/src/modules/LossPrevention.jsx +++ b/frontend/src/modules/LossPrevention.jsx @@ -189,13 +189,33 @@ function IncidentDetail({ inc, onClose }) { ); } -export default function LossPrevention({ nav, onBack }) { +export default function LossPrevention({ nav, onBack, lpIncidents, setLpIncidents }) { const { isMobile } = useBreakpoint(); - const [selectedInc, setSelectedInc] = useState(null); - const [filterRule, setFilterRule] = useState('All'); - const [filterSev, setFilterSev] = useState('All'); - - const incidents = LP_INCIDENTS; + const [selectedInc, setSelectedInc] = useState(null); + const [filterRule, setFilterRule] = useState('All'); + const [filterSev, setFilterSev] = useState('All'); + const [simulating, setSimulating] = useState(false); + const lastScenario = useRef(-1); + + const incidents = lpIncidents; + + const runSim = useCallback(() => { + if (simulating) return; + setSimulating(true); + let idx = Math.floor(Math.random() * LP_ATTACK_SIM_EVENTS.length); + if (LP_ATTACK_SIM_EVENTS.length > 1 && idx === lastScenario.current) { + idx = (idx + 1) % LP_ATTACK_SIM_EVENTS.length; + } + lastScenario.current = idx; + const scenario = LP_ATTACK_SIM_EVENTS[idx]; + setTimeout(() => { + setLpIncidents(prev => { + const maxNum = prev.reduce((m, i) => Math.max(m, parseInt(i.id.replace(/\D/g, ''), 10) || 0), 8); + return [{ ...scenario, id: `LP-INC-${String(maxNum + 1).padStart(3, '0')}`, detectedAt: new Date().toISOString() }, ...prev]; + }); + setSimulating(false); + }, 800); + }, [simulating, setLpIncidents]); const storeRisk = LP_STORE_RISK; const filtered = useMemo(() => incidents.filter(inc => {