Skip to content

feat: hourly billing, credit-only hourly plans, owner VM delete with credit refunds - #428

Merged
v0l merged 7 commits into
masterfrom
feat/hourly-billing
Oct 23, 2026
Merged

v0l merged 7 commits into
masterfrom
feat/hourly-billing

Conversation

@v0l

@v0l v0l commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds an hourly billing interval so a VM can run on account credit, and lets users delete a VM, stop its billing and get the unused time back as credit.

  • IntervalType::Hour (= 3, same SMALLINT column). Handled in pricing, expiry, mysql.rs, worker, discount engine, admin MRR report, MockDb, and the API enum ("hour").
  • Fixed 24h grace period for hourly subscriptions instead of the 1-14 day age-tiered window.
  • Credit-only hourly billing: renewals, purchases and upgrades are refused unless opted-in credit covers the whole bill. POST /api/v1/vm refuses an hourly order up front when credit can't cover the first hour (the unpaid VM is removed at once). Successful hourly renewals send no notification; failures still do. A payment to an hourly VM's LNURL tops up the owner's credit.
  • DELETE /api/v1/vm/{id}: queues DeleteVm with a new by_owner flag (default false). 409 while an open abuse case names the VM.
  • Unused time back as credit, for every interval and payment method: each paid period gives back its share of what it charged (tax included). Credit-funded parts return as the credit taken; cash-funded parts (Lightning, card, on-chain, swap) are converted at today's rate. Each refund row and its refund ledger event (linked to the row) are written in one transaction, and a repeat is refused by the derived row id.
  • Line items can be deactivated on their own: new nullable subscription_line_item.deactivated_at (migration 20261023105258). Deleting a VM deactivates its line item; the subscription ends only when no line item is still active. On a shared subscription only the VM line's share of each payment is refunded, and renewals, payment handling and the lifecycle skip deactivated items. Exposed as deactivated_at on customer and admin line item responses.

Testing

  • cargo test --lib: lnvps_api (722), lnvps_api_common (637), lnvps_api_admin (254) and the other library crates pass. lnvps_api run with --test-threads=1 (provisioner::migrate tests share state and fail in parallel, also on master).
  • ./scripts/run-e2e.sh --filter credit against MariaDB: 10 passed, including a new test for the migration, Hour round-tripping, and the refund transaction (atomic, booked once, ledger event linked).
  • cargo clippy: no new warnings.
  • Not run: the full e2e suite, cargo llvm-cov. The DELETE handler shell itself has no test (no Nip98Auth harness); its guard, the worker job and the refund are tested.

Not included

  • Low-balance (credit runway) warnings for hourly subscriptions.
  • A stopped hourly VM keeps billing.
  • If the credit refund fails after deletion it is logged and admins notified, not retried.

Comment thread lnvps_api/src/api/routes.rs Fixed
Comment thread lnvps_api/src/refund.rs Fixed
- Refund unused time to credit for every interval and every payment
  method: credit parts as debited, cash parts at today's rate
- Deactivate only the deleted VM's line item on a shared subscription
  (new subscription_line_item.deactivated_at); end the subscription
  when nothing on it is active, and skip deactivated items in renewals
- Book each refund row and its credit event in one transaction, once
- No notification for successful hourly credit renewals
- Refuse hourly orders up front when credit cannot cover the first hour
- Hourly VM LNURL payments top up account credit
- Owner refunds are not logged as admin actions
@v0l v0l changed the title feat: hourly billing interval, credit-only, owner VM delete feat: hourly billing, credit-only hourly plans, owner VM delete with credit refunds Oct 23, 2026
subscription_line_item.parent_line_item_id marks an add-on (e.g. paid
VM snapshots). Deleting a VM deactivates its line and every add-on
below it, ends the subscription when nothing independent of the VM is
left, and refunds the add-ons' share with the VM's.
Comment thread lnvps_api/src/refund.rs Fixed
Comment thread lnvps_api/src/refund.rs Fixed
@v0l
v0l merged commit 39324de into master Oct 23, 2026
10 checks passed
@v0l
v0l deleted the feat/hourly-billing branch October 23, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants