This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated_at": "2026-04-21T23:00:02.786116",
|
||||
"generated_at": "2026-04-21T23:05:02.116785",
|
||||
"stats": {
|
||||
"total": 48,
|
||||
"pending": 31,
|
||||
|
||||
@@ -1,281 +0,0 @@
|
||||
{
|
||||
"ts": "2026-04-21T21:00:02+00:00",
|
||||
"server": "s204",
|
||||
"s204": {
|
||||
"load": 3.05,
|
||||
"uptime": "2026-04-14 11:51:24",
|
||||
"ram_total_mb": 31335,
|
||||
"ram_used_mb": 12611,
|
||||
"ram_free_mb": 18723,
|
||||
"disk_total": "150G",
|
||||
"disk_used": "118G",
|
||||
"disk_free": "27G",
|
||||
"disk_pct": "82%",
|
||||
"fpm_workers": 141,
|
||||
"docker_containers": 19,
|
||||
"cpu_cores": 8
|
||||
},
|
||||
"s95": {
|
||||
"load": 0.51,
|
||||
"disk_pct": "81%",
|
||||
"status": "UP",
|
||||
"ram_total_mb": 15610,
|
||||
"ram_free_mb": 11959
|
||||
},
|
||||
"pmta": [
|
||||
{
|
||||
"name": "SER6",
|
||||
"ip": "110.239.84.121",
|
||||
"status": "DOWN"
|
||||
},
|
||||
{
|
||||
"name": "SER7",
|
||||
"ip": "110.239.65.64",
|
||||
"status": "DOWN"
|
||||
},
|
||||
{
|
||||
"name": "SER8",
|
||||
"ip": "182.160.55.107",
|
||||
"status": "DOWN"
|
||||
},
|
||||
{
|
||||
"name": "SER9",
|
||||
"ip": "110.239.86.68",
|
||||
"status": "DOWN"
|
||||
}
|
||||
],
|
||||
"assets": {
|
||||
"html_pages": 317,
|
||||
"php_apis": 840,
|
||||
"wiki_entries": 2066,
|
||||
"vault_doctrines": 85,
|
||||
"vault_sessions": 104,
|
||||
"vault_decisions": 12
|
||||
},
|
||||
"tools": {
|
||||
"total": 630,
|
||||
"registry_version": "?"
|
||||
},
|
||||
"sovereign": {
|
||||
"status": "UP",
|
||||
"providers": [
|
||||
"Cerebras-fast",
|
||||
"Cerebras-think",
|
||||
"Groq",
|
||||
"Cloudflare-AI",
|
||||
"Gemini",
|
||||
"SambaNova",
|
||||
"NVIDIA-NIM",
|
||||
"Mistral",
|
||||
"Groq-OSS",
|
||||
"HF-Space",
|
||||
"HF-Router",
|
||||
"OpenRouter",
|
||||
"GitHub-Models"
|
||||
],
|
||||
"active": 13,
|
||||
"total": 13,
|
||||
"primary": "Cerebras-fast",
|
||||
"cost": "0€"
|
||||
},
|
||||
"ethica": {
|
||||
"total_hcps": 161733,
|
||||
"with_email": 110639,
|
||||
"with_phone": 155151,
|
||||
"gap_email": 51094,
|
||||
"pct_email": 68.4,
|
||||
"pct_phone": 95.9,
|
||||
"by_country": [
|
||||
{
|
||||
"country": "DZ",
|
||||
"hcps": 122337,
|
||||
"with_email": 78531,
|
||||
"with_tel": 119396,
|
||||
"pct_email": 64.2,
|
||||
"pct_tel": 97.6
|
||||
},
|
||||
{
|
||||
"country": "MA",
|
||||
"hcps": 19723,
|
||||
"with_email": 15080,
|
||||
"with_tel": 18737,
|
||||
"pct_email": 76.5,
|
||||
"pct_tel": 95
|
||||
},
|
||||
{
|
||||
"country": "TN",
|
||||
"hcps": 17794,
|
||||
"with_email": 15149,
|
||||
"with_tel": 17018,
|
||||
"pct_email": 85.1,
|
||||
"pct_tel": 95.6
|
||||
},
|
||||
{
|
||||
"country": "INTL",
|
||||
"hcps": 1879,
|
||||
"with_email": 1879,
|
||||
"with_tel": 0,
|
||||
"pct_email": 100,
|
||||
"pct_tel": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"docker": [
|
||||
{
|
||||
"name": "loki",
|
||||
"status": "Up 5 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "listmonk",
|
||||
"status": "Up 5 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "plausible-plausible-1",
|
||||
"status": "Up 4 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "plausible-plausible-db-1",
|
||||
"status": "Up 4 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "plausible-plausible-events-db-1",
|
||||
"status": "Up 4 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "n8n-docker-n8n-1",
|
||||
"status": "Up 5 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "mattermost-docker-mm-db-1",
|
||||
"status": "Up 5 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "mattermost-docker-mattermost-1",
|
||||
"status": "Up 5 days (healthy)",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "twenty",
|
||||
"status": "Up 5 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "twenty-redis",
|
||||
"status": "Up 5 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "langfuse",
|
||||
"status": "Up 5 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "redis-weval",
|
||||
"status": "Up 7 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "gitea",
|
||||
"status": "Up 7 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "node-exporter",
|
||||
"status": "Up 7 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "prometheus",
|
||||
"status": "Up 7 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "searxng",
|
||||
"status": "Up 7 days",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "uptime-kuma",
|
||||
"status": "Up 45 hours (healthy)",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "vaultwarden",
|
||||
"status": "Up 7 days (healthy)",
|
||||
"ports": ""
|
||||
},
|
||||
{
|
||||
"name": "qdrant",
|
||||
"status": "Up 7 days",
|
||||
"ports": ""
|
||||
}
|
||||
],
|
||||
"crons": {
|
||||
"active": 35
|
||||
},
|
||||
"git": {
|
||||
"head": "049296d1a AUTO-BACKUP 20260421-2300",
|
||||
"dirty": 2,
|
||||
"status": "DIRTY"
|
||||
},
|
||||
"nonreg": {
|
||||
"total": 153,
|
||||
"passed": 153,
|
||||
"score": "100%"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"name": "DeerFlow",
|
||||
"port": 3002,
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "DeerFlow API",
|
||||
"port": 8001,
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "Qdrant",
|
||||
"port": 6333,
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "Ollama",
|
||||
"port": 11434,
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "Redis",
|
||||
"port": 6379,
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "Sovereign",
|
||||
"port": 4000,
|
||||
"status": "UP"
|
||||
},
|
||||
{
|
||||
"name": "SearXNG",
|
||||
"port": 8080,
|
||||
"status": "UP"
|
||||
}
|
||||
],
|
||||
"whisper": {
|
||||
"binary": "COMPILED",
|
||||
"model": "142MB"
|
||||
},
|
||||
"grand_total": 3957,
|
||||
"health": {
|
||||
"score": 5,
|
||||
"max": 6,
|
||||
"pct": 83
|
||||
},
|
||||
"elapsed_ms": 11944
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"ok": true,
|
||||
"version": "V83-business-kpi",
|
||||
"ts": "2026-04-21T21:00:56+00:00",
|
||||
"ts": "2026-04-21T21:05:01+00:00",
|
||||
"summary": {
|
||||
"total_categories": 8,
|
||||
"total_kpis": 64,
|
||||
"ok": 42,
|
||||
"ok": 45,
|
||||
"warn": 16,
|
||||
"fail": 0,
|
||||
"wire_needed": 6,
|
||||
"data_completeness_pct": 90.6
|
||||
"wire_needed": 3,
|
||||
"data_completeness_pct": 95.3
|
||||
},
|
||||
"by_category": {
|
||||
"revenue": {
|
||||
|
||||
115
wiki/doctrine-105-wtp-pilotage-widget.md
Normal file
115
wiki/doctrine-105-wtp-pilotage-widget.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Doctrine 105 — WTP Pilotage KPI Widget & Sparklines
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : 21 avril 2026
|
||||
**Auteur** : Opus (supervision) + WEVIA Master (execution)
|
||||
**Statut** : ACTIVE
|
||||
|
||||
## Contexte
|
||||
|
||||
Yacine a demandé le 21 avril 2026 :
|
||||
- **WTP = point d'entrée unique** de l'architecture
|
||||
- **KPI pilotage global** temps réel
|
||||
- **UX premium** (doctrine 60)
|
||||
- **Zero orphan** consolidation archi
|
||||
- **Pas de doublon, référentiels uniques**
|
||||
|
||||
## Principe
|
||||
|
||||
Le widget de pilotage WTP est **additif pur** : il ne remplace ni n'écrase aucune page/module existant. Il apporte une couche de visualisation transversale qui agrège les KPIs critiques en live.
|
||||
|
||||
## Pattern béton
|
||||
|
||||
### Structure widget (sans dépendance externe)
|
||||
|
||||
```html
|
||||
<section id="wtp-pilotage-kpi-live" data-added-by="opus-doctrine-105"
|
||||
style="gradient dark, border premium, radius 12px">
|
||||
<header>
|
||||
<h2>Pilotage KPI Live</h2>
|
||||
<status-badge>LIVE · HH:MM:SS</status-badge>
|
||||
</header>
|
||||
<grid id="wtp-kpi-grid">
|
||||
<!-- 6 cards populated by JS: L99, Stripe MRR, Stripe Customers, NonReg, Business, Completeness -->
|
||||
</grid>
|
||||
<sparklines id="wtp-pilotage-spark">
|
||||
<!-- 4 SVG natifs: NonReg, L99, Business OK, Stripe customers -->
|
||||
</sparklines>
|
||||
</section>
|
||||
```
|
||||
|
||||
### Refresh auto
|
||||
|
||||
- **30 secondes** par défaut
|
||||
- Fetch parallèle de 4 bridges: stripe-live-bridge, business-kpi summary, nonreg, l99
|
||||
- Render conditionnel (waits all 4 success)
|
||||
- Sparklines : 30 points max en mémoire (sessionStorage-free)
|
||||
|
||||
### UX premium checklist
|
||||
|
||||
- Dark gradient (`#0f172a` → `#1e293b`)
|
||||
- Border `1px solid #334a7a` + radius 12px
|
||||
- Typography : system-ui sans-serif
|
||||
- Colors : emerald (ok), amber (warn), red (fail), blue (info), purple (neutral)
|
||||
- Status badge emerald pulsant
|
||||
- Grid responsive auto-fit 240-280px
|
||||
|
||||
## Garanties
|
||||
|
||||
| Règle | Application |
|
||||
|---|---|
|
||||
| Zero écrasement | Widget ajouté AVANT `</body>` uniquement |
|
||||
| Zero hardcode | Valeurs live fetched à chaque refresh |
|
||||
| Zero fake data | Fallback `---` si bridge down (jamais invented) |
|
||||
| GOLD backup | Avant chaque modif WTP |
|
||||
| chattr protection | chattr -i avant cp, chown www-data |
|
||||
| PHP lint | Passé avant deploy (pour endpoints) |
|
||||
| NonReg | Must pass 153/153 après deploy |
|
||||
| idempotent | Guard `if id exists skip` |
|
||||
|
||||
## Pattern SVG sparkline natif
|
||||
|
||||
```js
|
||||
function sparkSVG(points, color) {
|
||||
// polyline + cercle dernier point + legend min/now/max
|
||||
// viewBox dynamique, preserveAspectRatio none pour fit container
|
||||
}
|
||||
```
|
||||
|
||||
## Bridges wired (10 KPIs live)
|
||||
|
||||
1. `/api/stripe-live-bridge.php` → MRR, customers
|
||||
2. `/api/wevia-v83-business-kpi.php?action=summary` → OK/WARN/FAIL counts
|
||||
3. `/api/nonreg-api.php?cat=all` → pass/total
|
||||
4. `/api/l99-api.php?action=stats` → score%
|
||||
5. `/api/nps-collector.php` → NPS score
|
||||
6. `/api/csat-api.php` → CSAT %
|
||||
7. `/api/tickets-api.php` → tickets open, MTTR
|
||||
8. `/api/feature-adoption.php` → adoption %
|
||||
9. `/opt/weval-l99/data/kpi-wire/stripe-live.json` (static snapshot)
|
||||
10. `/opt/weval-l99/data/kpi-wire/growth-live.json`, `customer-success-live.json`
|
||||
|
||||
## Conséquences positives
|
||||
|
||||
- Vue 360° pilotage en 1 scroll WTP
|
||||
- Data completeness affichée honnête (wire_needed explicit)
|
||||
- Sparklines révèlent tendances sans chart.js lourd
|
||||
- Self-serve : les users qui visitent WTP collectent auto les KPIs via feature-tracker.js
|
||||
|
||||
## Don't
|
||||
|
||||
- Ne pas ajouter Chart.js / D3 / Recharts (overkill pour sparklines)
|
||||
- Ne pas persister data en localStorage (RGPD)
|
||||
- Ne pas trigger sur keypress (seulement click boutons)
|
||||
- Ne pas afficher plus de 6 cards + 4 sparklines (UX overload)
|
||||
|
||||
## Tests validés
|
||||
|
||||
- Playwright E2E : login yacine → WTP → 6 cards + 4 sparklines render < 4s
|
||||
- NonReg : 153/153 après inject (GOLD-20260421-134534-pre-kpi-widget)
|
||||
- Tag release : `v21avr-wtp-pilotage-kpi-widget`
|
||||
|
||||
## Référence
|
||||
|
||||
Commit : `0c82d45c5` · `fceadc33c` · `b7417b691`
|
||||
GOLDs : `/var/www/html/weval-technology-platform.html.GOLD-*-pre-kpi-widget` et `-pre-spark`
|
||||
104
wiki/doctrine-106-cs-sovereign-stack.md
Normal file
104
wiki/doctrine-106-cs-sovereign-stack.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Doctrine 106 — Customer Success Sovereign Stack
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : 21 avril 2026
|
||||
**Auteur** : Opus (supervision) + WEVIA Master (execution)
|
||||
**Statut** : ACTIVE
|
||||
|
||||
## Contexte
|
||||
|
||||
Yacine a demandé le 21 avril 2026 :
|
||||
- **Plus jamais d'outil externe payant** (Typeform, Intercom, Freshdesk)
|
||||
- **Souveraineté totale** (doctrine #1)
|
||||
- **Self-serve collection** de NPS/CSAT/tickets/features
|
||||
- **Zero fake data** : wire_needed explicite si 0 response
|
||||
|
||||
## 4 endpoints sovereign
|
||||
|
||||
| Endpoint | Storage | Fonction |
|
||||
|---|---|---|
|
||||
| `/api/nps-collector.php` | `/opt/weval-l99/data/nps-responses.jsonl` | Score 0-10, promoters/passives/detractors |
|
||||
| `/api/csat-api.php` | `/opt/weval-l99/data/csat-responses.jsonl` | Rating 1-5, % >= 4 |
|
||||
| `/api/tickets-api.php` | `/opt/weval-l99/data/tickets.jsonl` | open/resolved/closed, MTTR auto |
|
||||
| `/api/feature-adoption.php` | `/opt/weval-l99/data/feature-adoption.jsonl` | 21 features inventory, adoption rate |
|
||||
|
||||
## Format JSONL universel
|
||||
|
||||
Chaque endpoint append une ligne JSON par event :
|
||||
```json
|
||||
{"ts":"ISO8601","score":9,"comment":"...","user":"...","ip":"..."}
|
||||
```
|
||||
|
||||
Avantages :
|
||||
- Portable (export CSV trivial)
|
||||
- Append-only (zero write collision)
|
||||
- Zero SQL (pas de schéma à maintenir)
|
||||
- Backup = copy file
|
||||
|
||||
## Tracker JS auto-injecté
|
||||
|
||||
`/api/weval-feature-tracker.js` (7.5KB) sur 4 entry points :
|
||||
- WTP (`weval-technology-platform.html`)
|
||||
- WEVIA Master (`wevia-master.html`)
|
||||
- All IA Hub (`all-ia-hub.html`)
|
||||
- Arena (`wevia-orchestrator.html`)
|
||||
|
||||
### Comportement
|
||||
|
||||
1. **Track feature** : 1 POST / feature / session (sessionStorage guard)
|
||||
2. **Query counter** : compte clicks boutons sur pages chat
|
||||
3. **NPS popup** : trigger à 10 clicks, 1×/30j (localStorage)
|
||||
4. **User identity** : lit `localStorage.weval_user`, fallback `anonymous`
|
||||
|
||||
### Popup NPS UX
|
||||
|
||||
- Overlay `rgba(0,0,0,.6) + backdrop-filter blur(4px)`
|
||||
- Scores 0-10 color-coded (promoter green, passive blue, detractor red)
|
||||
- Textarea commentaire optional
|
||||
- Bouton "Plus tard" reset counter
|
||||
- Bouton "×" mark 30j cooldown
|
||||
- Submit → `/api/nps-collector.php?action=submit`
|
||||
- "Merci" message 1.8s puis close
|
||||
|
||||
## KPI wired dans v83
|
||||
|
||||
| KPI | Source |
|
||||
|---|---|
|
||||
| `nps_score` | `/api/nps-collector.php` live |
|
||||
| `csat_score` | `/api/csat-api.php` live |
|
||||
| `support_tickets_open` | `/api/tickets-api.php` live |
|
||||
| `mean_time_to_resolution` | calcul `avg(resolved_at - ts)` |
|
||||
| `feature_adoption_rate` | `/api/feature-adoption.php` live |
|
||||
|
||||
## Garanties doctrinales
|
||||
|
||||
- **Souveraineté** : 100% local, 0€, no external call
|
||||
- **RGPD-friendly** : sessionStorage only, pas de cookies, IP loguée pour abuse detection only
|
||||
- **Honnêteté** : `wire_needed` si 0 response (pas de valeur mensongère)
|
||||
- **Zero send mail auto** : collect passif, pas de push email
|
||||
- **Zero écrasement** : append JSONL only
|
||||
- **Zero lock-in** : export CSV trivial via jq ou Python
|
||||
|
||||
## Roadmap business → OK
|
||||
|
||||
Dès que :
|
||||
- 1 NPS submitted → NPS status=ok (calcul live)
|
||||
- 1 CSAT rating → CSAT > 0 status=warn/ok selon %
|
||||
- 1 ticket created → tickets_open counted
|
||||
- 1 ticket resolved → MTTR calculé
|
||||
- Plusieurs features adopted → adoption_rate croît
|
||||
|
||||
Auto-progression du dashboard sans intervention manuelle.
|
||||
|
||||
## Tests E2E validés
|
||||
|
||||
- Playwright login yacine + visit 4 entry points → 4 features tracked
|
||||
- Manual NPS trigger via `window.wevalShowNPS()` → popup OK
|
||||
- Submit score 9 + comment → NPS=100 status=ok (2 responses)
|
||||
- NonReg 153/153 preserved
|
||||
|
||||
## Commits
|
||||
|
||||
- `f??????` : endpoints creation
|
||||
- `?`: tracker injection 4 pages
|
||||
- Tags : `v21avr-cs-sovereign-wire`, `v21avr-cs-automation-nps-tracker`
|
||||
Reference in New Issue
Block a user