fix(tenancy): use absolute URL in team invitation email link
Some checks failed
Some checks failed
Email clients need absolute URLs to make links clickable. The acceptance_link was a relative path (/store/invitation/accept?token=...) which rendered as plain text. Now prepends the platform domain with the correct protocol. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
73
docs/proposals/hosting-site-creation-fix.md
Normal file
73
docs/proposals/hosting-site-creation-fix.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Hosting Site Creation — Require Merchant or Prospect
|
||||
|
||||
## Problem
|
||||
|
||||
`hosted_site_service.create()` (lines 118-131) auto-creates a fake "HostWizard System" `Merchant` with no `owner_user_id` as a placeholder to satisfy the Store's `merchant_id` FK. This is wrong on two levels:
|
||||
|
||||
- Crashes because `Merchant.owner_user_id` is `nullable=False`
|
||||
- Conceptually wrong — POC sites should belong to a real entity
|
||||
|
||||
## Current Flow
|
||||
|
||||
```
|
||||
create() → invents a system merchant (broken)
|
||||
→ creates Store under it
|
||||
→ creates HostedSite
|
||||
|
||||
create_from_prospect() → reads prospect data
|
||||
→ calls create() (same broken path)
|
||||
|
||||
accept_proposal() → creates real merchant
|
||||
→ reassigns store to it
|
||||
```
|
||||
|
||||
## Proposed Design: Require merchant_id OR prospect_id
|
||||
|
||||
### Schema (`HostedSiteCreate`)
|
||||
|
||||
- Add `merchant_id: int | None` and `prospect_id: int | None`
|
||||
- Add `model_validator`: at least one must be provided
|
||||
- Remove `prospect_id` from the separate URL path endpoint — unify into one create endpoint
|
||||
|
||||
### Service (`create`)
|
||||
|
||||
- **If `merchant_id` provided**: validate merchant exists, create Store under it directly
|
||||
- **If `prospect_id` provided** (no merchant): auto-create a merchant from prospect data using `merchant_service.create_merchant_with_owner()` (same as `accept_proposal` does today), then create Store under it
|
||||
- **If both provided**: use the existing merchant, link the prospect
|
||||
- Remove the system merchant creation entirely (lines 118-131)
|
||||
|
||||
### `create_from_prospect` method
|
||||
|
||||
Can be removed — its logic merges into `create` via the `prospect_id` field.
|
||||
|
||||
### `accept_proposal`
|
||||
|
||||
Simplify — merchant already exists at this point, so it only needs to handle subscription creation and prospect status update. The store reassignment is no longer needed.
|
||||
|
||||
## Files to Change
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `hosting/schemas/hosted_site.py` | Add `merchant_id`, `prospect_id` fields + validator |
|
||||
| `hosting/services/hosted_site_service.py` | Rewrite `create()` to use provided merchant or create from prospect. Remove `create_from_prospect()`. Simplify `accept_proposal()`. |
|
||||
| `hosting/routes/api/admin_sites.py` | Remove `/from-prospect/{prospect_id}` endpoint. The main `POST /sites` handles both paths now. |
|
||||
| `hosting/templates/hosting/admin/site-new.html` | Add merchant selector (dropdown/autocomplete) and prospect selector. Validate one is chosen. |
|
||||
| `hosting/tests/conftest.py` | Update `hosted_site` fixture to pass `merchant_id` |
|
||||
| `hosting/tests/unit/test_hosted_site_service.py` | Update all `create` calls, remove `TestHostedSiteFromProspect` class (merge into main tests), add validation tests for the "at least one required" rule |
|
||||
|
||||
## Template Changes Needed
|
||||
|
||||
The form currently has a business name + contact fields + a prospect ID input at the bottom. It needs:
|
||||
|
||||
1. A **merchant selector** (autocomplete dropdown searching existing merchants)
|
||||
2. A **prospect selector** (autocomplete dropdown searching existing prospects)
|
||||
3. Validation: at least one must be selected
|
||||
4. When prospect is selected: auto-fill business_name, contact fields from prospect data
|
||||
5. When merchant is selected: auto-fill business_name from merchant name
|
||||
|
||||
## What Gets Deleted
|
||||
|
||||
- The entire "HostWizard System" merchant pattern (lines 118-131 in service)
|
||||
- The `POST /sites/from-prospect/{prospect_id}` endpoint
|
||||
- The `create_from_prospect()` service method
|
||||
- The prospect ID number input in the template (replaced by proper selector)
|
||||
Reference in New Issue
Block a user