Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/rest-apis/platform-api/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ login endpoint described under [Obtaining a token](#obtaining-a-token)
|ap:rest_api:api_key:delete|Delete an API key of a REST API|
|ap:rest_api:api_key:manage|Full access to a REST API's API keys|
|ap:rest_api:api_key:update|Update an API key of a REST API|
|ap:rest_api:build:create|Prepare a build of a REST API|
|ap:rest_api:build:manage|Full access to a REST API's builds|
|ap:rest_api:build:read|Read a REST API's builds|
|ap:rest_api:create|Create a REST API|
|ap:rest_api:delete|Delete a REST API|
|ap:rest_api:deployment:create|Deploy a REST API|
Expand Down
83 changes: 82 additions & 1 deletion platform-api/api/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions platform-api/config/config-template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,9 @@ enable_functionality_type_verification = false
# ---------------------------------------------------------------------------
[platform_api.deployments]
max_per_api_gateway = 20 # maximum API deployments per gateway
max_builds_per_api = 5 # maximum stored builds per API; preparing more removes
# the oldest builds no deployment holds, and is refused when
# every build is held (0 = keep all)

# Deployment timeout — mark stuck deployments as failed after timeout_duration seconds.
timeout_enabled = true
Expand Down
13 changes: 9 additions & 4 deletions platform-api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,10 +554,15 @@ type Database struct {

// Deployments holds deployment-specific configuration.
type Deployments struct {
MaxPerAPIGateway int `koanf:"max_per_api_gateway"`
TimeoutEnabled bool `koanf:"timeout_enabled"`
TimeoutInterval int `koanf:"timeout_interval"`
TimeoutDuration int `koanf:"timeout_duration"`
MaxPerAPIGateway int `koanf:"max_per_api_gateway"`
// MaxBuildsPerAPI caps how many builds are stored per API. Preparing another
// one at the cap first removes the API's oldest builds that no deployment
// holds; if every build is held, the prepare is refused rather than taking a
// build something can still be restored from. Zero or less keeps every build.
MaxBuildsPerAPI int `koanf:"max_builds_per_api"`
TimeoutEnabled bool `koanf:"timeout_enabled"`
TimeoutInterval int `koanf:"timeout_interval"`
TimeoutDuration int `koanf:"timeout_duration"`
}

// APIKey holds API key-specific configuration.
Expand Down
1 change: 1 addition & 0 deletions platform-api/config/default_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ func defaultConfig() *Server {
},
Deployments: Deployments{
MaxPerAPIGateway: 20,
MaxBuildsPerAPI: 5,
TimeoutEnabled: true,
TimeoutInterval: 20,
TimeoutDuration: 60,
Expand Down
3 changes: 3 additions & 0 deletions platform-api/internal/apperror/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ var (
// MCP proxy deployment operations. DeploymentNotActive's verb is the artifact
// kind, e.g. "API", "LLM provider".
var (
BuildNotFound = def(CodeBuildNotFound, http.StatusNotFound, "The specified build could not be found.")
BuildLimitReached = def(CodeBuildLimitReached, http.StatusConflict, "All %d stored builds of this API are in use by a deployment. Undeploy and delete a deployment to free its build before preparing another.")
BuildInUse = def(CodeBuildInUse, http.StatusConflict, "The build is in use by a deployment and cannot be deleted. Undeploy and delete that deployment first.")
DeploymentBaseNotFound = def(CodeDeploymentBaseNotFound, http.StatusNotFound, "The specified base deployment could not be found.")
DeploymentRestoreConflict = def(CodeDeploymentRestoreConflict, http.StatusConflict, "Cannot restore the currently deployed deployment, or the deployment is invalid.")
DeploymentNotFound = def(CodeDeploymentNotFound, http.StatusNotFound, "The specified deployment could not be found.")
Expand Down
1 change: 1 addition & 0 deletions platform-api/internal/apperror/catalog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var messageArity = map[string]int{
CodeOf(LLMProxyDeploymentValidationFailed): 1,
CodeOf(MCPProxyDeploymentValidationFailed): 1,
CodeOf(DeploymentNotActive): 1,
CodeOf(BuildLimitReached): 1,
CodeOf(ArtifactReadOnly): 1,
CodeOf(ArtifactRuntimeImmutable): 1,
CodeOf(ArtifactDeployed): 1,
Expand Down
3 changes: 3 additions & 0 deletions platform-api/internal/apperror/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ const (
// Deployment domain codes, shared across REST API / LLM provider / LLM proxy /
// MCP proxy deployment operations (identical conditions across all four).
const (
CodeBuildNotFound = "BUILD_NOT_FOUND"
CodeBuildLimitReached = "BUILD_LIMIT_REACHED"
CodeBuildInUse = "BUILD_IN_USE"
CodeDeploymentBaseNotFound = "DEPLOYMENT_BASE_NOT_FOUND"
CodeDeploymentRestoreConflict = "DEPLOYMENT_RESTORE_CONFLICT"
CodeDeploymentNotFound = "DEPLOYMENT_NOT_FOUND"
Expand Down
21 changes: 21 additions & 0 deletions platform-api/internal/database/schema.postgres.sql
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,23 @@ CREATE TABLE IF NOT EXISTS gateway_tokens (
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE
);

-- Builds table (immutable rendered snapshots of an API's definition)
CREATE TABLE IF NOT EXISTS builds (
uuid VARCHAR(40) PRIMARY KEY,
build_id VARCHAR(40) NOT NULL,
artifact_uuid VARCHAR(40) NOT NULL,
organization_uuid VARCHAR(40) NOT NULL,
description VARCHAR(1023),
content BYTEA NOT NULL,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
metadata BYTEA,
created_by VARCHAR(200),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
UNIQUE (artifact_uuid, build_id),
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE
);

-- Artifact Deployments table (immutable deployment artifacts)
CREATE TABLE IF NOT EXISTS deployments (
uuid VARCHAR(40) PRIMARY KEY,
Expand All @@ -273,11 +290,13 @@ CREATE TABLE IF NOT EXISTS deployments (
organization_uuid VARCHAR(40) NOT NULL,
gateway_uuid VARCHAR(40) NOT NULL,
base_deployment_uuid VARCHAR(40),
build_uuid VARCHAR(40),
content BYTEA NOT NULL,
metadata BYTEA,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
created_by VARCHAR(200),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (build_uuid) REFERENCES builds(uuid) ON DELETE NO ACTION,
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE,
Expand Down Expand Up @@ -488,6 +507,8 @@ CREATE INDEX IF NOT EXISTS idx_subscription_plans_status ON subscription_plans(s
CREATE INDEX IF NOT EXISTS idx_subscription_plan_limits_plan ON subscription_plan_limits(subscription_plan_uuid);

CREATE INDEX IF NOT EXISTS idx_artifact_subscription_plans_plan ON artifact_subscription_plans(subscription_plan_uuid);
CREATE INDEX IF NOT EXISTS idx_builds_artifact ON builds(artifact_uuid, organization_uuid, created_at);
CREATE INDEX IF NOT EXISTS idx_deployments_build ON deployments(build_uuid);

-- EventHub tables for multi-replica HA sync
CREATE TABLE IF NOT EXISTS gateway_states (
Expand Down
21 changes: 21 additions & 0 deletions platform-api/internal/database/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,23 @@ CREATE TABLE IF NOT EXISTS gateway_tokens (
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE
);

-- Builds table (immutable rendered snapshots of an API's definition)
CREATE TABLE IF NOT EXISTS builds (
uuid VARCHAR(40) PRIMARY KEY,
build_id VARCHAR(40) NOT NULL,
artifact_uuid VARCHAR(40) NOT NULL,
organization_uuid VARCHAR(40) NOT NULL,
description VARCHAR(1023),
content BLOB NOT NULL,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
metadata BLOB,
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE (artifact_uuid, build_id),
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE
);

-- Artifact Deployments table (immutable deployment artifacts)
CREATE TABLE IF NOT EXISTS deployments (
uuid VARCHAR(40) PRIMARY KEY,
Expand All @@ -265,11 +282,13 @@ CREATE TABLE IF NOT EXISTS deployments (
organization_uuid VARCHAR(40) NOT NULL,
gateway_uuid VARCHAR(40) NOT NULL,
base_deployment_uuid VARCHAR(40),
build_uuid VARCHAR(40),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
content BLOB NOT NULL,
metadata BLOB,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (build_uuid) REFERENCES builds(uuid) ON DELETE NO ACTION,
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE,
Expand Down Expand Up @@ -483,6 +502,8 @@ CREATE INDEX IF NOT EXISTS idx_subscription_plans_status ON subscription_plans(s
CREATE INDEX IF NOT EXISTS idx_subscription_plan_limits_plan ON subscription_plan_limits(subscription_plan_uuid);

CREATE INDEX IF NOT EXISTS idx_artifact_subscription_plans_plan ON artifact_subscription_plans(subscription_plan_uuid);
CREATE INDEX IF NOT EXISTS idx_builds_artifact ON builds(artifact_uuid, organization_uuid, created_at);
CREATE INDEX IF NOT EXISTS idx_deployments_build ON deployments(build_uuid);

-- EventHub tables for multi-replica HA sync
CREATE TABLE IF NOT EXISTS gateway_states (
Expand Down
21 changes: 21 additions & 0 deletions platform-api/internal/database/schema.sqlite.sql
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,23 @@ CREATE TABLE IF NOT EXISTS gateway_tokens (
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE
);

-- Builds table (immutable rendered snapshots of an API's definition)
CREATE TABLE IF NOT EXISTS builds (
uuid VARCHAR(40) PRIMARY KEY,
build_id VARCHAR(40) NOT NULL,
artifact_uuid VARCHAR(40) NOT NULL,
organization_uuid VARCHAR(40) NOT NULL,
description VARCHAR(1023),
content BLOB NOT NULL,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
metadata BLOB,
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE (artifact_uuid, build_id),
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE
);

-- Artifact Deployments table (immutable deployment artifacts)
CREATE TABLE IF NOT EXISTS deployments (
uuid VARCHAR(40) PRIMARY KEY,
Expand All @@ -273,11 +290,13 @@ CREATE TABLE IF NOT EXISTS deployments (
organization_uuid VARCHAR(40) NOT NULL,
gateway_uuid VARCHAR(40) NOT NULL,
base_deployment_uuid VARCHAR(40),
build_uuid VARCHAR(40),
Comment thread
coderabbitai[bot] marked this conversation as resolved.
content BLOB NOT NULL,
metadata BLOB,
data_version VARCHAR(20) NOT NULL DEFAULT '1.0',
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (build_uuid) REFERENCES builds(uuid) ON DELETE NO ACTION,
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
FOREIGN KEY (gateway_uuid) REFERENCES gateways(uuid) ON DELETE CASCADE,
Expand Down Expand Up @@ -488,6 +507,8 @@ CREATE INDEX IF NOT EXISTS idx_subscription_plans_status ON subscription_plans(s
CREATE INDEX IF NOT EXISTS idx_subscription_plan_limits_plan ON subscription_plan_limits(subscription_plan_uuid);

CREATE INDEX IF NOT EXISTS idx_artifact_subscription_plans_plan ON artifact_subscription_plans(subscription_plan_uuid);
CREATE INDEX IF NOT EXISTS idx_builds_artifact ON builds(artifact_uuid, organization_uuid, created_at);
CREATE INDEX IF NOT EXISTS idx_deployments_build ON deployments(build_uuid);

-- EventHub tables for multi-replica HA sync
CREATE TABLE IF NOT EXISTS gateway_states (
Expand Down
Loading
Loading