From f7366982cebbd83a8398d53caa0f7a965a6a36db Mon Sep 17 00:00:00 2001 From: Anukiran Date: Wed, 1 Apr 2026 14:57:53 -0500 Subject: [PATCH] docs update tutorials --- docs/guides/tailordb/versioning.md | 10 +- .../manage-data-schema/create-data-schema.md | 4 +- docs/tutorials/resolver.md | 57 +++++- .../setup-auth/register-identity-provider.md | 165 +++++++++--------- .../setup-executor/event-based-trigger.md | 25 ++- 5 files changed, 157 insertions(+), 104 deletions(-) diff --git a/docs/guides/tailordb/versioning.md b/docs/guides/tailordb/versioning.md index a7c9e1e..5672bf4 100644 --- a/docs/guides/tailordb/versioning.md +++ b/docs/guides/tailordb/versioning.md @@ -11,7 +11,7 @@ This approach preserves historical data and enables change monitoring and analys ## How to enable Data Versioning 1. Create a history table -2. Enable `PublishRecordEvents` settings +2. Enable `publishEvents` feature 3. Add an event based trigger ## Example @@ -51,15 +51,15 @@ db.type("StockSummaryHistory", { }); ``` -### 2. Enable `PublishRecordEvents` settings +### 2. Enable `publishEvents` feature -By enabling `PublishRecordEvents` in the `StockSummary` settings, you can create an event-based trigger that executes on every `StockSummary` record update. +By enabling `publishEvents` in the `StockSummary` features, you can create an event-based trigger that executes on every `StockSummary` record update. ```typescript db.type("StockSummary", { // fields... -}).settings({ - publishRecordEvents: true, +}).features({ + publishEvents: true, }); ``` diff --git a/docs/tutorials/manage-data-schema/create-data-schema.md b/docs/tutorials/manage-data-schema/create-data-schema.md index 9d7462a..c1e6115 100644 --- a/docs/tutorials/manage-data-schema/create-data-schema.md +++ b/docs/tutorials/manage-data-schema/create-data-schema.md @@ -30,7 +30,7 @@ export const task = db.type("Task", { .enum(["todo", "in_progress", "completed", "blocked"]) .description("Current task status"), priority: db.enum(["low", "medium", "high", "urgent"]).description("Task priority level"), - projectId: db.string().foreignKey(project).description("Associated project"), + projectId: db.uuid().relation({ type: "n-1", toward: { type: project } }).description("Associated project"), assigneeId: db.string().optional().description("ID of assigned team member"), dueDate: db.string().optional().description("Task due date"), estimatedHours: db.float().optional().description("Estimated hours to complete"), @@ -45,7 +45,7 @@ export type task = typeof task; - **description**: Optional detailed description - **status**: Enumeration with predefined status values - **priority**: Enumeration for priority levels -- **projectId**: Foreign key relationship to the Project type +- **projectId**: Many-to-one relation to the Project type - **assigneeId**: Optional reference to a team member - **dueDate**: Optional date field - **estimatedHours**: Optional float for time estimation diff --git a/docs/tutorials/resolver.md b/docs/tutorials/resolver.md index 34bccf5..190b464 100644 --- a/docs/tutorials/resolver.md +++ b/docs/tutorials/resolver.md @@ -49,8 +49,8 @@ export const task = db.type("Task", { description: db.string().optional().description("Task description"), status: db.enum(["todo", "in_progress", "completed"]).description("Task status"), priority: db.enum(["low", "medium", "high"]).description("Task priority"), - projectId: db.string().foreignKey(project).description("Associated project"), - assigneeId: db.string().foreignKey(teamMember).optional().description("Assigned team member"), + projectId: db.uuid().relation({ type: "n-1", toward: { type: project } }).description("Associated project"), + assigneeId: db.uuid().relation({ type: "n-1", toward: { type: teamMember } }).optional().description("Assigned team member"), dueDate: db.string().optional().description("Due date"), ...db.fields.timestamps(), }); @@ -153,7 +153,15 @@ export default createResolver({ ## 4. Deploy and Test -Deploy your changes to the workspace: +First, generate Kysely types for type-safe database queries: + +```bash +npm run generate +``` + +This generates TypeScript types and the `getDB()` helper in the `generated/` directory based on your TailorDB schema. + +Then deploy your changes to the workspace: ```bash npm run deploy -- --workspace-id @@ -248,6 +256,49 @@ You can view resolver execution logs in the [Console](https://console.tailor.tec This helps you debug issues and understand how your resolver processes requests. +## Advanced: Triggering Executors from Resolvers + +You can configure resolvers to publish events when they execute, allowing executors to trigger automatically after resolver execution. This is useful for post-processing tasks like sending notifications or updating related data. + +```typescript +export default createResolver({ + name: "assignTask", + operation: "mutation", + publishEvents: true, // Enable event publishing + // ... rest of resolver config +}); +``` + +**How it works:** + +- When `publishEvents: true`, the resolver publishes execution events +- Executors can listen for these events using `resolverExecutedTrigger()` +- The SDK **automatically enables** `publishEvents` when an executor references the resolver + +**Example executor that triggers after resolver execution:** + +```typescript +import { createExecutor, resolverExecutedTrigger } from "@tailor-platform/sdk"; +import assignTaskResolver from "../resolver/assign-task"; + +export default createExecutor({ + name: "notify-task-assigned", + trigger: resolverExecutedTrigger({ + resolver: assignTaskResolver, + condition: ({ result, error }) => !error && !!result.taskId, + }), + operation: { + kind: "function", + body: async ({ result }) => { + console.log(`Task ${result.taskId} assigned to ${result.assigneeName}`); + // Send notification logic here + }, + }, +}); +``` + +For more details, see [Executor Service - Resolver Executed Trigger](../sdk/services/executor#resolver-executed-trigger). + ## Next Steps Learn more about resolvers: diff --git a/docs/tutorials/setup-auth/register-identity-provider.md b/docs/tutorials/setup-auth/register-identity-provider.md index 6c6b994..21d2a4d 100644 --- a/docs/tutorials/setup-auth/register-identity-provider.md +++ b/docs/tutorials/setup-auth/register-identity-provider.md @@ -17,10 +17,45 @@ To enable authentication through an identity provider, you need to register it w ### OIDC (OpenID Connect) -Update your `tailor.config.ts` to include the Auth service with OIDC configuration: +First, ensure you have a User type defined in your database schema (e.g., `db/user.ts`): ```typescript -import { defineConfig, t } from "@tailor-platform/sdk"; +import { db } from "@tailor-platform/sdk"; + +export const user = db.type("User", { + email: db.string().unique(), // usernameField must be unique + name: db.string(), + roles: db.array(db.string()).optional(), + ...db.fields.timestamps(), +}); +``` + +Then update your `tailor.config.ts` to include the Auth service with OIDC configuration: + +```typescript +import { defineAuth, defineConfig } from "@tailor-platform/sdk"; +import { user } from "./db/user"; + +const auth = defineAuth("project-management-auth", { + userProfile: { + type: user, + usernameField: "email", + attributes: { + roles: true, + }, + }, + idProvider: { + name: "oidc-provider", + oidc: { + clientId: process.env.OIDC_CLIENT_ID!, + clientSecret: { + vaultName: "my-vault", + secretName: "oidc-client-secret", + }, + providerUrl: process.env.OIDC_PROVIDER_URL!, + }, + }, +}); export default defineConfig({ name: "project-management", @@ -29,30 +64,7 @@ export default defineConfig({ files: ["db/**/*.ts"], }, }, - auth: { - namespace: "project-management-auth", - idpConfigs: [ - { - name: "oidc-provider", - oidc: { - clientId: process.env.OIDC_CLIENT_ID!, - clientSecret: { - vaultName: "my-vault", - secretName: "oidc-client-secret", - }, - providerUrl: process.env.OIDC_PROVIDER_URL!, - }, - }, - ], - userProfileConfig: { - tailordb: { - namespace: "main-db", - type: "User", - usernameField: "email", - attributeFields: ["roles"], - }, - }, - }, + auth, }); ``` @@ -82,21 +94,6 @@ tailor-sdk secret create \ **Vault naming rules:** Only lowercase letters (a-z), numbers (0-9), and hyphens (-). Must start and end with a letter or number, 2-62 characters long. -**User Type Definition:** - -Make sure you have a User type defined in your database schema (e.g., `db/user.ts`): - -```typescript -import { t } from "@tailor-platform/sdk"; - -export const User = t.object({ - id: t.uuid(), - email: t.string().email(), - name: t.string(), - roles: t.array(t.string()).optional(), -}); -``` - ### SAML The Tailor Platform provides a built-in key for signing SAML authentication requests. When request signing is enabled, the platform automatically signs requests sent from the SP to the IdP. The SP metadata, including the public key for signature verification, is available at `https://api.tailor.tech/saml/{workspace_id}/{auth_namespace}/metadata.xml`. @@ -104,7 +101,27 @@ The Tailor Platform provides a built-in key for signing SAML authentication requ Update your `tailor.config.ts` to include SAML configuration: ```typescript -import { defineConfig } from "@tailor-platform/sdk"; +import { defineAuth, defineConfig } from "@tailor-platform/sdk"; +import { user } from "./db/user"; + +const auth = defineAuth("project-management-auth", { + userProfile: { + type: user, + usernameField: "email", + attributes: { + roles: true, + }, + }, + idProvider: { + name: "saml-provider", + saml: { + metadataUrl: process.env.SAML_METADATA_URL!, + // Alternative: use rawMetadata for inline XML + // rawMetadata: `...`, + enableSignRequest: false, // Set to true to enable request signing + }, + }, +}); export default defineConfig({ name: "project-management", @@ -113,28 +130,7 @@ export default defineConfig({ files: ["db/**/*.ts"], }, }, - auth: { - namespace: "project-management-auth", - idpConfigs: [ - { - name: "saml-provider", - saml: { - metadataUrl: process.env.SAML_METADATA_URL!, - // Alternative: use rawMetadata for inline XML - // rawMetadata: `...`, - enableSignRequest: false, // Set to true to enable request signing - }, - }, - ], - userProfileConfig: { - tailordb: { - namespace: "main-db", - type: "User", - usernameField: "email", - attributeFields: ["roles"], - }, - }, - }, + auth, }); ``` @@ -161,7 +157,25 @@ The metadata URL is provided by your Identity Provider (IdP). You can typically For ID Token-based authentication, update your `tailor.config.ts`: ```typescript -import { defineConfig } from "@tailor-platform/sdk"; +import { defineAuth, defineConfig } from "@tailor-platform/sdk"; +import { user } from "./db/user"; + +const auth = defineAuth("project-management-auth", { + userProfile: { + type: user, + usernameField: "email", + attributes: { + roles: true, + }, + }, + idProvider: { + name: "idtoken-provider", + idToken: { + clientId: process.env.ID_TOKEN_CLIENT_ID!, + providerUrl: process.env.ID_TOKEN_PROVIDER_URL!, + }, + }, +}); export default defineConfig({ name: "project-management", @@ -170,26 +184,7 @@ export default defineConfig({ files: ["db/**/*.ts"], }, }, - auth: { - namespace: "project-management-auth", - idpConfigs: [ - { - name: "idtoken-provider", - idToken: { - clientId: process.env.ID_TOKEN_CLIENT_ID!, - providerUrl: process.env.ID_TOKEN_PROVIDER_URL!, - }, - }, - ], - userProfileConfig: { - tailordb: { - namespace: "main-db", - type: "User", - usernameField: "email", - attributeFields: ["roles"], - }, - }, - }, + auth, }); ``` diff --git a/docs/tutorials/setup-executor/event-based-trigger.md b/docs/tutorials/setup-executor/event-based-trigger.md index 342c7d6..de333fb 100644 --- a/docs/tutorials/setup-executor/event-based-trigger.md +++ b/docs/tutorials/setup-executor/event-based-trigger.md @@ -10,7 +10,7 @@ To create an event-based trigger, you'll need to: 1. Configure the Executor service 2. Create the executor with a record updated trigger -3. Enable `PublishRecordEvents` setting on the Project type +3. Enable `publishEvents` feature on the Project type 4. Deploy the changes 5. Verify the trigger @@ -101,9 +101,9 @@ export default createExecutor({ 3. **Database Query**: Uses Kysely to query task completion statistics before sending the notification -### 3. Enable `PublishRecordEvents` Setting +### 3. Enable `publishEvents` Feature -To ensure the executor triggers when Project records are updated, enable `PublishRecordEvents` in your Project type definition. +To ensure the executor triggers when Project records are updated, enable `publishEvents` in your Project type definition. Update your `db/project.ts` file: @@ -122,12 +122,12 @@ export const project = db createdAt: db.string().description("Creation timestamp"), updatedAt: db.string().description("Last update timestamp"), }) - .settings({ - publishRecordEvents: true, + .features({ + publishEvents: true, }); ``` -The `.settings({ publishRecordEvents: true })` configuration enables the platform to publish events when Project records are created, updated, or deleted. Without this setting, the executor trigger will not fire. +The `.features({ publishEvents: true })` configuration enables the platform to publish events when Project records are created, updated, or deleted. Without this feature enabled, the executor trigger will not fire. ### 4. Deploy the Changes @@ -135,7 +135,14 @@ Before deploying, make sure you have: 1. Created a Slack webhook URL (see [Slack Incoming Webhooks](https://api.slack.com/messaging/webhooks)) 2. Replaced `YOUR_WEBHOOK_URL` in the executor code with your actual webhook URL -3. Generated Kysely types: `npm run generate` (if using Kysely type generator) + +Generate Kysely types for type-safe database access: + +```bash +npm run generate +``` + +This generates TypeScript types and the `getDB()` helper in the `generated/` directory. Deploy your application: @@ -143,7 +150,7 @@ Deploy your application: npm run deploy -- --workspace-id ``` -The SDK will deploy both the updated Project type with `publishRecordEvents` enabled and the new executor. +The SDK will deploy both the updated Project type with `publishEvents` enabled and the new executor. ### 5. Verify the Trigger @@ -212,7 +219,7 @@ Clicking `View Attempts` displays details of job execution attempts. The Tailor **Troubleshooting:** - **No notification received**: Verify your Slack webhook URL is correct -- **Executor not triggering**: Ensure `publishRecordEvents: true` is set on the Project type +- **Executor not triggering**: Ensure `publishEvents: true` is set in `.features()` on the Project type - **Error in logs**: Check the executor logs in the Console for detailed error messages ## Next Steps