Skip to content

feat(env): add environments to existing workspaces #153

Description

@bwl21

Problem

ct init can create the first environment while scaffolding a workspace, but there is no safe command for adding another ChurchTools instance later. Operators must currently edit ct.envs.json and create the matching instance/state layout by hand. That can leave the environment host, instance directory, state filename, and state content pointing at different hosts.

This is a follow-up to #131 and the multi-environment model introduced in #22.

Proposed interface

Add a shared application operation with a CLI projection such as:

ct env add staging \
  --host https://staging.example.church.tools \
  --protected

The local browser UI should call the same operation through its HTTP adapter and refresh its environment catalog afterward. The UI and CLI must not implement separate editing or validation logic.

For a process workspace, the default binding should follow the process scaffold convention:

ct.envs.json
instances/staging.example.church.tools/
└── ct-state.staging.example.church.tools.json

An explicit --state <path> may be considered for established non-process layouts, but it must not permit a host/state mismatch. The command should align with existing CLI naming and confirmation conventions before implementation.

Required behavior

  • Normalize and validate the ChurchTools host before writing anything.
  • Add exactly one (environment, host, state path, protected) binding to ct.envs.json.
  • Refuse an existing environment name without changing any file.
  • Detect an existing host or state binding and either reject ambiguity or handle an exact idempotent match deliberately.
  • For process workspaces, derive instances/<hostname>/ct-state.<hostname>.json; never create a generic hostless ct-state.json.
  • Create an empty host-bound state using the existing state schema, or clearly document if state creation is deferred. Reuse the lifecycle decision made by the process template from feat: add ct init for new config repositories #131.
  • Preflight every affected path and perform the change atomically: no partially updated environment file or half-created instance scaffold.
  • Never write login tokens, credentials, or literal secret values.
  • Do not contact ChurchTools; environment creation must be fully testable offline.
  • Do not initialize Git or create a nested repository.
  • Keep browser-supplied paths outside the trust boundary: the server owns the workspace root and resolves derived paths.
  • Return structured, deterministic output that CLI and UI adapters can render independently.

Design questions

  • How should the command distinguish a process workspace from the original standard ct init layout when no existing environment establishes a convention: persisted scaffold metadata, explicit layout option, or a conservative default?
  • Should adding an already identical binding be an idempotent success or a refusal?
  • Should the instance-local backups/, reference/, and reports/ directories be created eagerly, matching the process quickstart, or only when first used?

Acceptance criteria

  • ct env add and the browser UI use one application/core operation.
  • Adding a test environment to an existing process workspace produces one unambiguous host-bound environment/state mapping.
  • Protected status is preserved and visible in the environment catalog.
  • Duplicate names, host/state conflicts, malformed hosts, and pre-existing target files fail without partial writes.
  • Generated files contain no secrets and no live ChurchTools resource IDs.
  • The new environment appears in the UI selector without restarting the server.
  • Existing ct init behavior and existing environment profiles remain compatible.
  • Unit and integration tests require no network access.

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageUnsorted intake — decide in the weekly sweep

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions