38.1 Overview
ADL provides administrative endpoints for system introspection, domain management, user administration, and audit logging. These endpoints are used by admin interfaces, monitoring tools, and operational scripts.
All admin endpoints require authentication unless explicitly marked as public. User management endpoints require the admin role.
38.2 System Infrastructure
Health Check
GET /health
Auth: None (public)
Response (200): Direct response, no envelope
{
"status": "healthy"
}
Version Information
GET /version
Auth: None (public)
Response (200): Direct response, no envelope
{
"version": "0.3.1",
"build": "2026-05-17T14:30:00Z",
"commit": "a1b2c3d"
}
Server Status
GET /api/v1/status
Auth: None (public)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"uptime": 86400,
"memory": {
"rss": 52428800,
"heapTotal": 41943040,
"heapUsed": 31457280
},
"domains": 3,
"routes": 127
}
}
Plugin List
GET /api/v1/plugins
Auth: None (public)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"plugins": [
{ "name": "rest", "type": "transport", "status": "running" },
{ "name": "sqlite", "type": "store", "status": "running" },
{ "name": "authd", "type": "handler", "status": "running" },
{ "name": "adl", "type": "handler", "status": "running" },
{ "name": "seeder", "type": "handler", "status": "running" }
]
}
}
Route List
GET /api/v1/routes
Auth: None (public)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"count": 127,
"routes": [
{ "method": "GET", "path": "/api/v1/blog/posts", "action": "adl.blog.post.list" },
{ "method": "POST", "path": "/api/v1/auth/login", "action": "auth.login" },
{ "method": "GET", "path": "/health", "action": "kernel.health" }
]
}
}
38.3 Domain Management
List Domains
GET /api/v1/domains
Auth: None (public)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"domains": [
{
"name": "blog",
"version": "1.0.0",
"status": "active",
"resources": ["Post", "Tag", "Comment"],
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-15T10:00:00Z"
},
{
"name": "orders",
"version": "2.1.0",
"status": "active",
"resources": ["Order", "OrderItem", "Product", "Customer"],
"createdAt": "2026-02-01T00:00:00Z",
"updatedAt": "2026-03-10T14:00:00Z"
}
]
}
}
Get Domain
GET /api/v1/domains/{name}
Auth: None (public)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"name": "blog",
"version": "1.0.0",
"status": "active",
"checksum": "a1b2c3d4e5f6...",
"resources": ["Post", "Tag", "Comment"],
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-15T10:00:00Z",
"migrations": [
{
"id": 1,
"fromVersion": null,
"toVersion": "1.0.0",
"status": "success",
"stepsApplied": 5,
"stepsSkipped": 0,
"appliedAt": "2026-01-01T00:00:00Z"
}
]
}
}
Get Domain Schema
GET /api/v1/domains/{domain}/schema
Auth: None (public)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"domain": {
"name": "blog",
"version": "1.0.0"
},
"resources": {
"Post": {
"label": "Post",
"plural": "Posts",
"fields": {
"id": {
"type": "uuid",
"primaryKey": true,
"required": true,
"label": "ID"
},
"title": {
"type": "string",
"required": true,
"maxLength": 200,
"label": "Title"
},
"status": {
"type": "enum",
"ref": "PostStatus",
"label": "Status"
}
},
"stateMachine": {
"field": "status",
"initial": "draft",
"transitions": {
"publish": {
"from": ["draft", "review"],
"to": "published",
"label": "Publish",
"permissions": ["editor", "admin"]
}
}
},
"permissions": {
"list": ["*"],
"get": ["*"],
"create": ["authenticated"],
"update": ["owner", "editor", "admin"],
"delete": ["admin"]
},
"features": {
"softDelete": true,
"search": true,
"audit": true
},
"relationships": {
"comments": {
"type": "hasMany",
"resource": "Comment",
"foreignKey": "postId"
},
"tags": {
"type": "belongsToMany",
"resource": "Tag",
"junction": "post_tags"
}
}
}
},
"enums": {
"PostStatus": {
"values": {
"draft": { "label": "Draft", "color": "#94a3b8" },
"review": { "label": "In Review", "color": "#f59e0b" },
"published": { "label": "Published", "color": "#10b981" }
}
}
}
}
}
This endpoint is the primary discovery mechanism for admin UIs.
Submit Domain
POST /api/v1/domains
Content-Type: application/json
{
"content": "<domain YAML or JSON string>",
"format": "yaml",
"allow_destructive": false
}
Auth: Required (admin role)
Body fields:
content(required) — the ADL document as a YAML or JSON stringformat(optional) —"yaml"or"json"; auto-detected if omittedallow_destructive(optional, defaultfalse) — execute destructive migrations (drops, type narrowing) instead of refusing/deferring them (§30.6)
Response (201): Domain created or updated with migration applied
{
"status": "ok",
"code": 201,
"data": {
"domain": "blog",
"version": "1.1.0",
"status": "active",
"resources": [
{ "name": "Post", "table": "blog_posts", "fields": 6 }
],
"ddl_count": 3
}
}
Response (422): Migration refused (destructive change without allow_destructive)
{
"status": "error",
"code": 422,
"error_code": "DESTRUCTIVE_MIGRATION",
"error_message": "Migration contains destructive type changes that would risk data loss. Rename fields or use a Phase 3 explicit destructive migration.",
"data": [
"Type change for Post.views is narrowing (potentially destructive). Set allow_destructive: true to proceed."
]
}
38.4 User Management
All user management endpoints require the admin role.
List Users
GET /api/v1/admin/users
?limit=50&offset=0&search=alice&status=active
Auth: Required (admin role)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"items": [
{
"id": "a1b2c3d4-...",
"username": "alice",
"email": "alice@example.com",
"status": "active",
"verified": true,
"createdAt": "2026-01-01T00:00:00Z"
}
],
"count": 1
}
}
Get User
GET /api/v1/admin/users/{username}
Auth: Required (admin role)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"id": "a1b2c3d4-...",
"username": "alice",
"email": "alice@example.com",
"status": "active",
"verified": true,
"roles": ["editor", "author"],
"createdAt": "2026-01-01T00:00:00Z",
"lastLoginAt": "2026-05-17T10:00:00Z"
}
}
Set User Roles
POST /api/v1/admin/users/{username}/roles
Auth: Required (admin role)
Request:
{
"roles": ["editor", "reviewer"]
}
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"username": "alice",
"roles": ["editor", "reviewer"]
}
}
Verify User
POST /api/v1/admin/users/{username}/verify
Auth: Required (admin role)
Manually marks a user as email-verified.
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"username": "alice",
"verified": true
}
}
Suspend User
POST /api/v1/admin/users/{username}/suspend
Auth: Required (admin role)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"username": "alice",
"status": "suspended"
}
}
Suspended users receive HTTP 403 USER_SUSPENDED on all authenticated requests.
Unsuspend User
POST /api/v1/admin/users/{username}/unsuspend
Auth: Required (admin role)
Reverses suspension.
38.5 Role Management
List Roles
GET /api/v1/admin/roles
Auth: Required (admin role)
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"items": [
{ "name": "admin", "description": "Full system access" },
{ "name": "editor", "description": "Content editor" },
{ "name": "author", "description": "Content author" }
],
"count": 3
}
}
Create Role
POST /api/v1/admin/roles
Auth: Required (admin role)
Request:
{
"name": "reviewer",
"description": "Content reviewer"
}
Response (201):
{
"status": "ok",
"code": 201,
"data": {
"name": "reviewer",
"description": "Content reviewer"
}
}
38.6 Audit Log
Query Audit Log
GET /api/v1/admin/audit
?username=alice
&action=adl.blog.post.create
&status_code=200
&after=2026-01-01T00:00:00Z
&before=2026-01-31T23:59:59Z
&limit=100
&offset=0
Auth: Required (admin role)
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
username | string | Filter by username |
action | string | Filter by action name |
status_code | integer | Filter by HTTP status |
after | datetime | Records after timestamp |
before | datetime | Records before timestamp |
limit | integer | Max records (1-500, default 100) |
offset | integer | Records to skip |
Response (200):
{
"status": "ok",
"code": 200,
"data": {
"items": [
{
"id": "uuid",
"username": "alice",
"action": "adl.blog.post.create",
"transport": "rest",
"remoteAddr": "192.168.1.100",
"statusCode": 201,
"durationMs": 45,
"timestamp": "2026-05-17T10:30:00Z"
}
],
"count": 1
}
}
38.7 Reserved Domain Names
The following names cannot be used as domain names (case-insensitive):
auth, users, admin, domains, status, plugins, routes, version,
openapi, echo
These collide with infrastructure routes under /api/v1/.
38.8 Integration Points
| Feature | Integration |
|---|---|
| Authentication (§29) | User management endpoints |
| Migration (§30) | Domain submission triggers migration pipeline |
| Audit (§8) | Audit log query endpoint |
| Permissions (§11) | Admin role requirement on management endpoints |
| Schema (§5) | Schema endpoint for runtime introspection |
| OpenAPI (§37) | Per-domain OpenAPI spec |
End of Chapter 38.
Next: Chapter 39 — Error Contract