diff --git a/backend/spec/api.md b/backend/spec/api.md index 0fcbbf7..f0a7d8a 100644 --- a/backend/spec/api.md +++ b/backend/spec/api.md @@ -132,7 +132,7 @@ Notes: - Serves `POST /relays/:id/deactivate` - Authorizes admin or relay owner -- If relay is already inactive, return a `400` with `code=relay-is-inactive` +- If relay status is `inactive` or `delinquent`, return a `400` with `code=relay-is-inactive` - Call `command.deactivate_relay` - Return `data` is empty diff --git a/backend/spec/billing.md b/backend/spec/billing.md index e5ec40d..f95a62c 100644 --- a/backend/spec/billing.md +++ b/backend/spec/billing.md @@ -28,7 +28,7 @@ Manages the Stripe subscription and subscription items for a relay's tenant. Onl - Fetch the relay and tenant associated with the `activity` - **If relay plan is `free`**: if the relay has a `stripe_subscription_item_id`, delete it via the Stripe API and call `command.delete_relay_subscription_item`. Then check cleanup (below). Return early. -- **If relay is `inactive`**: if the relay has a `stripe_subscription_item_id`, delete it via the Stripe API and call `command.delete_relay_subscription_item`. Then check cleanup (below). Return early. +- **If relay is `inactive` or `delinquent`**: if the relay has a `stripe_subscription_item_id`, delete it via the Stripe API and call `command.delete_relay_subscription_item`. Then check cleanup (below). Return early. - **If relay is `active` and on a paid plan**: - **Ensure subscription exists**: If the tenant has no `stripe_subscription_id`, create a Stripe subscription for the customer with `collection_method: "charge_automatically"` and the relay's price as the first item. Save the subscription ID via `command.set_tenant_subscription` and the item ID via `command.set_relay_subscription_item`. Return early. - **Sync the subscription item**: If the tenant already has a subscription, create or update the relay's Stripe subscription item to the plan's `stripe_price_id` via the Stripe API, then call `command.set_relay_subscription_item`. @@ -85,7 +85,7 @@ Skip invoices with `amount_due` of 0. - Look up tenant by `stripe_customer_id` - If tenant has `past_due_at` set: - Clear `past_due_at` via `command.clear_tenant_past_due` - - Find all `inactive` relays for the tenant that were deactivated due to non-payment (i.e. relays on paid plans that are inactive) + - Find all `delinquent` relays on paid plans for the tenant (relays marked delinquent by the billing system due to non-payment) - Reactivate each one via `command.activate_relay` ## `fn handle_invoice_payment_failed(&self, invoice: &Invoice)` @@ -98,7 +98,7 @@ Skip invoices with `amount_due` of 0. ## `fn handle_invoice_overdue(&self, invoice: &Invoice)` - Look up tenant by `stripe_customer_id` -- Deactivate all active relays on paid plans via `command.deactivate_relay` +- Mark all active relays on paid plans as delinquent via `command.mark_relay_delinquent` (sets status to `delinquent`, distinct from user-initiated `deactivate_relay`) - Send a DM via `robot.send_dm` notifying the tenant that their paid relays have been deactivated due to non-payment ## `fn handle_subscription_updated(&self, subscription: &Subscription)` @@ -106,7 +106,7 @@ Skip invoices with `amount_due` of 0. - Look up tenant by `stripe_customer_id` - If subscription status is `canceled` or `unpaid`: - Clear `stripe_subscription_id` via `command.clear_tenant_subscription` - - Deactivate all active paid relays for the tenant via `command.deactivate_relay` + - Mark all active paid relays as delinquent via `command.mark_relay_delinquent` ## `fn handle_subscription_deleted(&self, subscription: &Subscription)` diff --git a/backend/spec/command.md b/backend/spec/command.md index 981c4d1..503de01 100644 --- a/backend/spec/command.md +++ b/backend/spec/command.md @@ -44,6 +44,14 @@ Notes: - Sets relay status to `inactive` - Logs activity as `(deactivate_relay, relay_id)` +- Used for user/admin-initiated deactivation only + +## `pub fn mark_relay_delinquent(&self, relay: &Relay) -> Result<()>` + +- Sets relay status to `delinquent` +- Logs activity as `(deactivate_relay, relay_id)` +- Used exclusively by the billing system when a relay's subscription becomes past due +- `delinquent` relays are automatically reactivated via `activate_relay` when payment is received ## `pub fn activate_relay(&self, relay: &Relay) -> Result<()>` diff --git a/backend/spec/models.md b/backend/spec/models.md index 0dd429f..d14e777 100644 --- a/backend/spec/models.md +++ b/backend/spec/models.md @@ -69,7 +69,7 @@ A relay is a nostr relay owned by a `tenant` and hosted by the attached zooid in - `subdomain` - the relay's subdomain - `plan` - the relay's plan - `stripe_subscription_item_id` (nullable) - the Stripe subscription item id. Only set for relays on paid plans. -- `status` - `active|inactive`. Only `active` relays count toward billing. +- `status` - one of `active|inactive|delinquent`. Only `active` relays count toward billing. `delinquent` is set by the billing system when a relay's subscription becomes past due; `inactive` is set when a user or admin manually deactivates a relay. - `synced` - whether the relay has been successfully synced to zooid at least once. - `sync_error` - a string indicating any errors encountered when synchronizing. - `info_name` - the relay's name