Branch: feature/immutable-deploy (worktree .claude/worktrees/immutable-deploy).
Full plan: docs/ONE_CLICK_DEPLOY.md.
- Create
src/routes/oneclick_deploy/mod.rswithvalidatehandler. - Handler: read raw YAML body →
StackerConfig::from_str→validate_semantics. - 200
{valid, name, version, composition}on success; 422{valid:false, errors[], warnings[]}on invalid. - Never 500 on bad config (map parse/semantic errors to 422).
- Wire route into
src/startup.rs(public scope, like/api/audit/*). - Casbin migration granting
group_anonymousPOST/api/v1/deploy/validate.
- Migration:
baked_snapshotstable (stack, version, provider, image_id, healthy, digests, created_at). -
src/models/baked_snapshot.rs+src/db/baked_snapshot.rs(resolve,record). - Extend
src/bin/bake.rsto persist theBakeRecordinto the registry (viaDATABASE_URL). - Run
cargo sqlx prepareand commit.sqlx/(registry queries use runtimequery_as, notquery_as!— no offline data needed).
- Handler: registry resolve →
BootConfig→render_user_data→create_server_from_image. - TryDirect-managed Hetzner token (
HetznerConfig::from_env()→HETZNER_TOKEN). - Response
{server_id, public_ipv4, stack, provider}; structured errors.
-
cargo check --lib/--bins(SQLX_OFFLINE=true) -
cargo test(3 oneclick_deploy tests passing) -
cargo clippy(no warnings in new code; pre-existing warnings only) -
cargo fmt - curl smoke test of validate endpoint (valid + invalid YAML).
- Bake
ai-automation-workflowsonce → snapshot → registryimage_id.