The install-time tint only recolored favicon.svg, but the page also shipped a
fixed raster favicon.ico + .png — and favicon-hash scanners hash /favicon.ico,
which was identical across every install. So the "car-paint" tint didn't change
what those tools cluster on.
- index.html links only the SVG now (drop the raster <link>s).
- Remove the unused favicon-16x16/32x32.png.
- install.sh: after tinting favicon.svg, copy it over favicon.ico too, so a
blind /favicon.ico fetch also returns the per-install color instead of a fixed
icon. (SVG bytes under an .ico name — browsers use the linked SVG; this only
affects what a scanner hashes at that URL.)
Still obscurity/defense-in-depth, not a real gate — but now it does what it says.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reduce how identifiable a panel is from its unauthenticated surface, without
losing the brand once you're inside.
- Public vs interior title: new `public_title` setting (default "Control
Panel") drives the sign-in/register/setup headings and the browser tab
before login (and the static first-paint <title>); `panel_title`
(ServerKit) still names the tab once signed in. PageTitleUpdater picks by
route. Both are exposed pre-auth on /auth/setup-status and editable in the
admin Site Settings → Panel Appearance card.
- Per-install favicon tint (install.sh randomize_favicon): the favicon is a
plain-text SVG, so each install recolors the tile to one of a curated set of
legible colors via a string replace — same mark, different color, so a
favicon-hash comparison across installs differs. No image tooling required;
if the step can't run, the shipped default color stays. Runs on both fresh
and release installs; existing installs are untouched.
Defense-in-depth / obscurity only — real protection is access control + auth.
Verified: eslint 0 errors, backend py_compile ok, install.sh `bash -n` ok,
favicon sed recolor confirmed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restore the ServerKit name, favicon, manifest, auth-page headings, and
service-worker strings. Genericizing the panel's identity was the wrong
trade: hiding the title/favicon is security-by-obscurity that a real scanner
sees through, and it erased the product identity for almost no benefit. The
pages it touched (login/setup/register) require server or admin access to
reach anyway, so there is nothing to hide there.
The one durable, no-cost measure is kept: the `X-Robots-Tag: noindex`
header (from the prior commit) stays on both nginx server blocks so the
panel isn't indexed by search engines. Real protection lives in access
control + auth, not in the favicon.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reduce how easily the panel can be enumerated by scanners (Shodan/Censys)
and search engines:
- nginx: emit `X-Robots-Tag: noindex, nofollow, noarchive` on the panel
server blocks (both the TLS and insecure fallback configs).
- Generic page identity: title "Control Panel" + neutral meta description
in index.html; the runtime document.title setters (App.jsx, usePageTitle)
and PWA manifest name/short_name match — so the browser tab and manifest
no longer say "ServerKit".
- Drop the distinctive favicon (.ico/.png removed, generic favicon.svg) so a
favicon-hash no longer clusters instances; strip the product name from the
service worker (cache name, push title, header comment).
- Neutralize the visible auth/splash copy (Login/Register/Setup headings,
AppLoader label) to a generic name.
Search engines are the easy case; the header is defense-in-depth. Real
hiding still requires access control (IP allowlist / VPN / zero-trust) and
is deployment-specific.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace spinners with skeleton placeholders across page/section loaders
(EmptyState, DataTable, and ~page surfaces), add a reusable Skeleton
component + _skeleton.scss, rework AppLoader into a branded "server
powering on" loader, and refresh the favicon set (incl. SVG icon link).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 0 of the ServerKit UI redesign (see docs/REDESIGN_MAP.md):
- Remap design tokens to the new infra-console palette behind existing names; add prototype token names (surface ramp, cyan/violet, accent-bright/-bg). Dark/light/system.
- Self-host IBM Plex (woff2 vendored via scripts/fetch-fonts.mjs); no Google Fonts CDN.
- Runtime-derive the full accent ramp in ThemeContext.
- Add shared design-system primitives in components/ds (Pill, EnvTag, SegControl, MetricCard, Gauge, ServiceTile, Sparkline, AreaChart, ScoreGauge, Feed, Drawer).
- Restyle the sidebar (gradient rail, mono section headers, left accent bar) and switch the brand to the demo's gradient-tile logo.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Below 768px the persistent sidebar was set to display:none with no
replacement, leaving every route unreachable on phones/tablets. It now
collapses into an off-canvas drawer driven by a fixed mobile top bar.
- MobileTopBar: fixed header with hamburger toggle + brand (white-label
aware, solid wordmark), shown only < 768px
- Sidebar becomes a translateX drawer at min(280px, 86vw); focus trap,
Escape-to-close, inert when closed (React 18 safe), 44px close button,
aria-label + id wired to the toggle's aria-controls
- DashboardLayout owns open state via useMediaQuery, closes on route
change, locks body scroll, renders the scrim
- Semantic z-index ladder (scrim/drawer/header), 100dvh + safe-area
insets, viewport-fit=cover, prefers-reduced-motion fallback
- Main content offset below the fixed header for normal and full-page
routes
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce a full email management feature: adds EmailService (Postfix/Dovecot/SpamAssassin/OpenDKIM management, account creation, forwarding, webmail, queue/logs, service control), new email API blueprint with admin-protected endpoints, and EmailAccount DB model. Register the email blueprint in app init. Frontend: add Email page, route and sidebar link, preload accent color + theme to prevent FOUC, new email styles and a dashboard layout hook. Also update ROADMAP.md to include Phase 21 SSO/OAuth and bump roadmap last-updated date.
Introduces backend logic to determine server resource tier and block WordPress site creation on insufficient resources (lite tier). Adds ResourceTierContext and ResourceGate component to the frontend, displaying a UI warning and disabling creation actions when requirements are not met. Updates WordPress page and styles to integrate the new resource gating mechanism.
Introduces a ThemeContext for managing theme state and switching between dark, light, and system themes. Adds CSS custom properties for theme variables, updates LESS files to use theme-sensitive variables, and refactors frontend to support runtime theme changes. Also updates .env.example files to include SERVERKIT_GITHUB_REPO.
Introduces a Site Settings tab in the Settings page for admins to toggle user registration. Adds dynamic page title updates based on route, updates the favicon and meta tags, and conditionally shows the registration link on the login page based on the registration setting. Also adds a reusable usePageTitle hook.
Add initial project files for a modern React dashboard template using Vite. Includes documentation, configuration, and core frontend source files with sidebar layout, routing, and sample dashboard page.