Skip to content

Migrate vm_payment to subscriptions payment system#114

Open
v0l wants to merge 52 commits intomasterfrom
feat/vm-payment-to-subscription
Open

Migrate vm_payment to subscriptions payment system#114
v0l wants to merge 52 commits intomasterfrom
feat/vm-payment-to-subscription

Conversation

@v0l
Copy link
Contributor

@v0l v0l commented Mar 2, 2026

Summary

  • Consolidate vm_payment into subscription_payment so there is a single unified payment table
  • VMs will link to subscriptions via vm.subscription_id
  • Full migration plan tracked in work/vm-payment-to-subscription.md

This PR will be built up incrementally. First commit: rename VmCostPlanIntervalTypeIntervalType and ApiVmCostPlanIntervalTypeApiIntervalType to decouple interval types from vm_cost_plan.

v0l added 30 commits March 2, 2026 15:08
Rename VmCostPlanIntervalType → IntervalType and
ApiVmCostPlanIntervalType → ApiIntervalType across the codebase
to decouple interval types from vm_cost_plan in preparation for
the subscription payment migration.
- Migration 20260302151134: re-add interval_amount/interval_type to
  subscription, add time_value/metadata to subscription_payment, add
  subscription_id FK to vm table
- Add VmRenewal=3 and VmUpgrade=4 to SubscriptionType
- Add Upgrade=2 to SubscriptionPaymentType
- Add interval_amount/interval_type to Subscription struct
- Add time_value/metadata to SubscriptionPayment and SubscriptionPaymentWithCompany
- Add subscription_id to Vm struct
- Fix subscription_payment_paid() transaction bug; implement VM path
  (extend by time_value seconds) and regular path (read interval from subscription)
- Add get_vm_by_subscription() and list_vm_subscription_payments() to
  LNVpsDbBase trait, MySQL impl, and MockDb
- Update insert_vm/update_vm SQL to include subscription_id
- Propagate new fields through admin and user-facing API models
- Add interval_amount/interval_type to AdminCreateSubscriptionRequest
  and AdminSubscriptionInfo
- Add migrate_vm_subscriptions binary: creates a Subscription +
  SubscriptionLineItem(VmRenewal) for each VM without subscription_id.
  Standard VMs use cost plan interval; custom VMs default to 1 Month.
  Supports --dry-run for preview. Idempotent: already-linked VMs skipped.
- Fix insert_subscription, insert_subscription_with_line_items, and
  update_subscription SQL to bind interval_amount and interval_type.
- Register migrate_vm_subscriptions in lnvps_api_admin/Cargo.toml.
- vm.subscription_id is now u64 (not Option); migration added to make
  it NOT NULL after data backfill
- provision() and provision_custom() create Subscription +
  SubscriptionLineItem(VmRenewal) before inserting the VM
- CostResult::Existing now holds SubscriptionPayment; deduplication
  checks list_vm_subscription_payments instead of list_vm_payment
- price_to_payment_with_type creates SubscriptionPayment using
  vm.subscription_id; inserts via insert_subscription_payment
- renew(), renew_intervals(), renew_amount() return SubscriptionPayment
- create_upgrade_payment() uses SubscriptionPaymentType::Upgrade and
  stores UpgradeConfig in metadata as JSON Value
- auto_renew_via_nwc() returns SubscriptionPayment
- handle_upgrade() accepts SubscriptionPayment, reads metadata field
- Lightning and Revolut webhook handlers updated to look up
  SubscriptionPayment by ID, mark paid via subscription_payment_paid,
  and find VM via get_vm_by_subscription
- API routes v1_renew_vm, v1_get_payment, v1_get_payment_invoice,
  v1_payment_history, v1_vm_upgrade all use SubscriptionPayment
- ApiVmPayment::from_subscription_payment and
  ApiInvoiceItem::from_subscription_payment added
- Mock insert_subscription and insert_subscription_with_line_items
  fixed to actually persist data
- Test helpers create proper subscriptions for VM fixture data
Instead of vm.subscription_id (VM -> subscription), VMs now carry
subscription_line_item_id (VM -> line item), matching the existing
ip_range_subscription -> subscription_line_item pattern.

This allows a single subscription to contain a VM renewal line item,
additional IP allocations, and other products, all billed together.
The subscription is reached by traversing: vm -> line_item -> subscription.

- Rename vm.subscription_id -> vm.subscription_line_item_id (NOT NULL)
- Merge 20260302154256 NOT NULL migration into 20260302151134
- Add fk_vm_subscription_line_item FK to subscription_line_item(id)
- Add get_vm_by_line_item() to DB trait (primary lookup)
- Add get_vm_by_subscription() joining through line_item for payment handlers
- insert_subscription_with_line_items() now returns (subscription_id, Vec<line_item_id>)
- provision() and provision_custom() store the line_item_id on the VM
- price_to_payment_with_type() resolves subscription_id via line_item lookup
- SubscriptionType::VmRenewal/VmUpgrade kept as discriminants on line items
- MockDb default now pre-populates subscription id=1 + line_item id=1
- migrate_vm_subscriptions binary updated to set subscription_line_item_id
Instead of calling list_companies() and picking the first result,
look up the region (template.region_id / pricing.region_id) and use
region.company_id. This is the correct relationship: template -> region -> company.
…st live

- Add is_setup BIT(1) NOT NULL DEFAULT 0 to subscription table (in
  20260302151134 migration) — set to 1 when first payment is confirmed
- Replace payment history scan (has_paid) with subscription.is_setup
  to determine Purchase vs Renewal payment type
- In renew_subscription(), always compute VmRenewal line item cost via
  PricingEngine::get_vm_cost_for_intervals — never use the stored amount,
  which is stale for standard VMs and zero for custom VMs
- subscription_payment_paid() now sets is_setup = 1 alongside is_active = 1
- Add is_setup to AdminSubscriptionInfo and all Subscription struct literals
- renew_subscription() now takes intervals: u32 parameter
- VmRenewal line items use get_vm_cost_for_intervals(vm.id, method, intervals)
- Non-VM line items multiply stored amount by intervals
- renew_intervals() passes its intervals arg through instead of ignoring it
- v1_renew_subscription API endpoint passes intervals=1 (non-VM subscriptions
  don't support multi-interval renewal via that endpoint yet)
…ements

- Add 20260303114230_fix_referral_constraint_names.sql to rename anonymous
  FK constraints on referral/referral_payout tables to explicit names,
  fixing mysqldump re-import collisions
- Add VmForMigration struct and LNVpsDbMysql helper methods
  (list_vm_ids_without_subscription, get_vm_for_migration,
  set_vm_subscription_line_item, pool) to allow migration binary to
  operate on VMs with NULL subscription_line_item_id
- Rework migrate_vm_subscriptions binary to use concrete DB type for
  VM reads/updates, avoiding Vm struct decode failures on NULL columns
…ment records

- Phase 1 now migrates ALL VMs including deleted ones (was previously
  skipping deleted VMs, leaving 863 VMs without subscriptions)
- Phase 2 backfills every vm_payment row into subscription_payment,
  preserving all fields including encrypted external_data (copied
  as raw string without decryption via new VmPaymentRaw struct)
- PaymentType::Renewal → SubscriptionPaymentType::Renewal
- PaymentType::Upgrade → SubscriptionPaymentType::Upgrade
- upgrade_params JSON string → metadata serde_json::Value
- time_value u64 (0=none) → Option<u64>
- Both phases are idempotent (re-run is safe)
- Validated against production backup: 1078 subscriptions created,
  2180 payments backfilled, 0 errors
…und-trip

The previous approach went through insert_subscription_payment which re-encrypted
external_data using the local key. On production the data is already encrypted
with the production key and must be copied verbatim.

- Add insert_subscription_payment_raw() to LNVpsDbMysql for raw byte copy
- Add list_subscription_payment_ids_for_subscription() for idempotency
  checking without decrypting external_data
- Add VmPaymentRaw struct with external_data as plain String
- Migration binary now uses raw insert for all payment backfilling
- renew_subscription: use NewPaymentInfo directly from get_vm_cost_for_intervals
  instead of re-passing already-converted BTC amounts through get_amount_and_rate
  (double-conversion bug causing ~65000x inflated BTC amounts)
- renew_subscription: set time_value on created SubscriptionPayment from summed
  NewPaymentInfo.time_value (was always None, so vm.expires was never extended)
- insert_subscription_payment / update_subscription_payment: add missing
  time_value, processing_fee, metadata columns to SQL (were silently dropped)
- subscription_payment_paid: also UPDATE vm.expires by time_value seconds, not
  only subscription.expires (vm expiry was never extended on payment confirmation)
- get_vm_cost_for_intervals: drop time_value from dedup key; match unpaid renewal
  by subscription+method+type only (time_value changes each call as vm.expires
  advances, so the old match always missed and created duplicate payments)
- next_template_expire / get_custom_vm_cost / get_template_vm_cost: clamp base
  to max(vm.expires, now) so expired VMs get correct time_value and new_expiry
- Skip data migrations when running in API-only mode (--mode api)
- Add time_value and amount sanity assertions to all renew tests
- Mock subscription_payment_paid now also updates vm.expires; test updated to
  insert VM and assert both subscription and VM expiry are extended
…e dedup

- Add list_pending_vm_subscription_payments to DB trait, MySQL impl, and mock:
  returns only unpaid payments whose expires > NOW(), so callers never see
  stale expired invoices
- get_vm_cost_for_intervals: use list_pending_vm_subscription_payments instead
  of list_vm_subscription_payments + in-memory filter; removes the redundant
  p.expires > Utc::now() check from the find predicate
- invoice.rs / revolut.rs: use list_pending_vm_subscription_payments when
  cancelling other pending upgrade payments; drop now-redundant !p.is_paid filter
- Add two tests: dedup reuses a valid unpaid payment (Existing), and dedup
  ignores an expired unpaid payment and returns New instead
After a VM upgrade (both standard→custom and custom→custom paths), the
SubscriptionLineItem.amount was never updated, leaving the displayed
subscription renewal cost stale.

- In convert_to_custom_template: compute new base-currency cost via
  PricingEngine::get_custom_vm_cost_amount and set it on the line item
- Add update_line_item_cost_for_custom_vm helper on LNVpsProvisioner
- Call the helper from the process_vm_upgrade worker step after updating
  an existing custom template's specs
- Add regression tests for both code paths
The migration tool created subscriptions with is_active=true for all VMs
including deleted ones. Add the deleted column to VmForMigration and its
backing SQL query, then set is_active=!vm.deleted when building the
Subscription record.
All 12 list endpoints that previously fetched the full table into memory
and paginated in Rust (skip/take) now use LIMIT/OFFSET in SQL with a
separate COUNT(*) for the total.

New paginated DB trait methods added:
- list_cost_plans_paginated
- list_custom_pricing_paginated (optional region_id + enabled filters)
- list_subscriptions_paginated (optional user_id filter)
- list_subscription_payments_paginated
- list_available_ip_space_paginated (optional is_available/is_reserved/registry filters)
- list_ip_space_pricing_by_space_paginated
- list_ip_range_subscriptions_by_space_paginated (optional user_id + is_active filters)
- list_payment_method_configs_paginated
- list_roles_paginated

Endpoints updated: v1_list_ip_space, v1_list_subscriptions,
v1_list_subscription_payments, admin_list_cost_plans,
admin_list_custom_pricing, admin_list_ip_space, admin_list_ip_space_pricing,
admin_list_ip_space_subscriptions, admin_list_payment_methods,
admin_list_subscriptions, admin_list_subscription_payments, admin_list_roles
…1-13)

- Add list_expiring_subscriptions, list_expired_subscriptions, deactivate_subscription to DB trait/MySQL/mock
- Implement all ip_range_subscription mock methods; add ip_range_subscriptions field to MockDb
- Add WorkJob::CheckSubscriptions; schedule at 30s interval alongside CheckVms
- Add check_subscriptions() + handle_subscription_state() to Worker:
  expiring-soon NWC auto-renewal, non-VM deactivation on expiry, grace-period notification
- Add vm_expires() helper: resolves subscription.expires via line item; falls back to vm.expires
- handle_vm_state now uses vm_expires() for stop/delete decisions
- Remove VM-specific NWC auto-renewal from handle_vm_state (now owned by handle_subscription_state)
v0l added 7 commits March 3, 2026 14:49
…ipeline (increments 16-17)

- Add PaymentCompletionHandler trait, VmPaymentCompletionHandler, NonVmPaymentCompletionHandler
- Add make_completion_handler dispatcher selecting by subscription_type
- Extract complete_payment(db, payment, handler, cancel_fn) free function
- Refactor NodeInvoiceHandler: replace mark_payment_paid(vm_id) with complete(payment)
- Refactor RevolutPaymentHandler: remove duplicated VM history logging; use complete_payment
- Remove VmHistoryLogger from both handler structs (now owned by VmPaymentCompletionHandler)
- admin_complete_subscription_payment: add missing CheckSubscriptions WorkJob dispatch
- Update invoice.rs tests to use new complete() API
- Implement StripePaymentHandler: listen() on WEBHOOK_BRIDGE, verify signature,
  handle payment_intent.succeeded, cancel competing upgrade PaymentIntents
- Wire into listen_all_payments behind #[cfg(feature = "stripe")]
- Add /api/v1/webhook/stripe route
- Add test: non-VM (IpRange) payment complete dispatches CheckSubscriptions not CheckVm
- 204 unit tests pass
Replace make_completion_handler (single handler for whole payment) with
CompositeLineItemHandler that iterates every subscription line item and
fires a type-specific handler for each one independently.

A subscription with a VM + IP range now correctly runs both
VmPaymentCompletionHandler and IpRangePaymentCompletionHandler.

Add get_vm_by_subscription_line_item to DB trait/MySQL/mock.
Add IpRangePaymentCompletionHandler (dispatches CheckSubscriptions).
Handle AsnSponsoring/DnsHosting variants (CheckSubscriptions stub).
Remove Box<dyn PaymentCompletionHandler> in favour of concrete CompositeLineItemHandler.
Add src/subscription/ module with a single SubscriptionLineItemHandler trait:
  on_payment()                - called by payment pipeline after mark-paid
  on_expiring_soon()          - called by lifecycle worker
  on_expired()                - called by lifecycle worker
  on_grace_period_exceeded()  - called by lifecycle worker

VmLineItemHandler: history logging, CheckVm/ProcessVmUpgrade dispatch,
  on_expired/on_grace_period_exceeded dispatch CheckVm for hypervisor pickup
IpRangeLineItemHandler: on_payment dispatches CheckSubscriptions,
  on_expired deactivates ip_range_subscription rows directly

payments/mod.rs: complete_payment now calls line_item_handler per line item
  instead of the old PaymentCompletionHandler / CompositeLineItemHandler stack.
  Removes handle_upgrade free function (inlined into VmLineItemHandler).

worker.rs handle_subscription_state: replaces all inline product branching
  (has_vm checks, deactivate_subscription call, etc.) with per-line-item
  calls to the appropriate handler. Single place to add new product types.
…f truth

Schema migration:
  DROP COLUMN expires, auto_renewal_enabled FROM vm

All expiry decisions now read subscription.expires exclusively.
Auto-renewal reads subscription.auto_renewal_enabled exclusively.

Changes:
- lnvps_db: remove Vm.expires/auto_renewal_enabled fields; fix insert/update SQL
- subscription_payment_paid: remove vm.expires write (no longer needed)
- vm_payment_paid: remove vm.expires update
- list_expired_vms: rewritten to join subscription table
- worker vm_expires(): returns Option<DateTime> from subscription; no fallback
- worker check_vms: is_new_vm detection uses subscription.is_setup = false
- worker StartVm guard: checks subscription expiry
- worker patch_firewall guard: checks subscription expiry
- subscription/vm.rs: vm_expires_before reads from subscription
- capacity: filters unpaid VMs by subscription.is_setup = false
- admin extend_vm: updates subscription.expires instead of vm.expires
- admin vm_ip_assignments: checks subscription.is_setup + subscription.expires
- admin model AdminVmInfo: serves subscription.expires/auto_renewal_enabled
- admin AdminRefundAmountInfo: serves subscription.expires
- user API ApiVmStatus: serves subscription.expires/auto_renewal_enabled
- api/routes.rs set_auto_renewal: updates subscription.auto_renewal_enabled
- pricing engine: vm_subscription_expires() helper; next_template_expire takes base DateTime
- pricing/capacity tests: set subscription.expires instead of vm.expires
@v0l v0l requested a review from Copilot March 7, 2026 16:37
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates VM payments to the unified subscriptions payment system, removing VM-specific payment/expiry fields and introducing a generalized subscription lifecycle + payment completion pipeline across payment methods (Lightning/Revolut/Stripe).

Changes:

  • Replace vm_payment usage with subscription_payment (including upgrade metadata/time_value support) and link VMs via vm.subscription_line_item_id.
  • Generalize lifecycle enforcement with a CheckSubscriptions worker job and per-line-item handlers.
  • Add DB-level pagination across multiple admin/user list endpoints and introduce a VM→subscription migration tool.

Reviewed changes

Copilot reviewed 52 out of 55 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
work/vm-payment-to-subscription.md Updates the migration plan/status and documents phases/tasks for the vm_payment → subscription_payment migration.
lnvps_db/src/mysql.rs Implements new subscription/VM linkage queries, payment updates, company-enriched payment queries, and multiple paginated list endpoints.
lnvps_db/src/model.rs Renames interval type, moves VM billing link to subscription_line_item_id, expands subscription/payment models, adds migration-only projections.
lnvps_db/src/lib.rs Extends DB trait with pagination methods and new subscription/VM/payment lookup APIs.
lnvps_db/src/admin.rs Updates admin DB trait (pagination + subscription_payment reporting).
lnvps_db/migrations/20260304000000_drop_vm_expires.sql Drops vm.expires and vm.auto_renewal_enabled to shift expiry/auto-renewal to subscriptions.
lnvps_db/migrations/20260302151134_vm_subscription_link.sql Adds subscription interval fields, payment metadata/time_value, and VM→subscription_line_item linkage.
lnvps_api_common/src/work/mod.rs Adds WorkJob::CheckSubscriptions and integrates it into Display/skip logic.
lnvps_api_common/src/vm_history.rs Removes logging of vm.expires and updates tests for new VM model shape.
lnvps_api_common/src/pricing.rs Switches VM expiry calculations to subscription expiry; updates dedupe to use pending subscription payments.
lnvps_api_common/src/model.rs Renames API interval enum and changes VM status expiry to Option<DateTime<Utc>> sourced from subscription.
lnvps_api_common/src/capacity.rs Changes capacity filtering to rely on subscription setup state instead of VM expiry.
lnvps_api_admin/src/bin/migrate_vm_subscriptions.rs Adds a standalone migration binary to backfill subscriptions and copy vm_payment rows into subscription_payment.
lnvps_api_admin/src/bin/generate_demo_data.rs Updates demo data generation to use IntervalType and new VM model fields.
lnvps_api_admin/src/admin/vms.rs Updates admin VM payment endpoints and manual completion to use subscription_payment + subscription expiry.
lnvps_api_admin/src/admin/vm_templates.rs Updates default interval type enum name in template creation.
lnvps_api_admin/src/admin/vm_ip_assignments.rs Switches “new/expired VM” checks to subscription is_setup / expires.
lnvps_api_admin/src/admin/subscriptions.rs Adds DB-level pagination for subscriptions/payments and dispatches CheckSubscriptions after manual completion.
lnvps_api_admin/src/admin/roles.rs Uses DB-level pagination for roles listing.
lnvps_api_admin/src/admin/reports.rs Adapts time-series report model to optional VM/host/region fields from subscription payments.
lnvps_api_admin/src/admin/payment_methods.rs Uses DB-level pagination for payment method configs listing.
lnvps_api_admin/src/admin/model.rs Updates admin API models for subscription-driven expiry + enriched subscription/payment fields.
lnvps_api_admin/src/admin/ip_space.rs Moves IP space/pricing/subscription listings to DB-level pagination.
lnvps_api_admin/src/admin/custom_pricing.rs Moves custom pricing listing to DB-level pagination.
lnvps_api_admin/src/admin/cost_plans.rs Moves cost plan listing to DB-level pagination.
lnvps_api_admin/Cargo.toml Registers the new migrate_vm_subscriptions binary.
lnvps_api/src/worker.rs Adds subscription lifecycle loop, VM expiry resolution via subscription, and schedules CheckSubscriptions.
lnvps_api/src/subscription/vm.rs Adds VM subscription line item handler for payment/lifecycle hooks (history + work dispatch).
lnvps_api/src/subscription/mod.rs Introduces generic subscription line-item handler abstraction and factory.
lnvps_api/src/subscription/ip_range.rs Adds IP Range subscription line item handler for activation/deactivation lifecycle.
lnvps_api/src/provisioner/rollback_tests.rs Updates provisioner tests for new VM model fields.
lnvps_api/src/provisioner/retry_tests.rs Updates provisioner tests for new VM model fields.
lnvps_api/src/provisioner/lnvps.rs Creates subscriptions during VM provisioning, rewrites renewal/upgrade payment creation to subscription_payment, updates upgrade flows.
lnvps_api/src/provisioner/integration_retry_tests.rs Updates integration retry tests for new VM model fields.
lnvps_api/src/payments/stripe.rs Implements Stripe webhook completion via centralized subscription_payment pipeline.
lnvps_api/src/payments/revolut.rs Refactors Revolut completion to centralized subscription_payment pipeline + upgrade cancellation.
lnvps_api/src/payments/mod.rs Adds centralized complete_payment pipeline and wires Stripe handler startup.
lnvps_api/src/payments/invoice.rs Refactors Lightning invoice completion to centralized subscription_payment pipeline and updates tests.
lnvps_api/src/mocks.rs Updates imports/types impacted by interval enum rename.
lnvps_api/src/lib.rs Exposes the new subscription module.
lnvps_api/src/host/mod.rs Updates host tests for new VM model fields.
lnvps_api/src/data_migration/ip6_init.rs Uses subscription expiry instead of VM expiry when skipping expired VMs.
lnvps_api/src/bin/api.rs Moves data migrations to worker mode and schedules CheckSubscriptions.
lnvps_api/src/api/webhook.rs Adds Stripe webhook route behind feature flag.
lnvps_api/src/api/subscriptions.rs Adds DB-level pagination and stores interval on subscriptions.
lnvps_api/src/api/routes.rs Migrates VM renew/payment/invoice/history endpoints to subscription_payment and subscription-based auto-renewal.
lnvps_api/src/api/model.rs Adds from_subscription_payment conversions for invoices and VM payment responses.
lnvps_api/src/api/legal.rs Includes VM subscription types in agreement generation.
lnvps_api/src/api/ip_space.rs Uses DB-level pagination for IP space listing.
docs/agents/migrations.md Documents the migration steps and the new migration binary.
docs/agents/api-guidelines.md Adds a guideline requiring DB-level pagination for list endpoints.
docs/agents-common Updates subproject reference.
API_CHANGELOG.md Documents API changes for VM payments/subscriptions and interval enum rename.
.github/workflows/build.yml Adds workflow_dispatch inputs and conditional Docker build selection logic.
Comments suppressed due to low confidence (3)

docs/agents/migrations.md:1

  • The documented invocation uses a --database-url flag, but the new migrate_vm_subscriptions binary's CLI (per Args) only supports --config and --dry-run. Update the docs to match the actual CLI (or add the documented flag). As written, following these instructions will fail.
# Database Migrations

lnvps_api_common/src/capacity.rs:1

  • This introduces an N+1 query pattern: for each VM on a host, it performs up to 2 additional DB calls (line item + subscription). For busy hosts this will be a noticeable latency multiplier. Prefer a DB-level query that returns only VMs whose linked subscription has is_setup = 1 (e.g., a join between vm → subscription_line_item → subscription with the host filter), or batch-load the needed subscriptions/line items.
    lnvps_api_common/src/capacity.rs:1
  • This introduces an N+1 query pattern: for each VM on a host, it performs up to 2 additional DB calls (line item + subscription). For busy hosts this will be a noticeable latency multiplier. Prefer a DB-level query that returns only VMs whose linked subscription has is_setup = 1 (e.g., a join between vm → subscription_line_item → subscription with the host filter), or batch-load the needed subscriptions/line items.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

v0l added 15 commits March 10, 2026 09:52
Replace LNVpsProvisioner with a unified SubscriptionHandler that owns
the VmProvisioner and pricing engine, so all API routes, payment
handlers, DVM, and worker code reference a single cohesive entry point.
Rename provisioner modules (lnvps → vm, lnvps_network → vm_network),
consolidate MockVmHost into DummyVmHost, and unify SubscriptionType
variants (VmRenewal/VmUpgrade → Vps).
…ng e2e ports

- Add scripts/run-e2e.sh: handles full e2e lifecycle (start docker, wait
  for LND, create per-run DB, patch configs, build+start APIs, run tests,
  teardown)
- lnvps_e2e/src/db.rs: per-run database isolation (lnvps_e2e_{run_id}),
  create/drop helpers, LNVPS_E2E_RUN_ID and LNVPS_DB_BASE_URL support
- lnvps_e2e/src/lifecycle.rs: drop test database at end of lifecycle test
- docker-compose.e2e.yaml: use ports 3377/6399 (DB/Redis) to avoid
  conflicting with the dev compose stack (3376/6398)
- .github/e2e/{api,admin}-config.yaml: update to ports 3377/6399
- .github/workflows/e2e.yml: delegate entirely to run-e2e.sh
- docs/agents/e2e-tests.md: update running instructions and CI docs
…missing revolut config

Also handle graceful error when get_vm_by_subscription fails during upgrade
payment completion — log a warning instead of propagating an error that
would mislead callers into thinking the payment was not completed.
…-> = 3)

subscription_type 4 was incorrectly included in several VM-related joins,
causing ambiguous or wrong results when fetching VMs by subscription.
…ination

Avoids fetching all payments just to get the total count in the admin
VM payments endpoint.
… errors

Replaces unwrap() calls when deserialising Revolut/Stripe external_data.
Payment history endpoint now always uses the paginated query path.
Previously the early return inside the nostr-nwc cfg block caused the
expiry notification to be skipped for users without NWC configured.
Now uses an auto_renewed flag so the fallback notification always fires
when auto-renewal was not attempted.
…xpiry, grace period, renewal)

- test_payment_activates_subscription_and_queues_vm
- test_on_expired_stops_vm
- test_on_grace_period_exceeded_deletes_vm
- test_renew_after_expiry_extends_expires

Also exposes DummyVmHost as pub(crate) and adds MockVmHost type alias.
…est docs

build.yml conditions were inverted — builds only ran on workflow_dispatch.
Now triggers on push and pull_request as well.
build-and-test.md clarifies docker compose requirement before running tests.
…er infra

- API_CHANGELOG.md: add entries for post-2026-03-03 changes (VmStatus.expires
  nullable, Stripe support, LNURL payment method, SubscriptionPayment.processing_fee
  and Upgrade payment type, console WebSocket, VM payment pagination, expiry
  notification fix, and retract false admin VM renew claim)
- API_DOCUMENTATION.md: fix VmStatus.expires to optional; add processing_fee and
  Upgrade variant to SubscriptionPayment; add lnurl to PaymentMethod; document
  WebSocket console endpoint; document VM payment pagination; remove duplicate
  incorrect Price definition in IP space section
- ADMIN_API_ENDPOINTS.md: document subscription field on AdminVmInfo; add
  company_base_currency, time_value, metadata to AdminSubscriptionPaymentInfo;
  add upgrade to SubscriptionPaymentType enum inline schemas; fix AdminVmInfo
  expires to nullable
- lnvps_e2e: add LND integration, worker lifecycle tests, expanded DB helpers
- lnvps_db: migration to drop legacy vm.created/expires columns
- various: e2e infra improvements (wait-for-lnd, docker-compose, run-e2e script)
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