@docyrus/docyrus 0.0.30 → 0.0.31

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.
Files changed (20) hide show
  1. package/main.js +3 -3
  2. package/main.js.map +1 -1
  3. package/package.json +3 -3
  4. package/resources/pi-agent/skills/docyrus-api-dev/SKILL.md +161 -0
  5. package/resources/pi-agent/skills/docyrus-api-dev/references/api-client.md +349 -0
  6. package/resources/pi-agent/skills/docyrus-api-dev/references/authentication.md +299 -0
  7. package/resources/pi-agent/skills/docyrus-api-dev/references/data-source-query-guide.md +2063 -0
  8. package/resources/pi-agent/skills/docyrus-api-dev/references/formula-design-guide-llm.md +312 -0
  9. package/resources/pi-agent/skills/docyrus-api-dev/references/query-and-formulas.md +592 -0
  10. package/resources/pi-agent/skills/docyrus-app-dev-react/SKILL.md +334 -0
  11. package/resources/pi-agent/skills/docyrus-app-dev-react/references/README.md +28 -0
  12. package/resources/pi-agent/skills/docyrus-app-dev-react/references/api-client-and-auth.md +326 -0
  13. package/resources/pi-agent/skills/docyrus-app-dev-react/references/collections-and-patterns.md +352 -0
  14. package/resources/pi-agent/skills/docyrus-app-dev-react/references/component-selection-guide.md +602 -0
  15. package/resources/pi-agent/skills/docyrus-app-dev-react/references/icon-usage-guide.md +463 -0
  16. package/resources/pi-agent/skills/docyrus-app-dev-react/references/preferred-components-catalog.md +242 -0
  17. package/resources/pi-agent/skills/docyrus-platform/SKILL.md +2 -2
  18. package/resources/pi-agent/skills/docyrus-platform/references/auth-and-multi-tenancy.md +9 -1
  19. package/resources/pi-agent/skills/docyrus-platform/references/developer-tools.md +3 -2
  20. package/resources/pi-agent/extensions/multi-edit.ts +0 -835
@@ -0,0 +1,334 @@
1
+ ---
2
+ name: docyrus-app-dev-react
3
+ description: Build Docyrus React TypeScript web applications end-to-end, combining authentication, API access, generated collections, TanStack Query/Form patterns, and production-grade UI implementation with preferred component libraries. Use when creating or modifying Docyrus-backed apps that use @docyrus/api-client, @docyrus/signin, Docyrus collections, queries, dashboards, forms, tables, layouts, or Docyrus UI components.
4
+ ---
5
+
6
+ # Docyrus App Dev React
7
+
8
+ Build Docyrus React TypeScript applications end-to-end. This skill combines app architecture, authentication, data access, query patterns, and production-grade UI guidance in one place.
9
+
10
+ ## Tech Stack
11
+
12
+ - React 19 + TypeScript + Vite
13
+ - TanStack Router (code-based), TanStack Query (server state), TanStack Form
14
+ - Tailwind CSS v4, shadcn/ui components
15
+ - `@docyrus/api-client` + `@docyrus/signin`
16
+ - Auto-generated collections from OpenAPI spec
17
+ - Preferred UI libraries: shadcn, diceui, animate-ui, docyrus-ui, reui
18
+
19
+ ## When to Use This Skill
20
+
21
+ Use this skill when you are:
22
+
23
+ - Building or modifying a Docyrus-backed React app
24
+ - Setting up authentication with `@docyrus/signin`
25
+ - Fetching or mutating data with generated collections or `@docyrus/api-client`
26
+ - Designing feature UIs such as dashboards, forms, tables, layouts, dialogs, analytics, or detail pages
27
+ - Selecting between shadcn, diceui, animate-ui, docyrus-ui, and reui components
28
+ - Implementing complete feature flows that combine data access and polished UI
29
+
30
+ ## End-to-End Feature Workflow
31
+
32
+ 1. Set up app auth, routing, and query providers.
33
+ 2. Use generated Docyrus collection hooks or the REST client for data access.
34
+ 3. Define `columns`, filters, formulas, child queries, and mutations correctly.
35
+ 4. Check preferred UI components before building anything custom.
36
+ 5. Use Docyrus form and detail patterns for create, edit, and item detail flows.
37
+ 6. Connect UI actions to TanStack Query mutations and invalidate relevant queries.
38
+
39
+ ## Quick Start: App Bootstrap
40
+
41
+ ### Root provider setup
42
+
43
+ ```tsx
44
+ import { DocyrusAuthProvider } from '@docyrus/signin'
45
+
46
+ <DocyrusAuthProvider
47
+ apiUrl={import.meta.env.VITE_API_BASE_URL}
48
+ clientId={import.meta.env.VITE_OAUTH2_CLIENT_ID}
49
+ redirectUri={import.meta.env.VITE_OAUTH2_REDIRECT_URI}
50
+ scopes={['offline_access', 'Read.All', 'DS.ReadWrite.All', 'Users.Read']}
51
+ callbackPath="/auth/callback"
52
+ >
53
+ <QueryClientProvider client={queryClient}>
54
+ <RouterProvider router={router} />
55
+ </QueryClientProvider>
56
+ </DocyrusAuthProvider>
57
+ ```
58
+
59
+ ### Auth gate and current-user access
60
+
61
+ ```tsx
62
+ const { status, user, hasRole, hasPermission } = useDocyrusAuth()
63
+
64
+ if (status === 'loading') return <Spinner />
65
+ if (status === 'unauthenticated') return <SignInButton />
66
+
67
+ // user is auto-fetched from /v1/users/me after authentication
68
+ // hasRole('super_admin') — check role by slug or uid
69
+ // hasPermission('edit', dataSourceId) — check ACL permission on a data source
70
+ ```
71
+
72
+ ### Data fetching with generated collections
73
+
74
+ ```tsx
75
+ const { list } = useBaseProjectCollection()
76
+ const { data: projects } = useQuery({
77
+ queryKey: ['projects'],
78
+ queryFn: () =>
79
+ list({
80
+ columns: ['name', 'status', 'record_owner(firstname,lastname)'],
81
+ filters: { rules: [{ field: 'status', operator: '!=', value: 'archived' }] },
82
+ orderBy: 'created_on DESC',
83
+ limit: 50,
84
+ }),
85
+ })
86
+ ```
87
+
88
+ ## Common Docyrus Asset URL Templates
89
+
90
+ - `User avatar path template`: `https://api.docyrus.app/storage/v1/object/tenant-public/:tenantId/users/:userId/:user.photo`
91
+ - `Tenant logo path template`: `https://api.docyrus.app/storage/v1/object/tenant-public/:tenantId/:tenant.logo`
92
+
93
+ Use these templates when wiring user chips, assignee avatars, comments, activity feeds, app shell branding, workspace switchers, and any `DataGrid` user option payload that needs `avatarUrl`.
94
+
95
+ ## Critical App/Data Rules
96
+
97
+ 1. **Always send `columns`** in `.list()` and `.get()` calls. Without it, only `id` is returned.
98
+ 2. **Collections are React hooks** — call `useBaseProjectCollection()`, `useUsersCollection()`, and similar hooks inside React components.
99
+ 3. **Data source endpoints are dynamic** — they only exist if the data source is defined in the tenant OpenAPI spec.
100
+ 4. **Use `id` for `count` calculations**. Use actual field slugs for `sum`, `avg`, `min`, and `max`.
101
+ 5. **Child query keys must appear in `columns`**.
102
+ 6. **Formula keys must appear in `columns`**.
103
+ 7. **Use `useUsersCollection().getMyInfo()`** for current user profile instead of making a direct profile call.
104
+ 8. **Regenerate collections after schema changes** by rebuilding the tenant OpenAPI spec, downloading the latest `openapi.json`, and re-running the collection generator.
105
+
106
+ ## Critical UI/UX Rules
107
+
108
+ 1. **Always check preferred components first** before creating anything custom.
109
+ 2. **Use `AwesomeCard` for dashboards** unless the user explicitly wants a different card style.
110
+ 3. **Use animate-ui `Sidebar` for app layouts** unless another layout is requested.
111
+ 4. **Prefer Recharts for charts**. shadcn chart primitives are the default wrapper.
112
+ 5. **Use icons in this order**: hugeicons, then fontawesome light, then lucide.
113
+ 6. **Use `AwesomeDialog` for item create forms**.
114
+ - Small/simple forms: `container="sheet"` with `side="right"`
115
+ - Long/complex forms: `container="modal"` or `container="drawer"`
116
+ 7. **Choose detail containers based on item complexity**.
117
+ - Large items: dedicated page
118
+ - Small items: `AwesomeDialog` right sheet
119
+ 8. **All forms must use TanStack Form + the Docyrus form system**. Do not build feature forms with plain HTML forms or React Hook Form directly.
120
+ 9. **Use `EditableRecordDetail` for inline editing** in item detail views.
121
+ 10. **Always enable `trackChanges`** for editable detail and grid experiences.
122
+ 11. **When using Docyrus `DataGrid`, always set the correct `meta.cell` variant for the field type**. Do not reuse a generic text cell for typed Docyrus data.
123
+ 12. **When rendering data source records in tables, cards, or lists, prefer the matching Docyrus value renderer** instead of handwritten display JSX.
124
+ 13. **When editing inline, pass the real `IField` metadata into `EditableRecordDetailField` or `EditableValue`** so Docyrus can dispatch the correct editor and display pair from `field.type`.
125
+ 14. **If a field type has no dedicated `DataGrid` cell variant, keep the grid cell read-only and move editing to a sheet, dialog, or detail page**.
126
+
127
+ ## Default UI Choices
128
+
129
+ | Use Case | Default Component | Library |
130
+ |----------|-------------------|---------|
131
+ | Item create form | `AwesomeDialog` | docyrus |
132
+ | Quick record create | `CreateRecordDialog` | docyrus |
133
+ | Item detail (small) | `AwesomeDialog` sheet right | docyrus |
134
+ | Item detail (large) | Dedicated page | — |
135
+ | Inline editing | `EditableRecordDetail` | docyrus |
136
+ | Dashboard card | `AwesomeCard` | docyrus |
137
+ | Stat dashboards | `AwesomeStats` | docyrus |
138
+ | App navigation | `Sidebar` | animate-ui |
139
+ | Data table | `DataTable` | diceui |
140
+ | Editable grid | `Data Grid` | docyrus |
141
+ | Grid saved views | `DataGridViewSelect` | docyrus |
142
+ | Forms | Docyrus form fields + TanStack Form | docyrus |
143
+ | Charts | shadcn chart + Recharts | shadcn |
144
+ | File upload | File Upload | diceui |
145
+ | Gantt/project scheduling | `Gantt` | docyrus |
146
+ | Resource scheduling | `ResourceSchedulerPanel` | docyrus |
147
+ | Team chat | `TeamChatChannel` | docyrus |
148
+ | AI interface | `DocyrusAgent` | docyrus |
149
+ | Pricing / quoting | `PricingEnginePanel` | docyrus |
150
+ | Analytics / pivot | `PivotGrid` | docyrus |
151
+
152
+ ## Data Source Field Type UI Mapping
153
+
154
+ If you already have Docyrus field metadata, prefer explicit Docyrus field-specific primitives over custom UI glue:
155
+
156
+ - Forms: use the specific `*FormField` for the field type
157
+ - Read-only display: matching value renderer / `DynamicValue`
158
+ - Inline editing: `EditableRecordDetailField` or `EditableValue`
159
+ - Editable grids: `DataGrid` with the matching `meta.cell` variant
160
+
161
+ Use the table below as the default mapping guide.
162
+
163
+ | Field type(s) | `DataGrid` cell variant | Form field | Inline edit | Value renderer | Notes |
164
+ |---------------|-------------------------|------------|-------------|----------------|-------|
165
+ | `field-text` | `short-text` | `TextFormField` | `EditableValue` with `field-text` | `TextValue` | Default single-line text |
166
+ | `field-textarea` | `long-text` | `TextareaFormField` | `EditableValue` with `field-textarea` | `TextValue` | Multi-line content |
167
+ | `field-email` | `email` | `EmailFormField` | `EditableValue` with `field-email` | `EmailValue` | Use for clickable email cells |
168
+ | `field-url` | `url` | `UrlFormField` | `EditableValue` with `field-url` | `UrlValue` | Prefer typed URL rendering over plain text |
169
+ | `field-phone` | `phone` | `PhoneFormField` | `EditableValue` with `field-phone` | `PhoneValue` | Supports phone-specific display and editing |
170
+ | `field-number` | `number` | `NumberFormField` | `EditableValue` with `field-number` | `NumberValue` | Standard numeric input |
171
+ | `field-money` | `currency` | `MoneyFormField` | `EditableValue` with `field-money` | `MoneyValue` | Use money-specific formatting |
172
+ | `field-currency` | `currency-code` | `CurrencyCodeFormField` | `EditableValue` with `field-currency` | `CurrencyCodeValue` | ISO currency codes |
173
+ | `field-duration` | `duration` | `DurationFormField` | `EditableValue` with `field-duration` | `DurationValue` | Duration editing/display |
174
+ | `field-rating` | `rating` | `RatingFormField` | `EditableValue` with `field-rating` | `RatingValue` | Star rating |
175
+ | `field-select` | `select` | `SelectFormField` | `EditableValue` with `field-select` | `SelectValue` | Single select with Docyrus enum options |
176
+ | `field-radioGroup` | `select` | `RadioGroupFormField` | `EditableValue` with `field-radioGroup` | `SelectValue` | In grids, use a select-style cell |
177
+ | `field-enum` | `enum` | `EnumFormField` | `EditableValue` with `field-enum` | `SelectValue` | Backend-driven enum values |
178
+ | `field-status` | `status` | `StatusFormField` | `EditableValue` with `field-status` | `StatusValue` | Preserves status metadata such as description/follow-up |
179
+ | `field-multiSelect` | `multi-select` | `MultiSelectFormField` | `EditableValue` with `field-multiSelect` | `MultiSelectValue` | Multi-badge selection |
180
+ | `field-tagSelect` | `tag-select` | `TagSelectFormField` | `EditableValue` with `field-tagSelect` | `MultiSelectValue` | Colored tag chips |
181
+ | `field-userSelect` | `user` | `UserSelectFormField` | `EditableValue` with `field-userSelect` | `UserValue` | Populate `CellUserOption.avatarUrl` using the user avatar template |
182
+ | `field-userMultiSelect` | `user-multi-select` | `UserMultiSelectFormField` | `EditableValue` with `field-userMultiSelect` | `UserMultiValue` | Use the avatar template for each selected user |
183
+ | `field-relation` | `relation` | `RelationFormField` | `EditableValue` with `field-relation` | `RelationValue` | Prefer Docyrus relation lookup behavior |
184
+ | `field-date` | `date` | `DateFormField` | `EditableValue` with `field-date` | `DateValue` | Date-only |
185
+ | `field-dateTime` | `datetime` | `DateTimeFormField` | `EditableValue` with `field-dateTime` | `DateTimeValue` | Date + time |
186
+ | `field-time` | `time` | `TimeFormField` | `EditableValue` with `field-time` | `TimeValue` | Time-only |
187
+ | `field-dateRange` | `date-range` | `DateRangeFormField` | `EditableValue` with `field-dateRange` | `DateRangeValue` | Start/end pairs |
188
+ | `field-checkbox` | `checkbox` | `CheckboxFormField` | `EditableValue` with `field-checkbox` | `CheckboxValue` | Boolean checkbox |
189
+ | `field-switch` | `switch` | `SwitchFormField` | `EditableValue` with `field-switch` | `SwitchValue` | Boolean toggle |
190
+ | `field-color` | `color` | `ColorFormField` | `EditableValue` with `field-color` | `ColorValue` | Use the swatch-aware UI |
191
+ | `field-icon` | `icon` | `IconFormField` | `EditableValue` with `field-icon` | `IconValue` | Keep icon selection/rendering typed |
192
+ | `field-file` | `file` | `FileFormField` | `EditableValue` with `field-file` when inline file editing is acceptable | `FileValue` | Grid editing is fine only when upload UX fits the workflow |
193
+ | `field-image` | `image` | `ImageFormField` | `EditableValue` with `field-image` when inline image editing is acceptable | `ImageValue` | Prefer preview-aware image handling |
194
+ | `field-locationSelect` | `—` | `LocationSelectFormField` | `EditableValue` with `field-locationSelect` | `LocationValue` | No dedicated `DataGrid` cell variant in current docs; prefer detail editing |
195
+ | `field-docEditor` | `—` | `DocEditorFormField` | `EditableValue` with `field-docEditor` | `DocEditorValue` | Avoid dense grid editing; use a detail view or sheet |
196
+ | `field-htmlEditor` | `—` | `HtmlEditorFormField` | `EditableValue` with `field-htmlEditor` | `RichTextValue` | Prefer detail editing over grid editing |
197
+ | `field-emailEditor` | `—` | `EmailEditorFormField` | `EditableValue` with `field-emailEditor` | `RichTextValue` | Better in a drawer/modal editor |
198
+ | `field-codeEditor` | `long-text` or `—` | `CodeEditorFormField` | `EditableValue` with `field-codeEditor` | `CodeValue` | Prefer a detail editor if syntax-aware editing matters |
199
+ | `field-taskList` | `—` | `TaskListFormField` | `EditableValue` with `field-taskList` | `TaskListValue` | Better in detail surfaces than grids |
200
+ | `field-queryBuilder` | `—` | `QueryBuilderFormField` | `EditableValue` with `field-queryBuilder` | `—` | Use dedicated query-builder UI |
201
+ | `field-dynamic` | `—` | `DynamicConfigFormField` | `EditableValue` with `field-dynamic` | `—` | Specialized config UX |
202
+ | `field-schemaRepeater` | `—` | `SchemaRepeaterFormField` | `EditableValue` with `field-schemaRepeater` | `—` | Repeater editing belongs in a form/detail surface |
203
+ | `field-approvalStatus` | `—` | `ApprovalStatusFormField` | `EditableValue` with `field-approvalStatus` | `ApprovalStatusValue` | No dedicated `DataGrid` cell variant in current docs |
204
+ | `field-inlineData`, `field-inlineForm`, `field-todo` | `—` | `—` | Use `EditableValue` only if the field has a supported dedicated inline experience | `InlineDataValue`, `TodoValue` | Prefer specialized detail UI over grid editing |
205
+ | `field-display`, `field-formula`, `field-relatedField`, `field-button`, `field-identity`, `field-autonumber`, `field-list` | `—` | `—` | Keep read-only by default | `TextValue`, `FormulaValue`, `RelatedFieldValue`, `ButtonValue`, `IdentityValue`, `ListValue` | These are commonly display/virtual/system-driven rather than user-editable |
206
+ | `field-code` | `—` | `—` | Keep read-only or build a custom feature-specific editor intentionally | `TextValue` | Do not force this into a generic grid editor unless the simplification is intentional |
207
+
208
+ ### Field-Type Mapping Notes
209
+
210
+ - `EditableValue` is the low-level inline editor. The important choice is the `field.type` you pass in; Docyrus uses that metadata to choose the correct inline form/display behavior.
211
+ - If a field type does not have a documented `DataGrid` cell variant, do not approximate it with a text cell unless the simplification is intentional and acceptable for the feature.
212
+ - For large rich-content or structured fields, prefer `AwesomeDialog`, dedicated detail pages, or `EditableRecordDetail` instead of dense grid editing.
213
+ - The current shared `FIELD_TYPES` list in the platform is the authoritative source. If UI docs mention a field type not present in the tenant schema/runtime, do not assume it is available.
214
+ - Reference docs:
215
+ - `https://ui.docy.app/docs/web/docyrus/value-renderers/llms.txt`
216
+ - `https://ui.docy.app/docs/web/docyrus/form-fields/llms.txt`
217
+ - `https://ui.docy.app/docs/web/docyrus/editable-value/llms.txt`
218
+ - `https://ui.docy.app/docs/web/docyrus/data-grid/llms.txt`
219
+
220
+ ## Quick UI Patterns
221
+
222
+ ### Item create form
223
+
224
+ ```tsx
225
+ <AwesomeDialog open={open} onOpenChange={setOpen} container="sheet" side="right" size="default">
226
+ <AwesomeDialogHeader title="Create Task" icon="far-plus" />
227
+ <AwesomeDialogBody>
228
+ <form.Field name="title">{(field) => <TextFormField field={field} label="Title" />}</form.Field>
229
+ <form.Field name="status">{(field) => <SelectFormField field={field} label="Status" />}</form.Field>
230
+ </AwesomeDialogBody>
231
+ <AwesomeDialogFooter>
232
+ <Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
233
+ <Button onClick={handleSubmit}>Create</Button>
234
+ </AwesomeDialogFooter>
235
+ </AwesomeDialog>
236
+ ```
237
+
238
+ ### Item detail with inline editing
239
+
240
+ ```tsx
241
+ <AwesomeDialog open={open} onOpenChange={setOpen} container="sheet" side="right" size="lg" fullscreenable>
242
+ <AwesomeDialogHeader
243
+ title="Task Detail"
244
+ description="Review and edit task fields inline"
245
+ headerButtons={<Button variant="outline" size="sm" onClick={switchToFullForm}>Edit All</Button>}
246
+ />
247
+ <AwesomeDialogBody>
248
+ <EditableRecordDetail fields={fields} record={record} onSave={handleSave} trackChanges>
249
+ <EditableRecordDetailField slug="title" />
250
+ <EditableRecordDetailField slug="status" />
251
+ <EditableRecordDetailField slug="assignee" />
252
+ <EditableRecordDetailField slug="due_date" />
253
+ </EditableRecordDetail>
254
+ </AwesomeDialogBody>
255
+ </AwesomeDialog>
256
+ ```
257
+
258
+ ## TanStack Query Pattern
259
+
260
+ ```typescript
261
+ function useProjects(params?: ICollectionListParams) {
262
+ const { list } = useBaseProjectCollection()
263
+ return useQuery({
264
+ queryKey: ['projects', 'list', params],
265
+ queryFn: () => list({ columns: PROJECT_COLUMNS, ...params }),
266
+ })
267
+ }
268
+
269
+ function useCreateProject() {
270
+ const { create } = useBaseProjectCollection()
271
+ const qc = useQueryClient()
272
+ return useMutation({
273
+ mutationFn: (data: Record<string, unknown>) => create(data),
274
+ onSuccess: () => {
275
+ void qc.invalidateQueries({ queryKey: ['projects'] })
276
+ },
277
+ })
278
+ }
279
+ ```
280
+
281
+ ## Collection CRUD Methods
282
+
283
+ ```typescript
284
+ const { list, get, create, update, delete: deleteOne, deleteMany } = useBaseProjectCollection()
285
+
286
+ list(params?: ICollectionListParams)
287
+ get(id, { columns })
288
+ create(data)
289
+ update(id, data)
290
+ deleteOne(id)
291
+ deleteMany({ recordIds })
292
+ ```
293
+
294
+ API endpoint pattern: `/v1/apps/{appSlug}/data-sources/{slug}/items`
295
+
296
+ ## Query Capabilities Summary
297
+
298
+ The `.list()` method supports:
299
+
300
+ - `columns`
301
+ - `filters`
302
+ - `filterKeyword`
303
+ - `orderBy`
304
+ - `limit` and `offset`
305
+ - `fullCount`
306
+ - `calculations`
307
+ - `formulas`
308
+ - `childQueries`
309
+ - `pivot`
310
+ - `expand`
311
+
312
+ ## Component Installation Pattern
313
+
314
+ ```bash
315
+ pnpm dlx shadcn@latest add button
316
+ pnpm dlx shadcn@latest add @diceui/data-table
317
+ pnpm dlx shadcn@latest add @animate-ui/sidebar
318
+ pnpm dlx @docyrus/cli add @docyrus/ui-awesome-card
319
+ pnpm dlx shadcn@latest add @reui/file-upload-default
320
+ ```
321
+
322
+ ## References
323
+
324
+ For deep dives, read:
325
+
326
+ - `references/README.md` — merged reference map for app development and UI design
327
+ - `references/api-client-and-auth.md`
328
+ - `references/collections-and-patterns.md`
329
+ - `../docyrus-api-dev/references/data-source-query-guide.md`
330
+ - `../docyrus-api-dev/references/formula-design-guide-llm.md`
331
+ - `../docyrus-api-dev/references/query-guide.md`
332
+ - `references/preferred-components-catalog.md`
333
+ - `references/component-selection-guide.md`
334
+ - `references/icon-usage-guide.md`
@@ -0,0 +1,28 @@
1
+ # Docyrus App Dev React Reference Map
2
+
3
+ This directory contains the full reference set for `docyrus-app-dev-react`.
4
+
5
+ ## App Development References
6
+
7
+ Read these files for data access, auth, query design, and collection patterns:
8
+
9
+ - `api-client-and-auth.md`
10
+ - `collections-and-patterns.md`
11
+ - `../../docyrus-api-dev/references/data-source-query-guide.md`
12
+ - `../../docyrus-api-dev/references/formula-design-guide-llm.md`
13
+ - `../../docyrus-api-dev/references/query-guide.md`
14
+
15
+ ## UI Design References
16
+
17
+ Read these files for component selection, design patterns, and UI library guidance:
18
+
19
+ - `preferred-components-catalog.md`
20
+ - `component-selection-guide.md`
21
+ - `icon-usage-guide.md`
22
+
23
+ ## How to Use This Skill
24
+
25
+ 1. Start with `../SKILL.md` for the merged operating guidance.
26
+ 2. Use the app-development references when working on auth, queries, collections, routing, and mutations.
27
+ 3. Use the UI-design references when selecting components, designing layouts, or implementing polished feature flows.
28
+ 4. Combine both when building end-to-end Docyrus React features.
@@ -0,0 +1,326 @@
1
+ # @docyrus/api-client & @docyrus/signin Reference
2
+
3
+ ## Table of Contents
4
+
5
+ 1. [RestApiClient](#restapiclient)
6
+ 2. [Authentication with @docyrus/signin](#authentication-with-docyrussignin)
7
+ 3. [Authorization (Roles & Permissions)](#authorization-roles--permissions)
8
+ 4. [API Client Access Pattern](#api-client-access-pattern)
9
+ 5. [Interceptors](#interceptors)
10
+ 6. [Error Handling](#error-handling)
11
+ 7. [Advanced Features](#advanced-features)
12
+
13
+ ---
14
+
15
+ ## RestApiClient
16
+
17
+ Type-safe REST API client from `@docyrus/api-client`.
18
+
19
+ ### HTTP Methods
20
+
21
+ ```typescript
22
+ import { RestApiClient } from '@docyrus/api-client'
23
+
24
+ client.get<T>(endpoint, params?) // GET
25
+ client.post<T>(endpoint, data) // POST
26
+ client.patch<T>(endpoint, data) // PATCH
27
+ client.put(endpoint, data) // PUT
28
+ client.delete(endpoint, data?) // DELETE
29
+ ```
30
+
31
+ ### Typed Responses
32
+
33
+ ```typescript
34
+ interface User { id: string; name: string; email: string }
35
+ const response = await client.get<User[]>('/v1/users')
36
+ ```
37
+
38
+ ### Config Options
39
+
40
+ ```typescript
41
+ interface ApiClientConfig {
42
+ baseURL?: string
43
+ tokenManager?: TokenManager
44
+ headers?: Record<string, string>
45
+ timeout?: number
46
+ fetch?: typeof fetch
47
+ FormData?: typeof FormData
48
+ AbortController?: typeof AbortController
49
+ storage?: Storage
50
+ }
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Authentication with @docyrus/signin
56
+
57
+ Package: `@docyrus/signin` (peer dep: `@docyrus/api-client >= 0.0.10`, `react >= 18`)
58
+
59
+ ### DocyrusAuthProvider Setup
60
+
61
+ Wrap application root:
62
+
63
+ ```tsx
64
+ import { DocyrusAuthProvider } from '@docyrus/signin'
65
+
66
+ <DocyrusAuthProvider
67
+ apiUrl={import.meta.env.VITE_API_BASE_URL}
68
+ clientId={import.meta.env.VITE_OAUTH2_CLIENT_ID}
69
+ redirectUri={import.meta.env.VITE_OAUTH2_REDIRECT_URI}
70
+ scopes={['offline_access', 'Read.All', 'DS.ReadWrite.All', 'Users.Read']}
71
+ callbackPath="/auth/callback"
72
+ >
73
+ <App />
74
+ </DocyrusAuthProvider>
75
+ ```
76
+
77
+ ### Provider Props
78
+
79
+ | Prop | Type | Default | Description |
80
+ |------|------|---------|-------------|
81
+ | `apiUrl` | `string` | `https://alpha-api.docyrus.com` | API base URL |
82
+ | `clientId` | `string` | Built-in default | OAuth2 client ID |
83
+ | `redirectUri` | `string` | `origin + callbackPath` | OAuth2 redirect URI |
84
+ | `scopes` | `string[]` | `['offline_access', 'Read.All', ...]` | OAuth2 scopes |
85
+ | `callbackPath` | `string` | `/auth/callback` | OAuth callback route |
86
+ | `forceMode` | `'standalone' \| 'iframe'` | Auto-detected | Force auth mode |
87
+ | `storageKeyPrefix` | `string` | `docyrus_oauth2_` | localStorage prefix |
88
+ | `allowedHostOrigins` | `string[]` | `undefined` | Extra trusted iframe origins |
89
+
90
+ ### Auth Modes
91
+
92
+ - **Standalone**: OAuth2 Authorization Code + PKCE via page redirect. Tokens stored in localStorage, auto-refreshed.
93
+ - **Iframe**: Receives tokens via `window.postMessage` from `*.docyrus.app` hosts. Requests refresh from host when expired.
94
+
95
+ ### useDocyrusAuth() Hook
96
+
97
+ ```typescript
98
+ const {
99
+ status, // 'loading' | 'authenticated' | 'unauthenticated'
100
+ mode, // 'standalone' | 'iframe'
101
+ client, // RestApiClient | null
102
+ tokens, // { accessToken, refreshToken, ... } | null
103
+ user, // DocyrusUser | null — auto-fetched from /v1/users/me
104
+ signIn, // () => void — redirects to Docyrus login
105
+ signOut, // () => void — logout and clear tokens
106
+ hasRole, // (role: string | string[]) => boolean — check role by slug or uid
107
+ hasPermission, // (operation: string, dataSourceId?: string) => boolean — check ACL permission
108
+ refreshUser, // () => Promise<void> — re-fetch user from API
109
+ error, // Error | null
110
+ } = useDocyrusAuth()
111
+ ```
112
+
113
+ ### useDocyrusClient() Hook
114
+
115
+ ```typescript
116
+ const client = useDocyrusClient() // RestApiClient | null
117
+ ```
118
+
119
+ ### SignInButton Component
120
+
121
+ ```tsx
122
+ // Basic
123
+ <SignInButton />
124
+
125
+ // Styled
126
+ <SignInButton className="btn" label="Log in with Docyrus" />
127
+
128
+ // Render prop
129
+ <SignInButton>
130
+ {({ signIn, isLoading }) => (
131
+ <button onClick={signIn} disabled={isLoading}>
132
+ {isLoading ? 'Redirecting...' : 'Sign in'}
133
+ </button>
134
+ )}
135
+ </SignInButton>
136
+ ```
137
+
138
+ ### Environment Variables (.env)
139
+
140
+ ```bash
141
+ VITE_API_BASE_URL=https://localhost:3366
142
+ VITE_OAUTH2_CLIENT_ID=your-client-id
143
+ VITE_OAUTH2_REDIRECT_URI=http://localhost:3000/auth/callback
144
+ VITE_OAUTH2_SCOPES=openid profile offline_access Users.Read DS.ReadWrite.All
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Authorization (Roles & Permissions)
150
+
151
+ The provider auto-fetches the current user from `/v1/users/me` after authentication. The `user`, `hasRole`, and `hasPermission` are available on the `useDocyrusAuth()` hook.
152
+
153
+ ### Role-Based UI Gating
154
+
155
+ ```tsx
156
+ function Dashboard({ dataSourceId }: { dataSourceId: string }) {
157
+ const { user, hasRole, hasPermission } = useDocyrusAuth()
158
+
159
+ if (!user) return <Spinner />
160
+
161
+ const canEdit = hasPermission('edit', dataSourceId)
162
+ const canDelete = hasPermission('delete', dataSourceId)
163
+ const isAdmin = hasRole('super_admin')
164
+
165
+ return (
166
+ <div>
167
+ {canEdit && <Button>Edit</Button>}
168
+ {canDelete && <Button variant="destructive">Delete</Button>}
169
+ {isAdmin && <AdminPanel />}
170
+ </div>
171
+ )
172
+ }
173
+ ```
174
+
175
+ ### Permission Resolution Order
176
+
177
+ 1. `super_admin` role → always granted
178
+ 2. `global_editor` role → granted for: view, create, edit, delete, create_bulk, export, import, print
179
+ 3. `global_viewer` role → granted only for: view
180
+ 4. Always-permitted system data sources (reports, todos, notes, etc.)
181
+ 5. User's `aclRules` array (merged from all roles by the server)
182
+
183
+ ### Pure Functions (No React)
184
+
185
+ ```typescript
186
+ import { hasRole, hasPermission } from '@docyrus/signin/core'
187
+ import type { DocyrusUser } from '@docyrus/signin/core'
188
+
189
+ hasRole(user, 'super_admin')
190
+ hasPermission(user, 'edit', 'some-ds-id')
191
+ ```
192
+
193
+ ---
194
+
195
+ ## API Client Access Pattern
196
+
197
+ Generated collections are React hooks that use `useDocyrusClient()` internally to get the authenticated `RestApiClient` from `DocyrusAuthProvider`. No manual client syncing is needed.
198
+
199
+ ```typescript
200
+ // Collections get the client automatically via useDocyrusClient()
201
+ function useBaseProjectCollection() {
202
+ const client = useDocyrusClient()
203
+ return {
204
+ list: (params?) => client!.get('/v1/apps/base/data-sources/project/items', params),
205
+ // ... other CRUD methods
206
+ }
207
+ }
208
+
209
+ // In your component — just call the collection hook
210
+ function ProjectList() {
211
+ const { list } = useBaseProjectCollection()
212
+ const { data } = useQuery({
213
+ queryKey: ['projects'],
214
+ queryFn: () => list({ columns: ['name', 'status'] }),
215
+ })
216
+ }
217
+ ```
218
+
219
+ For direct API access outside collections, use the `useDocyrusClient()` hook:
220
+
221
+ ```typescript
222
+ const client = useDocyrusClient()
223
+ const data = await client!.get<MyType>('/v1/custom-endpoint')
224
+ ```
225
+
226
+ ---
227
+
228
+ ## Interceptors
229
+
230
+ Add request/response interceptors via `client.use()`:
231
+
232
+ ```typescript
233
+ client.use({
234
+ request: (config) => {
235
+ // Transform columns array to comma-separated string
236
+ if (config.params?.columns && Array.isArray(config.params.columns)) {
237
+ config.params.columns = config.params.columns.join(',')
238
+ }
239
+ return config
240
+ },
241
+ response: (response) => {
242
+ // Unwrap nested .data property
243
+ if (response.data?.data && !Array.isArray(response.data)) {
244
+ response.data = response.data.data
245
+ }
246
+ return response
247
+ },
248
+ error: (error, request, response) => {
249
+ if (error.status === 401) { /* handle auth error */ }
250
+ return { error, request, response }
251
+ },
252
+ })
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Error Handling
258
+
259
+ ```typescript
260
+ import {
261
+ ApiError, NetworkError, TimeoutError,
262
+ AuthenticationError, AuthorizationError,
263
+ NotFoundError, RateLimitError, ValidationError,
264
+ OAuth2Error, InvalidGrantError,
265
+ } from '@docyrus/api-client'
266
+
267
+ try {
268
+ await client.get('/resource')
269
+ } catch (error) {
270
+ if (error instanceof AuthenticationError) { /* 401 */ }
271
+ else if (error instanceof AuthorizationError) { /* 403 */ }
272
+ else if (error instanceof NotFoundError) { /* 404 */ }
273
+ else if (error instanceof RateLimitError) { /* 429 - error.retryAfter */ }
274
+ else if (error instanceof NetworkError) { /* network issue */ }
275
+ else if (error instanceof TimeoutError) { /* timeout */ }
276
+ }
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Advanced Features
282
+
283
+ ### SSE (Server-Sent Events)
284
+
285
+ ```typescript
286
+ const eventSource = client.sse('/events', {
287
+ onMessage(data) { console.log(data) },
288
+ onError(error) { console.error(error) },
289
+ onComplete() { console.log('done') },
290
+ })
291
+ eventSource.close()
292
+ ```
293
+
294
+ ### File Upload
295
+
296
+ ```typescript
297
+ const formData = new FormData()
298
+ formData.append('file', fileInput.files[0])
299
+ await client.post('/upload', formData)
300
+ ```
301
+
302
+ ### File Download
303
+
304
+ ```typescript
305
+ const response = await client.get('/download/file.pdf', { responseType: 'blob' })
306
+ const url = URL.createObjectURL(response.data)
307
+ ```
308
+
309
+ ### HTML to PDF
310
+
311
+ ```typescript
312
+ await client.html2pdf({
313
+ html: '<html><body>Content</body></html>',
314
+ options: { format: 'A4', margin: { top: 10, bottom: 10 } },
315
+ })
316
+ ```
317
+
318
+ ### Retry Logic
319
+
320
+ ```typescript
321
+ import { withRetry } from '@docyrus/api-client'
322
+ const response = await withRetry(() => client.get('/endpoint'), {
323
+ retries: 3, retryDelay: 1000,
324
+ retryCondition: (error) => error.status >= 500,
325
+ })
326
+ ```