Skip to main content

Deploy Capability

The Deploy capability manages website deployments for works through the plugin system. It coordinates between deployment providers (Vercel, etc.), Git repositories, and the internal work model. The module handles single deployments, batch deployments, deployment verification, and status tracking.

Source: apps/api/src/plugins-capabilities/deploy/

Architecture​

DeployModule
├── DeployController -- REST API endpoints
├── DeployService -- Deployment orchestration
├── DeploymentVerifierService -- Async status polling
├── DeployFacadeService -- Plugin provider resolution
├── GitFacadeService -- Git operations
├── WorkOwnershipService -- Authorization checks
└── WebsiteUpdateService -- Repository content updates

The module imports several dependencies:

@Module({
imports: [
FacadesModule, // Deploy and Git facades
DatabaseModule, // WorkRepository
PluginsModule, // Plugin registry
WebsiteGeneratorModule, // Website update service
WorkModule, // Ownership service
AuthModule, // JWT authentication
],
controllers: [DeployController],
providers: [DeployService, DeploymentVerifierService],
exports: [DeployService, DeploymentVerifierService],
})

API Endpoints​

All endpoints require JWT authentication and use the /api/deploy prefix.

List Providers​

GET /api/deploy/providers

Returns all available deployment providers and their configuration status.

Response:

{
"status": "success",
"providers": [{ "id": "vercel", "name": "Vercel", "enabled": true }]
}

Check Provider Configuration​

GET /api/deploy/providers/:providerId/configured

Checks if a specific provider is available and enabled.

Deploy Work​

POST /api/deploy/works/:id

Deploys a work to its configured deployment provider. This is the primary deployment endpoint.

Request Body (DeployWorkDto):

FieldTypeRequiredDescription
teamScopestringNoTeam/org scope for the deployment

Deployment Flow:

  1. Verify user owns (or has edit access to) the work
  2. Check if deployment credentials are configured via DeployFacadeService
  3. Validate the deployment token
  4. Execute deployment via DeployService
  5. Start async verification via DeploymentVerifierService

Response:

{
"status": "pending",
"slug": "my-work",
"owner": "username",
"repository": "username/my-work-website",
"message": "Deployment started"
}

Validate Token​

POST /api/deploy/validate-token

Checks if the user has a valid deployment provider available.

Get Teams for Work​

POST /api/deploy/works/:id/teams

Fetches available teams/organizations from the deployment provider for a specific work.

Check Deployment Capability​

POST /api/deploy/works/:id/check

Returns detailed deployment capability status:

{
"status": "success",
"canDeploy": true,
"isShared": false,
"ownerHasToken": true,
"userHasToken": true
}

Lookup Existing Deployment​

POST /api/deploy/works/:id/lookup

Checks if a work has an existing deployment and returns its status.

Batch Deploy​

POST /api/deploy/batch

Deploy multiple works in a single request.

Request Body (BatchDeployDto):

{
"works": [{ "workId": "uuid-1", "teamScope": "team-slug" }, { "workId": "uuid-2" }],
"teamScope": "default-team"
}

Response (BatchDeployResponseDto):

{
"status": "partial",
"message": "Batch deployment: 2 started, 1 failed",
"totalRequested": 3,
"successfullyStarted": 2,
"failed": 1,
"results": [
{ "workId": "uuid-1", "slug": "dir-1", "status": "pending", "message": "Deployment started" },
{ "workId": "uuid-2", "slug": "dir-2", "status": "pending", "message": "Deployment started" },
{ "workId": "uuid-3", "slug": "unknown", "status": "error", "message": "Work not found" }
]
}

Batch status is success (0 failures), partial (some succeeded), or error (all failed). Batches process up to 5 works concurrently with a 2-second delay between batches.

DeployService Internals​

The DeployService orchestrates the full deployment pipeline:

Deployment Pipeline​

1. Get plugin and token via DeployFacadeService
2. Get Git access token via GitFacadeService
3. Create repository context (owner, repo, publicKey)
4. Enable GitHub Actions workflows
5. Set required secrets (DEPLOY_TOKEN, DATA_REPOSITORY, DEPLOY_PROVIDER)
6. Set optional secrets (DEPLOY_TEAM_SCOPE, GH_TOKEN)
7. Generate and set CRON_SECRET
8. Dispatch workflow with retry

GitHub Actions Secrets​

The service sets these secrets on the target repository:

SecretDescription
DATA_REPOSITORYName of the data repository (e.g., my-dir-data)
{PROVIDER}_TOKENProvider-specific token (e.g., VERCEL_TOKEN)
DEPLOY_TOKENGeneric deployment token
DEPLOY_TEAM_SCOPETeam/org scope (optional)
GH_TOKENGitHub token for repo operations (optional)
CRON_SECRETRandomly generated 32-byte hex secret for cron jobs

Additionally, a DEPLOY_PROVIDER repository variable is set (not a secret).

Workflow Dispatch with Retry​

The service attempts to dispatch GitHub Actions workflows in order:

  1. Try deploy_vercel.yaml
  2. Try deploy_prod.yaml
  3. If both fail, update the repository via WebsiteUpdateService
  4. Create a trigger commit (.deployment-trigger file)
  5. Wait 3 seconds, then retry dispatch
  6. If dispatch still fails, rely on the push-triggered workflow

DeploymentVerifierService​

Monitors deployment progress asynchronously after a deployment is initiated.

Verification Process​

Deployment States​

StateDescription
INITIALIZINGDeployment just started
QUEUEDWaiting in provider queue
BUILDINGBuild in progress
READYDeployment successful (terminal)
ERRORDeployment failed (terminal)
CANCELEDDeployment was cancelled (terminal)
TIMEOUTVerification timed out (terminal)

Timing Configuration​

ParameterValueDescription
POLL_INTERVAL10 secondsTime between status checks
FETCH_LIMIT18 attemptsMax polls before marking not-found as timeout
TIMEOUT13 minutesAbsolute timeout for verification

Queue Management​

The verifier maintains an in-memory map of active verifications. Starting a new verification for a work automatically cancels any existing one:

// Only one verification per work at a time
startVerification(work, userId, teamScope);

DTOs​

DeployWorkDto​

class DeployWorkDto {
@IsString()
@IsOptional()
teamScope?: string;
}

BatchDeployDto​

class BatchDeployDto {
@IsArray()
@ValidateNested({ each: true })
works: BatchDeployItemDto[];

@IsString()
@IsOptional()
teamScope?: string; // Default for all items
}

class BatchDeployItemDto {
@IsString()
workId: string;

@IsString()
@IsOptional()
teamScope?: string; // Override per-item
}

BatchDeployResponseDto​

class BatchDeployResponseDto {
status: 'success' | 'partial' | 'error';
message: string;
totalRequested: number;
successfullyStarted: number;
failed: number;
results: BatchDeployItemResultDto[];
}

Shared Work Handling​

The deploy capability supports shared works. When a non-owner collaborator triggers deployment:

  • The owner's deployment credentials are used (not the collaborator's)
  • The WorkOwnershipService determines the isCreator flag
  • Token validation runs against the owner's configuration

Source Files​

FilePurpose
apps/api/src/plugins-capabilities/deploy/deploy.module.tsModule definition
apps/api/src/plugins-capabilities/deploy/deploy.controller.tsREST API endpoints
apps/api/src/plugins-capabilities/deploy/deploy.service.tsDeployment orchestration
apps/api/src/plugins-capabilities/deploy/tasks/deployment-verifier.service.tsAsync polling
apps/api/src/plugins-capabilities/deploy/dto/deploy.dto.tsSingle deploy DTOs
apps/api/src/plugins-capabilities/deploy/dto/batch-deploy.dto.tsBatch deploy DTOs