Menu
Commandes + Cmd SAV & INFO Contacts Comptes pro Chiffrages Idées Messages
Utilisateur
Darsy
Messages
Chargement...
Nouvelle conversation
Sélectionnez un ou plusieurs participants :
Source : docs/50-pilotage/99-technique.md — ce document se lit aussi dans le dépôt, sans serveur.

Pilotage et outils — le côté technique


Les fichiers

RôleFichier
Tableau de bordpublic/erp/index.php + public/erp/assets/js/pages/index-2.js
Compteurs d'en-têtesrc/Http/Controllers/TopbarController.php
Analyticspublic/erp/analytics.php, src/Http/Controllers/AnalyticsController.php
Données Analyticssrc/Repository/AnalyticsRepository.php
La projectionsrc/Analytics/Projection.php
Attributionspublic/erp/attributions.php, src/Http/Controllers/AttributionController.php
Données attributionssrc/Repository/AttributionRepository.php
Exportpublic/erp/export.php, src/Http/Controllers/ExportController.php
Journal d'auditpublic/erp/audit.php, src/Http/Controllers/AuditController.php
Écriture du journalsrc/Service/AuditService.php
Recherchesrc/Http/Controllers/SearchController.php
Filtrage par modulesrc/Http/ModuleAccess.php

Les droits

ÉcranDroit
Analytics, attributionsModule analytics
Tableau de bord, recherche, compteursModule orders
ExportModule finance, et hr pour les fiches de paie
Journal d'auditAdministrateur

Les dix vues d'Analytics

GET /v1/analytics/overview          vue d'ensemble
GET /v1/analytics/sales-timeline    ventes dans le temps
GET /v1/analytics/products          produits
GET /v1/analytics/customers         clients
GET /v1/analytics/attribution       attribution
GET /v1/analytics/suppliers         fournisseurs
GET /v1/analytics/margins           marges
GET /v1/analytics/operations        operations
GET /v1/analytics/cash              tresorerie
GET /v1/analytics/quality           qualite (irregularites par fournisseur)

L'export vérifie le module par type

private const TYPES = [
    'bills'           => [/* … */ 'module' => 'finance'],
    'avoirs'          => [/* … */ 'module' => 'finance'],
    'salaires'        => [/* … */ 'module' => 'hr'],
    'bank-statements' => [/* … */ 'module' => 'finance'],
];

Ajouter un type sans son module le laisse accessible à tout détenteur de finance.


Rien n'est stocké côté lecture

audit_logs est écrite par AuditService et lue telle quelle. InnerPerf et la projection ne stockent rien non plus : tout se recalcule à chaque lecture.

Un chiffre stocké serait faux le jour où la règle qui le produit change, et personne ne saurait lequel des deux croire.


Les tests

tests/Unit/ProjectionTest.php, tests/Unit/DroitsDeModuleTest.php, tests/Unit/VocabulaireAuditTest.php, tests/Unit/LikePatternTest.php.

Sur MySQL : tests/Integration/AnalyticsAvanceeIntegrationTest.php.


Les recherches des clients

Pourquoi Darsy relève lui-même

L'API de statistiques de Doofinder est agrégée. clicks-with-users et inits-with-users comptent les utilisateurs, ils ne les nomment pas ; searches rend un total par jour. Un seul de leurs points d'entrée est individuel — /sales, qui donne le montant et la session de chaque vente.

Savoir ce qu'un client donné a cherché est donc hors de portée de leur API.

La capture observe le réseau, pas le DOM

Le module darsy-plugin/includes/recherches.php enfile un script qui enveloppe fetch et XMLHttpRequest et observe les appels vers le moteur de Doofinder.

La couche Doofinder n'expose que trois événements — doofinder.layer.load, .update, .carousel.load — et leur charge utile n'est pas documentée. Lire la valeur d'un champ de saisie au bon moment serait deviner, et casserait au premier changement de leur interface.

Ce que Doofinder demande est en revanche exactement ce que le visiteur a cherché. Et la réponse porte le nombre de résultats : les recherches sans résultat en sortent gratuitement.

Trois choses sont prises au passage :

SurOn lit
…/_searchla requête et son nombre de résultats
…/stats/clickl'article cliqué
n'importe quel appel de statistiquesl'identifiant de session de Doofinder

Ce dernier n'est donc pas deviné : il est lu. Il permettra de rapprocher nos relevés de leur point /sales.

La jointure n'existe que parce qu'on la pose

Notre propre identifiant de session vit dans un cookie, posé dès la première page, et le plugin l'écrit dans la méta _darsy_recherche_session au paiement. Sans cette méta, les relevés resteraient une masse anonyme : on saurait ce que « quelqu'un » a cherché, jamais ce que ce client a cherché.

Notre identifiant est le maître, pas le leur. Celui de Doofinder peut manquer — visiteur qui n'ouvre jamais la recherche, script bloqué, changement de leur côté. La jointure ne dépend donc de personne d'autre que nous.

Le cookie plutôt qu'un champ caché du formulaire : il fonctionne pour la commande classique et pour les blocs, et il survit au cache de pages — un champ caché serait servi figé.

Rien n'est stocké dans Darsy

Les relevés vivent sur la boutique, là où ils s'écrivent. Darsy les demande quand un opérateur ouvre un écran.

Une lecture par consultation au lieu d'une copie permanente à synchroniser : une seule vérité, aucune tâche planifiée, et pas de route d'écriture publique sur l'ERP pour de la télémétrie.

L'écriture publique est bornée par sa forme, pas par une identité

La route POST darsy/v1/recherche est appelée par le navigateur du visiteur : elle ne peut pas exiger de clé, et un jeton de formulaire serait servi périmé par le cache de pages.

Elle est donc bornée autrement : deux cents caractères par texte, trois cents événements par session, et une réponse 204 identique en cas de succès comme de refus — ce qui retire tout intérêt à la sonder. Une requête inventée ne peut que polluer nos propres statistiques, et seulement jusqu'à ces plafonds.

Les routes

RouteDroitCe qu'elle fait
GET /v1/searches/session/{session}commandesLa chronologie d'une session
GET /v1/searches/reportanalyticsLes deux listes, sur une période
POST /v1/searches/purgeadministrateurEfface avant une date, et le journalise

Côté plugin : POST darsy/v1/recherche (public, borné), GET darsy/v1/recherches/session/{session}, GET darsy/v1/recherches/rapport, POST darsy/v1/recherches/purge — les trois dernières derrière la clé partagée.

Le déploiement demande un geste de plus

Le module vit dans darsy-plugin/, qui est dans le dépôt Darsy mais s'exécute sur WordPress. Un git pull côté ERP ne le met donc pas en service : il faut copier darsy-plugin/ dans wp-content/plugins/ de la boutique. La table se crée toute seule au premier chargement — y compris sur un plugin déjà actif, qui ne rejouerait jamais son hook d'activation.