---
title: "Release, URLs, and Access Control"
category: "app-development"
canonical: "https://www.ai-go.app/en-US/docs/guide/app-release"
locale: "en-US"
last_updated: "2026-09-01"
source: "AI GO 開發者文件（https://www.ai-go.app）"
---

# Release, URLs, and Access Control

Once an application is written, three things decide whether it can go live safely: how it's released, where users come in, and who can access what.

---

## The release flow

Submit a version from the Builder's **Publish** tab.

1. Record a **version number** and a **changelog**
2. Behavior depends on permission:
   - With `builder.publish` → **publishes directly**
   - Without → creates a **publish request** for review

Requests can be approved, rejected (with a reason), or cancelled by the requester. This makes "who can push code to production" a controllable responsibility rather than something every developer holds.

### What release freezes

Publishing does more than ship code — it **freezes an authorization snapshot**:

- Reference declarations (which tables, which columns, which operations)
- Scope declarations

Which means changing reference settings during development does not affect the live version. A new release is required. That is deliberate: it prevents anyone from quietly widening permissions in development and having it take effect against production data immediately.

### Blocking pre-release checks

The platform detects configuration gaps at release time and blocks:

| Check | Why it blocks |
|---|---|
| External service not authorized | Code calls an external service whose domain hasn't been added to the allowlist |
| Fewer actions than before | This version dropped actions — possibly by accident; explicit confirmation required |

Both are classic "blows up in front of users after go-live" failures, hence catching them before release.

> **Note**: the pre-release check only verifies that a service is authorized (domain allowlist). The platform **neither stores nor validates** external service credentials — they live in App Secrets, and each action reads them out and assembles its own `Authorization` header. If an external API returns `401` after go-live, the application's own credentials are at fault; that is outside what the pre-release check can catch.

---

## URLs and identifiers

Every application carries two identifiers with different purposes:

| | Random identifier | Readable name |
|---|---|---|
| Chosen by | The system | You |
| Mutable | No | Yes, before release |
| Used for | Permanently stable internal identity | The public URL |

Readable name rules:

- 4–63 characters, lowercase alphanumerics and hyphens, not starting or ending with a hyphen
- Case-insensitive (`MyApp` normalizes to `myapp`)
- Reserved words are blocked (`admin`, `api`, `www`, `login`, and others)
- **Globally unique** across organizations; collisions are rejected

If your organization has chosen a workspace name, the public subdomain carries an organization prefix (of the form `{workspace}-{app}`). **Always use the URL the system returns rather than deriving it from the organization name** — existing applications are never renamed, so old and new conventions can coexist.

After release the URL is the user's entry point. Administrators copy it from the Dashboard and distribute it.

---

## Lifecycle management

| Operation | Effect |
|---|---|
| Republish | Ships a new version; users get it on next load |
| Suspend | Holders of the URL can no longer sign in; settings and code are retained |
| Delete | Removes the application and its URL. **Data Center data is not deleted** |

Deleting an app without deleting data is deliberate — data belongs to the organization, not to an application. It's the same principle that makes custom tables organization-level.

---

## Four layers of access control

What an application can touch is decided by four stacked layers. All four must pass.

### Layer 1: who can see the application

Internal apps can be restricted to **specific roles** — only members holding those roles see it in the application list and can sign in.

To a user who lacks access, the application is indistinguishable from nonexistent: it isn't listed, opening the URL directly is refused, and the response matches "no such application" so its existence isn't leaked.

### Layer 2: reference declarations (data scope)

An application must declare which ERP tables, columns, and operations it needs:

```json
{
  "table_name": "customers",
  "columns": ["id", "name", "email", "custom_data"],
  "permissions": ["read", "create", "update"]
}
```

Undeclared tables are unreachable. Declared tables with undeclared columns return nothing on read and silently drop them on write.

**Permission values**:

| Value | Allows |
|---|---|
| `read` | Query |
| `create` | Insert |
| `update` | Update |
| `delete` | Delete |

**Practical advice**: do not grant `delete` to ordinary operational applications. Model voiding as a status change and leave real deletion to administrators in a controlled environment. That preserves the audit trail and prevents accidents.

Core system tables (authentication, tenant management, permission settings, audit records) can **never** be referenced.

### Layer 3: scope approval (capability scope)

References govern *which data*. Scope governs *which capabilities*.

An application declares the scopes it needs (a code scan backfills them at release), and an administrator approves them in the Builder's **Scope** tab.

**High-risk scopes require an extra gate**: expanding into `db.write`, `erp.*`, `secret.read`, `http`, `knowledge.read`, and similar requires **the owner to enter their password on the spot**. This defends against authorization being widened quietly — even a compromised administrator account cannot escalate without the password.

External and Self-Built applications require explicit administrator approval and do not use the simplified internal flow.

Every scope grant change is recorded — who, when, and which scope — and is queryable in the audit log.

### Layer 4: user permissions (RBAC)

Even when the application is authorized, actual operations remain bound by the **user's roles**. Internal apps can read the triggering user's permission tags and decide what to show and allow.

Final server-side adjudication uses the triggering user's identity — a hidden front-end button is not a boundary.

---

## The three access modes compared

| | Internal | External | Self-Built |
|---|---|---|---|
| Use case | Internal tooling | Customer / supplier applications | Third-party system integration |
| Authentication | Organization member accounts | The app's own user system | **API key** |
| Code location | AI GO Builder | AI GO Builder | **Deployed by the third party** |
| Data access | Internal Proxy | External Proxy | **Open Proxy** |
| References need publishing | No (immediate) | No (immediate) | **Yes (published snapshot)** |

Self-Built serves the case of "we don't want to write code inside AI GO, we just want the data". It has no Builder and no front end — only an API key and data access. See Chapter 11.

---

## Auditing

All of the following are recorded:

- Application creation, release, suspension, deletion
- Reference declaration changes
- Scope grant changes (including who performed them)
- Every SDK call

Audit records are queryable under **System & Operations → Audit Log** with the `system.audit_log` permission.