Checked at
۰۶:۳۳:۰۸
Admin widget builder
F029 maps the applied builder draft into backend preview contracts and keeps real persistence fail-closed until authenticated admin save/audit is available.
Checked at
۰۶:۳۳:۰۸
Preview validate
READY
Direct save
BLOCKED
Warnings
2
This page intentionally does not collect credentials or perform persisted writes. It maps the applied Widget Builder draft into the backend preview payload shape used by `/api/admin/widget-instances/*-preview`, then keeps real create/update blocked until the authenticated admin save flow exists.
GET /api/admin/widget-instances/contract
Backend exposes the widget instance registry handoff contract for frontend/admin save planning.
GET /api/admin/widget-instances/schema
Backend exposes schema metadata describing tenant/license/widget-type binding and validate-before-persistence policy.
POST /api/admin/widget-instances/create-preview
Backend can validate a future create payload without persisting widget_instances. Frontend may use this as deterministic QA before enabling direct save.
PATCH /api/admin/widget-instances/update-preview
Backend can validate a future update payload without persistence. This keeps Apply/preview/copy safe before audited save is enabled.
POST /api/admin/widget-instances/validate-config
Backend validates shared widget config such as symbol, intervals, theme, locale, sizing, symbol URL, attribution and features.
POST /api/admin/widget-instances/runtime-config-preview
Backend can preview runtime eligibility for the applied widget config before bootstrap and iframe runtime are involved.
POST /api/admin/widget-instances/embed-snippet-preview
Backend returns placeholder-based embed snippets and explicitly keeps runtime tokens out of copy-code output.
POST /api/admin/widget-instances
A generic admin CRUD endpoint exists, but builder direct save must stay disabled until authenticated admin flow, ownership guard, saved/applied semantics and audit evidence are wired in frontend.
PATCH /api/admin/widget-instances/:id
A generic update endpoint exists for UUID-backed widget instances, but the current builder uses public widget codes for preview and must not guess persisted ids or collect credentials.
The request is dry-run only and carries the last applied builder draft. It is safe for validation/probe flows and does not contain runtime credentials.
{
"schemaVersion": "kline.admin-widget-config.v1",
"mode": "validate-config",
"draft": {
"widgetType": "advanced-kline-chart",
"config": {
"widgetId": "demo-advanced-kline",
"widgetType": "advanced-kline-chart",
"publicKey": "pk_demo_local_only",
"symbol": {
"id": "BINANCE:BTCUSDT",
"ticker": "BINANCE:BTCUSDT",
"displayName": "Bitcoin / Tether",
"exchange": "BINANCE",
"provider": "binance-public-demo",
"pricePrecision": 2,
"volumePrecision": 6,
"currency": "USDT",
"timezone": "UTC"
},
"interval": "1h",
"allowedIntervals": [
"1m",
"5m",
"15m",
"30m",
"1h",
"4h",
"1d"
],
"theme": "dark",
"locale": "fa",
"features": {
"toolbar": true,
"indicators": true,
"drawings": true,
"realtime": true,
"snapshot": true,
"objectTree": true
}
},
"chartStyle": "candle",
"appliedAt": 1767268800000
},
"parentContainer": {
"width": 1180,
"minHeight": 620,
"display": "block"
},
"dryRun": true,
"requestedAt": 1784097188362
}This is the shape the frontend can send to validate-config/runtime-config-preview once the backend is running. Persisted save is intentionally not called from this page.
{
"tenantId": "tenant_frontend_preview",
"license": {
"id": "license_frontend_preview",
"tenantId": "tenant_frontend_preview",
"status": "active",
"expiresAtMs": null,
"revokedAtMs": null
},
"widgetType": {
"id": "widget_type_advanced_chart",
"code": "advanced_chart",
"version": 1,
"status": "active",
"configSchemaJson": {
"type": "object",
"additionalProperties": true
},
"defaultConfigJson": {
"symbol": "BINANCE:BTCUSDT",
"symbols": [
"BINANCE:BTCUSDT"
],
"interval": "1h",
"intervals": [
"1m",
"5m",
"15m",
"30m",
"1h",
"4h",
"1d"
],
"theme": "dark",
"locale": "fa",
"use_container_size": true,
"transparent_background": false,
"legal_branding": "backend_managed",
"features": {
"indicators": true,
"drawings": true,
"fullscreen": true,
"realtime": true,
"compare": false,
"alerts": false,
"events": false,
"trading": false,
"watchlist": false,
"heatmapZoom": false,
"screening": false,
"calendar": false,
"news": false,
"technicalAnalysis": false,
"fundamentals": false,
"timeline": false
}
},
"symbolRequirement": "single_required",
"websiteEmbed": {
"category": "website_embeddable_widgets",
"mode": "iframe"
}
},
"plan": {
"maxWidgets": 10,
"currentWidgetCount": 1,
"maxSymbols": 20,
"allowedWidgetTypes": [
"advanced_chart",
"advanced_chart@v1"
],
"allowedSymbols": [
"BINANCE:BTCUSDT"
],
"allowedIntervals": [
"1m",
"5m",
"15m",
"30m",
"1h",
"4h",
"1d"
],
"featureFlags": {
"indicators": true,
"drawings": true,
"fullscreen": true,
"realtime": true,
"compare": false,
"alerts": false,
"events": false,
"trading": false,
"watchlist": false,
"heatmapZoom": false,
"screening": false,
"calendar": false,
"news": false,
"technicalAnalysis": false,
"fundamentals": false,
"timeline": false
},
"legalBrandingFeatureFlags": {
"hideAttribution": false
}
},
"name": "Advanced KLine Chart",
"code": "demo-advanced-kline",
"configJson": {
"widget_type": "advanced-kline-chart",
"symbol": "BINANCE:BTCUSDT",
"symbols": [
"BINANCE:BTCUSDT"
],
"interval": "1h",
"intervals": [
"1m",
"5m",
"15m",
"30m",
"1h",
"4h",
"1d"
],
"theme": "dark",
"locale": "fa",
"direction": "auto",
"use_container_size": true,
"transparent_background": false,
"features": {
"indicators": true,
"drawings": true,
"fullscreen": true,
"realtime": true,
"compare": false,
"alerts": false,
"events": false,
"trading": false,
"watchlist": false,
"heatmapZoom": false,
"screening": false,
"calendar": false,
"news": false,
"technicalAnalysis": false,
"fundamentals": false,
"timeline": false
},
"klinecharts": {
"chart_style": "candlestick",
"frontend_widget_type": "advanced-kline-chart",
"mvp_stage": "v1",
"render_mode": "chart-runtime"
}
},
"allowedSymbolsJson": [
"BINANCE:BTCUSDT"
],
"allowedIntervalsJson": [
"1m",
"5m",
"15m",
"30m",
"1h",
"4h",
"1d"
],
"locale": "fa",
"runtimeFeaturesJson": {
"indicators": true,
"drawings": true,
"fullscreen": true,
"realtime": true,
"compare": false,
"alerts": false,
"events": false,
"trading": false,
"watchlist": false,
"heatmapZoom": false,
"screening": false,
"calendar": false,
"news": false,
"technicalAnalysis": false,
"fundamentals": false,
"timeline": false
},
"parentContainer": {
"width": 1180,
"minHeight": 620,
"display": "block"
}
}