feat(v3.13.0): settings live DB reads, remove Directus/Appwrite, admin stats

Settings fixes:
- MAX_SITES_PER_USER, USER_RATE_LIMIT_PER_MIN/HR now read from DB settings
  table (DB > ENV > default), so dashboard/settings changes apply without
  restart. Sync cache refreshed on every save or delete.
- /api/me reports the live DB value for max_sites_per_user.

Admin improvements:
- Admin users bypass per-user rate limiting entirely (role=admin or ADMIN_EMAILS).
- Admin Overview now shows platform stats: registered users, new users (7d),
  total user sites, available tools.

Plugin cleanup:
- Appwrite and Directus plugins removed from the active registry (8 plugins
  now: WordPress, WooCommerce, WordPress Specialist, Gitea, n8n, Supabase,
  OpenPanel, Coolify). Plugin code is retained for future re-enabling.
- Settings page plugin visibility list updated to match.

Mobile onboarding:
- Stepper steps on narrow viewports stack vertically with correct full border
  and rounded corners on each step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 23:33:20 +02:00
parent f203ca88de
commit 43fd2201a0
223 changed files with 36183 additions and 4115 deletions

View File

@@ -0,0 +1,65 @@
// Logo + wordmark — uses the original brand mark from core/templates/static/logo.svg.
// Path data is inlined so we can drive fills with CSS variables (theme-aware).
// `original=true` swaps to the source palette (#51b9f4 / #fec13d) for marketing.
type LogoProps = {
size?: number;
className?: string;
/** When true, use the original brand colors instead of the theme tokens. */
original?: boolean;
};
export function Logo({ size = 28, className, original = false }: LogoProps) {
const a = original ? "#51b9f4" : "var(--brand-500)";
const b = original ? "#fec13d" : "var(--accent-500)";
return (
<svg
width={size}
height={size}
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
aria-label="MCP Hub"
className={className}
>
<path
fill={a}
d="m496.4 11.5q5.4-0.4 10.9-0.5 5.4-0.1 10.9 0.1 5.4 0.2 10.8 0.7 5.5 0.4 10.9 1.2c56.2 7.7 99.4 36 133.3 81.3 31 41.4 41 94.3 34.8 144.5-6.9 54.7-31.6 89.2-71.8 124.8-9.7 8.6-19.4 21-29.9 28.7 8 7.2 17.5 17 25.1 24.8 8.6-11.9 22.8-24.8 33.4-35.4 10.6-10.1 20.7-22.2 32.2-31.2 44.5-34.8 109.1-43.7 163.2-31.3 97.6 22.4 162.8 115.9 151.4 215.3-12.8 111.6-114.9 189.3-225.7 173.7-56.9-8-89.1-29.9-126.7-72.5-8.4-9.5-20.3-19-28.1-29.2-3 4.4-20.1 21-24.7 25.2q0.8 0.7 1.6 1.4c10.3 8.9 20.5 20.3 30 29.2 31.4 29.2 55.6 55.7 65.1 98.8 3 13.7 4.9 22.1 6.1 36.6 4.1 52.5-11.2 105-46 144.9-28.1 32.3-64.1 56.5-106.4 64.9-9.6 2-17.3 3.9-27.3 4.6-11.3 1.4-27.3 0.9-38.7-0.3-55.1-6.2-100.6-31.3-135.2-74.7-6.8-8.5-12.8-17.6-18.1-27.2-5.2-9.5-9.7-19.4-13.3-29.7-3.6-10.3-6.3-20.8-8.1-31.6-1.9-10.7-2.8-21.5-2.8-32.4-0.3-41.9 11.1-88.4 38.8-121 5-5.8 10.5-11.8 16.2-17.1 15.8-14.8 31.2-33.3 48-46.7-7.7-8-17.1-16.5-24.2-24.6-8.4 9.8-18.5 19-27.4 28.3-10.5 10.8-20.7 21.7-31.8 31.9-36.3 32.8-85.8 44.5-133.6 42.7-12.8-0.5-25.5-2.3-38-5.3-12.5-3-24.6-7.3-36.2-12.7-11.7-5.4-22.7-11.9-33.1-19.4-10.3-7.6-19.9-16.2-28.6-25.6-46.8-50.7-62.6-116.6-46.9-183.1 8.7-41.1 30.3-72.1 60.7-100.4 64.9-60.6 180.9-67.1 250.4-10.7 10.9 8.8 22.5 21.5 32.4 31.7 10.5 10.9 21.9 21.7 32.1 33 8.1-11 14.4-15.9 23.9-24.9-37.7-41.9-77.8-63.2-94-122.1-17.9-65.2-8.7-131.9 34.5-185.2 37.9-46.8 81.1-66.8 139.9-73.5z"
/>
<path
fill={b}
d="M210 432c44 0.6 79 36 79 80 0 44-36 79-80 79-44 0-80-36-80-80 0-44 37-80 81-79z m294-302c44-5 83 27 87 71 5 44-27 83-71 87-44 4-83-27-87-71-4-44 27-83 71-87z m0 606c44-5 83 27 88 70 5 44-27 83-71 88-44 5-83-27-88-71-5-43 27-83 71-87z m302-302c44-5 83 26 88 70 5 44-26 83-70 88-44 5-83-26-88-70-5-44 26-83 70-88z"
/>
</svg>
);
}
type WordmarkProps = {
/** Logo mark size in px. The wordmark text auto-scales to feel proportional. */
size?: number;
/** Hide the text — useful when the sidebar is collapsed. */
iconOnly?: boolean;
className?: string;
};
export function LogoWordmark({ size = 28, iconOnly = false, className }: WordmarkProps) {
// The brand "MCP Hub" must always read left-to-right regardless of page
// direction — flipping it to "Hub MCP" in RTL would mangle the proper noun.
// `dir="ltr"` pins the inline flow, then `unicode-bidi: bidi-override` (set
// via .logo-text in CSS) keeps the order stable even when the surrounding
// paragraph is RTL.
return (
<span
className={`logo-wrap${className ? ` ${className}` : ""}`}
style={{ ["--logo-size" as string]: `${size}px` }}
dir="ltr"
>
<Logo size={size} />
{iconOnly ? null : (
<span className="logo-text" aria-hidden={false}>
<span className="logo-text-primary">MCP</span>
<span className="logo-text-secondary">Hub</span>
</span>
)}
</span>
);
}