krizaka-billing
Facturation & crédits
Crédits, portefeuilles, plans, une grille tarifaire versionnée et le comptage : réserver → régler → libérer.
Le problème qu'elle supprime
Débiter après, et le travail tourne à crédit. Débiter avant, et les échecs sont facturés.
Facturer un travail coûteux échoue de deux façons : débiter après, et le travail a tourné sur un crédit que personne n'avait ; débiter avant, et un job échoué est facturé. Puis un message « job terminé » est relivré et le même job est débité deux fois.
- Un utilisateur qui lance dix jobs coûteux d'un coup avec le crédit d'un seul.
- Un rendu échoué facturé à son estimation.
- Un règlement relivré qui débite deux fois.
Ce qu'elle fait
holdsur l'estimation avant le travail, puissettleMeasuredourelease.- Chaque débit porte une clé d'idempotence : un message relivré n'est débité qu'une fois.
- Plans, abonnements, packs et portefeuilles autour d'un grand livre en ajout seul.
Un service et un client typé : l'appelant réserve les crédits estimés avant un travail coûteux, puis règle le coût mesuré ou libère la réservation. Les réservations jamais réglées expirent. Autour : plans, abonnements, packs, portefeuilles et statistiques d'usage.
Le flamant est payé pour ce qui a été fait, une fois — et personne ne paie un travail qui a échoué. Un job en échec libère sa réservation ; chaque débit porte une clé d'idempotence.
Décisions et compromis
Nous avons choisi
Réserver → régler → libérer, avec une expiration sur les réservations.
Nous avons refusé
Débiter après le travail, et prépayer sans réservation.
Parce que
Un travail ne démarre jamais sans le crédit pour le couvrir, et un échec ne coûte rien.
Ce que cela vous coûte
Un appel synchrone (la réservation) sur le chemin de la requête ; régler et libérer en sont hors.
Nous avons choisi
Un grand livre en ajout seul où chaque débit porte une clé d'idempotence, en plus de la déduplication des messages.
Nous avons refusé
Se fier à la seule déduplication.
Parce que
Deux gardes indépendantes : une relivraison qui passe l'une débite quand même une seule fois.
Ce que cela vous coûte
Le grand livre ne fait que grandir ; une correction est une nouvelle écriture.
Nous avons choisi
Les prix et la durée de vie d'une réservation sont des lignes d'une grille tarifaire versionnée ; une réservation fige la version à laquelle elle a été tarifée.
Nous avons refusé
Des prix dans le code ou la configuration.
Parce que
Changer un prix ne change jamais ce que coûte un job en cours, et ne demande aucun déploiement.
Ce que cela vous coûte
Un changement de prix est une migration de données que vous relisez.
Nous avons choisi
Un adaptateur neutre quand
krizaka.billing.enabledvaut false.Nous avons refusé
Un
if (billingEnabled)à chaque appel.Parce que
Le même code tourne avec et sans comptage.
Ce que cela vous coûte
Rien qui vaille d'être cité.
En code
CreditHoldResponse hold = credits.hold(new CreditHoldCommand(
userId, BillableCapability.IMAGE, "sdxl", requestId, jobId, estimate));
// InsufficientCreditsException carries what a structured 402 needs
try {
Render render = renderer.run(job);
// The ledger prices what was measured, at the price-book version the hold pinned.
credits.settleMeasured(hold.holdId(), render.consumption(), jobId); // jobId = idempotency key
} catch (RuntimeException failed) {
credits.release(hold.holdId(), "render failed"); // a failed job is never billed
throw failed;
}Ne l'utilisez pas quand
- Il vous faut des factures, des taxes ou des paiements par carte : billing compte des crédits ; encaisser reste à vous (une recharge crédite un portefeuille).
- Vos capacités ne sont pas du travail d'IA — aujourd'hui. Le contrat nomme encore celles d'Orazaka (CHAT, IMAGE, AUDIO, VIDEO, AGENT) et ses mesures (jetons, secondes GPU…) ; voir plus bas.
Où elle en est
0.1.0 sur Maven Central (api, client). La 0.2.0 — l'outbox implémente OutboxStore.append, chaque événement a son JSON Schema — est fusionnée et sort en novembre.
Publié
En cours
- Décidé : capacités et unités deviennent des clés déclarées dans la grille tarifaire, les mesures une table de quantités ; Orazaka garde ses enums chez Orazaka. Une brique de facturation réutilisable ne peut pas parler le vocabulaire d'un seul produit.krizaka-billing#7
- Le BOM 0.2.0 gère cette brique en 0.2.0, non publiée : déclarez 0.1.0 explicitement jusqu'au BOM 0.3.0.krizaka-build#11
L'adopter
<dependency>
<groupId>com.krizaka</groupId>
<artifactId>krizaka-billing-client</artifactId>
<version>0.1.0</version>
</dependency>
<!-- krizaka.billing.enabled: false wires a no-op adapter: no call site branches on "is billing on" -->Dites-nous où ça coince.
Une brique est juste quand elle survit à votre code, pas au nôtre. Posez votre question dans le fil de la brique, proposez un changement comme idée, ou signalez un bug sur son dépôt — chaque décision de cette page reste ouverte à un meilleur argument.
Les autres briques
- Platform kitUn événement publié après le commit se perd au prochain crash.
- UtilisateursL'inscription ressemble à un week-end. Jetons de reset, OAuth et JWT en font un trimestre.
- NotificationsUn e-mail envoyé dans une transaction annulée ne se rattrape pas.
- Build, BOM & kit de testLes POM parents dérivent — et un BOM Spring écrase en silence la version de Boot choisie.
- Krizaka UITrois produits, trois vocabulaires de jetons, 1 153 surcharges
light:dans une seule app.