4cc1c3a423
CI/CD / CI · API (dotnet build + test) (push) Successful in 1m3s
CI/CD / CI · Admin API (dotnet build) (push) Successful in 37s
CI/CD / CI · Dashboard (tsc) (push) Successful in 1m10s
CI/CD / CI · Admin Web (tsc) (push) Successful in 37s
CI/CD / CI · Website (tsc) (push) Successful in 44s
CI/CD / CI · Koja (tsc) (push) Successful in 53s
CI/CD / Deploy · all services (push) Successful in 1m41s
Adds a signed broker integration for online plan purchases:
- FlatPayService: POST /v1/pay/request with X-Api-Key + X-Signature =
hex(HMAC-SHA256(secret, raw JSON bytes)); the exact serialized bytes are both
signed and sent. VerifyWebhook does a fixed-time compare of the digest, plus an
in-memory first-seen idempotency set.
- POST /api/payment/request (auth, ManageBilling): parses a "Tier:Months" product
(e.g. "Pro:12"), prices it via the plan catalog, creates a Pending SubscriptionPayment
(provider=FlatPay) as the order, and returns the broker payment URL. The order id is
the client_ref / metadata.payment_id.
- POST /api/payment/webhook (anonymous; HMAC is the auth — 401 on bad signature):
on status=Paid + first-seen id, grants the order via the shared plan-activation
path (extracted ActivatePaymentAsync, reused by all providers). Always 200 after a
valid signature so the broker won't retry an accepted job.
- Config FlatPay__{ApiKey,Secret,BaseUrl,ReturnUrl} (env-supplied; secrets stay out
of git), compose + .env.example wiring. PaymentProvider.FlatPay appended (int, no
migration).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>