Support example
Search tickets, inspect details, edit a draft, and move status through a confirmed application action.
The Support example shows business UI: ticket text is untrusted input, but it cannot grant permissions, install code, or trigger a write.
Run it#
- 1
Open the scenario
Open Support in the playground. You should see a ticket table.
- 2
Run the scenario steps
Choose Search tickets, Browse open, Open ticket, then Edit ticket. You should see filtered results, a detail view, and a form holding the ticket's current values.
- 3
Watch the confirmation
Submit a change. You should see a review dialog first — the runtime validates the proposal, but confirming stays your decision.
- 4
Inspect the run
Choose Inspect. You should see the request, result, view policy, and any diagnostics.
- 5
Run it locally
Choose More → Export project, unzip the download, then run
pnpm installandpnpm dev. You should see a local browse view and the statusrenderer-ready.
What it exercises#
- Search permitted tickets through the bounded query contract.
- Open ticket detail by its stable ticket identity.
- Edit a draft with validation; dirty fields survive layout changes.
- Preview an action, require your confirmation, then execute once.
- Report action receipts through the host; retry or reconcile failed writes according to their outcome.
Make it yours#
- Swap the synthetic tickets for your data adapter.
- Read permissions from your real app state.
- Route writes through your registered action with fresh authorization.
- Dispose the app when the host removes the surface.
When it fails#
An unknown field or view returns a diagnostic and keeps the last permitted view. A denied permission read returns no data. Fix the contract or the trusted policy, then send the request again.
Local browse starter source#
The exported project renders one browse view. The additional Playground steps above require their resource meanings, forms/actions, or custom registrations; they are not bundled in this minimal starter. Follow Connect your data to add those contracts.
{
"name": "aeliqo-support-example",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build"
},
"dependencies": {
"@varendo/core": "0.1.0",
"@varendo/runtime": "0.1.0",
"@varendo/web": "0.1.0",
"zod": "4.5.4"
},
"devDependencies": {
"typescript": "7.0.2",
"vite": "8.2.2"
}
}{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"lib": [
"ES2022",
"DOM"
],
"types": [
"vite/client"
],
"strict": true,
"noEmit": true
},
"include": [
"src/**/*.ts"
]
}<!doctype html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Support tickets · Varendo</title></head><body><main><h1>Support tickets</h1><p id="status" role="status">Loading…</p><div id="app"></div></main><script type="module" src="/src/main.ts"></script></body></html>import {defineResource} from '@varendo/core';
import {createQueryFunctionRegistry} from '@varendo/core/expressions';
import {createLocalDataService} from '@varendo/runtime/data';
import {createAeliqoApp} from '@varendo/web/app';
import {z} from 'zod';
import './style.css';
const resource = defineResource({
id: 'tickets', revision: 'tickets-1', label: 'Support tickets', identity: ['id'],
schema: z.object({id: z.string(), subject: z.string(), customer: z.string(), status: z.string(), priority: z.string()}),
fields: {subject: {label: 'Subject'}, customer: {label: 'Customer'}, status: {label: 'Status', role: 'dimension'}, priority: {label: 'Priority'}},
presentation: {allowedViews: ["table","cards"]},
});
const functions = createQueryFunctionRegistry({version: '2'});
if (!functions.ok) throw new Error(functions.diagnostics[0].message);
const data = createLocalDataService({
snapshot: {catalog: resource.catalog, sourceRevision: 'synthetic-1', records: {tickets: [
{
"id": "t-1",
"subject": "Invoice PDF unavailable",
"customer": "Northstar",
"status": "Open",
"priority": "High"
},
{
"id": "t-2",
"subject": "Rotate API token",
"customer": "Kite Labs",
"status": "Resolved",
"priority": "Low"
}
]}},
functionRegistry: functions.value,
sourceLimits: {rows: 1_000, bytes: 1_000_000},
authorize: () => ({ok: true, value: {scopeDigest: 'local-demo', policyRevision: 'policy-1'}}),
});
const app = createAeliqoApp({
resources: [{resource, data}],
authority: {read: () => ({ok: true, value: {
principalKey: 'local-user', scopeDigest: 'local-demo', policyRevision: 'policy-1',
experienceRevision: 'web-1', grants: ['task.evaluate', 'result.inspect', 'experience.commit'],
readContext: {principal: 'local-user'},
}})},
});
const target = document.querySelector<HTMLElement>('#app');
if (target === null) throw new Error('The app target is missing.');
const mounted = app.mount({target, regionId: 'main', resourceId: resource.id});
if (!mounted.ok) throw new Error(mounted.diagnostics[0].message);
const receipt = await app.render({regionId: 'main', intent: {
version: '1', id: 'tickets-browse', kind: 'browse', resource: resource.id,
fields: ["subject","customer","status","priority"],
}});
document.querySelector('#status')!.textContent = receipt.status;
window.addEventListener('pagehide', () => app.dispose(), {once: true});:root{font-family:Inter,ui-sans-serif,system-ui;color:#202033;background:#f7f7fb}body{margin:0}main{inline-size:min(72rem,calc(100% - 2rem));margin:3rem auto}#app{container-type:inline-size;min-block-size:20rem}# Support tickets · Varendo 0.1.0
Synthetic source project exported from the Varendo playground. Install requires the pinned 0.1.0 packages to be published to npm.
```sh
pnpm install
pnpm dev
```
The application works without an AI provider. Replace the local snapshot and authority adapter with application-owned implementations before using real data.