@microsoft/rayfin-guide 1.1.0 → 1.33.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/docs/app-backend/deploy.md +256 -0
- package/assets/docs/app-backend/index.md +126 -0
- package/assets/docs/app-backend/pricing.md +66 -0
- package/assets/docs/auth/fabric.md +328 -0
- package/assets/docs/auth/index.md +33 -0
- package/assets/docs/auth/overview.md +130 -0
- package/assets/docs/cli/ai-files.md +146 -0
- package/assets/docs/cli/env-interpolation.md +187 -0
- package/assets/docs/cli/env-migration.md +135 -0
- package/assets/docs/cli/environment-variables.md +173 -0
- package/assets/docs/cli/index.md +84 -0
- package/assets/docs/cli/installation.md +107 -0
- package/assets/docs/cli/quickstart.md +88 -0
- package/assets/docs/data/graphql.md +267 -0
- package/assets/docs/data/index.md +20 -0
- package/assets/docs/data/overview.md +270 -0
- package/assets/docs/data/permissions.md +172 -0
- package/assets/docs/data/validation.md +165 -0
- package/assets/docs/getting-started/create-app-with-cli.md +118 -0
- package/assets/docs/getting-started/create-rayfin-item.md +73 -0
- package/assets/docs/getting-started/index.md +201 -0
- package/assets/docs/getting-started/project-structure.md +290 -0
- package/assets/docs/hosting/index.md +183 -0
- package/assets/docs/index.md +92 -45
- package/assets/docs/known-limitations.md +50 -0
- package/assets/docs/preview/local-dev-docker.md +124 -0
- package/package.json +1 -1
- package/assets/docs/quickstart.md +0 -81
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 3
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Data permissions
|
|
6
|
+
|
|
7
|
+
Rayfin uses the `@role` decorator to attach authorization rules directly to your data models.
|
|
8
|
+
Permissions are type-safe, refactor-friendly, and compiled into Data API Builder (DAB) configuration automatically.
|
|
9
|
+
|
|
10
|
+
## Built-in roles
|
|
11
|
+
|
|
12
|
+
Rayfin recognizes two built-in roles:
|
|
13
|
+
|
|
14
|
+
- **anonymous** — public access without authentication.
|
|
15
|
+
- **authenticated** — requires a valid user session.
|
|
16
|
+
|
|
17
|
+
## The `@role` decorator
|
|
18
|
+
|
|
19
|
+
Apply `@role` at the class level to control which roles can perform which actions on an entity.
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
@role(roleName, actions, options?)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Parameter | Description |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| `roleName` | The role name (`'anonymous'` or `'authenticated'`). |
|
|
28
|
+
| `actions` | A single action or array of actions: `'create'`, `'read'`, `'update'`, `'delete'`, or `'*'` for all. |
|
|
29
|
+
| `options` | Optional object with `check`, `include`, and `exclude` properties. |
|
|
30
|
+
|
|
31
|
+
## Basic example
|
|
32
|
+
|
|
33
|
+
Grant anonymous users read access and restrict authenticated users to their own data:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { entity, role, uuid, text } from '@microsoft/rayfin-core';
|
|
37
|
+
|
|
38
|
+
@entity()
|
|
39
|
+
@role('anonymous', 'read')
|
|
40
|
+
@role('authenticated', ['create', 'read', 'update', 'delete'], {
|
|
41
|
+
check: (claims, item) => claims.sub.eq(item.user_id),
|
|
42
|
+
})
|
|
43
|
+
export class Todo {
|
|
44
|
+
@uuid() id!: string;
|
|
45
|
+
@text() title!: string;
|
|
46
|
+
@text() description?: string;
|
|
47
|
+
@text() user_id!: string;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
In this example, authenticated users can only access Todo items where `user_id` matches their JWT `sub` claim.
|
|
52
|
+
|
|
53
|
+
## Type-safe policy expressions
|
|
54
|
+
|
|
55
|
+
The `check` callback provides typed access to both claims and entity fields.
|
|
56
|
+
TypeScript infers the entity type from the decorated class, so you get autocompletion and refactor safety with no extra configuration.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
check: (claims, item) => claims.sub.eq(item.user_id)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Supported claims
|
|
63
|
+
|
|
64
|
+
| Claim | Description |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `claims.sub` | Subject identifier (user ID). |
|
|
67
|
+
| `claims.email` | User email address. |
|
|
68
|
+
| `claims.role` | User role. |
|
|
69
|
+
|
|
70
|
+
### Expression operators
|
|
71
|
+
|
|
72
|
+
| Operator | Example | DAB output |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| `.eq()` | `claims.sub.eq(item.user_id)` | `@claims.sub eq @item.user_id` |
|
|
75
|
+
|
|
76
|
+
### Logical operators
|
|
77
|
+
|
|
78
|
+
Combine expressions with `.and()` and `.or()`:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
check: (claims, item) =>
|
|
82
|
+
claims.sub.eq(item.user_id).and(item.isActive.eq(true))
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Both sides are parenthesized automatically, so grouping is always explicit:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// (claims.role eq 'admin') or (claims.sub eq @item.owner_id)
|
|
89
|
+
check: (claims, item) =>
|
|
90
|
+
claims.role.eq('admin').or(claims.sub.eq(item.owner_id))
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Field-level permissions
|
|
94
|
+
|
|
95
|
+
Control which fields a role can access using `include` or `exclude` in the role options.
|
|
96
|
+
|
|
97
|
+
### Include specific fields
|
|
98
|
+
|
|
99
|
+
Only allow the `Title` field during create:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
@role('authenticated', 'create', {
|
|
103
|
+
check: (claims, item) => claims.sub.eq(item.createdBy),
|
|
104
|
+
include: ['Title'],
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Exclude specific fields
|
|
109
|
+
|
|
110
|
+
Hide sensitive fields from read operations:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
@role('authenticated', 'read', {
|
|
114
|
+
check: (_claims, item) => item.IsAdmin.eq(false),
|
|
115
|
+
exclude: ['last_login'],
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Field arrays are typed to the entity's actual property names.
|
|
120
|
+
Renaming a field produces a compile-time error in every `include` or `exclude` list that references it.
|
|
121
|
+
|
|
122
|
+
## Action-specific permissions
|
|
123
|
+
|
|
124
|
+
Apply different rules per action by using multiple `@role` decorators with single actions:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
@entity()
|
|
128
|
+
@role('anonymous', 'read')
|
|
129
|
+
@role('authenticated', 'create', {
|
|
130
|
+
check: (claims, item) => claims.sub.eq(item.createdBy),
|
|
131
|
+
include: ['Title'],
|
|
132
|
+
})
|
|
133
|
+
@role('authenticated', 'read', {
|
|
134
|
+
check: (claims, item) => claims.sub.eq(item.createdBy),
|
|
135
|
+
})
|
|
136
|
+
@role('authenticated', 'update', {
|
|
137
|
+
check: (claims, item) => claims.sub.eq(item.createdBy),
|
|
138
|
+
exclude: ['adminContent'],
|
|
139
|
+
})
|
|
140
|
+
export class SecureDocument {
|
|
141
|
+
@uuid() id!: string;
|
|
142
|
+
@text() Title!: string;
|
|
143
|
+
@text({ optional: true }) adminContent?: string;
|
|
144
|
+
@text() createdBy!: string;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Storage permissions
|
|
149
|
+
|
|
150
|
+
The same `@role` decorator works with storage entities.
|
|
151
|
+
When applied to a `@blob()` class, Rayfin generates a storage policy instead of a database policy:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { blob, role } from '@microsoft/rayfin-core';
|
|
155
|
+
|
|
156
|
+
@blob()
|
|
157
|
+
@role('authenticated', '*', {
|
|
158
|
+
check: (claims, item) => claims.sub.eq(item.owner_id),
|
|
159
|
+
})
|
|
160
|
+
export class ProfileImage {
|
|
161
|
+
owner_id!: string;
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## How it works
|
|
166
|
+
|
|
167
|
+
- The `@role` decorator collects permission metadata at class definition time.
|
|
168
|
+
- When you run `npx rayfin up db apply`, the CLI reads that metadata and generates DAB-compliant permission entries in the configuration.
|
|
169
|
+
- Policy callbacks are compiled into DAB OData-style policy strings (for example `@claims.sub eq @item.user_id`).
|
|
170
|
+
- Field `include`/`exclude` arrays map directly to DAB field permission configuration.
|
|
171
|
+
- Multiple `@role` decorators on the same class are aggregated per role.
|
|
172
|
+
Conflicting declarations produce a warning at generation time.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 4
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Form Validation
|
|
6
|
+
|
|
7
|
+
Rayfin can generate a [Standard Schema](https://standardschema.dev) validator directly from your decorated entity classes.
|
|
8
|
+
This lets you validate form input on the client without adding a separate validation library like Zod or Yup.
|
|
9
|
+
|
|
10
|
+
## Build a validator from an entity
|
|
11
|
+
|
|
12
|
+
Use `toStandardSchema` to create a validator from any `@entity()` class.
|
|
13
|
+
The `id` field and relationship navigation properties (`@one`, `@many`) are automatically excluded — you only need to list additional fields your form does not collect.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { toStandardSchema } from '@microsoft/rayfin-core';
|
|
17
|
+
import { Todo } from '../rayfin/data/Todo.js';
|
|
18
|
+
|
|
19
|
+
// id is auto-omitted. List fields you want to omit from validation.
|
|
20
|
+
const todoInputSchema = toStandardSchema(Todo, {
|
|
21
|
+
omit: ['createdAt', 'updatedAt'] as const,
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The returned object implements the Standard Schema v1 contract (`~standard`) so it works with any compatible library (TanStack Form, Conform, tRPC v11, and others).
|
|
26
|
+
It also exposes a convenience `.validate()` method for direct use.
|
|
27
|
+
|
|
28
|
+
## Validate form input
|
|
29
|
+
|
|
30
|
+
Call `.validate()` with your form values.
|
|
31
|
+
The result is either `{ value }` on success or `{ issues }` on failure.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
const result = todoInputSchema.validate({
|
|
35
|
+
title: title.trim(),
|
|
36
|
+
isCompleted: false,
|
|
37
|
+
priority: 'medium',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (result.issues) {
|
|
41
|
+
// Map issues to per-field errors by path[0]
|
|
42
|
+
const errors: Record<string, string> = {};
|
|
43
|
+
for (const issue of result.issues) {
|
|
44
|
+
const key = String(issue.path?.[0] ?? '_');
|
|
45
|
+
if (!errors[key]) errors[key] = issue.message;
|
|
46
|
+
}
|
|
47
|
+
// Display errors in the UI
|
|
48
|
+
} else {
|
|
49
|
+
// result.value is typed as Omit<Todo, 'id' | 'createdAt' | 'updatedAt'>
|
|
50
|
+
await api.createTodo(result.value);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Validation is synchronous.
|
|
55
|
+
All checks (type guards, string length, regex, enum membership) run in memory with no async overhead.
|
|
56
|
+
|
|
57
|
+
## Read field constraints for UI hints
|
|
58
|
+
|
|
59
|
+
Use `getFieldConstraints` to read the decorator constraints for a single field.
|
|
60
|
+
This is useful for displaying character counters, limit labels, or other UI hints without building a full schema.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { getFieldConstraints } from '@microsoft/rayfin-core';
|
|
64
|
+
import { Todo } from '../rayfin/data/Todo.js';
|
|
65
|
+
|
|
66
|
+
const titleConstraints = getFieldConstraints(Todo, 'title');
|
|
67
|
+
// { type: 'string', min: 1, max: 50, optional: false }
|
|
68
|
+
|
|
69
|
+
const maxLength =
|
|
70
|
+
titleConstraints?.type === 'string' ? titleConstraints.max : undefined;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The field name is type-checked against the entity — typos are caught at compile time.
|
|
74
|
+
|
|
75
|
+
## What gets validated
|
|
76
|
+
|
|
77
|
+
The validator checks each field based on its decorator:
|
|
78
|
+
|
|
79
|
+
| Decorator | Checks |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `@text()` | Is a string. Enforces `min`, `max`, and `regex` when specified. |
|
|
82
|
+
| `@uuid()` | Is a string matching the UUID format. |
|
|
83
|
+
| `@email()` | Is a string matching a practical email pattern. |
|
|
84
|
+
| `@int()` | Is a finite integer. Enforces `min` and `max` bounds. |
|
|
85
|
+
| `@decimal()` | Is a finite number. Enforces `min` and `max` bounds. |
|
|
86
|
+
| `@boolean()` | Is a boolean. |
|
|
87
|
+
| `@date()` | Is a `Date` object, ISO string, or numeric timestamp. |
|
|
88
|
+
| `@set()` | Value is one of the declared enum literals. |
|
|
89
|
+
|
|
90
|
+
Required fields (the default) produce a "required" issue when missing or `null`.
|
|
91
|
+
Optional fields (`{ optional: true }`) are silently skipped when absent.
|
|
92
|
+
Unknown fields not declared on the entity are rejected.
|
|
93
|
+
|
|
94
|
+
## Auto-omit behavior
|
|
95
|
+
|
|
96
|
+
`toStandardSchema` automatically excludes:
|
|
97
|
+
|
|
98
|
+
- The `id` primary key — typically server-generated, never part of a form.
|
|
99
|
+
- Relationship navigation properties (`@one`, `@many`) — not form inputs.
|
|
100
|
+
|
|
101
|
+
Pass additional field names in the `omit` option for other server-managed fields like timestamps or `user_id`.
|
|
102
|
+
The `omit` array is type-safe — misspelled field names are caught at compile time.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// Only need to list fields beyond id and relationships
|
|
106
|
+
const schema = toStandardSchema(Note, {
|
|
107
|
+
omit: ['createdAt', 'updatedAt', 'user_id'] as const,
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Complete React example
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { useMemo, useState } from 'react';
|
|
115
|
+
import { toStandardSchema, getFieldConstraints } from '@microsoft/rayfin-core';
|
|
116
|
+
import { Todo } from '../rayfin/data/Todo.js';
|
|
117
|
+
|
|
118
|
+
export function TodoForm({ onSubmit }) {
|
|
119
|
+
const [title, setTitle] = useState('');
|
|
120
|
+
const [error, setError] = useState('');
|
|
121
|
+
|
|
122
|
+
const todoInputSchema = useMemo(
|
|
123
|
+
() => toStandardSchema(Todo, { omit: ['createdAt', 'updatedAt'] as const }),
|
|
124
|
+
[]
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const titleConstraints = getFieldConstraints(Todo, 'title');
|
|
128
|
+
const maxLength =
|
|
129
|
+
titleConstraints?.type === 'string' ? titleConstraints.max : undefined;
|
|
130
|
+
|
|
131
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
const result = todoInputSchema.validate({ title: title.trim() });
|
|
134
|
+
if (result.issues) {
|
|
135
|
+
setError(result.issues[0].message);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
setError('');
|
|
139
|
+
await onSubmit(result.value);
|
|
140
|
+
setTitle('');
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<form onSubmit={handleSubmit}>
|
|
145
|
+
<input value={title} onChange={(e) => setTitle(e.target.value)} />
|
|
146
|
+
{maxLength && <span>{title.length}/{maxLength}</span>}
|
|
147
|
+
{error && <p style={{ color: 'red' }}>{error}</p>}
|
|
148
|
+
<button type="submit">Add</button>
|
|
149
|
+
</form>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Standard Schema interop
|
|
155
|
+
|
|
156
|
+
The object returned by `toStandardSchema` implements `StandardSchemaV1` from `@standard-schema/spec`.
|
|
157
|
+
Any library that reads the `~standard` property can consume it directly.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// TanStack Form, Conform, tRPC v11, etc. read ~standard automatically.
|
|
161
|
+
// You can also access it explicitly if needed:
|
|
162
|
+
const result = todoInputSchema['~standard'].validate(formValues);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The `RayfinStandardSchema` and `StandardSchemaV1` types are re-exported from `@microsoft/rayfin-core` so you do not need a direct dependency on `@standard-schema/spec`.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 5
|
|
3
|
+
title: Create app with CLI
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Project Rayfin is a modern **Backend-as-a-Service (BaaS)** platform that helps teams build and ship applications faster.
|
|
9
|
+
It provides ready-to-use backend infrastructure so you can focus on the product experience.
|
|
10
|
+
|
|
11
|
+
## Create an app from template
|
|
12
|
+
|
|
13
|
+
Run `npm create @microsoft/rayfin@latest` in a terminal window and select welcome template for Typescript.
|
|
14
|
+
|
|
15
|
+
## Run the app
|
|
16
|
+
|
|
17
|
+
1. In a terminal window, run `npx rayfin up` to start the Rayfin backend.
|
|
18
|
+
2. In a second terminal window run `npm run dev` to start the frontend.
|
|
19
|
+
3. When the frontend starts, it will output the page to visit.
|
|
20
|
+
Visit and ensure you can view the Timestamp Tracker.
|
|
21
|
+
4. Click **Send Timestamp** to POST the current time to `/api/graphql/Timestamp`, then use **Refresh list** to pull back the newest 100 entries.
|
|
22
|
+
5. All UI plus data-fetching logic lives in a single file: `src/main.ts`.
|
|
23
|
+
6. To point at a different backend, set `RAYFIN_PUBLIC_API_URL` in `rayfin/.env` and re-run `npm run dev` (defaults to `http://localhost:5168`).
|
|
24
|
+
|
|
25
|
+
## Update the data model
|
|
26
|
+
|
|
27
|
+
Add a `message` field to the **Timestamp** entity in `rayfin/data/Timestamp.ts`.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { entity, authenticated, uuid, text, date } from '@microsoft/rayfin-core';
|
|
31
|
+
|
|
32
|
+
@entity()
|
|
33
|
+
@authenticated('*')
|
|
34
|
+
export class Timestamp {
|
|
35
|
+
@uuid() id!: string;
|
|
36
|
+
@date() timestamp!: Date;
|
|
37
|
+
@text() message!: string;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Update the frontend to display the message
|
|
42
|
+
|
|
43
|
+
In `src/main.ts`, update the creation and query to include the `message` field, add a table header, and display the message in the table rows.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// 1. Update sendTimestamp to include message
|
|
47
|
+
await this.rayfinClient.data.gql.Timestamp.create({
|
|
48
|
+
timestamp: now,
|
|
49
|
+
message: 'Hello from Rayfin!', // Add this
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// 2. Update the query to include 'message'
|
|
53
|
+
const items = await this.rayfinClient.data.gql.Timestamp.select([
|
|
54
|
+
'id',
|
|
55
|
+
'timestamp',
|
|
56
|
+
'message', // Add this
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
// 3. Update the row template in the updateTable function
|
|
60
|
+
const rows = this.timestamps
|
|
61
|
+
.map(
|
|
62
|
+
(entry) => `
|
|
63
|
+
<tr>
|
|
64
|
+
<td class="timestamp-mono">${entry.id}</td>
|
|
65
|
+
<td>${formatDate(entry.timestamp)}</td>
|
|
66
|
+
<td>${entry.message}</td>
|
|
67
|
+
</tr>
|
|
68
|
+
`
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// 4. Update the table headers in the updateTable function
|
|
72
|
+
<thead>
|
|
73
|
+
<tr>
|
|
74
|
+
<th>ID</th>
|
|
75
|
+
<th>Timestamp</th>
|
|
76
|
+
<th>Message</th>
|
|
77
|
+
</tr>
|
|
78
|
+
</thead>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Apply database changes
|
|
82
|
+
|
|
83
|
+
After updating your data models, apply the changes to your database.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npx rayfin up db apply
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Test your changes
|
|
90
|
+
|
|
91
|
+
After updating your data models, test your app.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm run dev
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
> NOTE: Any changes to `rayfin.yml` require you to run `npx rayfin up` again.
|
|
98
|
+
|
|
99
|
+
## View your local database
|
|
100
|
+
|
|
101
|
+
1. Identify your container name or ID for the database service.
|
|
102
|
+
Use this command to list all running containers and note the name or ID of your database container.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
docker ps
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
1. Access the container's shell and use the container name or ID for the database.
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
docker exec -it <container_name_or_id> bash
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
1. Once inside the container's shell, use the appropriate command for your database system.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
psql -U RayfinDB
|
|
118
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
sidebar_position: 4
|
|
3
|
+
title: Create an App Backend
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This guide walks through creating a new Fabric data app directly in the Microsoft Fabric portal.
|
|
7
|
+
|
|
8
|
+
## Prerequisites
|
|
9
|
+
|
|
10
|
+
- A Microsoft account with access to Microsoft Fabric.
|
|
11
|
+
- A Fabric workspace where you have contributor or admin permissions.
|
|
12
|
+
- Fabric data app enabled in your tenant admin settings (see below).
|
|
13
|
+
|
|
14
|
+
## Enable Fabric data app in tenant admin settings
|
|
15
|
+
|
|
16
|
+
A Fabric tenant administrator must enable the Fabric data app workload before users can create Rayfin items.
|
|
17
|
+
If you are not a tenant admin, contact your organization's Fabric administrator to complete this step.
|
|
18
|
+
|
|
19
|
+
1. Sign in to the [Fabric admin portal](https://app.fabric.microsoft.com/admin-portal).
|
|
20
|
+
1. Navigate to **Tenant settings**.
|
|
21
|
+
1. Under **Fabric Apps (preview)**, toggle the setting to **Enabled**.
|
|
22
|
+
1. Choose whether to enable it for the entire organization or specific security groups.
|
|
23
|
+
1. Click **Apply**.
|
|
24
|
+
|
|
25
|
+
Changes may take a few minutes to propagate.
|
|
26
|
+
Once enabled, users in the allowed scope can create Fabric data apps in their workspaces.
|
|
27
|
+
|
|
28
|
+
## Step 1: Sign in to the Fabric portal
|
|
29
|
+
|
|
30
|
+
Open [Microsoft Fabric](https://app.fabric.microsoft.com) in your browser and sign in with your Microsoft account.
|
|
31
|
+
|
|
32
|
+
## Step 2: Select a workspace
|
|
33
|
+
|
|
34
|
+
After signing in, select a workspace from the left navigation panel.
|
|
35
|
+
If you do not have an existing workspace, create one:
|
|
36
|
+
|
|
37
|
+
1. Click **Workspaces** in the left navigation.
|
|
38
|
+
1. Click **New workspace**.
|
|
39
|
+
1. Enter a name for the workspace and select Fabric capacity.
|
|
40
|
+
|
|
41
|
+
## Step 3: Create a new Fabric data app
|
|
42
|
+
|
|
43
|
+
1. In the workspace view, click **New item**.
|
|
44
|
+
1. Search for **Fabric data app** in the item type list or scroll to find it.
|
|
45
|
+
1. Select **Fabric data app** to open the creation dialog.
|
|
46
|
+
1. Enter a name for your Fabric data app (for example, `my-rayfin-app`).
|
|
47
|
+
1. Click **Create**.
|
|
48
|
+
|
|
49
|
+
## Step 4: Open, edit, and deploy your app
|
|
50
|
+
|
|
51
|
+
After creating the Fabric data app, open the project in VS Code and use GitHub Copilot to build your app.
|
|
52
|
+
|
|
53
|
+
1. In the Fabric portal, click **Open in VS Code** on your newly created Fabric data app.
|
|
54
|
+
VS Code opens with the project files loaded.
|
|
55
|
+
1. Use **GitHub Copilot** to make changes to your app.
|
|
56
|
+
For example, ask Copilot to add a new data model, create a UI component, or update your API endpoints.
|
|
57
|
+
1. When you are ready to deploy, run the following command in the VS Code terminal:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx rayfin up
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
You can also use the Command Palette and select **Project Rayfin: Up: Deploy to Fabric**.
|
|
64
|
+
1. Once the deployment completes, Fabric provisions your app and displays the **App URL** in the terminal output.
|
|
65
|
+
1. Click the **App URL** to open your deployed application in the browser and verify your changes.
|
|
66
|
+
|
|
67
|
+
See [Deploy to Microsoft Fabric](../app-backend/deploy.md) to learn more about deployment options.
|
|
68
|
+
|
|
69
|
+
## Next steps
|
|
70
|
+
|
|
71
|
+
- Explore [Data Models & Decorators](../data/overview.md) to define your backend schema.
|
|
72
|
+
- Learn how to connect frontends with the [GraphQL guide](../data/graphql.md).
|
|
73
|
+
- Configure authentication with [Rayfin Auth](../auth/overview.md).
|