EnvironmentService¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
| Bounded context | BC-01 Project & Environment |
| Platform / plane | Control Plane / Control |
| Deployment granularity | module of host · host ControlPlaneApi |
| Status | target · ConnectSoft.Factory.Projects.Environments |
| Built from | connectsoft-microservice · libraries: connectsoft-extensions-saas-abstractions, connectsoft-extensions-saas-asp-net-core, connectsoft-extensions-messaging-model, connectsoft-extensions-persistence-model-nhibernate |
| Decisions | ADR-0015, ADR-0017 |
| Traceability | FR-01 FR-05 FUX-01 NFR-01 NFR-04 XL-01 XL-10 |
Purpose and responsibilities¶
An environment is a named target inside a project: a sandbox for autonomous experimentation, a development or test target, a staging target, or a production target of a generated product. EnvironmentService owns the environment's identity, its policy class, its state (including an operator freeze), the connections (BC-16) a run may use from it, and the reference to the desired deployment that the Runtime Cloud platform (BC-25) reconciles.
The policy class is the service's most important output. Action classes (D21) are evaluated per tool call by the Tools & MCP platform; the environment class raises the class of a call: a shared-write against a Production environment is a production action and always needs an approval bound to the exact proposal. The service never deploys anything; desired state lives here, observed state lives in BC-25.
Context and boundaries¶
flowchart LR
S["EnvironmentService"]
ToolAdapterService["ToolAdapterService"] -->|grpc| S
StudioBff["StudioBff"] -->|sync-http| S
S -->|grpc| ProjectService["ProjectService"]
S -->|event| RuntimeEnvironmentService["RuntimeEnvironmentService"]
S -. "EnvironmentCreated" .-> E_EnvironmentCreated(("event"))
S -. "EnvironmentStateChanged" .-> E_EnvironmentStateChanged(("event"))
Domain model¶
Environment — A named target inside a project with a policy class, connections and desired deployment references. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
environmentId |
guid |
yes | |
projectId |
guid |
yes | |
tenantId |
string |
yes | |
name |
string |
yes | |
class |
enum:EnvironmentClass |
yes | |
state |
enum:EnvironmentState |
yes | |
region |
string |
yes | |
connectionIds |
list:guid |
yes | Connections (BC-16) usable from this environment. |
desiredDeploymentRef |
string |
no | Reference to the desired deployment spec owned by BC-25. |
version |
long |
yes |
Invariants:
- Environment names are unique within a project.
- A Production-class environment cannot be targeted by a run whose release is not Published.
- Frozen environments reject every shared-write and production action until unfrozen by a Workspace admin.
stateDiagram-v2
Draft --> Active : Activate
Active --> Frozen : Freeze
Frozen --> Active : Unfreeze
Active --> Retired : Retire
Frozen --> Retired : Retire
Events: EnvironmentCreated, EnvironmentStateChanged · Tables: Environments, EnvironmentConnections · Repository: EnvironmentRepository
erDiagram
Environment {
guid environmentId PK
guid projectId
string tenantId
string name
enum_EnvironmentClass class
enum_EnvironmentState state
string region
list_guid connectionIds
string desiredDeploymentRef
long version
}
stateDiagram-v2
[*] --> Draft: CreateEnvironment
Draft --> Active: Activate
Active --> Frozen: Freeze
Frozen --> Active: Unfreeze
Active --> Retired: Retire
Frozen --> Retired: Retire
Retired --> [*]
A freeze is the operator's change-freeze or incident control: while an environment is Frozen, Run Control refuses to dispatch steps that target it with shared-write or production actions, and the Tools & MCP platform refuses the calls themselves, so a run already in flight stops at its next gated call instead of being killed.
Entities and value objects¶
None modelled
No entities or value objects are modelled for this item yet.
Data model and storage¶
| Store | Role | Engine / profile | Tables |
|---|---|---|---|
| Control plane relational store | primary | azure-sql / nhibernate-sqlserver | Environments, EnvironmentConnections |
| Table | Owner | Columns | Indexes |
|---|---|---|---|
dbo.Environments |
Environment | 9 | 1 |
dbo.EnvironmentConnections |
Environment | 3 | 0 |
Full DDL: appendix.
APIs¶
| Method | Path | Operation | Scope | Side effects | Idempotency | Gateway | Summary |
|---|---|---|---|---|---|---|---|
POST |
/factory/projects/{projectId}/environments |
CreateEnvironment | factory.projects.admin |
shared-write | key-header | GW-03 | Create an environment with a policy class. |
GET |
/factory/projects/{projectId}/environments |
ListEnvironments | factory.projects.read |
read | natural | GW-03 | Environments of a project with state and class. |
POST |
/factory/environments/{environmentId}/freeze |
FreezeEnvironment | factory.projects.admin |
production | natural | GW-03 | Block writes and production actions (incident or change freeze). |
POST |
/factory/environments/{environmentId}/unfreeze |
UnfreezeEnvironment | factory.projects.admin |
production | natural | GW-03 | Lift a freeze. |
| gRPC service | Method | Streaming | Visibility | Side effects | Summary |
|---|---|---|---|---|---|
Environments |
GetPolicyClass |
none | internal | read | Return the environment class and state for policy evaluation of a tool call. |
Messages¶
| Event | Topic | Scope / v | Aggregate | Consumers | Summary |
|---|---|---|---|---|---|
| EnvironmentCreated | projects.environments.v1.environment-created |
integration / 1 | Environment | IaCProvisioningService, RuntimeEnvironmentService, StudioBff | An environment exists. |
| EnvironmentStateChanged | projects.environments.v1.environment-state-changed |
integration / 1 | Environment | EnvironmentPromotionService, RunControlService, ToolAdapterService, StudioBff, AuditService | Activated, frozen, unfrozen or retired. |
EnvironmentCreated payload:
| Field | Type | Required | Description |
|---|---|---|---|
environmentId |
guid |
yes | |
projectId |
guid |
yes | |
tenantId |
string |
yes | |
class |
enum:EnvironmentClass |
yes |
EnvironmentStateChanged payload:
| Field | Type | Required | Description |
|---|---|---|---|
environmentId |
guid |
yes | |
tenantId |
string |
yes | |
fromState |
enum:EnvironmentState |
yes | |
toState |
enum:EnvironmentState |
yes |
| Command | Handled by | Result events | Summary |
|---|---|---|---|
CreateEnvironment |
Environment | EnvironmentCreated | |
FreezeEnvironment |
Environment | EnvironmentStateChanged |
None modelled
No consumed events are modelled for this item yet.
Workers and jobs¶
None modelled
No workers are modelled for this item yet.
Actors and grains¶
None modelled
No grains are modelled for this item yet.
Sagas and long-running flows¶
None modelled
No sagas are modelled for this item yet.
Options and configuration¶
| Section | Key | Type | Default | Reloadable | Secret | Summary |
|---|---|---|---|---|---|---|
Projects:Environments |
DefaultClasses |
string[] | [Sandbox, Development] |
yes | no | Environments created with a new project. |
Metrics and observability¶
| Metric | Instrument | Unit | Dimensions | Summary |
|---|---|---|---|---|
connectsoft.factory.environments.frozen |
updown | {environment} | tenant, class | Environments currently frozen. |
Security¶
| Authentication | oauth2-jwt |
| Scopes | factory.projects.read (Read environments.); factory.projects.admin (Create, freeze, retire.) |
| Roles | Operator, WorkspaceAdmin, PlatformAdmin, Observer |
| Tenant isolation | row-filter |
| Data classification | internal |
| Max side-effect class | production |
| Secrets | — |
Freeze and unfreeze are production actions even though they change only a row: they decide whether other production actions may happen, so they are audited with reason and are limited to Operators and Workspace admins.
Dependencies¶
Outbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ProjectService | grpc | Project existence and role resolution. | fail-fast | yes |
| RuntimeEnvironmentService | event | Desired deployment reconciliation (BC-25). | queue | no |
Inbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ToolAdapterService | grpc | Policy class of the target environment for tool calls. | — | yes |
| StudioBff | sync-http | Environment views and freeze actions. | — | yes |
Failure and recovery¶
| Scenario | Detection | Recovery | Data impact | RTO (min) |
|---|---|---|---|---|
| Provisioning reconciler unavailable | no observed-state updates | environment keeps desired refs; reconciliation resumes; Studio shows stale observed state | none | 60 |
NFR targets¶
| Target | Class value (pilot-interactive) | Override |
|---|---|---|
| latency_p95_ms | 2000 | — |
| availability_pct | 99.5 | — |
| throughput_rps | 50 | — |
| rpo_minutes | 15 | — |
| rto_minutes | 240 | — |
| cost_class | low | — |
Deployment¶
| Granularity | module of host · host ControlPlaneApi |
| Topologies | saas-default, hybrid, on-prem |
| Runtime | —; replicas —–— |
| Ports | — |
Current implementation¶
Nothing exists. Environment concepts appear only in the project lifecycle pages of the June-2026 target.
Later capabilities¶
Ephemeral preview environments created per run and retired automatically; environment promotion chains declared once per project; environment-scoped secrets through the Secret Broker (BC-40).
Decisions and traceability¶
| Family | Ids |
|---|---|
| FR | FR-01, FR-05 |
| FUX | FUX-01 |
| NFR | NFR-01, NFR-04 |
| XL | XL-01, XL-10 |