feat: consolidate media service, add merchant users page, fix metrics overlap

- Merge ImageService into MediaService with WebP variant generation,
  DB-backed storage stats, and module-driven media usage discovery
  via new MediaUsageProviderProtocol
- Add merchant users admin page with scoped user listing, stats
  endpoint, template, JS, and i18n strings (de/en/fr/lb)
- Fix merchant user metrics so Owners and Team Members are mutually
  exclusive (filter team_members on user_type="member" and exclude
  owner IDs) ensuring stat cards add up correctly
- Update billing and monitoring services to use media_service
- Update subscription-billing and feature-gating docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 21:17:11 +01:00
parent 4cb2bda575
commit 2250054ba2
30 changed files with 1220 additions and 805 deletions

View File

@@ -257,17 +257,29 @@ def get_media_usage(
"""
Get where this media file is being used.
- Check products using this media
- Return list of usage
Discovers usage from all registered module providers.
"""
# Service will raise MediaNotFoundException if not found
usage = media_service.get_media_usage(
# Verify media belongs to store (raises MediaNotFoundException if not found)
media_service.get_media(
db=db,
store_id=current_user.token_store_id,
media_id=media_id,
)
return MediaUsageResponse(**usage)
# Discover usage from registered providers
from app.modules.registry import MODULES
usage = []
for module in MODULES.values():
provider = module.get_media_usage_provider_instance()
if provider:
usage.extend(provider.get_media_usage(db, media_id))
return MediaUsageResponse(
media_id=media_id,
usage=usage,
total_usage_count=len(usage),
)
@store_media_router.post("/optimize/{media_id}", response_model=OptimizationResultResponse)