Garbage collector for stale products from deleted/inactive merchants #3
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
When an LNbits user deletes their account, the corresponding merchant record and their stalls/products may be cleaned up locally, but the kind 30017 (stall) and kind 30018 (product) events they previously published remain on Nostr relays indefinitely. Since these are parameterized replaceable events (NIP-33), they don't expire and their authoring pubkey doesn't get notified to remove them.
Customers browsing the marketplace continue to see products that:
The system isn't unsafe — invoices won't be issued for nonexistent merchants — but it's a poor UX. Customers click "buy", get a confusing error or silent timeout, and lose trust in the marketplace.
Examples of stale-product scenarios
active: false(orrestore_in_progressstuck), no relay subscription is active, orders won't be processed.Proposed approach
A periodic garbage-collection task that publishes kind 5 deletion events (NIP-09) for stalls/products that should no longer be advertised. Two layers:
1. Local-merchant GC (cheap, definitive)
DELETE /api/v1/merchant/{id}: publish kind 5 deletion events for every stall and product that merchant owned before wiping the local DB rows.update_merchant_to_nostrwithdelete=True— verify the merchant deletion endpoint atviews_api.py:204–230actually broadcasts deletes; if not, add it.2. Periodic stale-event reaper (best-effort)
For events where the merchant was lost without a graceful delete (account deletion at the LNbits level, server reset, etc.), publish kind 5 deletes from a cron-style task:
config.active == True:timeto refresh liveness.config.active == Falsefor > N days, oruser_idJOIN returns nothing), ortimehasn't been refreshed in > N days (suggests background tasks aren't running for this user)The merchant can still be revived if the account is restored — keep merchant rows but prune the published events.
3. Customer-side defensive UI (cheap, complementary)
In the customer-facing market, when a stall/product event is fetched but no kind 0 metadata or recent activity exists for the author pubkey, dim or hide the listing with a "Merchant unavailable" badge. This mitigates the case where deletion events haven't propagated yet.
Implementation notes
to_nostr_delete_event(pubkey)onStall/Product(seemodels.py) already builds kind 5 events. The hook is there.subscription_health_monitorintasks.pywould be the natural home.merchants.user_idagainstaccountstable. If no row → account is gone._auto_create_merchant/ migration flow.Out of scope
References
services.py:sign_and_send_to_nostr(merchant, n, delete=True)andviews_api.py:api_delete_merchant