From fabric-apps
Build data-driven applications on Microsoft Fabric Apps (the preview workload that turns TypeScript data models into a SQL database, GraphQL APIs, auth, and static hosting via the Rayfin CLI). Use this skill whenever the user is working with Fabric Apps, the Rayfin CLI (`rayfin`, `npx rayfin up`, `npm create @microsoft/rayfin`), the `@microsoft/rayfin-core` or `@microsoft/rayfin-client` packages, `RayfinClient`, `rayfin.yml`, the `rayfin/data/` folder, or `@entity()`/`@role()` decorators — even if they only say "build an app on Fabric", "scaffold a Fabric app", "add a table/entity to my Fabric app", "query my Fabric data with GraphQL", "deploy to Fabric with rayfin", or describe an internal tool/dashboard/prototype backed by Fabric capacity. Do NOT use this for Azure Service Fabric, Fabric data engineering (notebooks, lakehouses, pipelines, Spark), or Power BI — those are unrelated to Fabric Apps.
How this skill is triggered — by the user, by Claude, or both
Slash command
/fabric-apps:fabric-appsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Fabric Apps (preview) is a Microsoft Fabric workload for building full-stack, data-driven web
Fabric Apps (preview) is a Microsoft Fabric workload for building full-stack, data-driven web
apps. You write TypeScript entity classes decorated with @entity(), @text(), @role(),
etc., and the Rayfin CLI compiles them into a managed SQL database in Fabric, a
GraphQL Data API, row-level authorization, and static hosting — all behind a single
app endpoint with Microsoft Entra SSO.
The whole platform is the "Rayfin" toolchain. Three pieces show up constantly:
@microsoft/rayfin-core — decorators you use to define data models (@entity, @text, @role, …).@microsoft/rayfin-client — the type-safe RayfinClient your frontend uses to read/write data.@microsoft/rayfin-cli (rayfin / npx rayfin) — scaffold, run locally, apply schema, deploy.Mental model of the data flow — keep this in mind, because every "how do I…" question maps to one stage:
TypeScript entity classes (rayfin/data/*.ts)
→ decorators (@entity, @text, @one, @role …)
→ CLI compiles to → SQL schema + GraphQL API + auth policies
→ RayfinClient (generated, type-safe) → your frontend (React/Vue/Svelte/…)
Good fit: rapid prototypes, internal tools/dashboards, data-exploration UIs, and structured backends for AI/agent apps — anything where you want a live, authenticated, data-backed app without writing backend boilerplate.
Bad fit (tell the user up front, don't try to force it):
This is a preview product and the API surface moves. Your training data may be stale or
invented. Before generating non-trivial Rayfin code, verify decorator names, client method
signatures, and CLI flags against the live docs using the microsoft_docs_search /
microsoft_docs_fetch MCP tools (or microsoft-docs skill) and the reference files in this
skill. Inventing a decorator or a RayfinClient method that doesn't exist is the most common
failure mode here — a quick lookup prevents it.
If the user hasn't confirmed prerequisites, remind them once: the workspace needs Fabric capacity, and a tenant admin must enable the "Fabric Apps (preview)" workload before any deploy will work.
Follow these stages. Most requests are "do one stage" — identify which and go there.
New project from a template:
npm create @microsoft/rayfin@latest my-app # add --workspace <name> to target a workspace
cd my-app
Add Rayfin to an existing/empty directory instead (interactive: pick services, dialect, hosting):
npx rayfin init .
# non-interactive example:
npx rayfin init my-app --services db,storage --auth-methods fabric --static-hosting --overwrite
This produces the standard layout (see references/cli-and-config.md for the full tree):
your-project/
├── rayfin/
│ ├── data/ # entity classes + schema.ts ← you spend most time here
│ ├── rayfin.yml # backend service config (auth/data/storage/staticHosting)
│ ├── .env # local secrets/values for interpolation (gitignore it)
│ └── tsconfig.json # generated; don't edit
├── src/ # frontend (React/Vue/… depending on template)
└── package.json
Each entity is a class in rayfin/data/*.ts. This is the heart of the platform — get the
decorators right and everything downstream (DB, API, types) follows. Read
references/data-modeling.md for the full decorator reference, relationships, and the gotchas;
the essentials:
import { entity, uuid, text, int, decimal, boolean, date, set, one, many } from '@microsoft/rayfin-core';
@entity()
export class Notebook {
@uuid() id!: string;
@text({ min: 1, max: 100 }) name!: string;
@date() createdAt!: Date;
@many(() => Note) notes?: Note[]; // one-to-many: @many on parent
}
@entity()
export class Note {
@uuid() id!: string;
@text() title!: string;
@text({ optional: true }) content?: string;
@boolean({ default: false }) isPinned!: boolean;
@date() createdAt!: Date;
@one(() => Notebook) notebook?: Notebook; // many-to-one: @one on child, auto-creates notebook_id FK
}
Three rules that bite people constantly (full list in the reference):
@entity() ≠ TypeScript optional. A trailing ? only changes the static type. To make a
column nullable you must pass { optional: true } to the decorator. Use ! to tell
TypeScript the framework initializes required fields.rayfin/data/schema.ts or the client can't see it..js extensions between entity files (from './Note.js') — the
emitted ESM needs them.@role)Permissions live next to the data, as class-level @role(roleName, actions, options?) decorators.
The only built-in role is authenticated. Policies are type-safe expressions over JWT claims
and the item. Owner-only is the workhorse pattern:
@entity()
@role('authenticated', '*', {
policy: (claims, item) => claims.sub.eq(item.user_id),
})
export class Task {
@uuid() id!: string;
@text() title!: string;
@text() user_id!: string; // populate from claims.sub — no @one() to the system USER entity
}
See references/data-modeling.md for field-level include/exclude, per-action rules,
.and()/.or(), and admin-override patterns.
The generated RayfinClient gives a fluent, type-safe API — no raw GraphQL. Read
references/client-api.md for the full CRUD/query/pagination/auth surface; the shape:
import { RayfinClient } from '@microsoft/rayfin-client';
import type { Note } from '../rayfin/data/Note';
type AppSchema = { Note: Note };
const client = new RayfinClient<AppSchema>({
baseUrl: import.meta.env.VITE_RAYFIN_API_URL ?? 'http://localhost:5168',
publishableKey: import.meta.env.VITE_RAYFIN_PUBLISHABLE_KEY,
});
const pinned = await client.data.Note
.select(['id', 'title', 'notebook.name'])
.where({ isPinned: { eq: true } })
.orderBy({ createdAt: 'desc' })
.execute();
await client.data.Note.create({ title: 'Standup', isPinned: false, createdAt: new Date() });
await client.data.Note.update({ id }, { title: 'Renamed' });
await client.data.Note.delete({ id });
Note the limitations you'll hit: no count() (use results.length), PagedResult.totalCount
isn't populated, select only the fields you need.
npm run dev # frontend dev server (Vite-based templates)
npx rayfin up # deploy to Fabric: creates the item, applies schema, builds + uploads static content
npx rayfin up --dry-run --verbose # preview without changing anything
npx rayfin up db apply # apply just schema changes (add --force for destructive ops — data loss risk)
rayfin up requires sign-in (it'll prompt) and Fabric auth enabled in rayfin.yml
(services.auth.fabric.enabled: true). Email/password works locally but never on a deployed
app. Full command/flag reference and rayfin.yml schema are in references/cli-and-config.md.
After editing entities, run npx rayfin up db apply. If the frontend keeps returning stale data
shapes after a schema change, the generated config under rayfin/.temp/ is cached — stop the dev
stack, rm -rf rayfin/.temp/, and restart. Never commit .temp/.
Load these as needed — they hold the depth that doesn't belong in this overview:
references/data-modeling.md — every field decorator, type modifiers, relationships, foreign
keys, the full @role/policy/field-permission system, and modeling gotchas.references/client-api.md — RayfinClient init, read/filter/sort/relationship-navigation,
pagination, create/update/delete (incl. relationships), auth, and current limitations.references/cli-and-config.md — full Rayfin CLI command + flag reference, the rayfin.yml
service schema, project structure, env vars, and the deployment sequence.Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub nikolajunserrichter/fabric-apps-skill --plugin fabric-apps