feat(config): add APP_BASE_URL setting for outbound link construction
Some checks failed
Some checks failed
Adds app_base_url config (default http://localhost:8000) used for all outbound URLs: invitation emails, billing checkout redirects, signup login links, portal return URLs. Replaces hardcoded https://{main_domain} and localhost:8000 patterns. Configurable per environment via APP_BASE_URL env var: - Dev: http://localhost:8000 (or http://acme.localhost:9999) - Prod: https://wizard.lu main_domain is preserved for subdomain resolution and cookie config. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,11 @@ LOG_FILE=logs/app.log
|
|||||||
# Your main platform domain
|
# Your main platform domain
|
||||||
MAIN_DOMAIN=wizard.lu
|
MAIN_DOMAIN=wizard.lu
|
||||||
|
|
||||||
|
# Full base URL for outbound links (emails, billing redirects, etc.)
|
||||||
|
# Must include protocol and port if non-standard
|
||||||
|
# Examples: http://localhost:8000, http://acme.localhost:9999, https://wizard.lu
|
||||||
|
APP_BASE_URL=http://localhost:8000
|
||||||
|
|
||||||
# Custom domain features
|
# Custom domain features
|
||||||
# Enable/disable custom domains
|
# Enable/disable custom domains
|
||||||
ALLOW_CUSTOM_DOMAINS=True
|
ALLOW_CUSTOM_DOMAINS=True
|
||||||
|
|||||||
@@ -98,6 +98,11 @@ class Settings(BaseSettings):
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
main_domain: str = "wizard.lu"
|
main_domain: str = "wizard.lu"
|
||||||
|
|
||||||
|
# Full base URL for outbound links (emails, redirects, etc.)
|
||||||
|
# Must include protocol and port if non-standard.
|
||||||
|
# Examples: http://localhost:8000, http://acme.localhost:9999, https://wizard.lu
|
||||||
|
app_base_url: str = "http://localhost:8000"
|
||||||
|
|
||||||
# Custom domain features
|
# Custom domain features
|
||||||
allow_custom_domains: bool = True
|
allow_custom_domains: bool = True
|
||||||
require_domain_verification: bool = True
|
require_domain_verification: bool = True
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ def purchase_addon(
|
|||||||
store = billing_service.get_store(db, store_id)
|
store = billing_service.get_store(db, store_id)
|
||||||
|
|
||||||
# Build URLs
|
# Build URLs
|
||||||
base_url = f"https://{settings.main_domain}"
|
base_url = settings.app_base_url.rstrip("/")
|
||||||
success_url = f"{base_url}/store/{store.store_code}/billing?addon_success=true"
|
success_url = f"{base_url}/store/{store.store_code}/billing?addon_success=true"
|
||||||
cancel_url = f"{base_url}/store/{store.store_code}/billing?addon_cancelled=true"
|
cancel_url = f"{base_url}/store/{store.store_code}/billing?addon_cancelled=true"
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ def create_checkout_session(
|
|||||||
|
|
||||||
store_code = subscription_service.get_store_code(db, store_id)
|
store_code = subscription_service.get_store_code(db, store_id)
|
||||||
|
|
||||||
base_url = f"https://{settings.main_domain}"
|
base_url = settings.app_base_url.rstrip("/")
|
||||||
success_url = f"{base_url}/store/{store_code}/billing?success=true"
|
success_url = f"{base_url}/store/{store_code}/billing?success=true"
|
||||||
cancel_url = f"{base_url}/store/{store_code}/billing?cancelled=true"
|
cancel_url = f"{base_url}/store/{store_code}/billing?cancelled=true"
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ def create_portal_session(
|
|||||||
merchant_id, platform_id = subscription_service.resolve_store_to_merchant(db, store_id, current_user.token_platform_id)
|
merchant_id, platform_id = subscription_service.resolve_store_to_merchant(db, store_id, current_user.token_platform_id)
|
||||||
|
|
||||||
store_code = subscription_service.get_store_code(db, store_id)
|
store_code = subscription_service.get_store_code(db, store_id)
|
||||||
return_url = f"https://{settings.main_domain}/store/{store_code}/billing"
|
return_url = f"{settings.app_base_url.rstrip('/')}/store/{store_code}/billing"
|
||||||
|
|
||||||
result = billing_service.create_portal_session(db, merchant_id, platform_id, return_url)
|
result = billing_service.create_portal_session(db, merchant_id, platform_id, return_url)
|
||||||
|
|
||||||
|
|||||||
@@ -617,7 +617,7 @@ class SignupService:
|
|||||||
|
|
||||||
# Build login URL
|
# Build login URL
|
||||||
login_url = (
|
login_url = (
|
||||||
f"https://{settings.main_domain}"
|
f"{settings.app_base_url.rstrip('/')}"
|
||||||
f"/store/{store.store_code}/dashboard"
|
f"/store/{store.store_code}/dashboard"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -981,19 +981,10 @@ class StoreTeamService:
|
|||||||
):
|
):
|
||||||
"""Send team invitation email."""
|
"""Send team invitation email."""
|
||||||
from app.core.config import settings as app_settings
|
from app.core.config import settings as app_settings
|
||||||
from app.core.environment import is_production
|
|
||||||
from app.modules.messaging.services.email_service import EmailService
|
from app.modules.messaging.services.email_service import EmailService
|
||||||
|
|
||||||
# Build acceptance URL
|
base_url = app_settings.app_base_url.rstrip("/")
|
||||||
# Prod: https://{subdomain}.{main_domain}/invitation/accept?token=...
|
acceptance_link = f"{base_url}/store/{store.store_code}/invitation/accept?token={token}"
|
||||||
# Dev: http://localhost:8000/store/{store_code}/invitation/accept?token=...
|
|
||||||
main_domain = app_settings.main_domain.rstrip("/")
|
|
||||||
if is_production():
|
|
||||||
base_url = f"https://{store.subdomain}.{main_domain}"
|
|
||||||
else:
|
|
||||||
base_url = f"http://localhost:8000/store/{store.store_code}"
|
|
||||||
|
|
||||||
acceptance_link = f"{base_url}/invitation/accept?token={token}"
|
|
||||||
|
|
||||||
email_service = EmailService(db)
|
email_service = EmailService(db)
|
||||||
email_service.send_template(
|
email_service.send_template(
|
||||||
|
|||||||
Reference in New Issue
Block a user