# Compose API

2 operations under /api/v1. Errors are RFC 9457 problem+json with a stable `code` field. The complete schemas are in https://nebulactrl.com/api/v1/openapi.json.

## POST /environments/{environmentId}/compose-imports

Import a Docker Compose project

Creates the services of a Compose project as staged changes: services, volumes, config files, variables, domains, published ports, links (deploy order) and a canvas group. The request must match a plan without blockers. With `deploy: true` the new services are deployed in dependency order (needs `deployments:write`); otherwise review them and deploy from the staged bar.

Authentication: session cookie or `Authorization: Bearer nct_…` token.

Parameters:
- `Idempotency-Key` (header, string): Client-chosen key (<=255 chars). A retry with the same key replays the original response for 24 hours.
- `environmentId` (path, string, required)

Request body (application/json, required): ComposeImportRequest
  - `choices` (ComposeChoices, required)
  - `deploy` (boolean)
  - `mode` (enum: split | stack)
  - `serverId` (string, required)
  - `source` (ComposeSource, required)

Response 201: Created (ComposeImportResult)
  - `deployments` (DeploymentView[] | null, required)
  - `groupId` (string, required)
  - `name` (string, required)
  - `rewrites` (ComposeRewrite[] | null, required)
  - `services` (ServiceView[] | null, required)
  - `warnings` (string[] | null, required)
Errors: 401 Unauthorized; 403 Forbidden; 404 Not Found; 409 Conflict; 422 Unprocessable Entity; 500 Internal Server Error

## POST /environments/{environmentId}/compose-imports/plan

Review a Docker Compose import

Reads a docker-compose.yml (pasted, or from a git repository) and returns, for every Compose service, how it would be imported: source, ports and domains, variables (secrets are flagged and never returned), volumes, files, the rewritten references, what is not supported, and whether an official database image can become a managed database. `choices` change the defaults (include a service, switch to a managed database, publish a port, ...); send the same body again to see the effect. Nothing is written. Reading from a git repository needs `projects:write`.

Authentication: session cookie or `Authorization: Bearer nct_…` token.

Parameters:
- `environmentId` (path, string, required)

Request body (application/json, required): ComposePlanRequest
  - `choices` (ComposeChoices, required)
  - `mode` (enum: split | stack)
  - `serverId` (string)
  - `source` (ComposeSource, required)

Response 200: OK (ComposePlan)
  - `blockers` (string[] | null, required)
  - `checks` (ComposeCheck[] | null, required)
  - `commit` (string)
  - `installable` (boolean, required)
  - `missing` (string[] | null, required)
  - `mode` (enum: split | stack, required)
  - `name` (string, required)
  - `neededFiles` (ComposeNeededFile[] | null, required)
  - `networks` (ComposePlanNetwork[] | null, required)
  - `notes` (ComposeNote[] | null, required): Project-level remarks
  - `rewrites` (ComposeRewrite[] | null, required)
  - `services` (ComposePlanService[] | null, required)
  - `sourceKind` (enum: paste | repo, required)
  - `stack` (ComposeStackPlan)
  - `warnings` (string[] | null, required)
Errors: 401 Unauthorized; 403 Forbidden; 404 Not Found; 422 Unprocessable Entity; 500 Internal Server Error
