File size: 5,303 Bytes
d8e79f0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | -- Schema Supabase pour FraudShield AI SaaS
-- Production-grade schema with RLS policies
-- Table: transactions (core)
CREATE TABLE transactions (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
user_id TEXT NOT NULL,
amount DECIMAL(12,2) NOT NULL,
currency TEXT DEFAULT 'EUR',
merchant TEXT,
country TEXT,
device_id TEXT,
ip_address INET,
category TEXT CHECK (category IN ('retail', 'crypto', 'gaming', 'travel', 'other')),
risk_score DECIMAL(3,2) CHECK (risk_score >= 0 AND risk_score <= 1),
ml_score DECIMAL(3,2),
rule_score DECIMAL(3,2),
anomaly_score DECIMAL(3,2),
graph_score DECIMAL(3,2),
decision TEXT CHECK (decision IN ('ALLOW', 'REVIEW', 'BLOCK')),
reasons JSONB DEFAULT '[]',
velocity_1h INTEGER DEFAULT 0,
velocity_24h INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
processed_at TIMESTAMP WITH TIME ZONE,
CONSTRAINT check_scores CHECK (risk_score BETWEEN 0 AND 1)
);
-- Index for performance
CREATE INDEX idx_transactions_user_time ON transactions(user_id, created_at DESC);
CREATE INDEX idx_transactions_decision ON decision WHERE decision IN ('BLOCK', 'REVIEW');
CREATE INDEX idx_transactions_risk ON risk_score DESC;
-- Table: user_profiles (behavioral memory)
CREATE TABLE user_profiles (
user_id TEXT PRIMARY KEY,
avg_amount DECIMAL(12,2) DEFAULT 100,
total_transactions INTEGER DEFAULT 0,
home_country TEXT DEFAULT 'FR',
risk_level DECIMAL(3,2) DEFAULT 0.0,
device_history JSONB DEFAULT '[]',
geo_history JSONB DEFAULT '[]',
time_pattern JSONB DEFAULT '{}',
velocity_threshold INTEGER DEFAULT 10,
last_updated TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Table: fraud_feedback (auto-learning loop)
CREATE TABLE fraud_feedback (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
transaction_id UUID REFERENCES transactions(id) ON DELETE CASCADE,
is_fraud BOOLEAN NOT NULL,
confirmed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
label_source TEXT CHECK (label_source IN ('manual', 'chargeback', 'auto')),
confidence DECIMAL(3,2),
feedback_data JSONB
);
-- Table: device_fingerprints
CREATE TABLE device_fingerprints (
device_id TEXT PRIMARY KEY,
user_id TEXT REFERENCES user_profiles(user_id),
fingerprint_hash TEXT,
trust_score DECIMAL(3,2) DEFAULT 0.5,
first_seen TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_seen TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
risk_flags JSONB DEFAULT '[]',
canvas_entropy DECIMAL(5,2),
browser_entropy DECIMAL(5,2)
);
-- Table: graph_relations (network detection)
CREATE TABLE graph_relations (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
source_id TEXT NOT NULL,
target_id TEXT NOT NULL,
relation_type TEXT CHECK (relation_type IN ('user-device', 'user-ip', 'device-ip', 'user-merchant', 'ip-merchant')),
strength DECIMAL(3,2) DEFAULT 1.0,
fraud_count INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(source_id, target_id, relation_type)
);
-- Table: mcp_logs (orchestration tracking)
CREATE TABLE mcp_logs (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
transaction_id UUID REFERENCES transactions(id),
mcp_version TEXT,
ml_latency_ms INTEGER,
rule_latency_ms INTEGER,
graph_latency_ms INTEGER,
total_latency_ms INTEGER,
orchestration_metadata JSONB,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Row Level Security (RLS)
ALTER TABLE transactions ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE fraud_feedback ENABLE ROW LEVEL SECURITY;
-- RLS Policies for multi-tenant SaaS
CREATE POLICY tenant_isolation_transactions ON transactions
USING (auth.uid()::text = user_id OR auth.role() = 'service_role');
CREATE POLICY tenant_isolation_profiles ON user_profiles
USING (auth.uid()::text = user_id OR auth.role() = 'service_role');
-- Function: Update user profile stats
CREATE OR REPLACE FUNCTION update_user_profile()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO user_profiles (user_id, avg_amount, total_transactions, home_country)
VALUES (NEW.user_id, NEW.amount, 1, NEW.country)
ON CONFLICT (user_id) DO UPDATE SET
avg_amount = (user_profiles.avg_amount * user_profiles.total_transactions + NEW.amount) / (user_profiles.total_transactions + 1),
total_transactions = user_profiles.total_transactions + 1,
last_updated = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger to auto-update profiles
CREATE TRIGGER trigger_update_profile
AFTER INSERT ON transactions
FOR EACH ROW EXECUTE FUNCTION update_user_profile();
-- Function: Real-time fraud alerts ( edge function compatible)
CREATE OR REPLACE FUNCTION check_fraud_threshold()
RETURNS TRIGGER AS $$
BEGIN
IF NEW.risk_score > 0.8 THEN
-- Trigger edge function or webhook
PERFORM pg_notify('fraud_alert', json_build_object(
'transaction_id', NEW.id,
'user_id', NEW.user_id,
'score', NEW.risk_score,
'decision', NEW.decision
)::text);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_fraud_alert
AFTER INSERT ON transactions
FOR EACH ROW EXECUTE FUNCTION check_fraud_threshold(); |