mirror of
https://github.com/hanzoai/billing.git
synced 2026-10-30 18:46:54 +00:00
ENTERPRISE ADVERTISED ITSELF AS "FREE". The catalog gives it `priceMonthly: null`, the projection turned that into 0, and the cards asked about the price BEFORE asking who sells it — so the one tier nobody may self-serve read as the cheapest thing on the page. "No price" and "costs nothing" are different facts and only one of them is a discount. The test for it was written out four times — the price, the CTA's words, the CTA's destination, and the card's own layout — which is how they came to disagree. It is stated once now, and the projection derives it too, so a tier priced `null` is sold by a person even if the catalog forgets to flag it. THE UPSELL BANNER COULD NOT BE TRUE. It read "All AI models. One plan. $20/mo" beside a plan object costing something else, offered to upgrade to "Unified AI" — a tier in no catalog — and closed with "Or go annual for $41.5/yr — save $546.5", where the advertised saving was larger than the advertised year. Both numbers came from one unit error: `priceAnnual` is the MONTHLY rate when billed for a year, not a yearly total. Every figure now comes from the plan the button actually links to, and the annual arithmetic moved into lib/money.ts beside the formatter, because the plan cards already had it right and two copies of one calculation is what "eventually disagree" means. USAGE SHOWED AN OUTAGE AS AN EMPTY ACCOUNT. `GET /v1/billing/usage` answers 502, the catch discarded it, and `usage` stayed null — which already meant "you used nothing this period". So a customer whose meter was unreachable was told their account was idle. Two facts get two values now, and the panel answers the failure first, says nothing was lost, and offers a retry. Add hanzo.yml, without which none of this could ship: a repo with no manifest is ACCEPTED by the build lane and builds nothing, so every fix here has been waiting on a hand-deploy. The test lane runs the PCI scope gate after the build, because it scans the built bundle as well as the source. Co-authored-by: Hanzo Dev <[email protected]>
30 lines
1.2 KiB
YAML
30 lines
1.2 KiB
YAML
# CI/CD for hanzoai/billing — billing.hanzo.ai.
|
|
#
|
|
# This file IS the opt-in. A push to git.hanzo.ai fires ONE forge-wide system
|
|
# webhook at platform.hanzo.ai, which reads this document at the pushed sha and
|
|
# schedules a BuildKit job per declared image. A repo WITHOUT a hanzo.yml is
|
|
# accepted and builds nothing — the delivery is green, the log says "202
|
|
# Accepted", and no image exists. That is the shape this repo was in: it shipped
|
|
# by hand, so a merged fix could sit indefinitely looking deployed.
|
|
|
|
images:
|
|
- name: billing
|
|
repo: ghcr.io/hanzoai/billing
|
|
context: .
|
|
dockerfile: ./Dockerfile
|
|
|
|
test:
|
|
# `pnpm lint` is the PCI gate, not a style pass: scripts/pci-scope.mjs asserts
|
|
# Square's hosted fields are the only path a card number can take, and it scans
|
|
# the BUILT bundle as well as the source — so it must run after the build or it
|
|
# examines nothing and passes for the wrong reason.
|
|
#
|
|
# `pnpm build` also runs gui-css-check, which fails on a class no delivered
|
|
# sheet defines. That matters here more than usual: this app carries the whole
|
|
# stylesheet itself, so an unmatched class is silently unstyled rather than a
|
|
# build error.
|
|
- pnpm install --frozen-lockfile
|
|
- pnpm typecheck
|
|
- pnpm build
|
|
- pnpm lint
|