feat(middleware): harden routing with fail-closed policy, custom subdomain management, and perf fixes
Some checks failed
CI / pytest (push) Waiting to run
CI / ruff (push) Successful in 12s
CI / validate (push) Successful in 26s
CI / dependency-scanning (push) Successful in 31s
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled

- Fix IPv6 host parsing with _strip_port() utility
- Remove dangerous StorePlatform→Store.subdomain silent fallback
- Close storefront gate bypass when frontend_type is None
- Add custom subdomain management UI and API for stores
- Add domain health diagnostic tool
- Convert db.add() in loops to db.add_all() (24 PERF-006 fixes)
- Add tests for all new functionality (18 subdomain service tests)
- Add .github templates for validator compliance

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-15 18:13:01 +01:00
parent 07fab01f6a
commit 540205402f
38 changed files with 1827 additions and 134 deletions

View File

@@ -27,6 +27,13 @@ function adminStoreDetail() {
domainSaving: false,
newDomain: { domain: '', platform_id: '' },
// Custom subdomain management state
customSubdomains: [],
customSubdomainsLoading: false,
editingSubdomainPlatformId: null,
editingSubdomainValue: '',
subdomainSaving: false,
// Initialize
async init() {
// Load i18n translations
@@ -54,6 +61,7 @@ function adminStoreDetail() {
await Promise.all([
this.loadSubscriptions(),
this.loadDomains(),
this.loadCustomSubdomains(),
]);
}
} else {
@@ -274,6 +282,70 @@ function adminStoreDetail() {
}
},
// ====================================================================
// CUSTOM SUBDOMAIN MANAGEMENT
// ====================================================================
async loadCustomSubdomains() {
if (!this.store?.id) return;
this.customSubdomainsLoading = true;
try {
const url = `/admin/stores/${this.store.id}/custom-subdomains`;
const response = await apiClient.get(url);
this.customSubdomains = response.subdomains || [];
detailLog.info('Custom subdomains loaded:', this.customSubdomains.length);
} catch (error) {
if (error.status === 404) {
this.customSubdomains = [];
} else {
detailLog.warn('Failed to load custom subdomains:', error.message);
}
} finally {
this.customSubdomainsLoading = false;
}
},
startEditSubdomain(entry) {
this.editingSubdomainPlatformId = entry.platform_id;
this.editingSubdomainValue = entry.custom_subdomain || '';
},
cancelEditSubdomain() {
this.editingSubdomainPlatformId = null;
this.editingSubdomainValue = '';
},
async saveCustomSubdomain(platformId) {
if (!this.editingSubdomainValue || this.subdomainSaving) return;
this.subdomainSaving = true;
try {
await apiClient.put(
`/admin/stores/${this.store.id}/custom-subdomains/${platformId}`,
{ subdomain: this.editingSubdomainValue.trim().toLowerCase() }
);
Utils.showToast('Custom subdomain saved', 'success');
this.cancelEditSubdomain();
await this.loadCustomSubdomains();
} catch (error) {
Utils.showToast(error.message || 'Failed to save subdomain', 'error');
} finally {
this.subdomainSaving = false;
}
},
async clearCustomSubdomain(platformId, subdomainName) {
if (!confirm(`Clear custom subdomain "${subdomainName}"? The store will use its default subdomain on this platform.`)) return;
try {
await apiClient.delete(
`/admin/stores/${this.store.id}/custom-subdomains/${platformId}`
);
Utils.showToast('Custom subdomain cleared', 'success');
await this.loadCustomSubdomains();
} catch (error) {
Utils.showToast(error.message || 'Failed to clear subdomain', 'error');
}
},
// Refresh store data
async refresh() {
detailLog.info('=== STORE REFRESH TRIGGERED ===');