diff --git a/docker/logto-bootstrap.sh b/docker/logto-bootstrap.sh
index 04f076a..b1c2fc9 100644
--- a/docker/logto-bootstrap.sh
+++ b/docker/logto-bootstrap.sh
@@ -524,36 +524,10 @@ fi
# PHASE 6: Create organization + add users
# ============================================================
-log "Checking for organization '$TENANT_NAME'..."
-EXISTING_ORGS=$(api_get "/api/organizations")
-ORG_ID=$(echo "$EXISTING_ORGS" | jq -r ".[] | select(.name == \"$TENANT_NAME\") | .id")
-
-if [ -n "$ORG_ID" ]; then
- log "Organization exists: $ORG_ID"
-else
- log "Creating organization '$TENANT_NAME'..."
- ORG_RESPONSE=$(api_post "/api/organizations" "{
- \"name\": \"$TENANT_NAME\",
- \"description\": \"Bootstrap demo tenant\"
- }")
- ORG_ID=$(echo "$ORG_RESPONSE" | jq -r '.id')
- log "Created organization: $ORG_ID"
-fi
-
-# Add users to organization
-if [ -n "$ADMIN_USER_ID" ] && [ "$ADMIN_USER_ID" != "null" ]; then
- log "Adding platform owner to organization..."
- api_post "/api/organizations/$ORG_ID/users" "{\"userIds\": [\"$ADMIN_USER_ID\"]}" >/dev/null 2>&1
- api_put "/api/organizations/$ORG_ID/users/$ADMIN_USER_ID/roles" "{\"organizationRoleIds\": [\"$ORG_OWNER_ROLE_ID\"]}" >/dev/null 2>&1
- log "Platform owner added to org with owner role."
-fi
-
-if [ -n "$TENANT_USER_ID" ] && [ "$TENANT_USER_ID" != "null" ]; then
- log "Adding viewer user to organization..."
- api_post "/api/organizations/$ORG_ID/users" "{\"userIds\": [\"$TENANT_USER_ID\"]}" >/dev/null 2>&1
- api_put "/api/organizations/$ORG_ID/users/$TENANT_USER_ID/roles" "{\"organizationRoleIds\": [\"$ORG_VIEWER_ROLE_ID\"]}" >/dev/null 2>&1
- log "Viewer user added to org with viewer role."
-fi
+# No example organization created — the vendor creates tenants via the SaaS UI.
+# Users (admin, viewer) are created above but not added to any org.
+ORG_ID=""
+log "Skipping example organization (tenants are created by the vendor)."
# ============================================================
# PHASE 7: Configure cameleer3-server OIDC
@@ -795,12 +769,10 @@ fi
log ""
log "=== Bootstrap complete! ==="
# dev only — remove credential logging in production
-log " Platform Owner: $SAAS_ADMIN_USER / $SAAS_ADMIN_PASS (org role: owner)"
-log " Viewer: $TENANT_ADMIN_USER / $TENANT_ADMIN_PASS (org role: viewer)"
-log " Tenant: $TENANT_NAME (slug: $TENANT_SLUG)"
-log " Organization: $ORG_ID"
log " SPA Client ID: $SPA_ID"
if [ "$VENDOR_SEED_ENABLED" = "true" ]; then
log " Vendor: $VENDOR_USER / $VENDOR_PASS (role: saas-vendor)"
fi
log ""
+log " No tenants created — use the vendor console to create tenants."
+log ""
diff --git a/src/main/java/net/siegeln/cameleer/saas/config/BootstrapDataSeeder.java b/src/main/java/net/siegeln/cameleer/saas/config/BootstrapDataSeeder.java
deleted file mode 100644
index 96341d2..0000000
--- a/src/main/java/net/siegeln/cameleer/saas/config/BootstrapDataSeeder.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package net.siegeln.cameleer.saas.config;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import net.siegeln.cameleer.saas.tenant.TenantEntity;
-import net.siegeln.cameleer.saas.tenant.TenantRepository;
-import net.siegeln.cameleer.saas.tenant.TenantStatus;
-import net.siegeln.cameleer.saas.tenant.Tier;
-import net.siegeln.cameleer.saas.license.LicenseEntity;
-import net.siegeln.cameleer.saas.license.LicenseRepository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.stereotype.Component;
-
-import java.io.File;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-import java.util.Map;
-
-@Component
-public class BootstrapDataSeeder implements ApplicationRunner {
-
- private static final Logger log = LoggerFactory.getLogger(BootstrapDataSeeder.class);
- private static final String BOOTSTRAP_FILE = "/data/bootstrap/logto-bootstrap.json";
-
- private final TenantRepository tenantRepository;
- private final LicenseRepository licenseRepository;
- private final ObjectMapper objectMapper = new ObjectMapper();
-
- public BootstrapDataSeeder(TenantRepository tenantRepository,
- LicenseRepository licenseRepository) {
- this.tenantRepository = tenantRepository;
- this.licenseRepository = licenseRepository;
- }
-
- @Override
- public void run(ApplicationArguments args) {
- File file = new File(BOOTSTRAP_FILE);
- if (!file.exists()) {
- log.info("No bootstrap file found at {} — skipping data seeding", BOOTSTRAP_FILE);
- return;
- }
-
- try {
- JsonNode config = objectMapper.readTree(file);
- String orgId = getField(config, "organizationId");
- String tenantName = getField(config, "tenantName");
- String tenantSlug = getField(config, "tenantSlug");
-
- if (orgId == null || tenantSlug == null) {
- log.info("Bootstrap file missing organizationId or tenantSlug — skipping");
- return;
- }
-
- // Check if tenant already exists
- if (tenantRepository.existsBySlug(tenantSlug)) {
- log.info("Tenant '{}' already exists — skipping bootstrap seeding", tenantSlug);
- return;
- }
-
- log.info("Seeding bootstrap tenant '{}'...", tenantSlug);
-
- // Create tenant
- TenantEntity tenant = new TenantEntity();
- tenant.setName(tenantName != null ? tenantName : "Example Tenant");
- tenant.setSlug(tenantSlug);
- tenant.setTier(Tier.LOW);
- tenant.setStatus(TenantStatus.ACTIVE);
- tenant.setLogtoOrgId(orgId);
- tenant = tenantRepository.save(tenant);
- log.info("Created tenant: {} ({})", tenant.getSlug(), tenant.getId());
-
- // Create license
- LicenseEntity license = new LicenseEntity();
- license.setTenantId(tenant.getId());
- license.setTier("LOW");
- license.setFeatures(Map.of(
- "topology", true,
- "lineage", false,
- "correlation", false,
- "debugger", false,
- "replay", false
- ));
- license.setLimits(Map.of(
- "max_agents", 3,
- "retention_days", 7,
- "max_environments", 1
- ));
- license.setIssuedAt(Instant.now());
- license.setExpiresAt(Instant.now().plus(365, ChronoUnit.DAYS));
- license.setToken("bootstrap-license");
- licenseRepository.save(license);
- log.info("Created license for tenant '{}'", tenantSlug);
-
- log.info("Bootstrap data seeding complete.");
- } catch (Exception e) {
- log.error("Failed to seed bootstrap data: {}", e.getMessage(), e);
- }
- }
-
- private String getField(JsonNode node, String field) {
- return node.has(field) ? node.get(field).asText() : null;
- }
-}
diff --git a/ui/src/components/Layout.tsx b/ui/src/components/Layout.tsx
index c8d5de4..23e8340 100644
--- a/ui/src/components/Layout.tsx
+++ b/ui/src/components/Layout.tsx
@@ -4,7 +4,7 @@ import {
Sidebar,
TopBar,
} from '@cameleer/design-system';
-import { LayoutDashboard, ShieldCheck, Server, Users, Settings, KeyRound, Building } from 'lucide-react';
+import { LayoutDashboard, ShieldCheck, Server, Users, Settings, KeyRound, Building, Fingerprint } from 'lucide-react';
import { useAuth } from '../auth/useAuth';
import { useScopes } from '../auth/useScopes';
import { useOrgStore } from '../auth/useOrganization';
@@ -62,12 +62,25 @@ export function Layout() {
{isVendor && (