Compose: production README, env knobs, first-owner bootstrap — deployed & live
Made the Docker Compose route turn-key for a real self-host, then stood the whole stack up and drove a live chat through it. - First-owner bootstrap (cm-auth::bootstrap_owner): a fresh local-auth install has no users and no signup route, so the initial Owner + workspace are provisioned ONCE from CLAWMATES_BOOTSTRAP_* env on first boot — idempotent, never clobbers an existing install (keys on 'any workspace exists'). Two real-Postgres tests (creates + signs in; second call is a no-op). Wired into server boot, guarded on a non-empty password - deploy/compose/README.md: full production bring-up — services, the security topology, every config knob, Anthropic vs local-LLM, the broker-key backup, ops, and TLS/SSE proxy notes - .env.example fleshed out (bootstrap, LLM, auth mode, OTLP); compose uses optional env_file so only the knobs you set are injected (unset options never override clawmates.toml with empty strings) - volume-init one-shot chowns the broker's named volumes so the non-root scratch broker can write its socket + generated master key Deployed locally and verified end to end: all 5 containers healthy, broker generated its key, server bootstrapped owner@…, login + /api/user/me work, and a real message streamed a live Anthropic response through the gateway. Captured screenshots of login, workspace home, chat, and the Computer panel. 166 Rust tests (+2 bootstrap). Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
b9fdec9173
commit
447f7039d8
@@ -74,6 +74,29 @@ async fn run() -> Result<(), String> {
|
||||
e2e::seed(&pool).await?;
|
||||
}
|
||||
|
||||
// First-owner bootstrap (self-hosted local-auth installs). Provisions
|
||||
// the initial workspace + Owner from env exactly once; a no-op on
|
||||
// every later boot. CLAWMATES_BOOTSTRAP_OWNER_PASSWORD is the trigger.
|
||||
if let Some(password) = std::env::var("CLAWMATES_BOOTSTRAP_OWNER_PASSWORD")
|
||||
.ok()
|
||||
.filter(|p| !p.is_empty())
|
||||
{
|
||||
let email = std::env::var("CLAWMATES_BOOTSTRAP_OWNER_EMAIL")
|
||||
.unwrap_or_else(|_| "[email protected]".into());
|
||||
let workspace = std::env::var("CLAWMATES_BOOTSTRAP_WORKSPACE")
|
||||
.unwrap_or_else(|_| "My Workspace".into());
|
||||
let credits = std::env::var("CLAWMATES_BOOTSTRAP_CREDITS")
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(1250);
|
||||
let created = cm_auth::bootstrap_owner(&pool, &workspace, &email, &password, credits)
|
||||
.await
|
||||
.map_err(|e| format!("bootstrap owner: {e}"))?;
|
||||
if created {
|
||||
println!("clawmates-server: bootstrapped first owner {email} in '{workspace}'");
|
||||
}
|
||||
}
|
||||
|
||||
let provider = build_provider(&config)?;
|
||||
let blob: std::sync::Arc<dyn cm_files::BlobStore> = match config.storage.backend {
|
||||
cm_config::StorageBackend::Local => std::sync::Arc::new(cm_files::LocalBlobStore::new(
|
||||
|
||||
Reference in New Issue
Block a user