--- url: https://docs.tailor.tech/administration.md --- # Administration Platform administration guides for managing workspaces, accounts, and platform resources. ## Account Management * [Account Management](account-management.md) - User accounts, organizations, and role-based access control * [Workspace Management](workspace.md) - Creating and managing workspaces and folders * [IP Restriction](ip-restriction.md) - IP allowlists at the organization, folder, and application levels * [Data Retention](data-retention.md) - Data retention policies and compliance * [Support](support.md) - Getting help and support resources --- --- url: https://docs.tailor.tech/administration/account-management.md --- # Platform Account management The Tailor Platform enables comprehensive account management for admins and developers through the [Console](https://console.tailor.tech). This functionality is key to managing user permissions, roles, organization accounts, folders, and teams, facilitating effective collaboration and resource organization. ![Platform account management](./assets/platform-account-concept.png) The Platform implements a hierarchical structure to organize accounts and manage access: Structure Overview * Organizations * Folders * Workspace * Teams * Members Each level (Organization, Folder, Team) supports role-based access control to help manage permissions efficiently at every layer. To get started, please [contact us](https://www.tailor.tech/demo) to create an Organization. ## Organization Organization admins and editors manage teams and folders, while viewers can develop apps within assigned workspaces. Roles and permissions define access and responsibilities. Every permission is either a **view** or a **manage**. Viewing something is generally granted one role lower than changing it, so a viewer can see how the organization is set up without being able to alter it. The exception is anything that returns a credential — machine users — which stays with admins in both directions. Here's a list of permissions for each role | Permission | Admin | Editor | Viewer | | ----------------------------------- | ----- | ------ | ------ | | View the organization | ✅ | ✅ | ✅ | | Modify the organization | ✅ | 🚫 | 🚫 | | View organization access controls | ✅ | ✅ | ✅ | | Manage organization access controls | ✅ | 🚫 | 🚫 | | View folders and workspaces | ✅ | ✅ | ✅ | | Create folders | ✅ | ✅ | 🚫 | | Modify folders | ✅ | ✅ | 🚫 | | View teams and their members | ✅ | ✅ | ✅ | | Create teams | ✅ | ✅ | 🚫 | | Manage team members | ✅ | ✅ | 🚫 | | View IP restrictions | ✅ | ✅ | ✅ | | Manage IP restrictions | ✅ | 🚫 | 🚫 | | View machine users | ✅ | 🚫 | 🚫 | | Manage machine users | ✅ | 🚫 | 🚫 | Organization roles apply all the way down the hierarchy. An organization editor can act on every folder and workspace in the organization without being granted a role on them individually. ## Folders You can organize workspaces using folders and control team access. As a Folder admin, you can invite team members individually or an entire team with specific roles, ensuring members only interact with relevant resources. Here's a list of permissions for each role | Permission | Admin | Editor | Viewer | | ----------------------------- | ----- | ------ | ------ | | View the folder | ✅ | ✅ | ✅ | | Modify the folder name | ✅ | 🚫 | 🚫 | | View folder access controls | ✅ | ✅ | ✅ | | Manage folder access controls | ✅ | 🚫 | 🚫 | | Manage folders | ✅ | 🚫 | 🚫 | | Manage sub folders | ✅ | ✅ | 🚫 | | View workspaces | ✅ | ✅ | ✅ | | Manage workspace | ✅ | ✅ | 🚫 | | View IP restrictions | ✅ | ✅ | ✅ | | Manage IP restrictions | ✅ | 🚫 | 🚫 | | View machine users | ✅ | 🚫 | 🚫 | | Manage machine users | ✅ | 🚫 | 🚫 | Sub folder creators are granted admin rights only for the subfolder they create Roles are inherited down the folder tree: a role on a folder applies to everything nested inside it. An editor on a parent folder can therefore manage a child folder, including its access controls, even though an editor cannot manage the folder the role was granted on. To create a new folder from the [Console](https://console.tailor.tech), select the organization, click on the '+' sign, select 'Create new folder', enter the folder name, and click 'Submit'. ![Console Create New Folder](./assets/console-create-new-folder.png) To create a new workspace, select the organization, click on the '+' sign and select 'Create new workspace'. ![Console Create New Workspace](./assets/console-create-new-workspace.png) Select the region from the dropdown menu, enter the workspace name, and click 'Submit'. ![Console Create New Workspace Modal](./assets/console-create-new-workspace-modal.png) ## Workspaces A workspace can be shared with people directly, in addition to whatever access they inherit from the organization or the folder above it. Here's a list of permissions for each role | Permission | Admin | Editor | Viewer | | -------------------------------- | ----- | ------ | ------ | | View the workspace | ✅ | ✅ | ✅ | | Modify the workspace | ✅ | ✅ | 🚫 | | Delete the workspace | ✅ | 🚫 | 🚫 | | View workspace access controls | ✅ | ✅ | ✅ | | Manage workspace access controls | ✅ | 🚫 | 🚫 | | View apps and resources | ✅ | ✅ | ✅ | | Create and modify resources | ✅ | ✅ | 🚫 | | Run functions and workflows | ✅ | ✅ | 🚫 | | View the activity log | ✅ | ✅ | 🚫 | | View authentication settings | ✅ | ✅ | 🚫 | | Manage secrets | ✅ | 🚫 | 🚫 | | Delete all records in a type | ✅ | 🚫 | 🚫 | The activity log and authentication settings are the two reads that stop at editor. Both expose how a workspace is accessed rather than what it contains. ## Teams You can manage teams by inviting organization members and assigning roles to the team members. Here's a list of permissions for each role | Permission | Admin | Manager | Member | | ----------------------------- | ----- | ------- | ------ | | View the team and its members | ✅ | ✅ | ✅ | | Modify the team name | ✅ | 🚫 | 🚫 | | Manage team members | ✅ | ✅ | 🚫 | Team members can see their own team regardless of their organization role. To create a team in your organization, first select `Settings`, then select the `Teams` tab. ![Console Create New Workspace Modal](./assets/console-create-new-team.png) --- --- url: https://docs.tailor.tech/administration/data-retention.md --- # Data Retention Tailor Platform automatically removes old data after specific retention periods to maintain system performance and optimize storage. This document outlines the retention periods for different types of data in the platform. ## Retention Periods Logs for the following data types are automatically removed after their respective retention periods: | Data Type | Description | Retention Period | | -------------------------- | --------------------------------------------------------------------- | ---------------- | | Jobs and Attempts | Background tasks and their execution attempts in the Executor service | 30 days | | Executions | Function service execution records | 30 days | | Resolver Execution Results | Results of GraphQL resolver operations | 30 days | | Dataplane Events | System events from the data plane | 3 days | | Controlplane Activity Logs | Platform activity logs from the control plane | 90 days | After these retention periods expire, the data is permanently deleted from the system and cannot be recovered. ## Impact on Applications When building applications on the Tailor Platform, be aware of these retention periods and design your data storage and retrieval strategies accordingly. For data that needs to be retained for longer periods, consider implementing custom archiving solutions or exporting the data to external storage systems before the retention period expires. --- --- url: https://docs.tailor.tech/administration/ip-restriction.md --- # IP Restriction IP restriction lets you define an IP allowlist that controls which client IPs can reach your resources. Requests whose client IP does not match the configured CIDR blocks are rejected at the routing layer, before they reach any application. You can apply IP restriction at three levels, matching the [account hierarchy](account-management) (Organization → Folder → Workspace, with applications running inside workspaces): * **Organization** — applies to every workspace in the organization. * **Folder** — applies to every workspace in a folder. * **Application** — applies to a single application. Organization- and folder-level restrictions are managed through the [Tailor Platform Terraform provider](https://registry.terraform.io/providers/tailor-platform/tailor/latest) (version `>= 2.16.0`). Application-level restriction is configured in the [application manifest](/guides/application). ## How the layers combine When more than one layer is configured, a request must satisfy **all** of them — the layers compose with **AND**. For example, if both an organization-level and a folder-level rule exist, the client IP must match both allowlists to reach a workspace in that folder. A layer with no rule configured imposes no restriction at that level. ## Organization level Use [`tailor_organization_ip_restriction`](https://registry.terraform.io/providers/tailor-platform/tailor/latest/docs/resources/organization_ip_restriction) to apply an allowlist across every workspace in the organization. ```hcl {{ label: "organization_ip_restriction.tf" }} resource "tailor_organization_ip_restriction" "this" { organization_id = "" allowed_ip_addresses = [ "203.0.113.10/32", # a single public IP "198.51.100.0/24", # a public subnet range ] } ``` | Argument | Type | Description | | ---------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `organization_id` | String | The ID of the organization. Changing this forces replacement of the resource. **(required)** | | `allowed_ip_addresses` | List of String | List of allowed IPv4/IPv6 addresses or CIDR blocks. Each entry must be a **public** address; private, loopback, and multicast ranges are rejected. **(required)** | ## Folder level Use [`tailor_organization_folder_ip_restriction`](https://registry.terraform.io/providers/tailor-platform/tailor/latest/docs/resources/organization_folder_ip_restriction) to apply an allowlist to every workspace in a [folder](account-management#folders). This composes with any organization-level rule (AND). ```hcl {{ label: "organization_folder_ip_restriction.tf" }} resource "tailor_organization_folder_ip_restriction" "this" { organization_id = "" folder_id = "" allowed_ip_addresses = [ "203.0.113.10/32", "198.51.100.0/24", ] } ``` | Argument | Type | Description | | ---------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `organization_id` | String | The ID of the organization that owns the folder. Changing this forces replacement of the resource. **(required)** | | `folder_id` | String | The ID of the folder. Changing this forces replacement of the resource. **(required)** | | `allowed_ip_addresses` | List of String | List of allowed IPv4/IPv6 addresses or CIDR blocks. Each entry must be a **public** address; private, loopback, and multicast ranges are rejected. **(required)** | ## Application level To restrict access to a single application, set [`AllowedIPAddresses`](/guides/application) in the application manifest. This applies on top of any organization- and folder-level rules. ## Provider configuration The organization- and folder-level resources require the Tailor Platform Terraform provider: ```hcl {{ label: "provider.tf" }} terraform { required_providers { tailor = { source = "tailor-platform/tailor" version = ">= 2.16.0" } } } provider "tailor" {} ``` --- --- url: https://docs.tailor.tech/administration/support.md --- # Customer Support Tailor provides dedicated customer support to help you with any questions or issues you may encounter while using the Tailor Platform. ## Contact Us For support inquiries, please reach out to our support team via email: **Email:** ## Service Level Agreement (SLA) Our support team is committed to responding to all inquiries within **48 hours**. We strive to provide timely and helpful assistance to ensure your success with the Tailor Platform. --- --- url: https://docs.tailor.tech/administration/workspace.md --- # Workspace Administration A [Workspace](/getting-started/core-concepts/workspace-application#workspace) is the top-level namespace in the Tailor Platform for your organization, containing all applications, including each Tailor Platform service. Since changing workspace settings affects all the applications within the workspace, only [Platform users](#what-is-the-platform-user) have permission to manage workspaces. You can use the interactive mode of `tailor` to view all the options available for workspace management by running the following command. ```bash tailor workspace Commands: workspace app Manage workspace applications workspace create Create a new Tailor Platform workspace. workspace delete Delete a Tailor Platform workspace. workspace get Show detailed information about a workspace workspace list List all Tailor Platform workspaces. workspace restore Restore a deleted workspace workspace user Manage workspace users ``` Platform users with an admin role can create a new workspace, manage workspace users, and delete the workspace. By default, a maximum of 10 workspaces can be created per organization. ## What is the Platform user? The Platform user is the user who can log in to Tailor Platform using the following command: ```bash tailor login ``` When you sign up for an account, we create a Platform user with an admin role for you to manage your workspace. Please note that the [users you add to your application](/tutorials/setup-auth/login/create-user) are not Platform users and therefore cannot manage your workspace.\ To add a new Platform user, you can invite anyone with a Tailor Platform account to your workspace using the following command: ```bash tailor workspace user invite --email $userEmailAddress --role $(admin|editor|viewer) ``` Depending on the role assigned, the Platform user will have different permissions to manage workspaces. ## Platform User Permissions There are three roles for the Platform user: `admin`, `editor` and `viewer`. ### admin The `admin` role can manage all workspace and application settings. ### editor The `editor` role can manage all application settings but cannot manage workspace settings.\ However, `editor` users have read permission for the workspace settings they belong to. ### viewer The `viewer` role can only view all application and workspace settings. ### Here's a list of permissions for each role: | Permission | admin | editor | viewer | | ----------------------------- | ----- | ------ | ------ | | **Workspace** | | | | | Create a workspace | ✅ | | | | Describe a workspace | ✅ | ✅ | ✅ | | Delete a workspace | ✅ | | | | Restore a workspace | ✅ | | | | Invite users to a workspace | ✅ | | | | Remove users from a workspace | ✅ | | | | Update platform user role | ✅ | | | | List workspaces | ✅ | ✅ | ✅ | | List services | ✅ | ✅ | ✅ | | List machine users | ✅ | ✅ | | | List platform users | ✅ | ✅ | ✅ | | Delete services | ✅ | | | | List oauth2 clients | ✅ | ✅ | | ## Deleting and restoring a workspace Platform users with an `admin` role can destroy a workspace using the following command: ```bash tailor workspace delete -w {WORKSPACE_ID} ``` If you need to restore a destroyed workspace, you can do so within 2 weeks of deletion using the following command: ```bash tailor workspace restore -w {WORKSPACE_ID} ``` After 2 weeks, all data associated with the workspace will be permanently removed and cannot be recovered. --- --- url: https://docs.tailor.tech/app-shell/quickstart.md description: Install and set up your first AppShell application --- # Quick Start Get your first AppShell application running in minutes. ## Prerequisites * Node.js 16+ * React 19.2.7+ * A React project (Vite, Next.js, or any bundler) ## Step 1: Install AppShell ```bash # npm npm install @tailor-platform/app-shell # yarn yarn add @tailor-platform/app-shell # pnpm pnpm add @tailor-platform/app-shell ``` ## Step 2: Set Up File-Based Routing (Vite) Add the `appShellRoutes` plugin to your `vite.config.ts`: ```typescript // vite.config.ts import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import tailwindcss from "@tailwindcss/vite"; import { appShellRoutes } from "@tailor-platform/app-shell/vite-plugin"; export default defineConfig({ plugins: [react(), tailwindcss(), appShellRoutes({ entrypoint: "src/App.tsx" })], }); ``` ## Step 3: Create Your First App Add AppShell styles to your global CSS file: ```css /* index.css */ @import "tailwindcss"; @import "@tailor-platform/app-shell/styles"; ``` Create `src/App.tsx`: ```tsx // src/App.tsx import { AppShell, SidebarLayout } from "@tailor-platform/app-shell"; function App() { return ( ); } export default App; ``` Create your first page at `src/pages/page.tsx`: ```tsx // src/pages/page.tsx const HomePage = () => { return (

Welcome to AppShell

); }; export default HomePage; ``` ## Step 4: Run ```bash npm run dev ``` Navigate to `/` - you should see your page with automatic sidebar navigation. ## Add Nested Pages Create pages by adding directories and `page.tsx` files: ``` src/pages/ ├── page.tsx → / ├── dashboard/ │ ├── page.tsx → /dashboard │ └── orders/ │ ├── page.tsx → /dashboard/orders │ └── [id]/ │ └── page.tsx → /dashboard/orders/:id ``` ```tsx // src/pages/dashboard/page.tsx const DashboardPage = () => { return (

Dashboard

); }; export default DashboardPage; ``` ```tsx // src/pages/dashboard/orders/[id]/page.tsx import { useParams } from "@tailor-platform/app-shell"; const OrderDetailPage = () => { const { id } = useParams(); return (

Order #{id}

); }; export default OrderDetailPage; ``` AppShell automatically generates sidebar navigation and breadcrumbs. [Learn more about File-Based Routing →](concepts/file-based-routing) ## Framework-Specific Notes ### Next.js (App Router) Next.js does not support file-based routing with the Vite plugin. Use the module-based approach instead: ```tsx // app/dashboard/[[...props]]/page.tsx "use client"; import { AppShell, SidebarLayout, defineModule } from "@tailor-platform/app-shell"; const dashboardModule = defineModule({ path: "home", component: () =>
Home
, meta: { title: "Home" }, }); export default function Page() { return ( ); } ``` See [Modules & Resources](concepts/modules-and-resources) for the module-based API. ## Next Steps * [File-Based Routing](concepts/file-based-routing) - Define pages via directory structure * [Routing & Navigation](concepts/routing-navigation) - Navigation hooks * [Authentication](concepts/authentication) - Set up user authentication * [Sidebar Navigation](concepts/sidebar-navigation) - Customize sidebar menus * [Styling & Theming](concepts/styling-theming) - Theming and Tailwind CSS configuration * [Modules & Resources](concepts/modules-and-resources) - Legacy module-based routing --- --- url: https://docs.tailor.tech/app-shell/changelog.md --- # @tailor-platform/app-shell ## 1.13.0 ### Minor Changes * 41ae0e3: Add `filter.operators` on DataTable columns to narrow which conditions the built-in filter UI exposes. ```tsx column({ label: "Customer", filter: { field: "customer", type: "string", operators: ["contains", "eq"] }, }); ``` `inferColumns()` now also accepts `filter: { operators: [...] }` so metadata-derived columns can use the same restriction. * fdf7e6a: Bundle Noto Sans JP so `font-medium` is a real weight in Japanese text. Inter carries no CJK glyphs, so Japanese fell through to the system font. On Windows that is Yu Gothic UI, which ships only Light/Semilight/Regular/Semibold/Bold — no 500 — so CSS weight matching resolved `font-weight: 500` down to Regular and `font-medium`, the weight behind most labels, table cells and card titles, was indistinguishable from body copy. Current macOS was unaffected, since it ships Hiragino Sans W5. Bundling a variable font makes the weight scale hold on every platform instead of depending on what the OS installs. `@tailor-platform/app-shell/styles` now ships Noto Sans JP Variable (continuous 100–900 axis) alongside Inter, metric-harmonised against it so mixed Japanese/Latin strings read at one optical size and a line containing Japanese is exactly as tall as one without. No import change is needed. **This changes how Japanese text renders.** Japanese previously drew from the OS font (Hiragino Sans on macOS, Yu Gothic UI on Windows) and now draws from Noto Sans JP. Japanese runs measure about 6% narrower, which can relieve truncation and wrapping but not cause it; Latin is unaffected. Layouts pinned to the old Japanese metrics may need a look. It also adds roughly 4.8 MB of woff2 subsets to your build output even if your app renders no Japanese, and takes the stylesheet from about 98 KB to 200 KB uncompressed (15 KB to 45 KB gzipped). The faces are restricted to Japanese codepoint blocks, so users download only the subsets their content touches — nothing at all for an app with no Japanese, ~910 KB for a typical first Japanese screen — and weight costs nothing extra, since every weight shares one file. To opt out, or to use a brand font, set the new `--app-shell-font-sans` on `:root` after importing the styles: ```css @import "@tailor-platform/app-shell/styles"; :root { --app-shell-font-sans: "Your Brand Sans", ui-sans-serif, system-ui, sans-serif; } ``` Naming no Japanese family opts out of the download entirely, since each face carries a `unicode-range`. A replacement should be a variable font, or otherwise supply real 400/500/600/700 faces — the weight scale assumes all four exist. See [Typography and Fonts](https://github.com/tailor-platform/app-shell/blob/main/docs/concepts/styling-theming.md#typography-and-fonts). * 891a253: Fix the published type declarations, which referenced types they never declared. `dist/app-shell.d.ts` shipped with nine errors inside our own package. Consumers who compile with `skipLibCheck: false` saw all nine attributed to `@tailor-platform/app-shell`, not to their own code. We never noticed because `packages/core/tsconfig.json` sets `skipLibCheck: true`, so neither `pnpm type-check` nor CI ever looked at the declarations we emit. Three defects, all now fixed at the source: * **`PositionProps` was referenced but never declared.** It is the type of the `position` prop on `Menu.Content` and `Tooltip.Content`, but it was tagged `@internal`, so the declaration rollup stripped it while keeping five references to it. It is now **exported from the package root**, which is the additive change that makes this release a minor: consumers can finally name the type they are required to pass. ```tsx import { Menu, type PositionProps } from "@tailor-platform/app-shell"; const dropdown: PositionProps = { side: "bottom", align: "start", sideOffset: 8 }; ; ``` * **`Form` emitted a broken merged declaration** (TS2395). A `function` declaration carrying an expando `displayName` is emitted as a function/namespace merge, and the rollup duplicated the namespace — once exported, once local. `Form` is now a const with an explicit component type, following the same idiom already used by `Select`, `Combobox`, and `Autocomplete`. Its generic is unchanged, so `>` still infers callback values. * **`Layout.Header` was emitted as a type instead of a value** (TS2709). `Layout.Header = Header` emitted `var Header: typeof import("./Layout").Header`, which the rollup rewrote to a bare `Header` — a namespace, not a type. `Layout` now uses the explicit `Object.assign` idiom, like `Grid`. The public runtime API is unchanged: the built bundle exports exactly the same 100 names as before, and `PositionProps` is a type-only export. A `check-dts` gate now runs in CI to keep this from returning. It builds, packs the tarball, installs it into a scratch project, and type-checks every entry point that publishes `types` with `skipLibCheck: false` — the same thing a consumer does. Entry points are read from `package.json`, so new ones are covered as soon as they are added. * 7e1a1e3: Expand the re-exported React Router surface so an app never needs `react-router` as a direct dependency, and add `memory` routing to `AppShell` for tests. AppShell owns the router — it builds the route tree, constructs the router, and renders the `RouterProvider`. An app that also resolves its own copy of `react-router` ends up with two copies in the bundle and two unrelated router contexts: AppShell's navigation keeps working while the app's own `useNavigate` / `useLocation` / `` throw `may be used only in the context of a component`, with nothing for TypeScript to catch. Apps were reaching for a direct dependency because the re-exported surface was incomplete. This closes those gaps. **Newly available from `@tailor-platform/app-shell`:** * `useMatch`, `useResolvedPath` — route matching, for active states and relative paths * `useNavigation` — the in-flight navigation, for pending UI * `NavLink` — a link that knows when it is active * `useBlocker`, `useBeforeUnload` — guard navigation away from unsaved changes * Types: `Location`, `NavigateFunction`, `NavigateOptions`, `To`, `Params`, `PathMatch`, `LinkProps`, `NavLinkProps`, `Navigation`, `Blocker`, `BlockerFunction` **New `@tailor-platform/app-shell/testing` entry point**, so tests need no `react-router` either: * `AppShell` — the same shell, additionally accepting `memory` / `initialEntries` to mount at a fixed URL without touching `window.location`. For page and integration tests. * `TestRouter` — a minimal router context for unit-testing a single component that uses `useNavigate` or renders a ``, without booting the whole shell. Pass `path` when the component reads the route (`useParams`, `useMatch`), so the location matches something. ```tsx import { AppShell, TestRouter } from "@tailor-platform/app-shell/testing"; render( , ); ``` Memory routing is reachable only from `/testing`. The production `AppShell` pins it off, so it holds for JS callers and `any` spreads as well as typed ones. Router construction (`createBrowserRouter`, `RouterProvider`, `MemoryRouter`, `Routes`, `Route`) and the data-router APIs (`useLoaderData`, `useSubmit`, `useFetcher`, `useActionData`) remain deliberately unexported: AppShell owns the former and does not wire up the latter. If something you need is missing, ask for it rather than adding a direct `react-router` dependency. * 719ba91: Add standalone `Textarea` component * New `Textarea` — a styled multi-line text control wrapping Base UI's field control rendered as a `