Adds a 'Clear Instance Cache' card to /i/admin/settings/system that POSTs to a CSRF-protected route and calls LandingCacheService::invalidate(), which clears every key behind the landing page, /api/v(1|2)/instance, and nodeinfo.
Useful as an escape hatch after manual ConfigCache edits or when debugging stale-cache symptoms (like trying to set up a brand-new instance); under normal operation the event-driven invalidation in surrounding commits makes this unnecessary.
When an admin updates their avatar, bio, or display name via the regular Settings UI (not the admin panel), AvatarOptimize and HomeSettings::homeUpdate previously only invalidated the per-profile caches. The api:v1:instance-data:contact key, which embeds the admin's account object on the landing page and at /api/v(1|2)/instance, remained cached for up to 7 days (also the source of many hours' headaches).
AvatarOptimize now also calls AccountService::del() (the underlying pf:services:account:<pid> cache, which had been left stale) and, if the profile backs the configured contact account, LandingCacheService::invalidateContact(). HomeSettings does the contact hit too.
The profileBacksContact helper mirrors the resolution order in LandingService::get(): prefer instance.admin.pid when set, else fall back to the first is_admin user.
Replaces 14 duplicated Cache::forget blocks across AdminSettingsController (17 lines removed) plus the banner-image paths in AdminDirectoryController and the app:instance-update-total-local-posts command. Three pre-existing invalidation gaps are also closed as a side-effect of routing through the service:
- AdminSettingsController's settingsHomeStore + new_rule blocks predate the V2 endpoint and never hit api:v2:instance-data-response-v2; now they do.
- AdminDirectoryController banner upload + delete only hit the V1 wrapper, leaving the rememberForever-cached header blurhash and the instance.banner.blurhash config_cache short-circuit stale indefinitely (on a personal note, this was the singular item that got me going on this cache tear; I spent hours wondering why the banner wouldn't update). invalidateBanner clears all three layers.
- InstanceUpdateTotalLocalPosts only busted api:nodeinfo, leaving api:nodeinfo:users, api:nodeinfo:active-users-*, api:v1:instance-data:stats:v0, pf:services:instances:self: total-posts, and both wrappers stale until their own TTLs elapsed. invalidateStats clears the whole family.
Consolidates the 11 cache keys that back the landing page, /api/v1/instance, /api/v2/instance, and nodeinfo into a single service with granular invalidation helpers (invalidateContact, invalidateRules, invalidateBanner, invalidateStats) plus a profileBacksContact helper that mirrors the contact-account resolution logic in LandingService. No callers yet; subsequent commits route existing invalidation sites through this service.