Dillo example

Resort Concierge

AI asks. Staff confirm.

What this demonstrates

A resort concierge with an AI front end. The AI can request things on your behalf — but resort staff confirm before anything happens. The AI gets a backend; the humans keep the authority. That's the whole point.

How it works

The permissions are the app. This is the whole data model — schema.ts, the first of the app's three files (its import line, not shown, brings these names in from "create-dillo/schema"):

schema.ts
// The schema the live backend serves today (span2/live-schemas filing, re-verified at deploy).
export default schema({
  Audit: table({
    action: string().max(80),
    authorization: string().max(200),
    guestId: relation.user(),
    principalId: string().max(160),
    principalType: string().max(40),
    requestId: string().max(200),
    resourceId: string().max(200),
  }).permissions({ view: owner, edit: nobody }),

  Conversation: table({
    guest: relation.user(),
    resort: relation.team(),
    role: string().max(20),
    stay: relation('Stay'),
    text: string().max(1000),
  }).permissions({ view: members, edit: roles('admin', 'owner') }),

  Menu: table({
    content: file().accept('application/pdf').maxBytes(1048576),
    resort: relation.team(),
    title: string().max(120),
  }).permissions({ view: members, edit: roles('admin', 'owner') }),

  Request: table({
    details: string().max(1000),
    guest: relation.user(),
    resort: relation.team(),
    status: string().max(20),
    stay: relation('Stay'),
  }).permissions({ view: members, edit: roles('admin', 'owner') }),

  SpaSlot: table({
    available: boolean(),
    resort: relation.team(),
    startsAt: string().datetime(),
    stay: relation('Stay'),
  }).permissions({ view: members, edit: roles('admin', 'owner') }),

  Stay: table({
    arrivesAt: string().datetime(),
    guest: relation.user(),
    leavesAt: string().datetime(),
    resort: relation.team(),
    room: string().max(20),
  }).permissions({ view: members, edit: roles('admin', 'owner') }),

  Trace: table({
    agentId: string().max(120),
    guestId: relation.user(),
    input: string().max(20000),
    operation: string().max(80),
    output: string().max(20000),
    principalId: string().max(160),
    requestId: string().max(200),
  }).permissions({ view: owner, edit: nobody }),
});

Try it

  1. Open the live demo
  2. Ask the AI concierge for something
  3. Switch to staff view and approve it