@mostajs/fidelite
v0.2.0
Published
Fidélité de commerce de proximité : un client reconnu par une CLÉ (téléphone, carte, compte), un compteur de passages, et un avantage qui s'ouvre puis se CONSOMME. Idempotent par commande. Ne connaît ni la carte, ni les prix, ni l'encaissement : il rend u
Maintainers
Readme
@mostajs/fidelite
Une clé, un compteur, un avantage qui se consomme.
Auteur : Dr Hamid MADANI [email protected] · Licence : AGPL-3.0-or-later · Zéro dépendance npm
Ce qu'il fait
Compter les passages d'un client et lui ouvrir un avantage au seuil. C'est tout — et c'est délibéré : le module ne sait rien du client, rien des prix, rien des droits.
import { createFidelite, normaliserTelephone } from '@mostajs/fidelite';
const fidelite = createFidelite({
repositories: { cartes, passages },
regle: { seuil: 10, remisePourMille: 150 }, // EXIGÉE — aucun défaut
empreinte: (cle) => hmac(cle), // la clé n'est jamais stockée en clair
normaliser: normaliserTelephone,
});
const etat = await fidelite.etat({ cle: '06 12 34 56 78' });
// { passages: 10, seuil: 10, acquis: true, remisePourMille: 150 }La règle n'a pas de valeur par défaut
{ seuil, remisePourMille } est exigée. Un seuil deviné est une promesse commerciale inventée,
et le client la découvrirait à la caisse. Le module refuse de se construire sans elle.
Les taux sont en pour mille entiers — 150 = 15 %. Jamais un flottant sur une remise.
La clé n'est jamais stockée en clair
normaliserTelephone d'abord, empreinte ensuite. 06 12 34 56 78, +33612345678 et 0612345678
doivent désigner la même personne, sinon le client perd ses passages en changeant de manière de
dicter son numéro.
La base porte l'empreinte. Conséquence assumée : on peut vérifier qu'un client revient, on ne peut pas reconstituer une liste de clients à partir de la base. C'est ce qu'on veut d'un numéro de téléphone.
L'ordre des deux gestes
if (taux) await fidelite.consommer({ cle, commandeId: c.id }); // le droit était ouvert AVANT
await fidelite.compter({ cle, commandeId: c.id, montant }); // puis cette commande-ciL'inverse ferait compter la commande remisée comme un passage vers la remise suivante : le client gagnerait un passage gratuit à chaque récompense.
Pièges
compter()est idempotent parcommandeId— un rechargement de page ne double pas un passage. L'idempotence ignore les enregistrements de remise : sans cela, la remise et le passage partageant le mêmecommandeId, le client perdait une commande à chaque récompense.- Le seuil compte des passages, pas des montants.
montantsert à l'historique. - Le module constate, il ne décide pas qui a le droit d'accorder une remise : cela relève de la matrice de permissions de l'application.
Persistance
register() déclare CarteFidelite et PassageFidelite par le contrat
(@mostajs/module-contract). L'application ne tient aucune liste de schémas.
Documentation
llms.txt · CHANGELOG.md
