docs: add proposal for HostedSite → Store cascade delete
All checks were successful
All checks were successful
Deleting a HostedSite leaves the Store orphaned, blocking subdomain reuse. Proposal: cascade delete the Store when deleting the site. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
48
docs/proposals/hosting-cascade-delete.md
Normal file
48
docs/proposals/hosting-cascade-delete.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Hosting: Cascade Delete HostedSite → Store
|
||||
|
||||
## Problem
|
||||
|
||||
Deleting a HostedSite leaves the associated Store orphaned in the database. The Store's subdomain remains taken, so creating a new site with the same prospect/business fails with "slug already exists".
|
||||
|
||||
## Root Cause
|
||||
|
||||
- `hosted_site_service.delete()` does a hard delete on the HostedSite only
|
||||
- The Store (created by `hosted_site_service.create()`) is not deleted
|
||||
- `stores.subdomain` has a partial unique index (`WHERE deleted_at IS NULL`)
|
||||
- The orphaned Store is still active → subdomain collision on re-create
|
||||
|
||||
## Recommendation
|
||||
|
||||
When deleting a HostedSite, also delete the associated Store:
|
||||
|
||||
```python
|
||||
def delete(self, db: Session, site_id: int) -> bool:
|
||||
site = self.get_by_id(db, site_id)
|
||||
store = site.store
|
||||
db.delete(site)
|
||||
if store:
|
||||
# Soft-delete or hard-delete the store created for this site
|
||||
soft_delete(store) # or db.delete(store)
|
||||
db.flush()
|
||||
```
|
||||
|
||||
### Considerations
|
||||
|
||||
- **Soft vs hard delete**: If using soft-delete, the subdomain gets freed (partial unique index filters `deleted_at IS NULL`). If hard-deleting, cascade will also remove StorePlatform, ContentPages, StoreTheme, etc.
|
||||
- **CMS content**: Deleting the Store cascades to ContentPages (created by POC builder) — this is desired since the POC content belongs to that store
|
||||
- **Merchant**: The merchant created from the prospect should NOT be deleted — it may be used by other stores or relinked later
|
||||
- **Safety**: Only delete stores that were created by the hosting module (check if store has a HostedSite backref). Don't delete stores that existed independently.
|
||||
|
||||
## Files to modify
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `hosting/services/hosted_site_service.py` | Update `delete()` to also soft-delete/hard-delete the associated Store |
|
||||
| `hosting/tests/unit/test_hosted_site_service.py` | Update delete test to verify Store is also deleted |
|
||||
|
||||
## Quick workaround (for now)
|
||||
|
||||
Manually delete the orphaned store from the DB:
|
||||
```sql
|
||||
DELETE FROM stores WHERE subdomain = 'batirenovation-strasbourg' AND id NOT IN (SELECT store_id FROM hosted_sites);
|
||||
```
|
||||
Reference in New Issue
Block a user