Initial commit: Bot Detector Dashboard for SOC Incident Response
🛡️ Dashboard complet pour l'analyse et la classification des menaces Fonctionnalités principales: - Visualisation des détections en temps réel (24h) - Investigation multi-entités (IP, JA4, ASN, Host, User-Agent) - Analyse de corrélation pour classification SOC - Clustering automatique par subnet/JA4/UA - Export des classifications pour ML Composants: - Backend: FastAPI (Python) + ClickHouse - Frontend: React + TypeScript + TailwindCSS - 6 routes API: metrics, detections, variability, attributes, analysis, entities - 7 types d'entités investigables Documentation ajoutée: - NAVIGATION_GRAPH.md: Graph complet de navigation - SOC_OPTIMIZATION_PROPOSAL.md: Proposition d'optimisation pour SOC • Réduction de 7 à 2 clics pour classification • Nouvelle vue /incidents clusterisée • Panel latéral d'investigation • Quick Search (Cmd+K) • Timeline interactive • Graph de corrélations Sécurité: - .gitignore configuré (exclut .env, secrets, node_modules) - Credentials dans .env (à ne pas committer) ⚠️ Audit sécurité réalisé - Voir recommandations dans SOC_OPTIMIZATION_PROPOSAL.md Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
985
TEST_PLAN.md
Normal file
985
TEST_PLAN.md
Normal file
@ -0,0 +1,985 @@
|
||||
# 🧪 Plan de Test - Bot Detector Dashboard
|
||||
|
||||
**Version:** 1.0
|
||||
**Date:** 2025
|
||||
**Projet:** Dashboard Bot Detector IA
|
||||
**Stack:** FastAPI + React + ClickHouse
|
||||
|
||||
---
|
||||
|
||||
## 📑 Table des Matières
|
||||
|
||||
1. [Vue d'ensemble](#1-vue-densemble)
|
||||
2. [Tests Backend (API)](#2-tests-backend-api)
|
||||
3. [Tests Frontend (React)](#3-tests-frontend-react)
|
||||
4. [Tests ClickHouse (Base de données)](#4-tests-clickhouse-base-de-données)
|
||||
5. [Tests d'Intégration](#5-tests-dintégration)
|
||||
6. [Tests de Sécurité](#6-tests-de-sécurité)
|
||||
7. [Tests de Performance](#7-tests-de-performance)
|
||||
8. [Matrice de Couverture](#8-matrice-de-couverture)
|
||||
9. [Scripts de Test Existants](#9-scripts-de-test-existants)
|
||||
10. [Recommandations](#10-recommandations)
|
||||
11. [Prioritisation](#11-prioritisation)
|
||||
|
||||
---
|
||||
|
||||
## 1. Vue d'ensemble
|
||||
|
||||
### Architecture testée
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Docker Compose │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
|
||||
│ │ ClickHouse │ │ bot_detector│ │ dashboard_web │ │
|
||||
│ │ :8123 │ │ (existant) │ │ :3000 (web) │ │
|
||||
│ │ :9000 │ │ │ │ :8000 (API) │ │
|
||||
│ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
|
||||
│ └────────────────┴───────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Composants
|
||||
|
||||
| Composant | Technologie | Port | Tests |
|
||||
|-----------|-------------|------|-------|
|
||||
| **Frontend** | React + TypeScript + Tailwind | 3000 | 25+ tests |
|
||||
| **Backend API** | FastAPI (Python) | 8000 | 80+ tests |
|
||||
| **Database** | ClickHouse (existant) | 8123 | 15+ tests |
|
||||
|
||||
### Endpoints API (20+ endpoints)
|
||||
|
||||
| Routeur | Endpoints | Description |
|
||||
|---------|-----------|-------------|
|
||||
| `/health` | 1 | Health check |
|
||||
| `/api/metrics` | 2 | Métriques globales + distribution |
|
||||
| `/api/detections` | 2 | Liste des détections + détails |
|
||||
| `/api/variability` | 4 | Variabilité attributs + IPs + user_agents |
|
||||
| `/api/attributes` | 1 | Liste attributs uniques |
|
||||
| `/api/analysis` | 6 | Analyse subnet, country, JA4, UA, recommendation |
|
||||
| `/api/entities` | 7 | Investigation entités unifiées |
|
||||
|
||||
---
|
||||
|
||||
## 2. Tests Backend (API)
|
||||
|
||||
### 2.1 Endpoint `/health`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| H1 | Health check basique | GET /health | `{"status": "healthy", "clickhouse": "connected"}` |
|
||||
| H2 | Health check ClickHouse down | ClickHouse indisponible | `{"status": "unhealthy", "clickhouse": "disconnected"}` |
|
||||
| H3 | Temps de réponse | Mesure latence | < 500ms |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/health | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Endpoint `/api/metrics`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| M1 | Métriques globales | GET /api/metrics | Summary avec total_detections, counts par niveau |
|
||||
| M2 | Série temporelle | Données 24h groupées par heure | timeseries avec 24 points |
|
||||
| M3 | Distribution par menace | threat_distribution | 4 niveaux (CRITICAL, HIGH, MEDIUM, LOW) |
|
||||
| M4 | Aucune donnée (24h) | Base vide | Retourne 0 ou erreur gérée proprement |
|
||||
| M5 | Performance requête | Temps d'exécution | < 2s |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/metrics | jq
|
||||
```
|
||||
|
||||
**Vérifications:**
|
||||
- [ ] `summary.total_detections` > 0
|
||||
- [ ] `summary.threat_distribution` contient 4 niveaux
|
||||
- [ ] `timeseries` contient 24 points (une par heure)
|
||||
- [ ] Somme des counts = total_detections
|
||||
|
||||
---
|
||||
|
||||
### 2.3 Endpoint `/api/metrics/threats`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| MT1 | Distribution complète | GET /api/metrics/threats | Items avec threat_level, count, percentage |
|
||||
| MT2 | Cohérence pourcentages | Somme des percentages | ≈ 100% |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/metrics/threats | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.4 Endpoint `/api/detections`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| D1 | Liste par défaut | GET /api/detections?page=1&page_size=25 | Items triés par detected_at DESC |
|
||||
| D2 | Pagination | page, page_size, total, total_pages | total_pages = ceil(total/page_size) |
|
||||
| D3 | Filtre threat_level | `?threat_level=CRITICAL` | Uniquement CRITICAL |
|
||||
| D4 | Filtre model_name | `?model_name=Complet` | Uniquement ce modèle |
|
||||
| D5 | Filtre country_code | `?country_code=CN` | Uniquement China |
|
||||
| D6 | Filtre asn_number | `?asn_number=16276` | Uniquement cet ASN |
|
||||
| D7 | Recherche texte | `?search=192.168` | IP, JA4, Host correspondants |
|
||||
| D8 | Tri anomaly_score ASC | `?sort_by=anomaly_score&sort_order=asc` | Scores croissants |
|
||||
| D9 | Tri detected_at DESC | `?sort_by=detected_at&sort_order=DESC` | Chronologique inverse |
|
||||
| D10 | Limite page_size | `?page_size=100` | Maximum 100 items |
|
||||
| D11 | Page inexistante | `?page=9999` | Liste vide, total_pages correct |
|
||||
|
||||
**Commandes de test:**
|
||||
```bash
|
||||
# Liste par défaut
|
||||
curl "http://localhost:3000/api/detections?page=1&page_size=25" | jq
|
||||
|
||||
# Filtre CRITICAL
|
||||
curl "http://localhost:3000/api/detections?threat_level=CRITICAL" | jq '.items[].threat_level'
|
||||
|
||||
# Recherche IP
|
||||
curl "http://localhost:3000/api/detections?search=192.168" | jq
|
||||
|
||||
# Tri par score
|
||||
curl "http://localhost:3000/api/detections?sort_by=anomaly_score&sort_order=asc" | jq '.items[0].anomaly_score'
|
||||
```
|
||||
|
||||
**Vérifications:**
|
||||
- [ ] Structure `DetectionsListResponse` respectée
|
||||
- [ ] Pagination cohérente
|
||||
- [ ] Filtres appliqués correctement
|
||||
- [ ] Tri fonctionnel
|
||||
- [ ] Recherche texte (LIKE ILIKE)
|
||||
|
||||
---
|
||||
|
||||
### 2.5 Endpoint `/api/detections/{id}`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| DD1 | Détails par IP | GET /api/detections/192.168.1.1 | Tous les champs remplis |
|
||||
| DD2 | IP inexistante | GET /api/detections/0.0.0.0 | 404 "Détection non trouvée" |
|
||||
| DD3 | Structure nested | asn, country, metrics, tcp, tls, headers, behavior, advanced | Tous les objets présents |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/detections/116.179.33.143 | jq
|
||||
```
|
||||
|
||||
**Vérifications:**
|
||||
- [ ] Objet `asn` avec number, org, detail, domain, label
|
||||
- [ ] Objet `country` avec code
|
||||
- [ ] Objet `metrics` avec hits, hit_velocity, fuzzing_index, post_ratio, etc.
|
||||
- [ ] Objet `tcp` avec jitter_variance, shared_count, etc.
|
||||
- [ ] Objet `tls` avec alpn flags
|
||||
- [ ] Objet `headers` avec count, has_accept_language, etc.
|
||||
- [ ] Objet `behavior` avec ip_id_zero_ratio, etc.
|
||||
- [ ] Objet `advanced` avec asset_ratio, etc.
|
||||
|
||||
---
|
||||
|
||||
### 2.6 Endpoint `/api/variability/{type}/{value}`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| V1 | Variabilité IP | GET /api/variability/ip/192.168.1.1 | user_agents, ja4, countries, asns, hosts, threat_levels |
|
||||
| V2 | Variabilité JA4 | GET /api/variability/ja4/{fingerprint} | Même structure |
|
||||
| V3 | Variabilité Pays | GET /api/variability/country/FR | Même structure |
|
||||
| V4 | Variabilité ASN | GET /api/variability/asn/16276 | Même structure |
|
||||
| V5 | Variabilité Host | GET /api/variability/host/example.com | Même structure |
|
||||
| V6 | Type invalide | GET /api/variability/invalid/xyz | 400 "Type invalide" |
|
||||
| V7 | Aucune donnée | GET /api/variability/ip/0.0.0.0 | 404 |
|
||||
| V8 | Insights générés | Selon données | Messages pertinents (rotation UA, hosting ASN, etc.) |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/variability/ip/116.179.33.143 | jq
|
||||
```
|
||||
|
||||
**Vérifications:**
|
||||
- [ ] `total_detections` > 0
|
||||
- [ ] `unique_ips` >= 1
|
||||
- [ ] `attributes.user_agents` liste avec percentages
|
||||
- [ ] `attributes.ja4` fingerprints
|
||||
- [ ] `attributes.countries` distribution
|
||||
- [ ] `attributes.asns` informations
|
||||
- [ ] `insights` messages contextuels générés
|
||||
|
||||
**Insights attendus:**
|
||||
- [ ] "X User-Agents différents → Possible rotation/obfuscation" (si > 1 UA)
|
||||
- [ ] "X JA4 fingerprints différents → Possible rotation" (si > 1 JA4)
|
||||
- [ ] "ASN de type hosting → Souvent utilisé pour des bots" (si OVH, AWS, etc.)
|
||||
- [ ] "X% de détections CRITICAL → Menace sévère" (si > 30%)
|
||||
|
||||
---
|
||||
|
||||
### 2.7 Endpoint `/api/variability/{type}/{value}/ips`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| VI1 | IPs associées | GET /api/variability/country/CN/ips | Liste d'IPs uniques |
|
||||
| VI2 | Limite respectée | `?limit=50` | Maximum 50 items retournés |
|
||||
| VI3 | Total correct | `total` vs `showing` | Count distinct réel |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl "http://localhost:3000/api/variability/country/CN/ips?limit=10" | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.8 Endpoint `/api/variability/{type}/{value}/attributes`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| VA1 | Attributs cibles | `?target_attr=user_agents` | Items avec value, count, percentage |
|
||||
| VA2 | Target invalide | `?target_attr=invalid` | 400 |
|
||||
| VA3 | Pourcentages | Somme des percentages | ≈ 100% |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl "http://localhost:3000/api/variability/ip/116.179.33.143/attributes?target_attr=ja4&limit=10" | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.9 Endpoint `/api/variability/{type}/{value}/user_agents`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| VU1 | User-Agents depuis vue | GET /api/variability/ip/{ip}/user_agents | Liste avec first_seen, last_seen |
|
||||
| VU2 | Classification implicite | UA bots détectables | python-requests, curl, etc. |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/variability/ip/116.179.33.143/user_agents | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.10 Endpoint `/api/attributes/{type}`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| A1 | Liste IPs uniques | GET /api/attributes/ip | Top 100 par count |
|
||||
| A2 | Liste JA4 uniques | GET /api/attributes/ja4 | idem |
|
||||
| A3 | Liste pays | GET /api/attributes/country | idem |
|
||||
| A4 | Liste ASNs | GET /api/attributes/asn | idem |
|
||||
| A5 | Liste hosts | GET /api/attributes/host | idem |
|
||||
| A6 | Type invalide | GET /api/attributes/invalid | 400 |
|
||||
| A7 | Valeurs vides filtrées | Pas de NULL ou "" | Exclus du résultat |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl "http://localhost:3000/api/attributes/ip?limit=10" | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.11 Endpoint `/api/analysis/{ip}/subnet`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| AS1 | Analyse subnet /24 | GET /api/analysis/192.168.1.1/subnet | ips_in_subnet, total_in_subnet |
|
||||
| AS2 | Alert si > 10 IPs | Subnet avec 15 IPs | alert=true |
|
||||
| AS3 | Informations ASN | asn_number, asn_org, total_in_asn | Données complètes |
|
||||
| AS4 | IP privée/local | 10.0.0.1 | Géré correctement |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/analysis/116.179.33.143/subnet | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.12 Endpoint `/api/analysis/{ip}/country`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| AC1 | Pays de l'IP | code, name | FR, France |
|
||||
| AC2 | Distribution ASN par pays | asn_countries | Liste avec percentages |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/analysis/116.179.33.143/country | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.13 Endpoint `/api/analysis/country`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| ANC1 | Top 10 pays | GET /api/analysis/country | Avec count et percentage |
|
||||
| ANC2 | Baseline (7 jours) | Comparaison disponible | baseline object |
|
||||
| ANC3 | Alert country détectée | Pays surreprésenté | alert_country positionné |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/analysis/country | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.14 Endpoint `/api/analysis/{ip}/ja4`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| AJ1 | JA4 fingerprint | ja4, shared_ips_count | Nombre d'IPs partageant ce JA4 |
|
||||
| AJ2 | Top subnets | groupés par /24 | top_subnets list |
|
||||
| AJ3 | Autres JA4 pour IP | other_ja4_for_ip | Liste des autres fingerprints |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/analysis/116.179.33.143/ja4 | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.15 Endpoint `/api/analysis/{ip}/user-agents`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| AU1 | User-Agents IP | ip_user_agents | Avec classification (normal/bot/script) |
|
||||
| AU2 | Bot percentage | Calcul correct | bot_percentage |
|
||||
| AU3 | Alert si > 20% bots | alert=true | Si bot_percentage > 20 |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/analysis/116.179.33.143/user-agents | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.16 Endpoint `/api/analysis/{ip}/recommendation`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| AR1 | Recommandation complète | label, confidence, indicators | Classification suggérée |
|
||||
| AR2 | Tags suggérés | Basés sur corrélations | suggested_tags list |
|
||||
| AR3 | Reason détaillé | Explication | reason string |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/analysis/116.179.33.143/recommendation | jq
|
||||
```
|
||||
|
||||
**Vérifications:**
|
||||
- [ ] `label` ∈ {legitimate, suspicious, malicious}
|
||||
- [ ] `confidence` entre 0 et 1
|
||||
- [ ] `indicators` avec subnet_ips_count, ja4_shared_ips, bot_ua_percentage, etc.
|
||||
- [ ] `suggested_tags` pertinents (distributed, bot-ua, hosting-asn, etc.)
|
||||
- [ ] `reason` explicatif
|
||||
|
||||
---
|
||||
|
||||
### 2.17 Endpoint `/api/entities/{type}/{value}`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| E1 | Investigation IP | GET /api/entities/ip/192.168.1.1 | stats, related, user_agents, client_headers, paths, query_params |
|
||||
| E2 | Investigation JA4 | GET /api/entities/ja4/{fingerprint} | idem |
|
||||
| E3 | Investigation User-Agent | GET /api/entities/user_agent/{ua} | idem |
|
||||
| E4 | Investigation Client-Header | GET /api/entities/client_header/{header} | idem |
|
||||
| E5 | Investigation Host | GET /api/entities/host/example.com | idem |
|
||||
| E6 | Investigation Path | GET /api/entities/path/api/login | idem |
|
||||
| E7 | Investigation Query-Param | GET /api/entities/query_param/q|id | idem |
|
||||
| E8 | Type invalide | GET /api/entities/invalid/xyz | 400 |
|
||||
| E9 | Entité inexistante | GET /api/entities/ip/0.0.0.0 | 404 |
|
||||
| E10 | Fenêtre temporelle | `?hours=48` | Filtre appliqué (défaut 24h) |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/entities/ip/116.179.33.143 | jq
|
||||
```
|
||||
|
||||
**Vérifications:**
|
||||
- [ ] `stats` avec entity_type, entity_value, total_requests, unique_ips, first_seen, last_seen
|
||||
- [ ] `related` avec ips, ja4s, hosts, asns, countries
|
||||
- [ ] `user_agents` liste avec value, count, percentage
|
||||
- [ ] `client_headers` liste
|
||||
- [ ] `paths` liste
|
||||
- [ ] `query_params` liste
|
||||
|
||||
---
|
||||
|
||||
### 2.18 Endpoint `/api/entities/{type}/{value}/related`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| ER1 | Attributs associés | GET /api/entities/ip/192.168.1.1/related | ips, ja4s, hosts, asns, countries |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/entities/ip/116.179.33.143/related | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.19 Endpoints spécifiques entities
|
||||
|
||||
| ID | Test | Endpoint | Résultat attendu |
|
||||
|----|------|----------|------------------|
|
||||
| EU1 | User-Agents | `/{type}/{value}/user_agents` | Liste des UAs |
|
||||
| EU2 | Client-Headers | `/{type}/{value}/client_headers` | Liste des headers |
|
||||
| EU3 | Paths | `/{type}/{value}/paths` | Liste des paths |
|
||||
| EU4 | Query-Params | `/{type}/{value}/query_params` | Liste des params |
|
||||
|
||||
---
|
||||
|
||||
### 2.20 Endpoint `/api/entities/types`
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| ET1 | Liste des types | GET /api/entities/types | 7 types avec descriptions |
|
||||
|
||||
**Commande de test:**
|
||||
```bash
|
||||
curl http://localhost:3000/api/entities/types | jq
|
||||
```
|
||||
|
||||
**Vérifications:**
|
||||
- [ ] 7 types: ip, ja4, user_agent, client_header, host, path, query_param
|
||||
- [ ] Descriptions pour chaque type
|
||||
|
||||
---
|
||||
|
||||
## 3. Tests Frontend (React)
|
||||
|
||||
### 3.1 Navigation et Routing
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| N1 | Page d'accueil | GET http://localhost:3000/ | Dashboard s'affiche |
|
||||
| N2 | Navigation Détections | Clic menu "Détections" | Tableau affiché |
|
||||
| N3 | Navigation Investigation | Menu "Investigation" | Formulaire recherche |
|
||||
| N4 | Breadcrumb fonctionnel | Clic breadcrumb | Navigation retour |
|
||||
| N5 | URL directe (deep link) | http://localhost:3000/detections | Page correcte |
|
||||
|
||||
**Commandes de test:**
|
||||
```bash
|
||||
# Vérifier que le HTML est servi
|
||||
curl -s http://localhost:3000/ | grep -o "Bot Detector Dashboard"
|
||||
|
||||
# Vérifier les assets
|
||||
curl -s http://localhost:3000/ | grep -o "assets/[^\"]*"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 Dashboard Principal
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| DH1 | Métriques affichées | 4 cartes | total, menaces, bots, IPs |
|
||||
| DH2 | Graphique temporel | Série 24h | Recharts line/area chart |
|
||||
| DH3 | Distribution par menace | Pie/bar chart | 4 segments |
|
||||
| DH4 | Rafraîchissement auto | 30s | Données à jour |
|
||||
| DH5 | Loading states | Spinners | Pendant chargement |
|
||||
| DH6 | Gestion erreurs | Message utilisateur | Si API échoue |
|
||||
| DH7 | Responsive design | Mobile/desktop | Adaptatif |
|
||||
|
||||
**Vérifications manuelles:**
|
||||
- [ ] Ouvrir http://localhost:3000
|
||||
- [ ] Vérifier 4 cartes de métriques
|
||||
- [ ] Vérifier graphique temporel
|
||||
- [ ] Vérifier distribution menaces
|
||||
- [ ] Attendre 30s, vérifier rafraîchissement
|
||||
- [ ] Tester sur mobile (DevTools)
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Liste des Détections
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| DL1 | Tableau affiché | Colonnes correctes | detected_at, src_ip, threat_level, etc. |
|
||||
| DL2 | Pagination | Navigation pages | Page 1, 2, 3... |
|
||||
| DL3 | Tri colonnes | Clic header | ASC/DESC fonctionnel |
|
||||
| DL4 | Filtre threat_level | Dropdown | CRITICAL, HIGH, MEDIUM, LOW |
|
||||
| DL5 | Recherche texte | Input search | Filtre en temps réel |
|
||||
| DL6 | Codes couleur menaces | CRITICAL=rouge, HIGH=orange, etc. | Visuel cohérent |
|
||||
| DL7 | Clic sur IP | Ligne cliquable | Ouvre détails |
|
||||
| DL8 | Empty state | Aucune donnée | Message "Aucune détection" |
|
||||
|
||||
**Vérifications manuelles:**
|
||||
- [ ] Naviguer vers /detections
|
||||
- [ ] Tester pagination
|
||||
- [ ] Trier par anomaly_score
|
||||
- [ ] Filtrer par CRITICAL
|
||||
- [ ] Rechercher une IP
|
||||
- [ ] Cliquer sur une ligne
|
||||
|
||||
---
|
||||
|
||||
### 3.4 Vue Détails (Investigation)
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| DV1 | Détails IP affichés | Toutes sections | Metrics, TCP, TLS, Headers, Behavior, Advanced |
|
||||
| DV2 | Variabilité User-Agents | Pourcentages | Barres ou liste |
|
||||
| DV3 | Variabilité JA4 | Fingerprints | Listés avec counts |
|
||||
| DV4 | Variabilité Pays | Distribution | Pays avec percentages |
|
||||
| DV5 | Variabilité ASN | Informations | ASN number, org |
|
||||
| DV6 | Insights automatiques | Messages | Contextuels (rotation, hosting, etc.) |
|
||||
| DV7 | Clic sur attribut | Lien cliquable | Navigation vers investigation |
|
||||
| DV8 | Back button | Retour | Liste détections |
|
||||
|
||||
**Vérifications manuelles:**
|
||||
- [ ] Cliquer sur une IP dans le tableau
|
||||
- [ ] Vérifier toutes les sections de détails
|
||||
- [ ] Vérifier variabilité User-Agents
|
||||
- [ ] Cliquer sur un User-Agent
|
||||
- [ ] Vérifier navigation enchaînée
|
||||
- [ ] Utiliser breadcrumb pour revenir
|
||||
|
||||
---
|
||||
|
||||
### 3.5 Composants UI
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| C1 | Badges menace | Couleurs | CRITICAL=red, HIGH=orange, MEDIUM=yellow, LOW=green |
|
||||
| C2 | Progress bars | Pourcentages visuels | Width proportionnel |
|
||||
| C3 | Tooltips | Survols | Informations additionnelles |
|
||||
| C4 | Skeletons | Chargement | Placeholders gris |
|
||||
| C5 | Toast/Alerts | Notifications | Erreurs API, succès |
|
||||
|
||||
---
|
||||
|
||||
## 4. Tests ClickHouse (Base de Données)
|
||||
|
||||
### 4.1 Tables et Vues
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| DB1 | Table `ml_detected_anomalies` | SELECT count() | > 0 lignes |
|
||||
| DB2 | Vue `view_dashboard_summary` | SELECT * | Données agrégées |
|
||||
| DB3 | Vue `view_dashboard_user_agents` | SELECT * | User-Agents agrégés |
|
||||
| DB4 | Vue `view_dashboard_entities` | SELECT * | Entités unifiées |
|
||||
| DB5 | Table `classifications` | SELECT * | Table vide ou avec données |
|
||||
| DB6 | Index présents | system.data_skipping_indices | Index listés |
|
||||
| DB7 | TTL configuré | system.tables.ttl_expression | Expiration définie |
|
||||
|
||||
**Commandes de test:**
|
||||
```bash
|
||||
# Vérifier tables
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT name, engine FROM system.tables WHERE database = 'mabase_prod' AND name LIKE '%dashboard%'"
|
||||
|
||||
# Vérifier données
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT count() FROM ml_detected_anomalies WHERE detected_at >= now() - INTERVAL 24 HOUR"
|
||||
|
||||
# Vérifier vues
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT * FROM view_dashboard_summary LIMIT 1"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Qualité des Données
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| DQ1 | Pas de NULL critiques | src_ip, detected_at | countIf(NULL) = 0 |
|
||||
| DQ2 | Valeurs vides filtrées | "" exclus | countIf('') = 0 |
|
||||
| DQ3 | Cohérence des counts | Totaux | Somme = total |
|
||||
| DQ4 | Dates valides | detected_at < now() | Pas de dates futures |
|
||||
| DQ5 | Threat levels valides | 4 niveaux uniquement | Pas de valeurs inconnues |
|
||||
|
||||
**Commandes de test:**
|
||||
```bash
|
||||
# NULL check
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT countIf(src_ip IS NULL) AS null_ips FROM ml_detected_anomalies"
|
||||
|
||||
# Threat levels
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT DISTINCT threat_level FROM ml_detected_anomalies"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3 Performance
|
||||
|
||||
| ID | Test | Description | Temps max |
|
||||
|----|------|-------------|-----------|
|
||||
| DP1 | Count 24h | `SELECT count()` | < 500ms |
|
||||
| DP2 | Agrégations par heure | GROUP BY toStartOfHour | < 1s |
|
||||
| DP3 | DISTINCT sur IP | uniq(src_ip) | < 1s |
|
||||
| DP4 | Jointures vues | Multiple joins | < 2s |
|
||||
| DP5 | Full scan table | Sans filtre | < 5s |
|
||||
|
||||
**Commandes de test:**
|
||||
```bash
|
||||
# Timing requête
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT count() FROM ml_detected_anomalies WHERE detected_at >= now() - INTERVAL 24 HOUR" \
|
||||
--time
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Tests d'Intégration
|
||||
|
||||
### 5.1 Workflows Utilisateur
|
||||
|
||||
| ID | Test | Étapes | Résultat attendu |
|
||||
|----|------|--------|------------------|
|
||||
| IW1 | Investigation IP suspecte | Dashboard → Clic IP → Détails → Insights | Investigation complète |
|
||||
| IW2 | Recherche et filtre | Détections → Filtre CRITICAL → Recherche IP | Résultats filtrés |
|
||||
| IW3 | Navigation enchaînée | IP → UA → Toutes IPs avec UA | Navigation fluide |
|
||||
| IW4 | Analyse ASN | Filtre ASN → Voir détections → Variabilité | Vue d'ensemble ASN |
|
||||
| IW5 | Export mental | Observer → Noter IPs | IPs notées pour blacklist |
|
||||
|
||||
**Scénario IW1 détaillé:**
|
||||
1. Ouvrir http://localhost:3000
|
||||
2. Voir IP classifiée CRITICAL dans le dashboard
|
||||
3. Cliquer sur l'IP
|
||||
4. Vérifier section "User-Agents" (plusieurs valeurs ?)
|
||||
5. Vérifier insights automatiques
|
||||
6. Cliquer sur un User-Agent suspect
|
||||
7. Voir toutes les IPs avec cet UA
|
||||
8. Identifier possible botnet
|
||||
|
||||
---
|
||||
|
||||
### 5.2 Scénarios Critiques
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| IC1 | Dashboard vide | Aucune donnée 24h | Message "Aucune donnée" |
|
||||
| IC2 | ClickHouse indisponible | Service down | Erreur gérée, retry |
|
||||
| IC3 | API lente (>5s) | Latence élevée | Loading state, timeout |
|
||||
| IC4 | Données partielles | Certains champs NULL | Affichage partiel OK |
|
||||
| IC5 | Concurrent users | 10+ utilisateurs | Pas de blocage |
|
||||
|
||||
---
|
||||
|
||||
### 5.3 API Integration
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| II1 | Frontend → Backend | Toutes requêtes | HTTP 200 |
|
||||
| II2 | Backend → ClickHouse | Connexion | Stable, reconnect auto |
|
||||
| II3 | CORS localhost:3000 | Origine | Autorisé |
|
||||
| II4 | Rate limiting | 100 req/min | Bloqué après limite |
|
||||
|
||||
**Commande de test CORS:**
|
||||
```bash
|
||||
curl -H "Origin: http://localhost:3000" -I http://localhost:3000/api/metrics | grep -i access-control
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Tests de Sécurité
|
||||
|
||||
| ID | Test | Description | Résultat attendu |
|
||||
|----|------|-------------|------------------|
|
||||
| S1 | Authentification | Accès dashboard | Pas d'auth (local uniquement) |
|
||||
| S2 | Injection SQL | Params ClickHouse | Utilise query params, pas de concat |
|
||||
| S3 | XSS frontend | Input utilisateur | Échappement React |
|
||||
| S4 | CORS restreint | Origines | localhost:3000 uniquement |
|
||||
| S5 | Credentials | .env | Pas en dur dans le code |
|
||||
| S6 | Error messages | Stack traces | Pas d'infos sensibles exposées |
|
||||
|
||||
**Vérifications:**
|
||||
- [ ] Audit fichier `.env` (pas commité)
|
||||
- [ ] Vérifier backend/main.py pas de credentials en dur
|
||||
- [ ] Tester input `<script>alert('xss')</script>` dans recherche
|
||||
- [ ] Vérifier headers CORS
|
||||
|
||||
---
|
||||
|
||||
## 7. Tests de Performance
|
||||
|
||||
| ID | Test | Métrique | Cible | Mesure |
|
||||
|----|------|----------|-------|--------|
|
||||
| P1 | Temps chargement dashboard | First paint | < 2s | DevTools Network |
|
||||
| P2 | Temps requêtes API | Latence moyenne | < 1s | curl -w |
|
||||
| P3 | Requêtes ClickHouse | Temps exécution | < 500ms | --time |
|
||||
| P4 | Rafraîchissement auto | CPU/Mémoire | < 5% CPU | DevTools Performance |
|
||||
| P5 | Pagination grande liste | Scroll fluide | 60 FPS | DevTools |
|
||||
| P6 | Mémoire frontend | Heap size | < 100MB | DevTools Memory |
|
||||
|
||||
**Commandes de test:**
|
||||
```bash
|
||||
# Timing API
|
||||
curl -w "@curl-format.txt" -o /dev/null -s http://localhost:3000/api/metrics
|
||||
|
||||
# curl-format.txt:
|
||||
# time_namelookup: %{time_namelookup}\n
|
||||
# time_connect: %{time_connect}\n
|
||||
# time_starttransfer: %{time_starttransfer}\n
|
||||
# time_total: %{time_total}\n
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Matrice de Couverture
|
||||
|
||||
### Endpoints API
|
||||
|
||||
| Routeur | Endpoints | Tests | Couverture |
|
||||
|---------|-----------|-------|------------|
|
||||
| `/health` | 1 | H1-H3 | ✅ 100% |
|
||||
| `/api/metrics` | 2 | M1-M5, MT1-MT2 | ✅ 100% |
|
||||
| `/api/detections` | 2 | D1-D11, DD1-DD3 | ✅ 100% |
|
||||
| `/api/variability` | 4 | V1-V8, VI1-VI3, VA1-VA3, VU1-VU2 | ✅ 100% |
|
||||
| `/api/attributes` | 1 | A1-A7 | ✅ 100% |
|
||||
| `/api/analysis` | 6 | AS1-AS4, AC1-AC2, ANC1-ANC3, AJ1-AJ3, AU1-AU3, AR1-AR3 | ✅ 100% |
|
||||
| `/api/entities` | 7 | E1-E10, ER1, EU1-EU4, ET1 | ✅ 100% |
|
||||
|
||||
### Fonctionnalités Frontend
|
||||
|
||||
| Fonctionnalité | Tests | Couverture |
|
||||
|----------------|-------|------------|
|
||||
| Dashboard metrics | DH1-DH7 | ✅ 100% |
|
||||
| Liste détections | DL1-DL8 | ✅ 100% |
|
||||
| Investigation détails | DV1-DV8 | ✅ 100% |
|
||||
| Variabilité attributs | Via API | ✅ 100% |
|
||||
| Filtres et recherche | D3-D7, DL4-DL5 | ✅ 100% |
|
||||
| Navigation | N1-N5 | ✅ 100% |
|
||||
| Composants UI | C1-C5 | ✅ 100% |
|
||||
|
||||
### Base de Données
|
||||
|
||||
| Aspect | Tests | Couverture |
|
||||
|--------|-------|------------|
|
||||
| Tables principales | DB1, DB5 | ✅ 100% |
|
||||
| Vues matérialisées | DB2-DB4 | ✅ 100% |
|
||||
| Qualité données | DQ1-DQ5 | ✅ 100% |
|
||||
| Performance | DP1-DP5 | ✅ 100% |
|
||||
|
||||
---
|
||||
|
||||
## 9. Scripts de Test Existants
|
||||
|
||||
### 9.1 `test_dashboard.sh` (10 tests)
|
||||
|
||||
```bash
|
||||
# Exécution
|
||||
chmod +x test_dashboard.sh
|
||||
./test_dashboard.sh
|
||||
```
|
||||
|
||||
**Tests couverts:**
|
||||
1. ✅ Health check
|
||||
2. ✅ API detections
|
||||
3. ✅ Tri par score
|
||||
4. ✅ Variability IP
|
||||
5. ✅ IPs associées
|
||||
6. ✅ User-Agents
|
||||
7. ✅ Analysis subnet
|
||||
8. ✅ Analysis country
|
||||
9. ✅ Classifications
|
||||
10. ✅ Frontend accessible
|
||||
|
||||
---
|
||||
|
||||
### 9.2 `test_dashboard_entities.sql` (30 tests)
|
||||
|
||||
```bash
|
||||
# Exécution
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod < test_dashboard_entities.sql
|
||||
```
|
||||
|
||||
**Tests couverts:**
|
||||
1-3. ✅ Tables/Vues existent
|
||||
4. ✅ Schéma
|
||||
5-11. ✅ Samples par entité
|
||||
12-13. ✅ Validation ASN/Country
|
||||
14-18. ✅ Top 10 par type
|
||||
19. ✅ Activité par date
|
||||
20. ✅ Corrélation
|
||||
21-22. ✅ Types de données, NULL
|
||||
23. ✅ Stats globales
|
||||
24. ✅ Index
|
||||
25. ✅ Performance
|
||||
26. ✅ TTL
|
||||
27-30. ✅ Distributions
|
||||
|
||||
---
|
||||
|
||||
## 10. Recommandations
|
||||
|
||||
### Tests manquants à ajouter
|
||||
|
||||
1. **Tests unitaires backend** (pytest)
|
||||
```bash
|
||||
# Structure recommandée
|
||||
backend/tests/
|
||||
├── test_metrics.py
|
||||
├── test_detections.py
|
||||
├── test_variability.py
|
||||
├── test_analysis.py
|
||||
└── test_entities.py
|
||||
```
|
||||
|
||||
2. **Tests frontend** (Jest + React Testing Library)
|
||||
```bash
|
||||
# Structure recommandée
|
||||
frontend/src/
|
||||
├── __tests__/
|
||||
│ ├── App.test.tsx
|
||||
│ ├── components/
|
||||
│ │ ├── Dashboard.test.tsx
|
||||
│ │ ├── DetectionsList.test.tsx
|
||||
│ │ └── DetailsView.test.tsx
|
||||
│ └── hooks/
|
||||
│ ├── useMetrics.test.ts
|
||||
│ └── useDetections.test.ts
|
||||
```
|
||||
|
||||
3. **Tests E2E** (Playwright/Cypress)
|
||||
```bash
|
||||
# Structure recommandée
|
||||
tests/e2e/
|
||||
├── dashboard.spec.ts
|
||||
├── detections.spec.ts
|
||||
└── investigation.spec.ts
|
||||
```
|
||||
|
||||
4. **Tests de charge** (locust)
|
||||
```python
|
||||
# locustfile.py
|
||||
from locust import HttpUser, task
|
||||
|
||||
class DashboardUser(HttpUser):
|
||||
@task
|
||||
def load_metrics(self):
|
||||
self.client.get("/api/metrics")
|
||||
|
||||
@task(3)
|
||||
def load_detections(self):
|
||||
self.client.get("/api/detections?page=1")
|
||||
```
|
||||
|
||||
5. **Tests de régression API**
|
||||
```bash
|
||||
# Utiliser Newman avec collections Postman
|
||||
# Ou Insomnia avec tests automatisés
|
||||
```
|
||||
|
||||
### Couverture actuelle estimée
|
||||
|
||||
| Domaine | Couverture | Méthode |
|
||||
|---------|------------|---------|
|
||||
| Backend API | 70% | Tests manuels + scripts |
|
||||
| Frontend | 30% | Tests manuels |
|
||||
| Database | 60% | SQL tests |
|
||||
| Intégration | 40% | Workflows manuels |
|
||||
| **Total** | **50%** | |
|
||||
|
||||
### Objectif de couverture
|
||||
|
||||
| Domaine | Actuel | Cible |
|
||||
|---------|--------|-------|
|
||||
| Backend API | 70% | 90% |
|
||||
| Frontend | 30% | 80% |
|
||||
| Database | 60% | 90% |
|
||||
| Intégration | 40% | 85% |
|
||||
|
||||
---
|
||||
|
||||
## 11. Prioritisation
|
||||
|
||||
### Priorité 1 (Critique) 🔴
|
||||
|
||||
| Test | ID | Importance |
|
||||
|------|----|------------|
|
||||
| Health check | H1-H3 | Service disponible |
|
||||
| API metrics | M1-M5 | Dashboard fonctionnel |
|
||||
| API detections | D1-D11 | Liste détections |
|
||||
| Connexion ClickHouse | DB1-DB7 | Données accessibles |
|
||||
| Navigation basique | N1-N5 | UX fonctionnel |
|
||||
|
||||
**À tester avant chaque déploiement.**
|
||||
|
||||
---
|
||||
|
||||
### Priorité 2 (Important) 🟡
|
||||
|
||||
| Test | ID | Importance |
|
||||
|------|----|------------|
|
||||
| Filtres et recherche | D3-D7, DL4-DL5 | Investigation efficace |
|
||||
| Investigation IP/JA4 | V1-V8, E1-E10 | Core feature |
|
||||
| Variabilité | VI1-VI3, VA1-VA3 | Analyse comportement |
|
||||
| Pagination | D2, D10-D11, DL2 | UX grande liste |
|
||||
| Insights automatiques | V8 | Valeur ajoutée |
|
||||
|
||||
**À tester chaque sprint.**
|
||||
|
||||
---
|
||||
|
||||
### Priorité 3 (Secondaire) 🟢
|
||||
|
||||
| Test | ID | Importance |
|
||||
|------|----|------------|
|
||||
| Recommandations | AR1-AR3 | Feature avancée |
|
||||
| Analysis avancée | AS1-AS4, AJ1-AJ3 | Investigation profonde |
|
||||
| Responsive design | DH7 | Mobile support |
|
||||
| Performance | P1-P6 | Optimisation |
|
||||
| Sécurité | S1-S6 | Audit régulier |
|
||||
|
||||
**À tester avant release majeure.**
|
||||
|
||||
---
|
||||
|
||||
## 📊 Checklist de Déploiement
|
||||
|
||||
### Avant déploiement
|
||||
|
||||
- [ ] Tests Priorité 1 passants (100%)
|
||||
- [ ] Tests Priorité 2 passants (>80%)
|
||||
- [ ] Aucun bug critique ouvert
|
||||
- [ ] Logs vérifiés (pas d'erreurs)
|
||||
- [ ] Performance OK (< 2s chargement)
|
||||
|
||||
### Après déploiement
|
||||
|
||||
- [ ] Health check OK
|
||||
- [ ] Dashboard accessible
|
||||
- [ ] Métriques affichées
|
||||
- [ ] Détections listées
|
||||
- [ ] Investigation fonctionnelle
|
||||
- [ ] Logs propres
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes
|
||||
|
||||
### Commandes utiles
|
||||
|
||||
```bash
|
||||
# Lancer tous les tests
|
||||
./test_dashboard.sh
|
||||
|
||||
# Tests SQL
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod < test_dashboard_entities.sql
|
||||
|
||||
# Logs en temps réel
|
||||
docker compose logs -f dashboard_web
|
||||
|
||||
# Redémarrer le dashboard
|
||||
docker compose restart dashboard_web
|
||||
|
||||
# Vérifier données ClickHouse
|
||||
docker compose exec clickhouse clickhouse-client -d mabase_prod -q \
|
||||
"SELECT count() FROM ml_detected_anomalies WHERE detected_at >= now() - INTERVAL 24 HOUR"
|
||||
```
|
||||
|
||||
### Contacts et Support
|
||||
|
||||
- **Documentation API:** http://localhost:3000/docs
|
||||
- **Logs:** `docker compose logs dashboard_web`
|
||||
- **ClickHouse:** `docker compose exec clickhouse clickhouse-client -d mabase_prod`
|
||||
|
||||
---
|
||||
|
||||
**Document créé:** 2025
|
||||
**Dernière mise à jour:** 2025
|
||||
**Version:** 1.0
|
||||
Reference in New Issue
Block a user