Conversation
…e support, pre-built releases - Rewrite scripts/update.sh with pre-flight validator (disk, memory, Python, deps, network, health) and automatic rollback on failure. - Implement atomic blue/green install layout (/opt/serverkit-a|b + symlink). - Add explicit database migration step (flask db upgrade) before switching slots. - Add --dry-run, --force, --branch, --release flags to update.sh. - Add SERVERKIT_OFFLINE_TARBALL and SERVERKIT_MIRROR_URL support. - Verify release tarball SHA-256 checksums on download. - Ship pre-built frontend/dist and relocatable venv in release tarballs. - Make serverkit update delegate fully to scripts/update.sh; remove inline _update_source fallback. - Harden install.sh for blue/green, checksums, offline, and pre-built venv. - Update uninstall to remove both blue/green slots and backups. - Update docs/INSTALLATION.md and README.md with new options.
Adds the AI/LLM one-click templates and wires the panel's own AI assistant to a self-hosted Prompture Hub: - Templates: prompture-hub, ollama-webui, qdrant, chroma, litellm, flowise, langflow, anythingllm, librechat (brand-neutral, auto-port, generated secrets, lucide icons). - AI provider: new 'prompture-hub' provider routed through Prompture's OpenAI-compatible cachibot driver (hub key + endpoint), so ServerKit AI can call a local hub instead of raw provider keys. - Featured Prompture Hub + icon fallbacks in the Services UI. Roadmap: SERVICES_ROADMAP #1-#8. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Adds 16 one-click templates across the most-requested self-hosting categories: - Media/automation: audiobookshelf, calibre-web, and a *arr stack (sonarr, radarr, prowlarr, qbittorrent, jellyseerr) sharing a serverkit-media docker network so they interconnect by container name. - News/RSS: freshrss, miniflux. Documents: paperless-ngx (+redis +postgres), stirling-pdf, memos. - Finance: actualbudget, firefly-iii (+postgres). Project mgmt: vikunja, plane (full multi-service stack). - Brand-neutral, auto-port, generated secrets, lucide icons; icon fallbacks wired in Templates.jsx. Roadmap: SERVICES_ROADMAP #9-#15. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…plates Fills operational gaps so the catalog feels like a serious self-hosting panel: - Identity/SSO: authentik (server+worker+postgres+redis, bootstrap admin). - Monitoring: beszel (hub) and signoz (full OTel/ClickHouse observability stack; OTLP 4317/4318 exposed). - Search: meilisearch, typesense, searxng (+valkey). - Notifications: gotify, ntfy. - Networking/security: wg-easy (WireGuard VPN, fixed UDP 51820) and pihole (DNS sinkhole, fixed 53). Tailscale is host-level and intentionally deferred. Roadmap: SERVICES_ROADMAP #16-#20. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Adds the heavier business/community tools (larger support surface, gated behind Phases 0-2): - Customer engagement & signing: chatwoot (rails+sidekiq+pgvector+redis), documenso (+postgres, self-signed cert flow documented). - Product analytics: metabase (+postgres), posthog (full ClickHouse/Kafka/Zookeeper/MinIO hobby stack, ~4GB RAM). - Community & bookmarks: nodebb (+postgres), linkding, karakeep (web+chrome+meilisearch). Roadmap: SERVICES_ROADMAP #21-#23. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Makes the expanded catalog usable end-to-end: - #24 Auto-domain: templates can opt in with 'auto_domain: true'; on install the app is published at <slug>.<base_domain> via the existing SiteDomainService (HTTPS only if the wildcard cert is already set up — never forces SSL; remote installs skipped). - #25 Category consolidation: getCategoryIcon now covers the new tags (ai/llm/search/finance/documents/rss/vpn/dns/identity/observability/...). - #26 Icon strategy: each template ships an inline lucide-style base64 icon with a keyed lucide fallback map; documented in Templates.jsx. - #27 Update flow: update_app now normalizes list-format variables and re-renders the files: section + bind mounts, so converted/file-based templates (litellm, signoz, posthog) update correctly. - #28 Community repo: TemplateService.build_repo_index()/export_repo_index() generate the index.json the sync mechanism already expects, exposed via GET /repos/index and POST /repos/index/export. Roadmap: SERVICES_ROADMAP #24-#28. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Validates all 105 bundled templates parse + validate via the real TemplateService, ids match filenames, and every template has an icon; the 42 roadmap templates additionally use inline base64 icons, list-shaped vars, and are brand-neutral; and build_repo_index() covers the whole catalog. 149 cases, all green. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Introduce a ServerKit-managed per-site Fail2ban layer to protect WordPress login endpoints. Adds Fail2banJailService (write-side) to generate filter and per-site jail configs, enable/disable jails, reload fail2ban, and unban IPs (Linux-only, best-effort, ownership-guarded). Wire it into WordPress service lifecycle (enable on site create, remove on delete) and WpSecurityService wrapper methods. Expose API endpoints for status, toggle and unban in backend API. Add unit tests for Fail2banJailService (config rendering, naming/safety, lifecycle, graceful degradation). Frontend: Security tab loads brute-force status, can toggle protection, shows ban counts and unban action; API client and styles updated. NginxService gains canonical per-site log/error path helpers. Docs updated to reflect shipped brute-force jail feature.
… template magic vars Four foundational enhancements toward the deploy-code developer experience: - Container status aggregator (C7): new ContainerStatusService applies a deterministic priority hierarchy (degraded > restarting > running:unhealthy > starting > running:healthy > exited > unknown) over an app's containers, cached with a short TTL. Exposed at /api/v1/status and pushed over a new container_status Socket.IO channel; Applications page now renders an aggregated ContainerStatusPill with sub-status tooltip. - API token scopes + sensitive data masking (C10): require_scope() decorator enforces fine-grained scopes for API-key requests (pass-through for JWT), a canonical SCOPES catalog at /api/v1/api-keys/scopes, and a reusable sensitive_data_filter (mask_sensitive) honoring secrets:read. Frontend gains a grouped ApiKeyScopesModal picker and per-key scope pills. - Server onboarding state machine (C8): new onboarding lifecycle (pending -> validating -> installing_prerequisites -> installing_docker -> pairing_agent -> ready/failed) with ServerOnboardingService, a server_onboarding_logs table, servers.onboarding_* columns, REST endpoints, and an OnboardingWizard surfaced on the server detail overview. - Declarative template catalog (C5): documented catalog schema and magic-variable resolution (SERVICE_PASSWORD_/USER_/FQDN_/URL_/BASE64_*) layered onto the existing YAML template loader without changing behavior for templates that don't use them; GET /api/v1/templates/catalog/schema. Migration 029 adds the onboarding table + columns. 60 new tests pass; frontend builds clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…atalog certification
- Build packs / zero-Dockerfile deploys (C1): new BuildpackService detects the
stack from a cloned repo (Node/Python/Go/PHP/Ruby/Rust/static), produces a
transparent build plan and a generated Dockerfile, and persists the plan +
overrides on the Application. POST /api/v1/buildpacks/{detect,generate}; a
BuildpackPreview shows the detected plan + editable overrides + Dockerfile in
the create wizard and the app Build tab. Builds on the existing build_method
plumbing instead of duplicating it.
- Deployment config snapshots + diff engine (C4): ConfigurationService captures
an immutable, hashed snapshot of resolved config (env keys + masked values,
domains, image/tag, build method, volumes) at every deploy and rollback; new
DeploymentSnapshot model + /api/v1/apps/<id>/snapshots[/diff|/restore]. A
DeploymentTimeline + ConfigDiffModal surface "what changed" and one-click
restore in the app Deploy tab. Secret values are never serialized.
- Template catalog certification (C5 cont.): a whole-catalog validation test
proves all 105 declarative templates conform to the documented schema; fixed
the stale index.json (was 63/105 entries) to list every bundled template.
Migration 030 adds the buildpack columns + deployment_snapshots table. Full
backend suite: 820 passed, 14 skipped; frontend builds clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
… PR previews, proxy stacks - Project / Environment hierarchy (C2): Workspace -> Project -> Environment org model. New Project/Environment models + CRUD APIs, nullable applications.project_id/environment_id (opt-in, no destructive backfill), ProjectService.ensure_default, a Projects list + ProjectDetail (env tabs), a project/environment selector in the create wizard, and sidebar nav. - Polymorphic shared resources facade (C9): ResourceTag + SharedVariableGroup /SharedVariable/attachment models keyed by (resource_type, resource_id), reusing the env-var Fernet encryption; SharedResourceService resolves merged variables (most-recent attachment wins) with secrets masked. /api/v1/shared endpoints + reusable TagsPanel/EnvironmentVariablesPanel + a Shared Variables management page. Existing per-resource tables untouched (facade first). - PR preview environments (C3): ApplicationPreview + settings models, a PreviewService with pure domain-templating + reconcile (open PRs vs active previews) cores and best-effort provisioning (incl. guarded WordPress file+DB clone), a pull_request webhook endpoint, preview.* jobs, and a Previews tab on the app detail page. - Per-server managed proxy stack (C6): opt-in Dockerized Traefik/Caddy as a Compose stack (host Nginx stays default and superior for PHP/WordPress). ProxyStack model + ProxyStackService with pure compose/config generators and versioned config backups, /api/v1/servers/<id>/proxy endpoints, and a Proxy tab on the server detail page. Migrations 031-034 add the new tables/columns; the full chain applies cleanly from an empty DB. Full backend suite: 871 passed, 14 skipped; frontend builds. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ared-resource depth, docs
- Server onboarding completion (C8): a pure pre-flight compatibility check
(arch/distro/kernel/cpu/memory) gating validate; real-but-guarded
distro-aware install_prerequisites/install_docker/pair_agent steps that
no-op safely on dev/Windows and never raise; audit + best-effort
notifications on each transition; and a live auto-scrolling log trail +
elapsed timer in the onboarding wizard.
- Fleet-wide proxy dashboard (C6): ProxyStackService.fleet_overview aggregates
every server's proxy posture (configured stack vs host Nginx default) behind
GET /api/v1/servers/proxy/overview, surfaced as a new Fleet Proxy page in the
Servers tab group with summary tiles + click-through to each server's proxy.
- Polymorphic shared resources depth (C9): hierarchical variable resolution
(workspace < project < environment < direct attachment < resource) with
source provenance and {{group.KEY}} interpolation, an audit trail on every
tag/group/variable/attachment mutation, GET /api/v1/shared/resolved/
hierarchical, and the reusable Tags/Environment-Variables panels embedded on
the application and server detail pages.
- Docs & coverage: docs/ENHANCEMENTS.md (brand-neutral guide to all ten
capabilities + verified endpoints), README/CHANGELOG updates, and a
cross-cutting integration test asserting the new endpoints are wired.
Full backend suite: 924 passed, 14 skipped; frontend builds clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…tack)
Both reverse proxies bind 80/443, so pointing the same domain at host Nginx and
a Dockerized proxy stack is an operational footgun. This tags each app with the
plane it expects and surfaces disagreements instead of leaving them implicit.
- Each app carries an `ingress_plane` ('nginx' | 'proxy_stack'); NULL reads as
the host-Nginx default. New pure helpers in app/utils/ingress.py: only
container-based services are proxy-stack eligible, and a requested proxy_stack
is forced back to nginx for PHP/WordPress/static/Python apps. to_dict() also
exposes `ingress_proxy_eligible`.
- ProxyStackService.ingress_audit(server) reports which of a server's apps
disagree with its active proxy mode; fleet_overview now includes per-server
app_count + mismatch_count. New GET /servers/<id>/proxy/ingress-audit.
- Create wizard offers the proxy stack only for Docker/Compose services and
keeps the default on Nginx; app detail shows an Ingress badge; the fleet proxy
dashboard flags mismatch counts; the server proxy panel warns and lists the
specific mismatched apps with reasons.
Migration 035 adds applications.ingress_plane. Backend suite green (incl. 8 new
ingress tests); frontend builds clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Tightens the seams the recent features introduced:
- Secret precedence/conflict: the embedded shared-variables panel now resolves
via the hierarchical endpoint, shows a per-variable source-scope badge +
precedence legend, and flags keys that are also set locally with a
"Set locally — local value applies" badge (shared groups are a facade and are
not injected into the container; the app's own env var is authoritative).
- Split inventory: apps now expose project_name/environment_name; the Services
list shows a project/environment badge (or "Unassigned") and a "Move to
project" bulk action (POST /apps/move-to-project, workspace-validated,
null-unassigns).
- Fleet proxy actionability: fleet_overview rows carry a {level,text}
recommendation (mismatch warning / idle stack / empty host / aligned),
rendered as a per-row pill.
- Onboarding wizard: "Step X of 5" + progress bar + rough ETA, and a
collapsible step-history trail so returning users get a clean summary.
- Config diff: a plain-language summary ("3 environment variables and the image
tag (app:1.2.1 -> app:1.1.9) changed") above the technical diff and echoed in
the restore confirmation.
- Container status: an always-visible "N issues" / "healthy/total" badge so a
degraded sub-container isn't hidden behind hover.
- Sidebar: Projects, Shared Variables and Workspaces collapse under a single
"Organization" group.
No schema change (project/environment names are derived). Backend suite: 935
passed, 14 skipped; frontend builds clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…ence)
Shared variable groups were resolved/displayed but never reached the container.
EnvService.get_effective_env(app) now merges them in: shared groups
(workspace < project < environment < direct) form the base layer and the app's
own local env vars override them, so a key set in both yields the local value —
matching the "Set locally — local value applies" UI hint. Secrets are decrypted
for injection; shared resolution is best-effort and never blocks a deploy.
The docker deploy path (_deploy_docker) now injects this merged env via
run_container, which also fixes a latent bug there (it called .get('success')
on get_env_vars()'s list result, so env was effectively never applied). Updated
the shared-variables panel note to say shared vars now apply at deploy with
local taking precedence.
Proving test test_effective_env.py (6 cases) covers the merge precedence, the
best-effort fallback, and that _deploy_docker hands run_container the merged env.
Full backend suite: 941 passed, 14 skipped; frontend builds clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Single-container apps already get the effective env via docker run -e. Compose apps get container env from the compose file's environment:, so this wires them the same way through a managed override compose file. ComposeEnvService.refresh_for_project writes docker-compose.serverkit.yml next to a managed app's base compose, adding an environment: overlay to every service built from EnvService.get_effective_env (shared variable groups under the app's own local env vars). Compose merges the override on top of the base, so the effective env wins on collisions — consistent with the docker-run path. Dollar signs are escaped ($ -> $$) so values survive compose interpolation intact. DockerService.compose_up now includes the override as a second -f (via _compose_cmd_with_overlay); `up -d` recreates changed containers so updated env takes effect on the next deploy. It's non-destructive (ServerKit only owns the override; the base compose is never edited), best-effort/guarded (a build failure falls back to the plain base command and never blocks a deploy), regenerated each up, and removed when the app has no effective env. Non-app dirs (e.g. proxy stacks) and env-less apps are left untouched. Proving test test_compose_env_overlay.py (6 cases): overlay injects shared+local into every service with local winning collisions, $ escaping, stale-override cleanup, non-app dirs untouched, and compose_up running with -f base -f override. Full backend suite: 947 passed, 14 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
A variable can now land on one compose service instead of all of them. Both EnvironmentVariable and SharedVariable gain an optional target_service (NULL = all services), threaded through the shared resolver as an inclusion filter (a var applies to a service when it targets all OR that service). EnvService.get_effective_env_for_services(app, services) computes each service's merged env (all-services vars + that-service vars, local overriding shared), and ComposeEnvService builds the override's per-service environment from it — so a var targeted at "db" only appears under the db service, untargeted vars appear everywhere. The single-container docker-run path is unchanged (one container gets the full effective env regardless of target). API: env-var create/update and shared-variable create/update accept target_service; GET /apps/<id>/compose-services lists a compose app's services. UI: the Environment tab shows an "Applies to" selector (gated to compose apps via the service list) with a per-row target chip; the shared variable editor gains a target-service field. Migration 036 adds the two columns; single Alembic head; chain applies from empty. Proving tests cover per-service distribution + the resolver helper. Full backend suite: 949 passed, 14 skipped; frontend builds clean. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the big one — eighteen commits that grow
devinto a proper release. At its heart sit ten new platform capabilities spanning developer experience (container-status aggregation, build packs, deploy-time config snapshots), team-and-scale organization (projects/environments, shared resources, PR previews), fleet (a server-onboarding state machine and opt-in per-server proxy stacks), and security (fine-grained API-key scopes). Around that, the one-click service catalog roughly doubles — 42 new templates across AI/LLM, media, identity, monitoring, search, and business — backed by a documented schema and auto-resolved${SERVICE_*}magic variables so a template never hardcodes a generated secret or host. The installer and updater got a ground-up rewrite into atomic blue/green slots with pre-flight checks, automatic rollback, checksum-verified release tarballs, and offline installs. Two long-standing gaps also close here: shared variable groups were resolved and displayed but never actually injected into containers, and there was nothing stopping a domain from being claimed by both host Nginx and a Dockerized proxy at once — both are fixed. Rounding it out is a per-site Fail2ban jail for WordPress brute-force protection and a pass of UX hardening across all the new surfaces.Highlights
X-API-Keycallers while web/JWT users stay RBAC-governed.serverkit update— atomic blue/green updates with pre-flight checks, DB backup + migration, automatic rollback,--dry-run/--branch/--releaseflags, and offline-tarball installs.Technical changes
Developer experience
container_status_service.pyprovides a pure, Docker-free aggregation function over a fixed priority hierarchy plus short-TTL live-fetch helpers;api/container_status.pymountsGET /api/v1/status/app/<id>and/status/apps;sockets.pyaddssubscribe_container_statuswith change-only deltas on thecontainer_statuschannel. Frontend:useContainerStatus.js,ContainerStatusPill.jsx,_container-status.scss.buildpack_service.pyinspects a repo (cloning via a stored source connection when given), emits a build plan, and renders a Dockerfile + compose;api/buildpacks.pyexposes/detect(cached by repo+commit) and pure/generate. Plan persisted onapplications.buildpack_type/buildpack_plan/buildpack_overrides. FrontendBuildpackPreview.jsx+_buildpack.scss.deployment_snapshot.pymodel +configuration_service.pycapture secret-masked env/domain snapshots before deploy;api/snapshots.pylists, fetches, diffs (?against=<id|previous>), and restores (@developer_required, re-uses the normal deploy path). FrontendConfigDiffModal.jsx,DeploymentTimeline.jsx,_deployments.scss.Declarative template catalog
template_service.pyresolves${SERVICE_PASSWORD/USER/FQDN/URL/BASE64_<NAME>}magic variables and thestring|password|port|uuid|randomvariable types at install time;api/templates.pyexposesGET /templates/catalog/schema. Schema documented indocs/TEMPLATE_CATALOG_SCHEMA.md.backend/templates/*.yamlfiles plus a heavily expandedindex.json;auto_domain: truepublishes a template at<slug>.<base_domain>viaSiteDomainService(HTTPS only if the wildcard cert already exists — never forces SSL; remote installs skipped).getCategoryIconcovers the new tags; inline lucide-style base64 icons with a keyed fallback;update_appnormalizes list-format variables and re-rendersfiles:+ bind mounts so file-based templates (litellm/signoz/posthog) update correctly;build_repo_index()/export_repo_index()backGET /repos/indexandPOST /repos/index/export. FrontendNewService.jsx,Services.jsx,Templates.jsx,_services.scss.Team & scale
project.py+environment.pymodels,project_service.py,api/projects.pyandapi/environments.py(create auto-makes a default environment; deletes refuse409when apps remain / when it's the only environment). Applications gain nullableproject_id/environment_id; writes gated byWorkspaceService.can_write_in_workspace, active workspace resolved fromX-Workspace-Id/?workspace_id=. FrontendProjects.jsx,ProjectDetail.jsx,_projects.scss.shared_resource.py(resource_tags,shared_variable_groups,shared_variables,shared_variable_group_attachments) +shared_resource_service.py+api/shared_resources.pyfor polymorphic tags, attachable variable groups, and a merged/shared/resolvedview; secrets masked via group-level masking plusapp/utils/sensitive_data_filter.py. FrontendSharedVariableGroups.jsx,EnvironmentVariablesPanel.jsx,TagsPanel.jsx,_shared-resources.scss.application_preview.py(application_previews+application_preview_settings) +preview_service.pyregisteringpreview.create|sync|destroyQueue Bus jobs;api/previews.py(developer-gated settings/sync/redeploy/teardown) and publicapi/webhooks.pyPOST /webhooks/pull-request/<token>reusing the push-webhook signature, always200to avoid provider retries. FrontendPreviewList.jsx,_previews.scss.Fleet
server_onboarding_service.pydrivespending → validating → installing_prerequisites → installing_docker → pairing_agent → ready|failedvia theserver.onboarding.advancejob kind;server_onboarding_log.pyholds the authoritative step history,serverscachesonboarding_state/onboarding_progress/onboarding_updated_at;api/servers.pyexposes start/retry/status. FrontendOnboardingWizard.jsx(Step X of 5, progress bar, ETA, collapsible history) +_onboarding-wizard.scss.proxy_stack.pymodel (one row per server, defaultnginx) +proxy_stack_service.pygenerating Traefik/Caddy compose joined to the externalserverkitnetwork;api/proxy.pyfor state, compose-preview, configure/regenerate/switch (developer-gated) andingress-audit. FrontendFleetProxy.jsx,ProxyStackPanel.jsx,_fleet-proxy.scss,_proxy.scss.Security & access
api/middleware/api_scope_middleware.pyholds the canonical scope catalog and arequire_scopedecorator that is a pass-through for JWT/session callers and only enforces scopes onX-API-Keyrequests (*master scope,resource:*wildcards);GET /api/v1/api-keys/scopessurfaces the catalog. FrontendApiKeyScopesModal.jsx,ApiKeyModal.jsx,ApiSettingsTab.jsx,_api-key-scopes.scss.fail2ban_jail_service.py(write-side) renders a filter + per-site jail, enables/disables, reloads fail2ban, and unbans IPs (Linux-only, best-effort, ownership-guardedserverkit-*); wired intowordpress_service.pylifecycle andwp_security_service.py;nginx_service.pygains canonical per-site log/error path helpers. API status/toggle/unban +WordPressDetail.jsxSecurity tab +_wordpress.scss.Ingress plane
app/utils/ingress.py(pure helpers): only container/Compose apps are proxy-stack eligible; a requestedproxy_stackis forced back tonginxfor PHP/WordPress/static/Python apps.applications.ingress_plane(migration 035; NULL reads as host Nginx);to_dict()exposesingress_proxy_eligible.ProxyStackService.ingress_audit()reports mismatched apps;fleet_overviewcarries per-serverapp_count/mismatch_countand a{level,text}recommendation pill. UI: ingress badge on app detail, mismatch warnings in the proxy panel and fleet dashboard.Shared-variable env injection
env_service.pyget_effective_env(app)merges shared groups (workspace < project < environment < direct) under the app's own local env vars, decrypting secrets for injection (best-effort, never blocks a deploy);_deploy_dockernow passes the merged env torun_container(also fixing a latent bug that called.get('success')on a list result, so env was effectively never applied).compose_env_service.pyrefresh_for_projectwrites a manageddocker-compose.serverkit.ymloverlay ($escaped to$$);docker_service.pycompose_upadds it as a second-fvia_compose_cmd_with_overlay, non-destructively and regenerated each up. Per-service targeting:EnvironmentVariableandSharedVariablegaintarget_service(migration 036; NULL = all services), withget_effective_env_for_servicesandGET /apps/<id>/compose-services. FrontendEnvironmentVariables.jsx"Applies to" selector +_env-vars.scss.Installer & updater
scripts/update.shrewritten with a pre-flight validator (disk/memory/Python/deps/network/health) and automatic rollback; atomic blue/green layout (/opt/serverkit-a|b+ symlink); explicitflask db upgradebefore slot switch;--dry-run/--force/--branch/--releaseflags;SERVERKIT_OFFLINE_TARBALL/SERVERKIT_MIRROR_URL; SHA-256 checksum verification on download.serverkitdelegates fully toupdate.sh(inline_update_sourcefallback removed);install.shhardened for blue/green, checksums, offline, and a pre-built relocatable venv; uninstall removes both slots + backups.scripts/build-release.shships pre-builtfrontend/dist+ venv;release.ymlupdated.Wiring, migrations & docs
app/__init__.pyregisters the new blueprints and job handlers;config.pyadds related settings;App.jsx/sidebarItems.jsadd routes and collapse Projects/Shared Variables/Workspaces under an "Organization" group.target_service(single Alembic head; chain applies from empty).docs/ENHANCEMENTS.md,docs/TEMPLATE_CATALOG_SCHEMA.md,docs/INSTALLATION.md;CHANGELOG.md/README.mdupdated.