From 87b028862b3b0244d41d13a9feb9b2f5dbfb776c Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Thu, 10 Sep 2026 17:54:04 -0700 Subject: [PATCH 1/2] feat(gitlab): support non-admin tokens with CSV permissions --- apps/docs/content/docs/search/gitlab.mdx | 147 +- apps/docs/content/docs/search/index.mdx | 2 +- .../static/search/gitlab-csv-uploads.jpg | Bin 0 -> 38529 bytes .../static/search/gitlab-non-admin-setup.jpg | Bin 0 -> 37910 bytes .../api/knowledge/[id]/connectors/route.ts | 1 + .../[connectorType]/provider-detail.tsx | 2 +- .../add-connector-modal.test.tsx | 17 +- .../add-connector-modal.tsx | 76 +- .../connector-access-field.test.tsx | 14 +- .../connector-access-field.tsx | 8 + .../connector-settings-fields.tsx | 116 +- .../use-connector-settings-form.ts | 58 +- apps/sim/connectors/gitlab/gitlab.test.ts | 85 + apps/sim/connectors/gitlab/gitlab.ts | 56 +- apps/sim/connectors/gitlab/meta.ts | 1 + .../gitlab/permission-config/capability.ts | 48 + .../gitlab/permission-config/fields.test.tsx | 193 + .../gitlab/permission-config/fields.tsx | 116 + .../gitlab/permission-config/parser.test.ts | 97 + .../gitlab/permission-config/parser.ts | 123 + .../gitlab/permission-config/prepare.ts | 96 + .../gitlab/permission-config/repository.ts | 201 + .../gitlab/permission-config/types.ts | 62 + .../permission-config/use-permission-form.ts | 96 + apps/sim/connectors/gitlab/permissions.ts | 47 + apps/sim/connectors/types.ts | 6 + apps/sim/hooks/queries/kb/connectors.test.ts | 24 + apps/sim/hooks/queries/kb/connectors.ts | 35 +- .../knowledge/connector-permissions.ts | 14 + .../lib/api/contracts/knowledge/connectors.ts | 10 + .../contracts/knowledge/gitlab-permissions.ts | 35 + .../connector-permissions.integration.ts | 106 + .../gitlab-live.integration.ts | 533 +- .../knowledge/access/connector-permissions.ts | 35 + apps/sim/lib/knowledge/access/predicate.ts | 1 + apps/sim/lib/knowledge/access/scope.test.ts | 5 + apps/sim/lib/knowledge/access/scope.ts | 5 + .../knowledge/application/connector-access.ts | 7 + .../lib/knowledge/application/connectors.ts | 136 +- .../lib/knowledge/connectors/access-modes.ts | 17 + .../connectors/external-group-sync.ts | 4 +- .../connectors/permission-config.server.ts | 59 + .../knowledge/connectors/permission-config.ts | 39 + .../knowledge/connectors/permission-store.ts | 96 + .../knowledge/connectors/permission-tokens.ts | 4 + .../lib/knowledge/connectors/sync-engine.ts | 2 + .../knowledge/connectors/sync-primitives.ts | 12 +- .../lib/knowledge/orchestration/connectors.ts | 65 +- .../migrations/0339_connector_permissions.sql | 21 + .../db/migrations/meta/0339_snapshot.json | 26297 ++++++++++++++++ packages/db/migrations/meta/_journal.json | 7 + packages/db/schema.ts | 46 + 52 files changed, 29102 insertions(+), 181 deletions(-) create mode 100644 apps/docs/public/static/search/gitlab-csv-uploads.jpg create mode 100644 apps/docs/public/static/search/gitlab-non-admin-setup.jpg create mode 100644 apps/sim/connectors/gitlab/permission-config/capability.ts create mode 100644 apps/sim/connectors/gitlab/permission-config/fields.test.tsx create mode 100644 apps/sim/connectors/gitlab/permission-config/fields.tsx create mode 100644 apps/sim/connectors/gitlab/permission-config/parser.test.ts create mode 100644 apps/sim/connectors/gitlab/permission-config/parser.ts create mode 100644 apps/sim/connectors/gitlab/permission-config/prepare.ts create mode 100644 apps/sim/connectors/gitlab/permission-config/repository.ts create mode 100644 apps/sim/connectors/gitlab/permission-config/types.ts create mode 100644 apps/sim/connectors/gitlab/permission-config/use-permission-form.ts create mode 100644 apps/sim/lib/api/contracts/knowledge/connector-permissions.ts create mode 100644 apps/sim/lib/api/contracts/knowledge/gitlab-permissions.ts create mode 100644 apps/sim/lib/knowledge/__integration__/connector-permissions.integration.ts create mode 100644 apps/sim/lib/knowledge/access/connector-permissions.ts create mode 100644 apps/sim/lib/knowledge/connectors/permission-config.server.ts create mode 100644 apps/sim/lib/knowledge/connectors/permission-config.ts create mode 100644 apps/sim/lib/knowledge/connectors/permission-store.ts create mode 100644 apps/sim/lib/knowledge/connectors/permission-tokens.ts create mode 100644 packages/db/migrations/0339_connector_permissions.sql create mode 100644 packages/db/migrations/meta/0339_snapshot.json diff --git a/apps/docs/content/docs/search/gitlab.mdx b/apps/docs/content/docs/search/gitlab.mdx index 45f91816db9..79386df40c3 100644 --- a/apps/docs/content/docs/search/gitlab.mdx +++ b/apps/docs/content/docs/search/gitlab.mdx @@ -1,22 +1,32 @@ --- title: GitLab -description: Index a self-managed GitLab project with its source permissions +description: Connect a self-managed GitLab project with an administrator token or a non-admin token and CSV permissions --- import { Callout } from 'fumadocs-ui/components/callout' import { Step, Steps } from 'fumadocs-ui/components/steps' import { Image } from '@/components/ui/image' -GitLab Search uses an administrator connection to sync a project's content and permissions. Teammates do not connect individual GitLab accounts. They sign in to the Sim organization with a verified email matching their confirmed primary GitLab email. +Connect one GitLab project per source. Choose an **Administrator token** to refresh permissions from GitLab, or a **Non-admin token** with two CSV files to manage access in Sim. Teammates do not connect individual GitLab accounts. -Admin setup uses your organization's **Settings → Sources** page. Teammates do not need a personal GitLab connection. For workspace Search, use **Search → Add source** instead. +Organization admins set up sources in **Settings → Sources**. For workspace Search, use **Search → Add source**. The same token paths are available when adding a GitLab connector to a regular knowledge base. -## Before you start +## Choose a token path -Use a self-managed GitLab instance running version **17.4 or later**. Setup needs both a Sim organization admin and an active GitLab **instance administrator**. A project Maintainer or group Owner is insufficient. +| | Administrator token | Non-admin token | +|---|---|---| +| GitLab identity | Active instance administrator | Dedicated identity that can read the selected project's content; an Auditor identity is supported | +| PAT scopes | `read_api`; also `admin_mode` if Admin Mode is enabled | `read_api`; no `admin_mode` required | +| Permission source | GitLab directory, memberships, and source policy | Uploaded user mapping and project permissions | +| Membership changes | Refreshed from GitLab during background sync | An administrator must replace the CSV files | +| Confidential issues and their comments | Included only for users whose supported GitLab permissions allow access | Excluded | - - This Search path requires GitLab's administrator directory and settings APIs. GitLab.com projects do not support this setup. General knowledge-base GitLab connectors can still use project-readable tokens, but their knowledge-base access rules are different from Search's source permissions. +Use a self-managed GitLab instance reachable by Sim over HTTPS. The administrator path requires GitLab **17.4 or later** and access to administrator directory and settings APIs. A project Maintainer or group Owner is not an instance administrator. + +The CSV path validates the token's identity and access to the selected project without requesting the administrator directory or instance settings. It was tested with an **Auditor** identity on GitLab **19.2.5 Ultimate**, including an identity assigned a custom admin role containing only `read_admin_users`. That custom role is not required by the CSV path: user identities come from the uploaded mapping. + + + CSV files define access in Sim. Each mapped user listed for the selected project can read all of that source's indexed, non-confidential content. Sim does not infer that user's GitLab role or feature restrictions in this path. Include only users who should have that access, and replace the files whenever memberships or email mappings change. ## Add a project @@ -24,69 +34,122 @@ Use a self-managed GitLab instance running version **17.4 or later**. Setup need -### Create the administrator token - -Sign in to your self-managed GitLab instance as an instance administrator, then open **Avatar → Edit profile → Access → Personal access tokens**. On current releases choose **Generate token → Legacy token**; older versions show **Add new token** or the token form directly. - -Official GitLab example of the Access Tokens page with the Add new token button +### Create a personal access token -*Official [GitLab Handbook example](https://handbook.gitlab.com/handbook/security/product-security/security-platforms-architecture/product-security-engineering/runbooks/rotate-service-account-personal-access-tokens/). Navigation and button labels vary by version. The example's existing `api` tokens are unrelated to Sim; use the scopes below.* +Sign in to GitLab as the identity you chose. Open **Avatar → Edit profile → Access → Personal access tokens**, then create a traditional scoped PAT. Navigation labels vary by GitLab version; see GitLab's [token creation instructions](https://docs.gitlab.com/user/profile/personal_access_tokens/#create-a-personal-access-token). -| Token setting | Value for Sim Search | -|---|---| -| Token name | A recognizable name, such as `Sim Search` | -| Expiration date | A date allowed by your instance's token policy | -| Scopes | `read_api`; also `admin_mode` if Admin Mode is enabled | - -Select **Generate token** or **Create personal access token**, then copy the value into Sim. GitLab only shows it once. This connector uses the traditional scoped PAT flow; do not substitute a project/group token or assume a fine-grained token has the required administrator API permissions. See GitLab's [current token creation steps](https://docs.gitlab.com/user/profile/personal_access_tokens/#create-a-personal-access-token). +Give the token a recognizable name, set an expiration date allowed by your instance, and select the scopes in the table above. Copy the value when GitLab displays it. Sim uses read-only GitLab API requests and scheduled sync; no webhook or write scope is needed. -The token must read the project, users, inherited project membership, instance settings, and related group settings. Sim checks these before accepting source permission mirroring. See GitLab's [token scopes](https://docs.gitlab.com/security/tokens/access_token_scopes/). +For the non-admin path, give the identity read access to every content type you select. An Auditor identity can provide instance-wide read access on a licensed instance. A project-scoped service identity can be used when its project permissions are sufficient. See GitLab's [Auditor permissions](https://docs.gitlab.com/user/permissions/#auditor-users) and [token scopes](https://docs.gitlab.com/security/tokens/access_token_scopes/). -### Configure the source in Sim +### Open GitLab setup + +Open **Settings → Sources → Add source**, then select **GitLab**. If GitLab is already listed, open it and select **Add project**. In **Add GitLab project**, choose **Administrator token** or **Non-admin token**. + +Fill in the shared fields. Switching tabs preserves the token, host, project, content choice, and other options. -Open **Settings → Sources → Add source** and select **GitLab**. This opens **Add GitLab project**. Add one project per connection; to add another, open **GitLab** from the Sources list and select **Add project**. Paste the **Personal Access Token**, enter your **Host** and **Project**, and choose the content to index. +Add GitLab project with Administrator token and Non-admin token tabs, without a separate connection-method toggle | Field | What to enter | |---|---| +| Personal Access Token | The PAT created above. | | Host | Your self-managed domain, such as `gitlab.example.com`. | -| Project | `group/project` or the numeric project ID. Use **Add project** for another project. | -| Content | Defaults to **Wiki & Issues**. Choose **Code, Wiki, Issues & Merge Requests** to include all supported types. | -| Branch | Optional branch or tag for repository files; blank uses the project's default branch. | -| Path Filter / File Extensions | Optional limits for repository files. | -| Issue State / Labels / Milestone | Optional filters for issues. | -| Max Items | Optional positive whole-number limit. Leave blank for all matching items. | +| Project | The full `group/project` path or numeric project ID. Each connection crawls one project. | +| Content | **Wiki & Issues** by default. Select **Code, Wiki, Issues & Merge Requests** for all supported types. | + +**More options** contains repository branch, path, and file-extension filters; issue state, label, and milestone filters; **Max Items**; and **Metadata tags**. Leave Max Items blank to index all matching items. Regular KB connectors also expose their sync schedule. + + + + +### Upload permissions for a non-admin token + +The **Non-admin token** tab requires both files. Use **Download template** beside each upload, replace its example rows, then select **Upload CSV**. Files remain in the form until you save; validation errors appear beside the affected upload. + +GitLab user mapping and project permissions uploads with downloadable templates, file limits, and the confidentiality exclusion notice + +**User mapping** maps numeric GitLab user IDs to the verified email addresses those people use in Sim: -**More options** contains the repository and issue filters, **Max Items**, and **Metadata tags**. Unlike member-account sources, GitLab retains this optional item limit. +```csv +user_id,email +123,alice@example.com +456,bob@example.com +``` -Select **Connect & Sync**. Sim validates the token and source policy, then starts indexing. +**Project permissions** lists one project and user ID per grant: + +```csv +project_path,user_id +engineering/platform,123 +engineering/platform,456 +``` + +Use the full namespace path in `project_path`, even if you entered a numeric ID in the Project field. Use GitLab user IDs, not usernames. Include inherited group members when they should have access. Administrators can obtain IDs from GitLab's [members API](https://docs.gitlab.com/api/members/). + +Both files follow these rules: + +- Exactly two columns, in the order shown. Headerless files and the exact template headers are accepted. +- UTF-8 CSV, at most **4 MiB and 100,000 data rows per file**. The total request must also fit Sim's **10 MiB** request limit. +- Identical rows are deduplicated. Conflicting user-ID/email mappings and malformed rows are rejected. +- A project-permission row whose user has no email mapping grants no access. +- Rows for other projects do not grant access to this source or expand its crawl. + +Administrator-token setup does not require CSV uploads. -### Let teammates search +### Connect and verify + +Select **Connect & Sync**. Sim validates the token and configuration, saves the encrypted token and permissions, and starts indexing. -Invite teammates to the Sim organization using their verified work email. Sim matches that email against their confirmed primary GitLab email and applies project, feature, and confidential-issue permissions. Confirmed secondary addresses are not matched. No GitLab **Connect** step is required. +Open the source's **Documents** view to inspect the documents you can read, or **Sync history** to inspect sync outcomes. Have a listed teammate search for a known document, and verify that an unlisted teammate cannot find it. -Admins open **Settings → Sources**, open **GitLab**, then open the source to inspect **Documents**, edit **Settings**, or review **Sync history**. Permission and membership changes are picked up during background refreshes. +Teammates must belong to the owning Sim organization or workspace and have a verified email. The administrator path matches their confirmed primary GitLab email; the CSV path matches the uploaded email. Organization or workspace membership alone does not grant access to source documents. ## What is indexed -The connector supports text repository files, wiki pages, issues, merge requests, and non-internal issue and merge-request comments. It does not index internal comments, binaries, or epics. **Metadata tags** controls optional result metadata. +The connector supports text repository files, wiki pages, issues, merge requests, and their non-internal comments. It does not index internal comments, binaries, or epics. + +With CSV permissions, confidential issues and their comments are always excluded. Sim checks confidentiality during listing and again when fetching an issue. If a previously indexed issue becomes confidential, the next sync removes it from the index. An intentional confidential-issue exclusion does not create a failed sync. + +Content and upstream confidentiality changes follow the source's sync schedule. CSV membership changes follow the replacement behavior below. + +## Update permissions or rotate the token + +Open **Settings → Sources → GitLab**, select the project, and open **Settings**. Regular KBs expose the same fields in their connector settings. + +To update membership, select **Replace CSV** beside either file, then **Save**. You can replace one file while retaining the other. Sim validates the resulting pair before committing anything. Invalid uploads preserve the saved configuration and grants. Settings displays filenames, upload dates, and row counts; it does not return saved CSV contents or the PAT. + +A membership-only replacement takes effect on the next document or search read, without waiting for a crawl or re-embedding documents. Removed users lose access, and newly listed users gain access to existing indexed content. If another admin saved first, reload Settings and apply your changes to the latest revision. + +To rotate the PAT, enter the replacement in **Personal Access Token** and save. Leave it blank to keep the saved token. + +You can also switch token tabs or change the project. CSV mode requires both files; switching to the administrator path requires an administrator token. These changes temporarily block document access while Sim clears the old permissions and resyncs. If interrupted, keep the source active and resume syncing before expecting results. ## Troubleshooting | Problem | Next step | |---|---| -| Administrator token required | Use an active instance administrator's PAT with `read_api`, plus `admin_mode` when required. A project or group token cannot replace it. | -| Source permissions cannot be mirrored | Read the reported policy. Sim rejects unsupported external authorization, IP restrictions, download-ban policies, or session-specific step-up requirements. | -| Project not found | Check the host, project path or ID, and token access. | -| A teammate sees no results | Confirm their verified Sim email matches their confirmed primary GitLab email and the user has the required GitLab project or feature access. | -| Token expired | Remove and add the source again with a new token. This connector does not support replacing its token in place or refreshing PATs automatically. | - -Custom GitLab roles may grant more access than Sim's conservative role mapping recognizes. A source requiring unsupported policies must remain unavailable until its access model can be represented accurately. +| Administrator token required | Use an instance administrator PAT, or select **Non-admin token** and provide both CSV files. | +| Project not found or unreadable | Check Host, Project, token expiration, and the identity's access to the selected project and content types. | +| CSV validation error | Correct the reported row, column order, user ID, email, quoting, or conflicting mapping, then upload again. The saved files remain in effect. | +| Upload or request too large | Keep each file within 4 MiB and 100,000 rows, and the encoded request within 10 MiB. Remove unrelated project rows if needed. | +| A listed teammate sees no results | Check their verified Sim email, current organization/workspace membership, user mapping, and exact project path. Then check whether indexing has completed. | +| A removed teammate still sees results | Save the replacement file and run a new search. Check for another source or KB that independently grants access to the same content. | +| Confidential issue is missing | This is expected with CSV permissions. The administrator path can include it when the supported source permissions allow access. | +| Permissions changed while saving | Reload Settings and save against the latest files; a stale save cannot restore removed grants. | +| Token expired | Enter a new PAT in the source's Settings and save. PATs do not refresh automatically. | +| Source permissions cannot be mirrored | On the administrator path, review the reported GitLab policy. Unsupported external authorization, IP restrictions, download bans, or session-specific requirements remain unavailable. | + +Custom GitLab roles can grant more access than the administrator path's conservative role mapping recognizes. CSV permissions are an explicit administrator-managed grant set, not automatic mirroring of those roles. + +## Self-hosted rollout + +Apply the additive connector-permission migration first, deploy compatible Trigger workers, then deploy the application that exposes the two token paths. Keep this order so a CSV connection cannot be picked up by an older worker. Existing permission-aware connections continue on the administrator path until explicitly changed. diff --git a/apps/docs/content/docs/search/index.mdx b/apps/docs/content/docs/search/index.mdx index f9203ead4e1..eb3925ff674 100644 --- a/apps/docs/content/docs/search/index.mdx +++ b/apps/docs/content/docs/search/index.mdx @@ -69,7 +69,7 @@ Some member sources offer **Sync documents with**, either directly in setup or u | --- | --- | --- | | [Confluence](/search/confluence) | Pages and blog posts | Service account or member accounts; each teammate connects | | [GitHub](/search/github) | Repository text files | App installation or member indexing; each teammate connects | -| [GitLab](/search/gitlab) | Repository files, wikis, issues, merge requests | Self-managed instance administrator token; no member connection | +| [GitLab](/search/gitlab) | Repository files, wikis, issues, merge requests | Self-managed administrator token, or non-admin token with CSV permissions; no member connection | | [Gmail](/search/gmail) | Email thread text | Delegated service account or member accounts | | [Google Calendar](/search/google-calendar) | Meetings | Delegated service account or member accounts | | [Google Drive](/search/google-drive) | Supported Drive files | Delegated service account or member accounts | diff --git a/apps/docs/public/static/search/gitlab-csv-uploads.jpg b/apps/docs/public/static/search/gitlab-csv-uploads.jpg new file mode 100644 index 0000000000000000000000000000000000000000..562476e59d3ec813d6a88f96a66cde39162329a8 GIT binary patch literal 38529 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 literal 0 HcmV?d00001 diff --git a/apps/docs/public/static/search/gitlab-non-admin-setup.jpg b/apps/docs/public/static/search/gitlab-non-admin-setup.jpg new file mode 100644 index 0000000000000000000000000000000000000000..69627564c8a17d2b99145a2b20c8422092f5d9bd GIT binary patch literal 37910 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 { } ) - it.each(SEARCH_SETUP_FIELDS)( + it.each(SEARCH_SETUP_FIELDS.filter(({ connectorType }) => connectorType !== 'gitlab'))( 'keeps $connectorType general knowledge-base fields and sync frequency outside document details', async ({ connectorType, primary, optional, cap }) => { await render({ @@ -814,6 +814,21 @@ describe('Search setup options', () => { } ) + it('uses GitLab service-account access and token tabs without an access selector in regular KBs', async () => { + await render({ + initialConnectorType: 'gitlab', + initialAccessMode: 'workspace', + isSearchIndex: false, + }) + expect(document.body.textContent).toContain('Administrator token') + expect(document.body.textContent).toContain('Non-admin token') + expect(document.body.textContent).not.toContain('Connection method') + expect(button('More options')).toHaveAttribute('aria-expanded', 'false') + expect(document.body.textContent).not.toContain('Sync Frequency') + await act(async () => button('More options').click()) + expect(document.body.textContent).toContain('Sync Frequency') + }) + it('keeps administrator-required fields in the primary form even if metadata marks them optional', async () => { mocks.credentials = [{ id: 'service', name: 'Indexing account', type: 'service_account' }] await render({ initialConnectorType: 'google_drive', initialAccessMode: 'admin' }) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx index 12162fd88c7..b112a3640f1 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx @@ -21,6 +21,7 @@ import { ArrowLeft, ChevronDown, ChevronRight, Plus, Search } from '@sim/emcn/ic import type { ConnectorData } from '@/lib/api/contracts/knowledge/connectors' import { type ResourceScope, resourceScopeFields } from '@/lib/core/resource-scope' import { getIntegrationsForCredentialProvider } from '@/lib/integrations/credential-display' +import { initialConnectorAccessMode } from '@/lib/knowledge/connectors/access-modes' import { getCanonicalScopesForProvider, getProviderIdFromServiceId, @@ -62,6 +63,11 @@ import { import { SettingsResourceRow } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' import { withBrandIcon } from '@/blocks/brand-icon' import { getConnectorApiKeyConfig, isConnectorCredentialTypeAllowed } from '@/connectors/auth' +import { + GitLabPermissionTabs, + GitLabPermissionUploads, +} from '@/connectors/gitlab/permission-config/fields' +import { useGitLabPermissionForm } from '@/connectors/gitlab/permission-config/use-permission-form' import { CONNECTOR_META_REGISTRY } from '@/connectors/registry' import type { ConnectorConfigField, ConnectorMeta } from '@/connectors/types' import { useCreateConnector } from '@/hooks/queries/kb/connectors' @@ -134,14 +140,16 @@ export function AddConnectorModal({ draft?.contentCredentialId ?? null ) const [access, setAccess] = useState(() => ({ - accessMode: + accessMode: initialConnectorAccessMode( + initialType ? CONNECTOR_META_REGISTRY[initialType] : undefined, lockedAccessMode ?? - (lockConnectorType ? initialAccessMode : draft?.accessMode) ?? - (isSearchIndex && initialAccessMode === 'workspace' - ? initialType && CONNECTOR_META_REGISTRY[initialType]?.auth.mode === 'apiKey' - ? 'admin' - : 'members' - : initialAccessMode), + (lockConnectorType ? initialAccessMode : draft?.accessMode) ?? + (isSearchIndex && initialAccessMode === 'workspace' + ? initialType && CONNECTOR_META_REGISTRY[initialType]?.auth.mode === 'apiKey' + ? 'admin' + : 'members' + : initialAccessMode) + ), })) const [disabledTagIds, setDisabledTagIds] = useState>( () => new Set(draft?.disabledTagIds) @@ -154,6 +162,7 @@ export function AddConnectorModal({ ) const [showGitHubInstallationModal, setShowGitHubInstallationModal] = useState(false) + const gitlabPermissions = useGitLabPermissionForm() const [apiKeyValue, setApiKeyValue] = useState('') const [useApiKey, setUseApiKey] = useState(!isSearchIndex) const [apiKeyFocused, setApiKeyFocused] = useState(false) @@ -182,6 +191,7 @@ export function AddConnectorModal({ ? getSearchConnectionLabels(selectedType, access.accessMode) : undefined const modalTitle = searchLabels?.title ?? `Configure ${connectorConfig?.name}` + const showGitLabPermissions = selectedType === 'gitlab' && access.accessMode === 'admin' const isMembersMode = access.accessMode === 'members' const apiKeyConfig = connectorConfig ? getConnectorApiKeyConfig(connectorConfig.auth) : undefined const isApiKeyMode = @@ -347,7 +357,7 @@ export function AddConnectorModal({ } const isOptionalSetupField = (field: ConnectorConfigField) => - isSearchIndex && + (isSearchIndex || connectorConfig?.supportedAccessModes?.length === 1) && field.setupGroup === 'options' && Boolean(connectorConfig && !isConnectorFieldRequired(field, connectorConfig, access.accessMode)) const hasOptionalSetupFields = connectorConfig?.configFields.some( @@ -433,24 +443,32 @@ export function AddConnectorModal({ const closeSetup = (nextOpen: boolean) => { if (!nextOpen && setupDraftKey) useConnectorSetupStore.getState().clearDraft(setupDraftKey) + if (!nextOpen) { + gitlabPermissions.reset() + setApiKeyValue('') + } onOpenChange(nextOpen) } const handleSelectType = (type: string) => { if (setupDraftKey) useConnectorSetupStore.getState().clearDraft(setupDraftKey) + gitlabPermissions.reset() setSelectedType(type) setSourceConfig( isSearchIndex ? { ...CONNECTOR_META_REGISTRY[type]?.searchDefaultSourceConfig } : {} ) setSelectedCredentialId(null) setContentCredentialId(null) - setAccess( - isSearchIndex - ? { - accessMode: CONNECTOR_META_REGISTRY[type]?.auth.mode === 'apiKey' ? 'admin' : 'members', - } - : WORKSPACE_ACCESS - ) + setAccess({ + accessMode: initialConnectorAccessMode( + CONNECTOR_META_REGISTRY[type], + isSearchIndex + ? CONNECTOR_META_REGISTRY[type]?.auth.mode === 'apiKey' + ? 'admin' + : 'members' + : 'workspace' + ), + }) setApiKeyValue('') setUseApiKey(!isSearchIndex) setApiKeyFocused(false) @@ -477,6 +495,7 @@ export function AddConnectorModal({ const canSubmit = Boolean( connectorConfig && hasRequiredCredential && + (!showGitLabPermissions || gitlabPermissions.complete) && hasSearchAccess && (access.accessMode !== 'admin' || allowAdmin) && (!isMembersMode || allowMembers) && @@ -518,6 +537,7 @@ export function AddConnectorModal({ { knowledgeBaseId, connectorType: selectedType, + ...(showGitLabPermissions ? { permissionConfig: gitlabPermissions.input } : {}), accessMode: access.accessMode, ...(isApiKeyMode ? apiKeyValue.trim() @@ -625,6 +645,9 @@ export function AddConnectorModal({ ) : connectorConfig ? ( <> + {showGitLabPermissions && ( + + )} {integrationAvailabilityError && ( )} + {showGitLabPermissions && ( + + )} {(hasOptionalSetupFields || contentCredentialField || @@ -786,7 +812,9 @@ export function AddConnectorModal({ aria-expanded={showMetadata} onClick={() => setShowMetadata((visible) => !visible)} > - {isSearchIndex ? 'More options' : 'Document details (optional)'} + {isSearchIndex || hasOptionalSetupFields + ? 'More options' + : 'Document details (optional)'} {showMetadata && ( @@ -841,15 +869,19 @@ export function AddConnectorModal({ )} - {!isSearchIndex && ( + {!isSearchIndex && (!hasOptionalSetupFields || showMetadata) && ( { expect(onChange).toHaveBeenCalledWith({ accessMode: 'admin' }) }) - it('summarizes a single supported method without a selector', async () => { + it('omits the field when the connector supports only the selected method', async () => { await render({ connectorConfig: gitlabConnectorMeta, value: { accessMode: 'admin' } }) expect(container.querySelector('[role="radiogroup"]')).toBeNull() - expect(container.textContent).toContain('Admin or service account') + expect(container.textContent).toBe('') + }) + + it('keeps pending upgrade actions without restoring the redundant selector', async () => { + await render({ + connectorConfig: gitlabConnectorMeta, + value: { accessMode: 'admin' }, + footer: , + }) + expect(container.querySelector('[role="radiogroup"]')).toBeNull() + expect(container.querySelector('button')?.textContent).toBe('Apply changes') }) it('shows ordinary members a summary without editable or disabled choices', async () => { diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-access-field/connector-access-field.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-access-field/connector-access-field.tsx index 3496cde7065..138b76a8d6e 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-access-field/connector-access-field.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-access-field/connector-access-field.tsx @@ -12,6 +12,7 @@ import { } from '@sim/emcn' import type { ConnectorAccessMode } from '@/lib/api/contracts/knowledge/connectors' import { type ResourceScope, resourceScopeFromOwner } from '@/lib/core/resource-scope' +import { supportsConnectorAccessMode } from '@/lib/knowledge/connectors/access-modes' import { slackSearchSetupHref } from '@/lib/sim-search/setup-navigation' import { connectorMemberProvider } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/connector-access-field/connector-access' import { @@ -135,6 +136,13 @@ export function ConnectorAccessField({ allowed: adminSupported && allowAdmin, }, ] + for (const entry of modes) + entry.allowed &&= supportsConnectorAccessMode(connectorConfig, entry.mode) + if ( + connectorConfig.supportedAccessModes?.length === 1 && + modes.some((entry) => entry.mode === value.accessMode && entry.allowed) + ) + return canAdmin && footer ?
{footer}
: null /** Keep a retired current method visible so an admin can select an available replacement. */ const visibleModes = modes.filter((entry) => entry.allowed || entry.mode === value.accessMode) const currentMode = modes.find((entry) => entry.mode === value.accessMode) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx index ee36b6d49de..665029c9d65 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx @@ -10,7 +10,7 @@ import { ChipModalField, type ComboboxOption, } from '@sim/emcn' -import { Plus } from '@sim/emcn/icons' +import { ChevronDown, ChevronRight, Plus } from '@sim/emcn/icons' import type { ConnectorAccessMode } from '@/lib/api/contracts/knowledge/connectors' import { type ResourceScope, resourceScopeFields } from '@/lib/core/resource-scope' import { @@ -23,6 +23,10 @@ import { ConnectServiceAccountModal, useServiceAccountConnectTarget, } from '@/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal' +import { + derivedAclCapFieldIds, + isConnectorFieldRequired, +} from '@/app/workspace/[workspaceId]/knowledge/[id]/components/connector-access-field/connector-access' import { ConnectorAccessField, type ConnectorAccessSelection, @@ -40,6 +44,11 @@ import type { } from '@/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config-fields' import { SettingsQueryErrorState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' import { isConnectorCredentialTypeAllowed } from '@/connectors/auth' +import { + GitLabPermissionTabs, + GitLabPermissionUploads, +} from '@/connectors/gitlab/permission-config/fields' +import type { GitLabPermissionForm } from '@/connectors/gitlab/permission-config/use-permission-form' import type { ConnectorConfigField, ConnectorMeta } from '@/connectors/types' import { useOAuthCredentials } from '@/hooks/queries/oauth/oauth-credentials' import { useCredentialRefreshTriggers } from '@/hooks/use-credential-refresh-triggers' @@ -53,6 +62,7 @@ const SWITCH_NOTICE: Record = { } export interface ConnectorSettingsFieldsProps { + gitlabPermissions?: GitLabPermissionForm availability: { error: Error | null isFetching: boolean @@ -102,6 +112,7 @@ export interface ConnectorSettingsFieldsProps { } export function ConnectorSettingsFields({ + gitlabPermissions, availability, isSearchIndex, connectorConfig, @@ -163,6 +174,7 @@ export function ConnectorSettingsFields({ serviceIcon: connectorConfig?.icon, }) const [showServiceAccountModal, setShowServiceAccountModal] = useState(false) + const [showMoreOptions, setShowMoreOptions] = useState(false) const isContentCredentialChange = accessDirty && !accessModeChanged const { data: rawCredentials = [], @@ -196,8 +208,44 @@ export function ConnectorSettingsFields({ [rawCredentials, connectorConfig, access.accessMode] ) + const hiddenCapFieldIds = derivedAclCapFieldIds(connectorConfig, access.accessMode) + const isOptionalSetupField = (field: ConnectorConfigField) => + Boolean(gitlabPermissions && connectorConfig) && + field.setupGroup === 'options' && + !isConnectorFieldRequired(field, connectorConfig!, access.accessMode) + const configFieldsProps = connectorConfig + ? { + scope, + accessMode: access.accessMode, + connectorConfig, + sourceConfig, + selectionLabels, + credentialId: selectorCredential?.id ?? null, + credentialType: selectorCredential?.type, + canonicalGroups, + canonicalModes, + onFieldChange, + onToggleCanonicalMode, + disabled: isSaving, + } + : null + return ( <> + {gitlabPermissions && ( + <> + + + + )} {availability.error && ( )} - {connectorConfig && ( + {configFieldsProps && ( + isFieldVisible(field) && + !hiddenCapFieldIds.has(field.id) && + !isOptionalSetupField(field) + } /> )} - {!isSearchIndex && ( + {gitlabPermissions && ( + + )} + + {gitlabPermissions && ( + <> +
+ setShowMoreOptions((visible) => !visible)} + > + More options + +
+ {showMoreOptions && configFieldsProps && ( + + isFieldVisible(field) && + !hiddenCapFieldIds.has(field.id) && + isOptionalSetupField(field) + } + /> + )} + + )} + + {!isSearchIndex && (!gitlabPermissions || showMoreOptions) && ( (null) + const gitlabPermissions = useGitLabPermissionForm( + connector.permissionConfig ?? { + provider: 'gitlab', + mode: 'administrator', + revision: 0, + userMapping: null, + projectPermissions: null, + } + ) + const showGitLabPermissions = + connector.connectorType === 'gitlab' && connector.accessMode === 'admin' /** * Seeds from the stored canonical config. For canonical-pair fields (selector + @@ -295,6 +308,7 @@ export function useConnectorSettingsForm({ ) const hasChanges = + (showGitLabPermissions && gitlabPermissions.dirty) || syncInterval !== connector.syncIntervalMinutes || didCanonicalModesChange(canonicalModes, persistedCanonicalModes) || Object.entries(resolveSourceConfig()).some( @@ -302,11 +316,21 @@ export function useConnectorSettingsForm({ !hiddenCapFieldIds.has(key) && !valuesEqual(connector.sourceConfig[key], value) ) - const handleSave = useCallback(() => { - if (!searchSettingsAllowed || !settingsComplete || accessDirty) return + const handleSave = () => { + if ( + !searchSettingsAllowed || + !settingsComplete || + accessDirty || + (showGitLabPermissions && !gitlabPermissions.complete) + ) + return setError(null) - const updates: { sourceConfig?: Record; syncIntervalMinutes?: number } = {} + const updates: UpdateConnectorBody = {} + if (showGitLabPermissions && gitlabPermissions.dirty) { + updates.permissionConfig = gitlabPermissions.input + if (gitlabPermissions.apiKey.trim()) updates.apiKey = gitlabPermissions.apiKey + } if (syncInterval !== connector.syncIntervalMinutes) { updates.syncIntervalMinutes = syncInterval @@ -340,27 +364,17 @@ export function useConnectorSettingsForm({ updateConnector( { knowledgeBaseId, connectorId: connector.id, updates }, { - onSuccess: onSaved, + onSuccess: (updated) => { + gitlabPermissions.reset(updated.permissionConfig) + onSaved(updated) + }, onError: (err) => { logger.error('Failed to update connector', { error: err.message }) setError(err.message) }, } ) - }, [ - searchSettingsAllowed, - settingsComplete, - accessDirty, - syncInterval, - connector, - resolveSourceConfig, - canonicalModes, - persistedCanonicalModes, - hiddenCapFieldIds, - onSaved, - updateConnector, - knowledgeBaseId, - ]) + } /** * The mode switch is its own admin operation: it rewrites document access @@ -411,6 +425,7 @@ export function useConnectorSettingsForm({ }, [connector]) const fieldsProps: ConnectorSettingsFieldsProps = { + gitlabPermissions: showGitLabPermissions ? gitlabPermissions : undefined, availability: { error: integrationAvailabilityError, isFetching: isIntegrationAvailabilityFetching, @@ -462,7 +477,12 @@ export function useConnectorSettingsForm({ dirty: hasChanges || accessDirty, saving: isSaving, canSave: - hasChanges && !accessDirty && !isSaving && searchSettingsAllowed && Boolean(settingsComplete), + hasChanges && + !accessDirty && + !isSaving && + searchSettingsAllowed && + Boolean(settingsComplete) && + (!showGitLabPermissions || gitlabPermissions.complete), save: handleSave, fieldsProps, } diff --git a/apps/sim/connectors/gitlab/gitlab.test.ts b/apps/sim/connectors/gitlab/gitlab.test.ts index a9076957454..ef81e0057b3 100644 --- a/apps/sim/connectors/gitlab/gitlab.test.ts +++ b/apps/sim/connectors/gitlab/gitlab.test.ts @@ -14,6 +14,7 @@ vi.mock('@/connectors/gitlab/permissions', () => ({ import { gitlabConnector } from '@/connectors/gitlab/gitlab' import { gitlabConnectorMeta } from '@/connectors/gitlab/meta' +import { setGitLabCsvContext } from '@/connectors/gitlab/permission-config/types' import type { ExternalDocument } from '@/connectors/types' import { CONNECTOR_TEXT_DOCUMENT_MAX_BYTES } from '@/connectors/utils' @@ -366,4 +367,88 @@ describe('GitLab connector provider lifecycle', () => { 'merge requests: 403' ) }) + + it('excludes confidential and unknown-status issues before hydration in CSV mode', async () => { + const context = { mirrorsSourceAcls: true } + setGitLabCsvContext(context, { + connectorId: 'csv-connector', + host: 'gitlab.example.com:8443', + projectId: 42, + projectPath: 'group/project', + }) + const listing = await gitlabConnector.listDocuments( + 'pat', + { ...config, contentTypes: 'issues' }, + undefined, + context + ) + expect(listing.documents[0]).toMatchObject({ + title: 'Excluded GitLab issue', + content: '', + acl: [], + skippedExistingDisposition: 'replace', + }) + expect(JSON.stringify(listing.documents[0])).not.toContain('Investigate indexing') + const hydrated = await gitlabConnector.getDocument('pat', config, 'issue:1', context) + expect(hydrated).toMatchObject({ skippedExistingDisposition: 'replace', acl: [], content: '' }) + expect(calls.some((call) => call.url.pathname.endsWith('/notes'))).toBe(false) + }) + + it('revokes an issue that becomes confidential between listing and hydration', async () => { + const context = { mirrorsSourceAcls: true } + setGitLabCsvContext(context, { + connectorId: 'csv-connector', + host: 'gitlab.example.com:8443', + projectId: 42, + projectPath: 'group/project', + }) + issues[0].confidential = false + const listing = await gitlabConnector.listDocuments( + 'pat', + { ...config, contentTypes: 'issues' }, + undefined, + context + ) + expect(listing.documents[0].skippedReason).toBeUndefined() + issues[0].confidential = true + expect(await gitlabConnector.getDocument('pat', config, 'issue:1', context)).toMatchObject({ + skippedExistingDisposition: 'replace', + content: '', + acl: [], + }) + expect(calls.some((call) => call.url.pathname.endsWith('/notes'))).toBe(false) + }) + + it('excludes a newly hidden issue only after confirming the project is still readable', async () => { + const context = { mirrorsSourceAcls: true, projectPath: 'group/project' } + setGitLabCsvContext(context, { + connectorId: 'csv-connector', + host: 'gitlab.example.com:8443', + projectId: 42, + projectPath: 'group/project', + }) + override = ({ url }) => + url.pathname.endsWith('/issues/1') ? new Response(null, { status: 404 }) : undefined + expect(await gitlabConnector.getDocument('pat', config, 'issue:1', context)).toMatchObject({ + skippedExistingDisposition: 'replace', + content: '', + acl: [], + }) + expect(calls.some(({ url }) => url.pathname === PROJECT_PATH)).toBe(true) + override = () => new Response(null, { status: 404 }) + await expect(gitlabConnector.getDocument('pat', config, 'issue:1', context)).rejects.toThrow( + 'Cannot access GitLab project' + ) + }) + + it('does not trust CSV setup supplied through sourceConfig', async () => { + const doc = await gitlabConnector.getDocument( + 'pat', + { ...config, permissionConfig: { mode: 'csv' } }, + 'issue:1', + { mirrorsSourceAcls: true } + ) + expect(doc?.skippedReason).toBeUndefined() + expect(doc?.metadata?.confidential).toBe(true) + }) }) diff --git a/apps/sim/connectors/gitlab/gitlab.ts b/apps/sim/connectors/gitlab/gitlab.ts index 95c794b2a36..6b791d8de97 100644 --- a/apps/sim/connectors/gitlab/gitlab.ts +++ b/apps/sim/connectors/gitlab/gitlab.ts @@ -7,6 +7,11 @@ import { decodeTextBuffer } from '@/lib/file-parsers/utils' import { secureFetchWithRetry } from '@/lib/knowledge/documents/secure-fetch.server' import { VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import { gitlabConnectorMeta } from '@/connectors/gitlab/meta' +import { gitLabPermissionConfig } from '@/connectors/gitlab/permission-config/capability' +import { + getGitLabCsvContext, + setGitLabCsvContext, +} from '@/connectors/gitlab/permission-config/types' import { getGitLabDocumentAcls, openGitLabDirectory, @@ -611,6 +616,9 @@ function workItemToStub( kind: WorkItemKind, syncContext?: Record ): ExternalDocument { + if (kind === 'issue' && getGitLabCsvContext(syncContext) && item.confidential !== false) { + return excludedCsvIssue(item.iid) + } const title = item.title?.trim() || `${kind === 'issue' ? 'Issue #' : 'Merge Request !'}${item.iid}` const resource = kind === 'issue' ? 'issues' : 'merge_requests' @@ -643,6 +651,25 @@ function workItemToStub( } } +/** An authoritative exclusion revokes any older indexed version without retaining private metadata. */ +function excludedCsvIssue(iid: number): ExternalDocument { + return { + ...markSkipped( + { + externalId: `${ISSUE_PREFIX}${iid}`, + title: 'Excluded GitLab issue', + content: '', + contentHash: `gitlab:excluded-issue:${iid}`, + mimeType: 'text/plain', + metadata: { contentType: 'issue' }, + acl: [], + }, + 'Non-admin token connections exclude issues unless GitLab explicitly marks them non-confidential.' + ), + skippedExistingDisposition: 'replace', + } +} + /** Notes share their parent audience only when neither internal nor confidential. */ async function hydrateWorkItem( accessToken: string, @@ -764,6 +791,10 @@ async function resolveProjectPath( } const project = (await response.json()) as GitLabProject + const csv = getGitLabCsvContext(syncContext) + if (csv && (project.id !== csv.projectId || new URL(apiBase).host !== csv.host)) { + throw new Error('GitLab project identity changed. Reconfigure the connection before syncing.') + } const path = project.path_with_namespace ?? '' if (syncContext) { if (path) syncContext.projectPath = path @@ -886,6 +917,7 @@ function applyMaxItemsCap( export const gitlabConnector: ConnectorConfig = { ...gitlabConnectorMeta, + permissionConfig: gitLabPermissionConfig, openDirectory: openGitLabDirectory, getDocumentAcls: getGitLabDocumentAcls, @@ -1230,11 +1262,24 @@ export const gitlabConnector: ConnectorConfig = { maxResponseBytes: MAX_METADATA_RESPONSE_BYTES, }) if (!response.ok) { - if (response.status === 404) return null + if (response.status === 404) { + const csv = getGitLabCsvContext(syncContext) + if (kind === 'issue' && csv) { + /** A fresh project check distinguishes item exclusion from lost project access. */ + const currentContext = {} + setGitLabCsvContext(currentContext, csv) + await resolveProjectPath(currentContext, apiBase, encodedProject, accessToken) + return excludedCsvIssue(iid) + } + return null + } throw new Error(`Failed to fetch GitLab ${kind}: ${response.status}`) } const item = readWorkItem(await response.json()) if (item.iid !== iid) throw new Error('GitLab returned a different issue or merge request') + if (kind === 'issue' && getGitLabCsvContext(syncContext) && item.confidential !== false) { + return excludedCsvIssue(iid) + } return hydrateWorkItem(accessToken, apiBase, encodedProject, host, projectPath, item, kind) } @@ -1313,7 +1358,7 @@ export const gitlabConnector: ConnectorConfig = { const choice = getContentTypeChoice(sourceConfig) try { - if (syncContext?.mirrorsSourceAcls === true) { + if (syncContext?.mirrorsSourceAcls === true && !getGitLabCsvContext(syncContext)) { await validateGitLabPermissionToken(accessToken, sourceConfig) } const response = await fetchProject( @@ -1334,6 +1379,13 @@ export const gitlabConnector: ConnectorConfig = { } const projectRecord = (await response.json()) as GitLabProject + const csv = getGitLabCsvContext(syncContext) + if (csv && (projectRecord.id !== csv.projectId || host !== csv.host)) { + return { + valid: false, + error: 'GitLab returned a different project. Reload the connection settings.', + } + } if (activePhases(choice).includes('wiki')) { const accessLevel = projectRecord.wiki_access_level diff --git a/apps/sim/connectors/gitlab/meta.ts b/apps/sim/connectors/gitlab/meta.ts index 9734c76d449..809081a4eec 100644 --- a/apps/sim/connectors/gitlab/meta.ts +++ b/apps/sim/connectors/gitlab/meta.ts @@ -10,6 +10,7 @@ export const gitlabConnectorMeta: ConnectorMeta = { 'Sync repository files, wiki pages, issues, merge requests, and their non-internal comments from a GitLab project', version: '1.3.0', mirrorsSourceAcls: true, + supportedAccessModes: ['admin'], adminSetupHint: 'Use a self-managed GitLab instance administrator token with read_api access (and admin_mode when required). Enter your instance host.', icon: GitLabIcon, diff --git a/apps/sim/connectors/gitlab/permission-config/capability.ts b/apps/sim/connectors/gitlab/permission-config/capability.ts new file mode 100644 index 00000000000..8e469ea538e --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/capability.ts @@ -0,0 +1,48 @@ +import type { ConnectorPermissionConfigCapability } from '@/lib/knowledge/connectors/permission-config' +import { prepareGitLabPermissionChange } from '@/connectors/gitlab/permission-config/prepare' +import { + readGitLabPermissionSummaries, + seedGitLabCsvContext, + writeGitLabPermissions, +} from '@/connectors/gitlab/permission-config/repository' +import { setGitLabCsvContext } from '@/connectors/gitlab/permission-config/types' + +export const gitLabPermissionConfig: ConnectorPermissionConfigCapability = { + async prepare(input) { + const change = await prepareGitLabPermissionChange({ + ...input, + connectorType: 'gitlab', + permissions: input.permissionConfig, + }) + const prepared = change.permissions + if (!prepared) return undefined + return { + requiresAclReset: prepared.rewriteAccess, + requiresContentSync: prepared.rewriteAccess || Boolean(change.encryptedApiKey), + encryptedApiKey: change.encryptedApiKey, + populateSyncContext(context, connectorId) { + if (prepared.snapshot.mode === 'csv') + setGitLabCsvContext(context, { connectorId, ...prepared.snapshot }) + }, + write: (tx, connectorId) => writeGitLabPermissions(tx, connectorId, prepared), + } + }, + async readSummaries(connectorIds) { + const summaries = await readGitLabPermissionSummaries(connectorIds) + return new Map( + connectorIds.map((id) => [ + id, + { + provider: 'gitlab' as const, + ...(summaries.get(id) ?? { + mode: 'administrator' as const, + revision: 0, + userMapping: null, + projectPermissions: null, + }), + }, + ]) + ) + }, + populateSyncContext: seedGitLabCsvContext, +} diff --git a/apps/sim/connectors/gitlab/permission-config/fields.test.tsx b/apps/sim/connectors/gitlab/permission-config/fields.test.tsx new file mode 100644 index 00000000000..e8a18f2d389 --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/fields.test.tsx @@ -0,0 +1,193 @@ +/** @vitest-environment jsdom */ +import { act, type ReactNode, useState } from 'react' +import { ChipModal, ChipModalBody, ChipModalField, ChipModalHeader } from '@sim/emcn' +import { sleep } from '@sim/utils/helpers' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, describe, expect, it, vi } from 'vitest' +import type { + GitLabPermissionData, + GitLabPermissionUploadInput, +} from '@/lib/api/contracts/knowledge/gitlab-permissions' +import { + GitLabPermissionTabs, + GitLabPermissionUploads, +} from '@/connectors/gitlab/permission-config/fields' +import { useGitLabPermissionForm } from '@/connectors/gitlab/permission-config/use-permission-form' + +interface HarnessProps { + saved?: GitLabPermissionData + submit: (input: GitLabPermissionUploadInput) => void +} + +function Harness({ saved, submit }: HarnessProps) { + const form = useGitLabPermissionForm(saved) + const [project, setProject] = useState('group/project') + return ( + {}} srTitle='Configure GitLab'> + Configure GitLab + + + + + + + + + ) +} + +let root: Root +let container: HTMLDivElement +async function render(element: ReactNode) { + container = document.createElement('div') + document.body.append(container) + root = createRoot(container) + await act(async () => { + root.render(element) + }) +} +function button(label: string): HTMLButtonElement { + const found = Array.from(document.querySelectorAll('button')).find( + (node) => node.textContent === label + ) + if (!found) throw new Error(`Missing button: ${label}`) + return found +} +function input(label: string): HTMLInputElement { + const labelled = document.querySelector(`input[aria-label="${label}"]`) + if (labelled) return labelled + const fieldLabel = Array.from(document.querySelectorAll('label')).find( + (node) => node.textContent === label + ) + const node = fieldLabel ? document.getElementById(fieldLabel.htmlFor) : null + if (!(node instanceof HTMLInputElement)) throw new Error(`Missing input: ${label}`) + return node +} +async function click(label: string) { + await act(async () => { + button(label).click() + }) +} +async function change(label: string, value: string) { + await act(async () => { + Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')!.set!.call( + input(label), + value + ) + input(label).dispatchEvent(new Event('input', { bubbles: true })) + }) +} +async function upload(label: string, content: string, filename = 'upload.csv') { + const file = new File([content], filename, { type: 'text/csv' }) + Object.defineProperty(file, 'arrayBuffer', { + value: async () => new TextEncoder().encode(content).buffer, + }) + await act(async () => { + Object.defineProperty(input(label), 'files', { value: [file], configurable: true }) + input(label).dispatchEvent(new Event('change', { bubbles: true })) + }) +} +afterEach(async () => { + if (root) await act(async () => root.unmount()) + container?.remove() + vi.restoreAllMocks() +}) + +describe('GitLab permission setup modal', () => { + it('preserves shared inputs across keyboard tab changes and requires both uploads', async () => { + const submit = vi.fn() + await render() + await change('Personal Access Token', 'fixture-pat') + await change('Project', 'team/docs') + const admin = button('Administrator token') + admin.focus() + await act(async () => { + admin.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true })) + await sleep(1) + }) + expect(button('Non-admin token').getAttribute('aria-checked')).toBe('true') + expect(button('Save').disabled).toBe(true) + await upload('User mapping', 'user_id,email\n1,alice@example.com') + await upload('Project permissions', 'team/docs,1') + expect(button('Save').disabled).toBe(false) + await click('Administrator token') + await click('Non-admin token') + expect(input('Project').value).toBe('team/docs') + expect(input('Personal Access Token').value).toBe('fixture-pat') + await click('Save') + expect(submit).toHaveBeenCalledWith( + expect.objectContaining({ + provider: 'gitlab', + mode: 'csv', + userMapping: expect.objectContaining({ + content: expect.stringContaining('alice@example.com'), + }), + projectPermissions: expect.objectContaining({ content: 'team/docs,1' }), + }) + ) + }) + + it('shows inline validation and supplies both exact CSV templates', async () => { + const templates: string[] = [] + vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(function () { + templates.push(decodeURIComponent(this.href.split(',')[1])) + }) + await render() + await click('Non-admin token') + for (const node of document.querySelectorAll('button')) + if (node.textContent === 'Download template') await act(async () => node.click()) + expect(templates).toEqual([ + 'user_id,email\n123,alice@example.com\n', + 'project_path,user_id\ngroup/project,123\n', + ]) + await upload('User mapping', '1,a@example.com\n1,b@example.com') + expect(document.body.textContent).toContain('conflicts with another identity mapping') + expect(button('Save').disabled).toBe(true) + expect(document.body.textContent).toContain( + 'Confidential issues and their comments are excluded' + ) + }) + + it('replaces one saved file and submits the revision without resending the other file', async () => { + const submit = vi.fn() + await render( + + ) + expect(document.body.textContent).toContain('saved-projects.csv') + await upload('User mapping', '1,new@example.com', 'replacement.csv') + expect(document.body.textContent).toMatch(/replacement.csv.*Ready to save/) + await click('Save') + expect(submit).toHaveBeenCalledWith({ + provider: 'gitlab', + mode: 'csv', + expectedRevision: 7, + userMapping: { filename: 'replacement.csv', content: '1,new@example.com' }, + projectPermissions: undefined, + }) + }) +}) diff --git a/apps/sim/connectors/gitlab/permission-config/fields.tsx b/apps/sim/connectors/gitlab/permission-config/fields.tsx new file mode 100644 index 00000000000..b1a10354872 --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/fields.tsx @@ -0,0 +1,116 @@ +'use client' + +import { useRef } from 'react' +import { Chip, ChipModalField, ChipModalTabs } from '@sim/emcn' +import type { GitLabCsvKind } from '@/connectors/gitlab/permission-config/types' +import type { GitLabPermissionForm } from '@/connectors/gitlab/permission-config/use-permission-form' + +const TABS = [ + { value: 'administrator', label: 'Administrator token' }, + { value: 'csv', label: 'Non-admin token' }, +] as const +const FILES = { + userMapping: { + title: 'User mapping', + filename: 'gitlab-users.csv', + template: 'user_id,email\n123,alice@example.com\n', + }, + projectPermissions: { + title: 'Project permissions', + filename: 'gitlab-project-permissions.csv', + template: 'project_path,user_id\ngroup/project,123\n', + }, +} as const + +interface GitLabPermissionFieldsProps { + form: GitLabPermissionForm + disabled?: boolean +} + +export function GitLabPermissionTabs({ form, disabled }: GitLabPermissionFieldsProps) { + return ( +
+ { + if (!disabled && (value === 'administrator' || value === 'csv')) form.setMode(value) + }} + /> +
+ ) +} + +export function GitLabPermissionUploads({ form, disabled }: GitLabPermissionFieldsProps) { + if (form.mode !== 'csv') return null + return ( + <> +

+ These CSVs control access to this project in Sim. Replace them when memberships change. + Confidential issues and their comments are excluded. +

+ {(['userMapping', 'projectPermissions'] as const).map((kind) => ( + + ))} + + ) +} + +interface GitLabCsvFileProps extends GitLabPermissionFieldsProps { + kind: GitLabCsvKind +} + +function GitLabCsvFile({ kind, form, disabled }: GitLabCsvFileProps) { + const inputRef = useRef(null) + const definition = FILES[kind] + const selected = form.files[kind] + const saved = form.saved?.[kind] + const filename = selected?.upload?.filename ?? saved?.filename + const count = selected?.rowCount ?? saved?.rowCount + const downloadTemplate = () => { + const link = document.createElement('a') + link.href = `data:text/csv;charset=utf-8,${encodeURIComponent(definition.template)}` + link.download = definition.filename + link.click() + } + return ( + + {(aria) => ( +
+ { + const file = event.target.files?.[0] + event.target.value = '' + if (file) void form.selectFile(kind, file) + }} + /> + inputRef.current?.click()} + > + {selected?.loading ? 'Validating…' : filename ? 'Replace CSV' : 'Upload CSV'} + + Download template +
+ )} +
+ ) +} diff --git a/apps/sim/connectors/gitlab/permission-config/parser.test.ts b/apps/sim/connectors/gitlab/permission-config/parser.test.ts new file mode 100644 index 00000000000..097f700b692 --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/parser.test.ts @@ -0,0 +1,97 @@ +/** @vitest-environment node */ +import { describe, expect, it } from 'vitest' +import { gitLabCsvSubjects, parseGitLabCsv } from '@/connectors/gitlab/permission-config/parser' +import { GITLAB_CSV_MAX_BYTES } from '@/connectors/gitlab/permission-config/types' + +describe('GitLab CSV permission uploads', () => { + it('accepts templates, headerless rows, BOM, CRLF, quotes and identical duplicates', () => { + expect( + parseGitLabCsv( + { + filename: 'users.csv', + content: '\uFEFFuser_id,email\r\n"12", "Alice@Example.com"\r\n12,alice@example.com', + }, + 'userMapping' + ) + ).toEqual([['12', 'alice@example.com']]) + expect( + parseGitLabCsv( + { filename: 'projects.csv', content: 'org/group/project,12\norg/group/project,12' }, + 'projectPermissions' + ) + ).toEqual([['org/group/project', '12']]) + }) + it.each([ + ['1,a@example.com\n1,b@example.com', 'conflicts'], + ['1,a@example.com\n2,A@example.com', 'conflicts'], + ['-1,a@example.com', 'user_id'], + ['9007199254740992,a@example.com', 'user_id'], + ['user_id,email\n', 'at least one'], + ['', 'at least one'], + ['1,', 'email'], + ['1,not-an-email', 'email'], + ['1,a@example.com,extra', 'two columns'], + ['1,"a@example.com', 'Malformed CSV'], + ['1,a@example.com\n2', 'Malformed CSV'], + ])('rejects malformed or conflicting mappings without echoing cells: %s', (content, message) => { + expect(() => parseGitLabCsv({ filename: 'users.csv', content }, 'userMapping')).toThrow(message) + try { + parseGitLabCsv({ filename: 'users.csv', content }, 'userMapping') + } catch (error) { + expect(String(error)).not.toContain('a@example.com') + } + }) + it('rejects malformed project rows and unsafe filenames', () => { + for (const content of [ + 'project_path,user_id\n', + '../project,1', + 'group/project,', + 'group/project,no', + ]) { + expect(() => + parseGitLabCsv({ filename: 'projects.csv', content }, 'projectPermissions') + ).toThrow() + } + expect(() => + parseGitLabCsv({ filename: '../users.csv', content: '1,a@example.com' }, 'userMapping') + ).toThrow('filename') + }) + it('requires an exact selected project and mapping; unrelated rows and unknown users grant nothing', () => { + expect( + gitLabCsvSubjects( + [ + ['1', 'a@example.com'], + ['2', 'b@example.com'], + ], + [ + ['group/project', '1'], + ['group/other', '2'], + ['group/project', '99'], + ], + 'group/project' + ) + ).toEqual(['u:a@example.com']) + }) + it('checks UTF-8 bytes, not just string length', () => { + expect(() => + parseGitLabCsv( + { filename: 'users.csv', content: '😀'.repeat(GITLAB_CSV_MAX_BYTES / 4 + 1) }, + 'userMapping' + ) + ).toThrow('4 MiB') + }) + it('accepts 100,000 rows within a bounded parsing budget and rejects the next row', () => { + const content = Array.from({ length: 100_000 }, (_, i) => `${i + 1},u${i}@example.com`).join( + '\n' + ) + const start = performance.now() + expect(parseGitLabCsv({ filename: 'users.csv', content }, 'userMapping')).toHaveLength(100_000) + expect(performance.now() - start).toBeLessThan(5000) + expect(() => + parseGitLabCsv( + { filename: 'users.csv', content: `${content}\n100001,last@example.com` }, + 'userMapping' + ) + ).toThrow('100,000') + }) +}) diff --git a/apps/sim/connectors/gitlab/permission-config/parser.ts b/apps/sim/connectors/gitlab/permission-config/parser.ts new file mode 100644 index 00000000000..c0334ee2732 --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/parser.ts @@ -0,0 +1,123 @@ +import { isValidEmailSyntax, normalizeEmail } from '@sim/utils/string' +import { parse } from 'csv-parse/browser/esm/sync' +import { + GITLAB_CSV_MAX_BYTES, + GITLAB_CSV_MAX_ROWS, + type GitLabCsvKind, + type GitLabCsvUpload, +} from '@/connectors/gitlab/permission-config/types' + +const USER_ID = /^[1-9]\d{0,15}$/ +const PROJECT_PATH = /^[\p{L}\p{N}_.-]+(?:\/[\p{L}\p{N}_.-]+)+$/u +const HEADERS = { + userMapping: ['user_id', 'email'], + projectPermissions: ['project_path', 'user_id'], +} as const + +export class GitLabCsvValidationError extends Error { + constructor( + readonly field: GitLabCsvKind, + message: string + ) { + super(`${field === 'userMapping' ? 'User mapping' : 'Project permissions'}: ${message}`) + this.name = 'GitLabCsvValidationError' + } +} + +/** Strict, bounded parsing. Diagnostics never include uploaded cell contents. */ +export function parseGitLabCsv(upload: GitLabCsvUpload, kind: GitLabCsvKind): [string, string][] { + const reject = (message: string): never => { + throw new GitLabCsvValidationError(kind, message) + } + if ( + !upload.filename.trim() || + upload.filename.length > 255 || + /[\p{Cc}/\\]/u.test(upload.filename) + ) { + reject('Use a filename of 1–255 characters without path separators.') + } + if (new TextEncoder().encode(upload.content).byteLength > GITLAB_CSV_MAX_BYTES) { + reject('The file must be 4 MiB or smaller.') + } + const rows: [string, string][] = [] + const seen = new Set() + const identities = new Map() + const emails = new Map() + let recordCount = 0 + let firstRecord = true + try { + parse(upload.content, { + bom: true, + trim: true, + skip_empty_lines: true, + max_record_size: 4096, + on_record(record: string[], context: { lines: number }) { + const line = context.lines + if (record.length !== 2) + reject(`Row ending at line ${line} must contain exactly two columns.`) + if (firstRecord) { + firstRecord = false + if (record[0] === HEADERS[kind][0] && record[1] === HEADERS[kind][1]) return null + } + recordCount++ + if (recordCount > GITLAB_CSV_MAX_ROWS) reject('The file must contain at most 100,000 rows.') + const id = kind === 'userMapping' ? record[0] : record[1] + if (!USER_ID.test(id) || !Number.isSafeInteger(Number(id))) { + reject(`Row ending at line ${line} has an invalid user_id; use a positive integer.`) + } + let row: [string, string] + if (kind === 'userMapping') { + const email = normalizeEmail(record[1]) + if (email.length > 254 || !isValidEmailSyntax(email)) + reject(`Row ending at line ${line} has an invalid email.`) + if ( + (identities.has(id) && identities.get(id) !== email) || + (emails.has(email) && emails.get(email) !== id) + ) { + reject(`Row ending at line ${line} conflicts with another identity mapping.`) + } + identities.set(id, email) + emails.set(email, id) + row = [id, email] + } else { + const path = record[0] + if ( + path.length > 1024 || + !PROJECT_PATH.test(path) || + path.split('/').some((part) => part === '.' || part === '..') + ) { + reject(`Row ending at line ${line} has an invalid project_path; use group/project.`) + } + row = [path, id] + } + const key = JSON.stringify(row) + if (!seen.has(key)) { + seen.add(key) + rows.push(row) + } + return null + }, + }) + } catch (error) { + if (error instanceof GitLabCsvValidationError) throw error + reject('Malformed CSV. Check quoting, column counts, and field lengths.') + } + if (rows.length === 0) reject('The file must contain at least one data row.') + return rows +} + +/** Only explicitly mapped users in the selected canonical project receive grants. */ +export function gitLabCsvSubjects( + users: readonly [string, string][], + permissions: readonly [string, string][], + projectPath: string +): string[] { + const identities = new Map(users) + const subjects = new Set() + for (const [path, id] of permissions) { + if (path !== projectPath) continue + const email = identities.get(id) + if (email) subjects.add(`u:${email}`) + } + return [...subjects].sort() +} diff --git a/apps/sim/connectors/gitlab/permission-config/prepare.ts b/apps/sim/connectors/gitlab/permission-config/prepare.ts new file mode 100644 index 00000000000..7147ed900a5 --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/prepare.ts @@ -0,0 +1,96 @@ +import { getErrorMessage } from '@sim/utils/errors' +import { decryptApiKey, encryptApiKey } from '@/lib/api-key/crypto' +import { OrchestrationError } from '@/lib/core/orchestration/types' +import { GitLabCsvValidationError } from '@/connectors/gitlab/permission-config/parser' +import { + loadGitLabPermissionSnapshot, + type PreparedGitLabPermissions, + prepareGitLabPermissions, +} from '@/connectors/gitlab/permission-config/repository' +import type { GitLabPermissionInput } from '@/connectors/gitlab/permission-config/types' +import { validateGitLabCsvToken } from '@/connectors/gitlab/permissions' + +/** Prepares private writes after the application has authorized the canonical connector owner. */ +export async function prepareGitLabPermissionChange(input: { + connectorType: string + accessMode: string + sourceConfig: Record + permissions?: GitLabPermissionInput + apiKey?: string + existing?: { + id: string + encryptedApiKey: string | null + sourceConfig: unknown + } +}): Promise<{ permissions?: PreparedGitLabPermissions; encryptedApiKey?: string }> { + if (input.connectorType !== 'gitlab') { + if (input.permissions || (input.existing && input.apiKey !== undefined)) { + throw new OrchestrationError( + 'validation', + 'GitLab token and CSV settings require a GitLab source with permission-aware access.' + ) + } + return {} + } + if (input.accessMode !== 'admin' && (input.permissions || input.apiKey !== undefined)) { + throw new OrchestrationError( + 'validation', + 'Token and CSV settings require permission-aware access.' + ) + } + const existing = input.existing ? await loadGitLabPermissionSnapshot(input.existing.id) : null + if (input.accessMode !== 'admin' && !existing) return {} + if (!input.permissions && !existing && !input.apiKey) return {} + if ( + input.existing && + (input.permissions || input.apiKey) && + input.permissions?.expectedRevision === undefined + ) { + throw new OrchestrationError( + 'conflict', + 'Reload GitLab settings before saving the token or permissions.' + ) + } + const permissions = input.permissions ?? { + mode: existing?.mode ?? 'administrator', + expectedRevision: existing?.revision ?? 0, + } + const previousConfig = input.existing?.sourceConfig as Record | undefined + const sameProject = + existing && + previousConfig && + previousConfig.host === input.sourceConfig.host && + previousConfig.project === input.sourceConfig.project + const project = + sameProject && !input.apiKey && existing.mode === permissions.mode + ? { host: existing.host, projectId: existing.projectId, projectPath: existing.projectPath } + : await validateGitLabCsvToken( + input.apiKey ?? + (input.existing?.encryptedApiKey + ? (await decryptApiKey(input.existing.encryptedApiKey)).decrypted + : ''), + input.sourceConfig + ).catch((error: unknown) => { + throw new OrchestrationError( + 'validation', + getErrorMessage(error, 'Unable to validate the GitLab token and project.') + ) + }) + try { + return { + permissions: prepareGitLabPermissions( + permissions, + project, + existing, + Boolean(input.existing) + ), + ...(input.existing && input.apiKey + ? { encryptedApiKey: (await encryptApiKey(input.apiKey)).encrypted } + : {}), + } + } catch (error) { + if (error instanceof GitLabCsvValidationError) + throw new OrchestrationError('validation', error.message) + throw error + } +} diff --git a/apps/sim/connectors/gitlab/permission-config/repository.ts b/apps/sim/connectors/gitlab/permission-config/repository.ts new file mode 100644 index 00000000000..bb012b5c4e8 --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/repository.ts @@ -0,0 +1,201 @@ +import { isPlainRecord } from '@sim/utils/object' +import { z } from 'zod' +import { gitLabPermissionSummarySchema } from '@/lib/api/contracts/knowledge/gitlab-permissions' +import { OrchestrationError } from '@/lib/core/orchestration/types' +import type { DbTransaction } from '@/lib/db/types' +import { + loadConnectorPermissionSnapshot, + readConnectorPermissionMetadata, + writeConnectorPermissions, +} from '@/lib/knowledge/connectors/permission-store' +import { gitLabCsvSubjects, parseGitLabCsv } from '@/connectors/gitlab/permission-config/parser' +import { + GITLAB_CSV_MAX_ROWS, + type GitLabPermissionInput, + type GitLabPermissionSummary, + setGitLabCsvContext, +} from '@/connectors/gitlab/permission-config/types' + +const metadataSchema = gitLabPermissionSummarySchema + .omit({ provider: true, revision: true }) + .extend({ + host: z.string().min(1), + projectId: z.number().int().positive(), + projectPath: z.string().min(1), + }) +type Snapshot = z.output & { + connectorId: string + revision: number + userMappingRows: [string, string][] | null + projectPermissionRows: [string, string][] | null +} + +export interface PreparedGitLabPermissions { + expectedRevision: number + snapshot: Omit + subjects: string[] + rewriteAccess: boolean +} + +function invalidSnapshot(): never { + throw new OrchestrationError('internal', 'Could not read the stored GitLab permissions.') +} + +function readMetadata(value: unknown) { + const parsed = metadataSchema.safeParse(value) + if (!parsed.success) return invalidSnapshot() + const result = parsed.data + if ( + result.mode === 'csv' + ? !result.userMapping || !result.projectPermissions + : result.userMapping !== null || result.projectPermissions !== null + ) + return invalidSnapshot() + return result +} + +/** Validate stored tuples without allocating another copy of a large CSV snapshot. */ +function readRows(value: unknown): [string, string][] | null { + if (value === null) return null + const isRow = (row: unknown): row is [string, string] => + Array.isArray(row) && row.length === 2 && row.every((cell) => typeof cell === 'string') + if (!Array.isArray(value) || value.length > GITLAB_CSV_MAX_ROWS || !value.every(isRow)) + return invalidSnapshot() + return value +} + +/** Private contents are loaded only when preparing an authorized replacement. */ +export async function loadGitLabPermissionSnapshot(connectorId: string): Promise { + const row = await loadConnectorPermissionSnapshot(connectorId) + if (!row) return null + const metadata = readMetadata(row.metadata) + if (!isPlainRecord(row.payload)) return invalidSnapshot() + const userMappingRows = readRows(row.payload.userMappingRows) + const projectPermissionRows = readRows(row.payload.projectPermissionRows) + if ( + metadata.mode === 'csv' + ? !userMappingRows || + !projectPermissionRows || + metadata.userMapping?.rowCount !== userMappingRows.length || + metadata.projectPermissions?.rowCount !== projectPermissionRows.length + : userMappingRows !== null || projectPermissionRows !== null + ) + return invalidSnapshot() + return { + connectorId, + revision: row.revision, + ...metadata, + userMappingRows, + projectPermissionRows, + } +} + +export function prepareGitLabPermissions( + input: GitLabPermissionInput, + project: { host: string; projectId: number; projectPath: string }, + existing: Snapshot | null, + replacing: boolean +): PreparedGitLabPermissions { + const revision = existing?.revision ?? 0 + if (replacing && input.expectedRevision !== revision) { + throw new OrchestrationError( + 'conflict', + 'GitLab permissions changed. Reload the connection before saving.' + ) + } + if (input.mode === 'administrator' && (input.userMapping || input.projectPermissions)) { + throw new OrchestrationError('validation', 'CSV uploads require Non-admin token mode.') + } + const now = new Date().toISOString() + const file = (kind: 'userMapping' | 'projectPermissions') => { + const upload = input[kind] + if (!upload) { + const metadata = existing?.mode === 'csv' ? existing[kind] : null + const rows = + kind === 'userMapping' ? existing?.userMappingRows : existing?.projectPermissionRows + return metadata && rows ? { ...metadata, rows } : null + } + return { filename: upload.filename.trim(), uploadedAt: now, rows: parseGitLabCsv(upload, kind) } + } + const userMapping = input.mode === 'csv' ? file('userMapping') : null + const projectPermissions = input.mode === 'csv' ? file('projectPermissions') : null + if (input.mode === 'csv' && (!userMapping || !projectPermissions)) { + throw new OrchestrationError('validation', 'Non-admin token mode requires both CSV files.') + } + return { + expectedRevision: revision, + snapshot: { + ...project, + mode: input.mode, + revision: revision + 1, + userMapping: userMapping + ? { + filename: userMapping.filename, + uploadedAt: userMapping.uploadedAt, + rowCount: userMapping.rows.length, + } + : null, + projectPermissions: projectPermissions + ? { + filename: projectPermissions.filename, + uploadedAt: projectPermissions.uploadedAt, + rowCount: projectPermissions.rows.length, + } + : null, + userMappingRows: userMapping?.rows ?? null, + projectPermissionRows: projectPermissions?.rows ?? null, + }, + subjects: + userMapping && projectPermissions + ? gitLabCsvSubjects(userMapping.rows, projectPermissions.rows, project.projectPath) + : [], + rewriteAccess: + replacing && + ((existing?.mode ?? 'administrator') !== input.mode || + (existing !== null && + (existing.host !== project.host || existing.projectId !== project.projectId))), + } +} + +/** The shared store serializes revision checks and grants inside the owning connector transaction. */ +export async function writeGitLabPermissions( + tx: DbTransaction, + connectorId: string, + prepared: PreparedGitLabPermissions +): Promise { + const { + revision: _revision, + userMappingRows, + projectPermissionRows, + ...metadata + } = prepared.snapshot + await writeConnectorPermissions(tx, connectorId, { + expectedRevision: prepared.expectedRevision, + metadata, + payload: { userMappingRows, projectPermissionRows }, + groups: [{ groupKey: 'project', subjects: prepared.subjects }], + }) +} + +/** Projects only safe metadata; CSV contents never reach a response or browser draft. */ +export async function readGitLabPermissionSummaries( + connectorIds: readonly string[] +): Promise> { + const result = new Map() + for (const row of await readConnectorPermissionMetadata(connectorIds)) { + const { mode, userMapping, projectPermissions } = readMetadata(row.metadata) + result.set(row.connectorId, { mode, revision: row.revision, userMapping, projectPermissions }) + } + return result +} + +/** Workers load canonical mode without loading the potentially large CSV snapshot. */ +export async function seedGitLabCsvContext( + connectorId: string, + context: Record +): Promise { + const [row] = await readConnectorPermissionMetadata([connectorId]) + if (!row) return + const { mode, host, projectId, projectPath } = readMetadata(row.metadata) + if (mode === 'csv') setGitLabCsvContext(context, { connectorId, host, projectId, projectPath }) +} diff --git a/apps/sim/connectors/gitlab/permission-config/types.ts b/apps/sim/connectors/gitlab/permission-config/types.ts new file mode 100644 index 00000000000..0ae990937c7 --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/types.ts @@ -0,0 +1,62 @@ +import { connectorPermissionGroupToken } from '@/lib/knowledge/connectors/permission-tokens' + +export const GITLAB_CSV_MAX_BYTES = 4 * 1024 * 1024 +export const GITLAB_CSV_MAX_ROWS = 100_000 +export const GITLAB_PERMISSION_MODES = ['administrator', 'csv'] as const + +export type GitLabPermissionMode = (typeof GITLAB_PERMISSION_MODES)[number] +export type GitLabCsvKind = 'userMapping' | 'projectPermissions' + +export interface GitLabCsvUpload { + filename: string + content: string +} + +export interface GitLabPermissionInput { + mode: GitLabPermissionMode + /** Required on replacement; zero identifies a legacy administrator connection. */ + expectedRevision?: number + userMapping?: GitLabCsvUpload + projectPermissions?: GitLabCsvUpload +} + +export interface GitLabCsvFileSummary { + filename: string + uploadedAt: string + rowCount: number +} + +export interface GitLabPermissionSummary { + mode: GitLabPermissionMode + revision: number + userMapping: GitLabCsvFileSummary | null + projectPermissions: GitLabCsvFileSummary | null +} + +/** Contains no user identities; only server-loaded configuration may populate this context. */ +export interface GitLabCsvSyncContext { + connectorId: string + host: string + projectId: number + projectPath: string +} + +const syncContexts = new WeakMap, GitLabCsvSyncContext>() + +export function setGitLabCsvContext( + context: Record, + configuration: GitLabCsvSyncContext +): void { + syncContexts.set(context, configuration) +} + +export function getGitLabCsvContext( + context?: Record +): GitLabCsvSyncContext | undefined { + return context ? syncContexts.get(context) : undefined +} + +/** A connector-local audience prevents another connector's CSV from granting access. */ +export function gitLabCsvGroupToken(connectorId: string): string { + return connectorPermissionGroupToken(connectorId, 'project') +} diff --git a/apps/sim/connectors/gitlab/permission-config/use-permission-form.ts b/apps/sim/connectors/gitlab/permission-config/use-permission-form.ts new file mode 100644 index 00000000000..99a3d0cc6f0 --- /dev/null +++ b/apps/sim/connectors/gitlab/permission-config/use-permission-form.ts @@ -0,0 +1,96 @@ +'use client' + +import { useRef, useState } from 'react' +import { getErrorMessage } from '@sim/utils/errors' +import type { + GitLabPermissionData, + GitLabPermissionUploadInput, +} from '@/lib/api/contracts/knowledge/gitlab-permissions' +import { parseGitLabCsv } from '@/connectors/gitlab/permission-config/parser' +import { + GITLAB_CSV_MAX_BYTES, + type GitLabCsvKind, +} from '@/connectors/gitlab/permission-config/types' + +interface SelectedFile { + upload?: { filename: string; content: string } + rowCount?: number + error?: string + loading?: boolean +} + +/** PATs and uploaded content stay in ephemeral component state, never in persisted setup drafts. */ +export function useGitLabPermissionForm(initial?: GitLabPermissionData) { + const generations = useRef({ userMapping: 0, projectPermissions: 0 }) + const [saved, setSaved] = useState(initial) + const [mode, setMode] = useState( + initial?.mode ?? 'administrator' + ) + const [files, setFiles] = useState>>({}) + const [apiKey, setApiKey] = useState('') + const complete = + mode === 'administrator' || + (['userMapping', 'projectPermissions'] as const).every( + (kind) => + !files[kind]?.error && + !files[kind]?.loading && + Boolean(files[kind]?.upload || saved?.[kind]) + ) + const dirty = + mode !== (saved?.mode ?? 'administrator') || + Boolean(apiKey) || + (mode === 'csv' && + Object.values(files).some((file) => file.upload || file.error || file.loading)) + const input: GitLabPermissionUploadInput = { + provider: 'gitlab', + mode, + ...(saved ? { expectedRevision: saved.revision } : {}), + ...(mode === 'csv' + ? { + userMapping: files.userMapping?.upload, + projectPermissions: files.projectPermissions?.upload, + } + : {}), + } + async function selectFile(kind: GitLabCsvKind, file: File) { + const generation = ++generations.current[kind] + setFiles((previous) => ({ ...previous, [kind]: { loading: true } })) + let selected: SelectedFile + try { + if (file.size > GITLAB_CSV_MAX_BYTES) throw new Error('The file must be 4 MiB or smaller.') + const content = new TextDecoder('utf-8', { fatal: true }).decode(await file.arrayBuffer()) + const upload = { filename: file.name, content } + const rows = parseGitLabCsv(upload, kind) + selected = { upload, rowCount: rows.length } + } catch (error) { + selected = { + error: getErrorMessage(error, 'Could not read this CSV. Save it as UTF-8 and try again.'), + } + } + if (generation === generations.current[kind]) + setFiles((previous) => ({ ...previous, [kind]: selected })) + } + function reset(next?: GitLabPermissionData) { + generations.current.userMapping++ + generations.current.projectPermissions++ + setFiles({}) + setApiKey('') + setSaved(next) + setMode(next?.mode ?? 'administrator') + } + return { + mode, + setMode, + saved, + files, + apiKey, + setApiKey, + input, + complete, + dirty, + selectFile, + reset, + } +} + +export type GitLabPermissionForm = ReturnType diff --git a/apps/sim/connectors/gitlab/permissions.ts b/apps/sim/connectors/gitlab/permissions.ts index e19f3fb9885..51fc4c0f503 100644 --- a/apps/sim/connectors/gitlab/permissions.ts +++ b/apps/sim/connectors/gitlab/permissions.ts @@ -2,6 +2,10 @@ import { normalizeEmail } from '@sim/utils/string' import { groupToken, sortAccessTokens, userToken } from '@/lib/knowledge/access/tokens' import { secureFetchWithRetry } from '@/lib/knowledge/documents/secure-fetch.server' import { VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' +import { + getGitLabCsvContext, + gitLabCsvGroupToken, +} from '@/connectors/gitlab/permission-config/types' import { discoverGitLabPermissionPolicy, type GitLabSourcePolicy, @@ -18,6 +22,7 @@ type Feature = (typeof FEATURES)[number] export interface GitLabPermissionProject { id: number + path_with_namespace?: string visibility: 'private' | 'internal' | 'public' repository_access_level?: string merge_requests_access_level?: string @@ -27,6 +32,27 @@ export interface GitLabPermissionProject { shared_with_groups?: Array<{ group_id: number }> } +/** CSV access is managed by Sim administrators, so only identity and project reads are needed. */ +export async function validateGitLabCsvToken( + token: string, + sourceConfig: Record +): Promise<{ host: string; projectId: number; projectPath: string }> { + const { base, project } = sourceAddress(sourceConfig) + const viewer = await read(`${base}/user`, token, true) + if (viewer.state !== 'active' || viewer.locked === true || !Number.isSafeInteger(viewer.id)) { + throw new Error('An active GitLab identity with read_api access is required') + } + const record = await read(`${base}/projects/${project}`, token, true) + if (!Number.isSafeInteger(record.id) || record.id <= 0 || !record.path_with_namespace) { + throw new Error('GitLab did not return the project identity') + } + return { + host: normalizeGitLabHost(sourceConfig.host), + projectId: record.id, + projectPath: record.path_with_namespace, + } +} + export interface GitLabPermissionUser { id: number email?: string @@ -290,6 +316,15 @@ export async function openGitLabDirectory( config: Record, context?: Record ): Promise { + const csv = getGitLabCsvContext(context) + if (csv) { + return { + providerId: 'gitlab', + tenantId: `csv-${csv.connectorId}`, + listGroups: async () => [], + listGroupMembers: async (group) => ({ group, memberTokens: [], complete: true }), + } + } const { tenant, base, project } = sourceAddress(config) const identity = await read<{ id: number }>(`${base}/projects/${project}`, token) if (!Number.isInteger(identity.id)) throw new Error('GitLab did not return a project identity') @@ -340,6 +375,18 @@ export async function getGitLabDocumentAcls( documents: readonly ExternalDocument[], context?: Record ): Promise> { + const csv = getGitLabCsvContext(context) + if (csv) { + const result: Record = {} + for (const doc of documents) { + const known = /^(file|wiki|issue|merge_request):/.test(doc.externalId) + const excluded = + doc.skippedReason || + (doc.externalId.startsWith('issue:') && doc.metadata?.confidential !== false) + result[doc.externalId] = known && !excluded ? [gitLabCsvGroupToken(csv.connectorId)] : [] + } + return result + } const state = await snapshot(token, config, context) const { tenant } = sourceAddress(config) const users = new Map(state.users.map((person) => [person.id, person])) diff --git a/apps/sim/connectors/types.ts b/apps/sim/connectors/types.ts index 323325dc743..dc36523449b 100644 --- a/apps/sim/connectors/types.ts +++ b/apps/sim/connectors/types.ts @@ -1,4 +1,6 @@ import type { MirroredDocumentAcl } from '@/lib/knowledge/access/types' +import type { ConnectorAccessMode } from '@/lib/knowledge/connectors/access-modes' +import type { ConnectorPermissionConfigCapability } from '@/lib/knowledge/connectors/permission-config' import type { OAuthService } from '@/lib/oauth/types' import type { SelectorKey } from '@/lib/selectors/manifest' @@ -325,6 +327,8 @@ export interface ConnectorConfigField { * mirroring the `XBlockMeta` pattern in `blocks/`. */ export interface ConnectorMeta { + /** Restricts new setup and mode changes; existing sources keep their stored access policy. */ + supportedAccessModes?: readonly ConnectorAccessMode[] /** Opts a source into workspace Search after its indexing and permission paths are verified. */ search?: true /** Source setup guide shown only in Search connection flows. */ @@ -429,6 +433,8 @@ export interface ConnectorMeta { * Adding a new connector = creating one of these + registering it. */ export interface ConnectorConfig extends ConnectorMeta { + /** Optional private permission setup, including transactional replacement and worker context. */ + permissionConfig?: ConnectorPermissionConfigCapability /** Bounds local hydration fan-out to avoid queueing siblings behind a serial provider gate. */ contentConcurrency?: 1 | 2 | 3 | 4 | 5 /** diff --git a/apps/sim/hooks/queries/kb/connectors.test.ts b/apps/sim/hooks/queries/kb/connectors.test.ts index 457a1c648fe..cba05e736ad 100644 --- a/apps/sim/hooks/queries/kb/connectors.test.ts +++ b/apps/sim/hooks/queries/kb/connectors.test.ts @@ -3,6 +3,7 @@ */ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { knowledgeKeys } from '@/hooks/queries/utils/knowledge-keys' import { searchSourceKeys } from '@/hooks/queries/utils/search-source-keys' const mocks = vi.hoisted(() => ({ @@ -118,6 +119,29 @@ function lastListStatusUpdater() { return call?.[1] as (connectors?: ConnectorData[]) => ConnectorData[] | undefined } +describe('connector permission cache reconciliation', () => { + beforeEach(() => vi.clearAllMocks()) + it.each([true, false])( + 'refreshes document visibility after permission saves (failed=%s)', + (failed) => { + useUpdateConnector() + const options = mocks.useMutation.mock.calls.at(-1)![0] + options.onSettled(undefined, failed ? new Error('Conflict') : null, { + knowledgeBaseId: KB_ID, + connectorId: 'connector-1', + updates: { permissionConfig: { provider: 'gitlab', mode: 'csv', expectedRevision: 1 } }, + }) + for (const queryKey of [ + knowledgeKeys.documentLists(KB_ID), + knowledgeKeys.documentDetails(KB_ID), + knowledgeKeys.searches(), + ]) { + expect(mocks.invalidateQueries).toHaveBeenCalledWith({ queryKey }) + } + } + ) +}) + describe('isConnectorSyncingOrPending', () => { it('treats a queued sync as in flight', () => { expect(isConnectorSyncingOrPending(makeConnector({ status: 'pending' }))).toBe(true) diff --git a/apps/sim/hooks/queries/kb/connectors.ts b/apps/sim/hooks/queries/kb/connectors.ts index 8c524b253fb..807d908b116 100644 --- a/apps/sim/hooks/queries/kb/connectors.ts +++ b/apps/sim/hooks/queries/kb/connectors.ts @@ -35,8 +35,11 @@ import { type ViewerConnectorMembership, type WorkspaceMemberConnector, } from '@/lib/api/contracts/knowledge' +import type { + CreateConnectorBody, + UpdateConnectorBody, +} from '@/lib/api/contracts/knowledge/connectors' import { - type ConnectorAccessMode, type ConnectorDocumentsQuery, type PrepareSearchSourceBody, prepareSearchSourceContract, @@ -294,17 +297,7 @@ function optimisticallyQueueSync( return { status: cached.status } } -interface CreateConnectorParams { - knowledgeBaseId: string - connectorType: string - credentialId?: string - apiKey?: string - sourceConfig: Record - syncIntervalMinutes?: number - accessMode?: ConnectorAccessMode - credentialGroupId?: string - credentialGroupOptionId?: string -} +type CreateConnectorParams = CreateConnectorBody & { knowledgeBaseId: string } async function createConnector({ knowledgeBaseId, @@ -350,11 +343,7 @@ export function useCreateConnector() { interface UpdateConnectorParams { knowledgeBaseId: string connectorId: string - updates: { - sourceConfig?: Record - syncIntervalMinutes?: number - status?: 'active' | 'paused' - } + updates: UpdateConnectorBody } async function updateConnector({ @@ -392,10 +381,20 @@ export function useUpdateConnector() { }) } }, - onSettled: (_data, _error, { knowledgeBaseId }) => { + onSettled: (_data, _error, { knowledgeBaseId, updates }) => { queryClient.invalidateQueries({ queryKey: connectorKeys.all(knowledgeBaseId) }) queryClient.invalidateQueries({ queryKey: searchSourceKeys.lists() }) queryClient.invalidateQueries({ queryKey: searchIntegrationKeys.lists() }) + if (updates.permissionConfig || updates.apiKey !== undefined) { + queryClient.invalidateQueries({ queryKey: knowledgeKeys.documentLists(knowledgeBaseId) }) + queryClient.invalidateQueries({ queryKey: knowledgeKeys.documentDetails(knowledgeBaseId) }) + queryClient.invalidateQueries({ + queryKey: knowledgeKeys.detail(knowledgeBaseId), + exact: true, + }) + queryClient.invalidateQueries({ queryKey: knowledgeKeys.lists() }) + queryClient.invalidateQueries({ queryKey: knowledgeKeys.searches() }) + } }, }) } diff --git a/apps/sim/lib/api/contracts/knowledge/connector-permissions.ts b/apps/sim/lib/api/contracts/knowledge/connector-permissions.ts new file mode 100644 index 00000000000..fd6fa65f17d --- /dev/null +++ b/apps/sim/lib/api/contracts/knowledge/connector-permissions.ts @@ -0,0 +1,14 @@ +import { z } from 'zod' +import { + gitLabPermissionInputSchema, + gitLabPermissionSummarySchema, +} from '@/lib/api/contracts/knowledge/gitlab-permissions' + +export const connectorPermissionConfigSchema = z.discriminatedUnion('provider', [ + gitLabPermissionInputSchema, +]) +export const connectorPermissionSummarySchema = z.discriminatedUnion('provider', [ + gitLabPermissionSummarySchema, +]) +export type ConnectorPermissionConfigInput = z.input +export type ConnectorPermissionConfigData = z.output diff --git a/apps/sim/lib/api/contracts/knowledge/connectors.ts b/apps/sim/lib/api/contracts/knowledge/connectors.ts index ce2185c981d..a84ae2f1ab3 100644 --- a/apps/sim/lib/api/contracts/knowledge/connectors.ts +++ b/apps/sim/lib/api/contracts/knowledge/connectors.ts @@ -1,4 +1,8 @@ import { z } from 'zod' +import { + connectorPermissionConfigSchema, + connectorPermissionSummarySchema, +} from '@/lib/api/contracts/knowledge/connector-permissions' import { knowledgeBaseParamsSchema, knowledgeConnectorParamsSchema, @@ -43,10 +47,12 @@ export const createConnectorBodySchema = z.object({ connectorType: z.string().min(1), credentialId: z.string().min(1).optional(), apiKey: z.string().min(1).optional(), + permissionConfig: connectorPermissionConfigSchema.optional(), sourceConfig: z.record(z.string(), z.unknown()), syncIntervalMinutes: z.number().int().min(0).default(1440), accessMode: connectorRequestedAccessModeSchema.optional().default('workspace'), }) +export type CreateConnectorBody = z.input export const updateConnectorAccessBodySchema = z.object({ accessMode: connectorRequestedAccessModeSchema, @@ -56,10 +62,13 @@ export const updateConnectorAccessBodySchema = z.object({ export type UpdateConnectorAccessBody = z.input export const updateConnectorBodySchema = z.object({ + apiKey: z.string().min(1).max(4096).optional(), + permissionConfig: connectorPermissionConfigSchema.optional(), sourceConfig: z.record(z.string(), z.unknown()).optional(), syncIntervalMinutes: z.number().int().min(0).optional(), status: z.enum(['active', 'paused']).optional(), }) +export type UpdateConnectorBody = z.input export const deleteConnectorQuerySchema = z.object({ /** Also hard-delete the documents the connector produced; kept by default. */ @@ -110,6 +119,7 @@ export const connectorDataSchema = z id: z.string(), knowledgeBaseId: z.string(), connectorType: z.string(), + permissionConfig: connectorPermissionSummarySchema.optional(), credentialId: z.string().nullable(), sourceConfig: z.record(z.string(), z.unknown()), syncMode: z.string().nullable(), diff --git a/apps/sim/lib/api/contracts/knowledge/gitlab-permissions.ts b/apps/sim/lib/api/contracts/knowledge/gitlab-permissions.ts new file mode 100644 index 00000000000..f91d6f6aaa6 --- /dev/null +++ b/apps/sim/lib/api/contracts/knowledge/gitlab-permissions.ts @@ -0,0 +1,35 @@ +import { z } from 'zod' +import { + GITLAB_CSV_MAX_BYTES, + GITLAB_PERMISSION_MODES, +} from '@/connectors/gitlab/permission-config/types' + +const gitLabCsvUploadSchema = z + .object({ + filename: z.string().trim().min(1).max(255), + content: z.string().min(1).max(GITLAB_CSV_MAX_BYTES), + }) + .strict() +export const gitLabPermissionInputSchema = z + .object({ + provider: z.literal('gitlab'), + mode: z.enum(GITLAB_PERMISSION_MODES), + expectedRevision: z.number().int().nonnegative().optional(), + userMapping: gitLabCsvUploadSchema.optional(), + projectPermissions: gitLabCsvUploadSchema.optional(), + }) + .strict() +export type GitLabPermissionUploadInput = z.input +const gitLabCsvFileSummarySchema = z.object({ + filename: z.string().min(1).max(255), + uploadedAt: z.string().datetime(), + rowCount: z.number().int().nonnegative().max(100_000), +}) +export const gitLabPermissionSummarySchema = z.object({ + provider: z.literal('gitlab'), + mode: z.enum(GITLAB_PERMISSION_MODES), + revision: z.number().int().nonnegative(), + userMapping: gitLabCsvFileSummarySchema.nullable(), + projectPermissions: gitLabCsvFileSummarySchema.nullable(), +}) +export type GitLabPermissionData = z.output diff --git a/apps/sim/lib/knowledge/__integration__/connector-permissions.integration.ts b/apps/sim/lib/knowledge/__integration__/connector-permissions.integration.ts new file mode 100644 index 00000000000..4809c361621 --- /dev/null +++ b/apps/sim/lib/knowledge/__integration__/connector-permissions.integration.ts @@ -0,0 +1,106 @@ +/** Real PostgreSQL coverage for provider-independent snapshots and administrator-managed grants. */ +import { db } from '@sim/db' +import { knowledgeConnector, organization, user, workspace } from '@sim/db/schema' +import { eq, inArray } from 'drizzle-orm' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' +import { seedKnowledgeAclFixture } from '@/lib/knowledge/__integration__/seed-source-access-fixture' +import { loadConnectorPermissionGroupTokens } from '@/lib/knowledge/access/connector-permissions' +import { + loadConnectorPermissionSnapshot, + readConnectorPermissionMetadata, + writeConnectorPermissions, +} from '@/lib/knowledge/connectors/permission-store' +import { connectorPermissionGroupToken } from '@/lib/knowledge/connectors/permission-tokens' + +describe('connector-owned permission storage', () => { + const owners: Awaited>[] = [] + beforeAll(async () => { + owners.push(await seedKnowledgeAclFixture()) + owners.push(await seedKnowledgeAclFixture(undefined, { connectorType: 'google_drive' })) + }) + afterAll(async () => { + for (const owner of owners) { + await db.delete(workspace).where(eq(workspace.id, owner.workspaceId)) + await db.delete(organization).where(eq(organization.id, owner.organizationId)) + await db.delete(user).where(inArray(user.id, [owner.aliceId, owner.bobId])) + } + await db.$client.end() + }) + const save = (connectorId: string, input: Parameters[2]) => + db.transaction(async (tx) => { + await tx + .select({ id: knowledgeConnector.id }) + .from(knowledgeConnector) + .where(eq(knowledgeConnector.id, connectorId)) + .for('update') + await writeConnectorPermissions(tx, connectorId, input) + }) + + it('isolates grants by connector and owner without knowing a provider payload format', async () => { + const subject = `u:${owners[0].aliceId}@fixture.test` + for (const owner of owners) { + await save(owner.connectorId, { + expectedRevision: 0, + metadata: { format: 'fixture' }, + payload: { privateRows: ['fixture-private-payload'] }, + groups: [{ groupKey: 'readers', subjects: [subject] }], + }) + expect( + await loadConnectorPermissionGroupTokens(subject, { + kind: 'workspace', + workspaceId: owner.workspaceId, + }) + ).toEqual([connectorPermissionGroupToken(owner.connectorId, 'readers')]) + } + expect(await readConnectorPermissionMetadata([owners[0].connectorId])).toEqual([ + { connectorId: owners[0].connectorId, revision: 1, metadata: { format: 'fixture' } }, + ]) + expect((await loadConnectorPermissionSnapshot(owners[0].connectorId))?.payload).toEqual({ + privateRows: ['fixture-private-payload'], + }) + await db + .update(knowledgeConnector) + .set({ accessRewritePending: true }) + .where(eq(knowledgeConnector.id, owners[0].connectorId)) + expect( + await loadConnectorPermissionGroupTokens(subject, { + kind: 'workspace', + workspaceId: owners[0].workspaceId, + }) + ).toEqual([]) + await db + .update(knowledgeConnector) + .set({ accessRewritePending: false }) + .where(eq(knowledgeConnector.id, owners[0].connectorId)) + }) + + it('rolls back private writes and rejects stale revisions before a replacement can restore grants', async () => { + const owner = owners[0] + const before = await loadConnectorPermissionSnapshot(owner.connectorId) + const update = { + expectedRevision: 1, + metadata: { format: 'updated' }, + payload: { privateRows: ['replacement-private-payload'] }, + groups: [{ groupKey: 'readers', subjects: ['invalid-private-subject'] }], + } + await expect(save(owner.connectorId, update)).rejects.toMatchObject({ + code: 'internal', + message: 'Could not save permissions. The previous configuration was preserved.', + }) + expect(await loadConnectorPermissionSnapshot(owner.connectorId)).toEqual(before) + const replacements = await Promise.allSettled([ + save(owner.connectorId, { ...update, groups: [] }), + save(owner.connectorId, { ...update, groups: [] }), + ]) + expect(replacements.filter((result) => result.status === 'fulfilled')).toHaveLength(1) + expect(replacements.find((result) => result.status === 'rejected')).toMatchObject({ + reason: { code: 'conflict' }, + }) + expect( + await loadConnectorPermissionGroupTokens(`u:${owner.aliceId}@fixture.test`, { + kind: 'workspace', + workspaceId: owner.workspaceId, + }) + ).toEqual([]) + }) +}) diff --git a/apps/sim/lib/knowledge/__integration__/gitlab-live.integration.ts b/apps/sim/lib/knowledge/__integration__/gitlab-live.integration.ts index e568ded8457..0ffcd293d9f 100644 --- a/apps/sim/lib/knowledge/__integration__/gitlab-live.integration.ts +++ b/apps/sim/lib/knowledge/__integration__/gitlab-live.integration.ts @@ -1,33 +1,65 @@ /** - * Opt-in self-hosted GitLab test. GITLAB_LIVE_FIXTURE_FILE contains {url, token} - * for a disposable instance at https://localhost:8443; NODE_EXTRA_CA_CERTS must - * trust its fixture certificate. Uses real provider APIs, encrypted PAT storage, - * sync engines, parsing, Postgres, and application authorization. Only embeddings - * are substituted. Only this fixture workspace's stored files are removed afterward. + * Opt-in self-hosted GitLab test. GITLAB_LIVE_FIXTURE_FILE contains {url, token, + * auditorToken?} for a disposable localhost HTTPS instance. The administrator + * token seeds fixture data; an optional read_api Auditor token exercises the CSV + * path on a licensed instance. NODE_EXTRA_CA_CERTS must trust its certificate. + * Provider APIs, encrypted PAT storage, ingestion, Postgres and authorization are + * real. Model outputs/capacity are substituted; requestContext supplies Next's + * headers for authenticated route-handler calls. Cleanup removes only fixture + * resources and files, including the fixture organization and workspace. */ + +import { AsyncLocalStorage } from 'node:async_hooks' import { readFile } from 'node:fs/promises' import type { Principal } from '@sim/auth/principal' import { db } from '@sim/db' import { document, embedding, + knowledgeBase, knowledgeConnector, + knowledgeConnectorPermissionGrant, + knowledgeConnectorPermissionSnapshot, + member, + organization, + organizationSearchIntegration, permissions, + session, user, workspace, workspaceFiles, } from '@sim/db/schema' +import { sleep } from '@sim/utils/helpers' import { generateId } from '@sim/utils/id' import { isPlainRecord } from '@sim/utils/object' -import { and, eq, inArray, isNull } from 'drizzle-orm' +import { serializeSignedCookie } from 'better-call' +import { and, eq, inArray, isNull, or } from 'drizzle-orm' +import { NextRequest } from 'next/server' import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest' +import type { EmbedOptions } from '@/lib/embeddings/types' const fixture = vi.hoisted(() => ({ embeddingCalls: 0 })) -vi.mock('@/lib/embeddings', async () => ({ - ...(await import('@/lib/embeddings/client')), +const requestContext = new AsyncLocalStorage() +vi.mock('next/headers', () => ({ + headers: async () => requestContext.getStore() ?? new Headers(), + cookies: async () => ({ get: () => undefined, set: () => {} }), +})) +vi.mock('@/lib/embeddings/client', () => ({ + BYOK_EMBEDDING_CREDENTIAL_REJECTION_MESSAGE: 'Fixture embedding credential rejected', + EMBEDDING_QUOTA_EXHAUSTED_MESSAGE: 'Fixture embedding quota exhausted', + EmbeddingOutputLimitError: class extends Error {}, + getEmbeddingAggregateItemLimit: () => 1000, + isBYOKEmbeddingCredentialRejection: () => false, + isEmbeddingQuotaExhaustion: () => false, + embed: () => { + throw new Error('Unexpected model call in GitLab fixture') + }, + embedOpenRouter: () => { + throw new Error('Unexpected model call in GitLab fixture') + }, assertKnowledgeEmbeddingCapacity: async () => {}, - embedKnowledge: async (texts: string[]) => { - fixture.embeddingCalls += 1 + embedKnowledge: async (texts: string[], options?: EmbedOptions) => { + if (options?.taskType !== 'query') fixture.embeddingCalls += 1 return { embeddings: texts.map(() => [1, ...Array(1535).fill(0)]), totalTokens: texts.length, @@ -39,18 +71,30 @@ vi.mock('@/lib/embeddings', async () => ({ }, })) -import { encryptApiKey } from '@/lib/api-key/crypto' -import { resolveBillingAttribution } from '@/lib/billing/core/billing-attribution' +import type { + ConnectorData, + CreateConnectorBody, + UpdateConnectorBody, +} from '@/lib/api/contracts/knowledge/connectors' +import { decryptApiKey, encryptApiKey } from '@/lib/api-key/crypto' +import { + resolveBillingAttribution, + resolveOrganizationBillingAttribution, +} from '@/lib/billing/core/billing-attribution' import { seedKnowledgeAclFixture } from '@/lib/knowledge/__integration__/seed-source-access-fixture' import { listKnowledgeChunks } from '@/lib/knowledge/application/chunks' import { updateKnowledgeConnectorAccess } from '@/lib/knowledge/application/connector-access' import { updateKnowledgeConnector } from '@/lib/knowledge/application/connectors' import { readKnowledgeDocument } from '@/lib/knowledge/application/documents' +import { readSearchDocument } from '@/lib/knowledge/application/read-search-document' import { searchKnowledge } from '@/lib/knowledge/application/search' import { executeSync } from '@/lib/knowledge/connectors/sync-engine' import * as storage from '@/lib/uploads/core/storage-service' import { downloadFileFromUrl } from '@/lib/uploads/utils/file-utils.server' +import { PATCH as updateConnectorRoute } from '@/app/api/knowledge/[id]/connectors/[connectorId]/route' +import { POST as createConnectorRoute } from '@/app/api/knowledge/[id]/connectors/route' import { gitlabConnector } from '@/connectors/gitlab/gitlab' +import { ResolvedSecretTraceRegistry } from '@/executor/utils/resolved-secret-trace-registry' interface GitLabPerson { id: number @@ -70,6 +114,7 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission let ids: Awaited> let base: string let adminToken: string + let auditorToken: string | undefined let groupId: number | undefined let projectId: number let issueIid: number @@ -80,6 +125,8 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission const createdUserIds: number[] = [] const extraSimIds: string[] = [] let config: Record + let adminCookie: string + let readerCookie: string const principal = (person: GitLabPerson): Principal => ({ kind: 'personal_api_key', userId: person.simId, @@ -91,6 +138,17 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission keyId: 'gitlab-live-fixture', }) + async function waitForProjectAccess(person: GitLabPerson, expectedStatus: number) { + let status = 0 + const deadline = Date.now() + 300_000 + while (Date.now() < deadline) { + status = (await response(`/projects/${projectId}`, person.token)).status + if (status === expectedStatus) return + await sleep(1000) + } + expect(status, 'GitLab project authorization did not converge').toBe(expectedStatus) + } + async function response( resource: string, token = adminToken, @@ -197,13 +255,35 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission const access: unknown = JSON.parse(await readFile(fixtureFile!, 'utf8')) if ( !isPlainRecord(access) || - access.url !== 'https://localhost:8443' || + typeof access.url !== 'string' || + !/^https:\/\/localhost:\d+$/.test(access.url) || typeof access.token !== 'string' ) throw new Error('Only the explicit disposable localhost GitLab fixture is supported') base = access.url adminToken = access.token + auditorToken = typeof access.auditorToken === 'string' ? access.auditorToken : undefined ids = await seedKnowledgeAclFixture() + async function sessionCookie(userId: string) { + const token = generateId() + await db.insert(session).values({ + id: generateId(), + token, + userId, + expiresAt: new Date(Date.now() + 3_600_000), + createdAt: new Date(), + updatedAt: new Date(), + }) + return ( + await serializeSignedCookie( + 'better-auth.session_token', + token, + process.env.BETTER_AUTH_SECRET! + ) + ).split(';')[0] + } + adminCookie = await sessionCookie(ids.aliceId) + readerCookie = await sessionCookie(ids.bobId) const suffix = generateId().replaceAll('-', '') const group = await api('/groups', 'POST', { name: `Sim Search E2E ${suffix}`, @@ -220,7 +300,7 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission default_branch: 'main', }) projectId = project.id - config = { host: 'localhost:8443', project: project.path_with_namespace, contentTypes: 'all' } + config = { host: new URL(base).host, project: project.path_with_namespace, contentTypes: 'all' } for (const [name, role] of [ ['reporter', 20], ['guest', 10], @@ -261,7 +341,7 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission 'POST', { name: 'Disposable search test', - scopes: ['api'], + scopes: ['read_api'], expires_at: new Date(Date.now() + 86400000).toISOString().slice(0, 10), } ) @@ -330,7 +410,7 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission encryptedApiKey: (await encryptApiKey(adminToken)).encrypted, }) .where(eq(knowledgeConnector.id, ids.connectorId)) - }, 180000) + }, 600000) afterAll(async () => { const cleanup = await Promise.allSettled([ @@ -343,7 +423,12 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission const files = await db .select({ key: workspaceFiles.key }) .from(workspaceFiles) - .where(eq(workspaceFiles.workspaceId, ids.workspaceId)) + .where( + or( + eq(workspaceFiles.workspaceId, ids.workspaceId), + eq(workspaceFiles.organizationId, ids.organizationId) + ) + ) for (const file of files) { try { await storage.deleteFile({ key: file.key, context: 'knowledge-base' }) @@ -353,6 +438,7 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission } } await db.delete(workspace).where(eq(workspace.id, ids.workspaceId)) + await db.delete(organization).where(eq(organization.id, ids.organizationId)) await db.delete(user).where(inArray(user.id, [ids.aliceId, ids.bobId, ...extraSimIds])) } })(), @@ -362,6 +448,9 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission }, 120000) it('validates a custom HTTPS instance and ingests repository, wiki, issues and merge requests through the real engine', async () => { + for (const person of [people.reporter, people.guest, people.planner]) { + await waitForProjectAccess(person, 200) + } expect(await gitlabConnector.validateConfig!(adminToken, config)).toEqual({ valid: true }) expect( await gitlabConnector.validateConfig!(adminToken, config, { mirrorsSourceAcls: true }) @@ -397,7 +486,7 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission expect(content).toContain('Orion merge review comment.') expect(content).not.toContain('INTERNAL_FIXTURE_NOTE_MUST_NOT_BE_INDEXED') expect(await search(workspaceKey())).toEqual(new Set()) - }, 120000) + }, 600000) it('matches GitLab private-project decisions for inherited Reporter, Guest, Planner, outside and external users', async () => { await assertProviderParity(['reporter', 'guest', 'planner', 'outsider', 'external']) @@ -423,6 +512,7 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission expect(await storedVectors()).toEqual(before) await assertProviderParity(['reporter', 'guest']) await api(`/groups/${groupId}/members/${people.guest.id}`, 'DELETE') + await waitForProjectAccess(people.guest, 404) await sync() await assertProviderParity(['guest']) await api(`/groups/${groupId}/members`, 'POST', { user_id: people.guest.id, access_level: 10 }) @@ -430,7 +520,8 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission assignee_ids: [people.guest.id], }) await api(`/groups/${groupId}/members/${people.reporter.id}`, 'PUT', { access_level: 20 }) - }, 120000) + await waitForProjectAccess(people.guest, 200) + }, 600000) it('indexes edited comments and updates confidential permissions on an unchanged issue body', async () => { await api(`/projects/${projectId}/issues/${issueIid}/notes/${publicNoteId}`, 'PUT', { @@ -468,7 +559,7 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission await api(`/users/${people.reporter.id}/unblock`, 'POST') }, 180000) - it('switches between explicit workspace sharing and mirrored access with immediate authorization changes', async () => { + it('rejects new workspace sharing and upgrades legacy GitLab connections with immediate authorization changes', async () => { const scope = { knowledgeBaseId: ids.knowledgeBaseId, connectorId: ids.connectorId, @@ -490,20 +581,21 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission input: { ...scope, updates: { status: 'paused' } }, }) const before = await storedVectors() - const shared = await updateKnowledgeConnectorAccess.execute({ - principal: actor, - input: { ...scope, accessMode: 'workspace' }, - }) - expect(shared.changed).toBe(true) + await expect( + updateKnowledgeConnectorAccess.execute({ + principal: actor, + input: { ...scope, accessMode: 'workspace' }, + }) + ).rejects.toMatchObject({ code: 'validation' }) + await db + .update(knowledgeConnector) + .set({ accessMode: 'workspace' }) + .where(eq(knowledgeConnector.id, ids.connectorId)) + await db + .update(document) + .set({ acl: ['ws'], aclRequirements: [] }) + .where(eq(document.connectorId, ids.connectorId)) expect(await search(workspaceKey())).toEqual(new Set((await stored()).map((row) => row.id))) - expect( - ( - await updateKnowledgeConnectorAccess.execute({ - principal: actor, - input: { ...scope, accessMode: 'workspace' }, - }) - ).changed - ).toBe(false) await updateKnowledgeConnectorAccess.execute({ principal: actor, input: { ...scope, accessMode: 'admin' }, @@ -558,4 +650,379 @@ describe.skipIf(!fixtureFile)('live self-hosted GitLab ingestion and permission expect(await stored()).toEqual([]) expect(await search(principal(people.reporter))).toEqual(new Set()) }, 120000) + + async function connectorRequest( + knowledgeBaseId: string, + body: CreateConnectorBody | UpdateConnectorBody, + connectorId?: string, + cookie = adminCookie + ) { + const headers = new Headers({ + cookie, + 'content-type': 'application/json', + origin: 'http://localhost:3000', + }) + const path = `/api/knowledge/${knowledgeBaseId}/connectors${connectorId ? `/${connectorId}` : ''}` + const request = new NextRequest(`http://localhost:3000${path}`, { + method: connectorId ? 'PATCH' : 'POST', + headers, + body: JSON.stringify(body), + }) + return requestContext.run(headers, async () => + connectorId + ? updateConnectorRoute(request, { + params: Promise.resolve({ id: knowledgeBaseId, connectorId }), + }) + : createConnectorRoute(request, { params: Promise.resolve({ id: knowledgeBaseId }) }) + ) + } + + async function waitForSync(connectorId: string) { + for (let attempt = 0; attempt < 600; attempt++) { + const [row] = await db + .select() + .from(knowledgeConnector) + .where(eq(knowledgeConnector.id, connectorId)) + if (row && !['syncing', 'pending'].includes(row.status)) { + expect(row.lastSyncError).toBeNull() + return row + } + await sleep(100) + } + throw new Error('Disposable connector sync did not finish within one minute') + } + + it.each([false, true])( + 'enforces non-admin CSV permissions through authenticated API, indexing and every read surface (Search=%s)', + async (isSearchIndex) => { + await api(`/projects/${projectId}`, 'PUT', { visibility: 'private' }) + await api(`/projects/${projectId}/issues/${issueIid}`, 'PUT', { confidential: false }) + const owner = isSearchIndex + ? { organizationId: ids.organizationId } + : { workspaceId: ids.workspaceId } + if (isSearchIndex) { + await db.insert(member).values( + Object.values(people).map((person) => ({ + id: generateId(), + userId: person.simId, + organizationId: ids.organizationId, + role: person.simId === ids.aliceId ? 'owner' : 'member', + createdAt: new Date(), + })) + ) + await db + .insert(organizationSearchIntegration) + .values({ organizationId: ids.organizationId, connectorType: 'gitlab', approved: true }) + } + const attribution = isSearchIndex + ? await resolveOrganizationBillingAttribution({ + actorUserId: ids.aliceId, + organizationId: ids.organizationId, + }) + : await resolveBillingAttribution({ + actorUserId: ids.aliceId, + workspaceId: ids.workspaceId, + }) + const knowledgeBaseId = generateId() + await db.insert(knowledgeBase).values({ + id: knowledgeBaseId, + userId: ids.aliceId, + ...owner, + name: `CSV live fixture ${isSearchIndex ? 'Search' : 'KB'}`, + isSearchIndex, + chunkingConfig: { maxSize: 1024, minSize: 1, overlap: 20 }, + }) + const mapping = { + filename: 'users.csv', + content: `user_id,email\n${people.reporter.id},${people.reporter.email}\n${people.guest.id},${people.guest.email}\n`, + } + const projectPermissions = (userId: number) => ({ + filename: 'permissions.csv', + content: `project_path,user_id\n${config.project},${userId}\nunrelated/project,${people.guest.id}\n${config.project},999999999\n`, + }) + if (!auditorToken) await waitForProjectAccess(people.reporter, 200) + const indexingToken = auditorToken ?? people.reporter.token + const createBody: CreateConnectorBody = { + connectorType: 'gitlab', + accessMode: 'admin', + apiKey: indexingToken, + sourceConfig: { ...config, contentTypes: 'issues' }, + syncIntervalMinutes: 60, + permissionConfig: { + provider: 'gitlab', + mode: 'csv', + userMapping: mapping, + projectPermissions: projectPermissions(people.reporter.id), + }, + } + const denied = await connectorRequest(knowledgeBaseId, createBody, undefined, readerCookie) + expect(denied.status).toBe(403) + const unsupported = await connectorRequest(knowledgeBaseId, { + ...createBody, + accessMode: 'workspace', + }) + expect(unsupported.status).toBe(400) + const inaccessibleProject = await connectorRequest(knowledgeBaseId, { + ...createBody, + sourceConfig: { ...createBody.sourceConfig, project: 'missing-fixture-project' }, + }) + expect(inaccessibleProject.status).toBe(400) + const createdResponse = await connectorRequest(knowledgeBaseId, createBody) + const created = await createdResponse.json() + expect(createdResponse.status, JSON.stringify(created)).toBe(201) + let connector = created.data as ConnectorData + expect(connector.permissionConfig).toMatchObject({ + provider: 'gitlab', + mode: 'csv', + revision: 1, + userMapping: { rowCount: 2 }, + }) + expect(JSON.stringify(created)).not.toContain(indexingToken) + expect(JSON.stringify(created)).not.toContain(people.reporter.email) + expect(connector.sourceConfig).not.toHaveProperty('permissionConfig') + const storedConnector = await waitForSync(connector.id) + expect(storedConnector.encryptedApiKey).not.toBe(indexingToken) + expect( + (await decryptApiKey(storedConnector.encryptedApiKey!)).decrypted === indexingToken + ).toBe(true) + const docs = await db.select().from(document).where(eq(document.connectorId, connector.id)) + const ordinary = docs.find((doc) => doc.externalId === `issue:${issueIid}`)! + expect(ordinary.processingStatus).toBe('completed') + const excluded = docs.find((doc) => doc.externalId === `issue:${confidentialIid}`) + if (excluded) { + expect(excluded.acl).toEqual([]) + expect(excluded.storageKey).toBeNull() + } + const searchFor = async (person: GitLabPerson) => + ( + await searchKnowledge.execute({ + principal: principal(person), + input: { + ...owner, + knowledgeBaseIds: [knowledgeBaseId], + query: 'Orion', + topK: 100, + }, + }) + ).results.map((row) => row.documentId) + const assertReads = async (person: GitLabPerson, allowed: boolean) => { + expect((await searchFor(person)).includes(ordinary.id)).toBe(allowed) + const operations: Array<() => Promise> = [ + () => + readKnowledgeDocument.execute({ + principal: principal(person), + input: { knowledgeBaseId, documentId: ordinary.id }, + }), + () => + listKnowledgeChunks.execute({ + principal: principal(person), + input: { knowledgeBaseId, documentId: ordinary.id, limit: 10, offset: 0 }, + }), + ] + const download = () => + downloadFileFromUrl(ordinary.fileUrl!, { userId: person.simId, knowledgeAccess: 'user' }) + if (isSearchIndex) { + await expect(download()).rejects.toThrow('Access denied') + operations.push(() => + readSearchDocument.execute({ + principal: principal(person), + input: { + documentId: ordinary.id, + assertedOrganizationId: ids.organizationId, + offset: 0, + limit: 10, + resultSecretRegistry: new ResolvedSecretTraceRegistry(), + }, + }) + ) + } else operations.push(download) + for (const operation of operations) { + if (allowed) await expect(operation()).resolves.toBeDefined() + else await expect(operation()).rejects.toBeDefined() + } + } + await assertReads(people.reporter, true) + await assertReads(people.guest, false) + await assertReads(people.outsider, false) + const vectors = await db + .select({ content: embedding.content }) + .from(embedding) + .where(eq(embedding.documentId, ordinary.id)) + expect(vectors.map((row) => row.content).join('\n')).not.toContain( + 'INTERNAL_FIXTURE_NOTE_MUST_NOT_BE_INDEXED' + ) + const before = fixture.embeddingCalls + const tooLarge = await connectorRequest( + knowledgeBaseId, + { + permissionConfig: { + provider: 'gitlab', + mode: 'csv', + expectedRevision: 1, + userMapping: { filename: 'large.csv', content: 'x'.repeat(4 * 1024 * 1024 + 1) }, + }, + }, + connector.id + ) + expect(tooLarge.status).toBe(400) + const overRequestLimit = await connectorRequest( + knowledgeBaseId, + { + sourceConfig: { description: 'x'.repeat(10 * 1024 * 1024) }, + }, + connector.id + ) + expect(overRequestLimit.status).toBe(413) + const invalid = await connectorRequest( + knowledgeBaseId, + { + permissionConfig: { + provider: 'gitlab', + mode: 'csv', + expectedRevision: 1, + userMapping: { filename: 'bad.csv', content: '1,not-an-email' }, + }, + }, + connector.id + ) + expect(invalid.status).toBe(400) + await assertReads(people.reporter, true) + const replace = await connectorRequest( + knowledgeBaseId, + { + permissionConfig: { + provider: 'gitlab', + mode: 'csv', + expectedRevision: 1, + projectPermissions: projectPermissions(people.guest.id), + }, + }, + connector.id + ) + expect(replace.status).toBe(200) + connector = (await replace.json()).data + expect(connector.permissionConfig?.revision).toBe(2) + await assertReads(people.reporter, false) + await assertReads(people.guest, true) + expect(fixture.embeddingCalls).toBe(before) + const stale = await connectorRequest( + knowledgeBaseId, + { + permissionConfig: { + provider: 'gitlab', + mode: 'csv', + expectedRevision: 1, + projectPermissions: projectPermissions(people.reporter.id), + }, + }, + connector.id + ) + expect(stale.status).toBe(409) + const concurrent = await Promise.all( + [people.reporter, people.guest].map((person) => + connectorRequest( + knowledgeBaseId, + { + permissionConfig: { + provider: 'gitlab', + mode: 'csv', + expectedRevision: 2, + projectPermissions: projectPermissions(person.id), + }, + }, + connector.id + ) + ) + ) + expect(concurrent.map((result) => result.status).sort()).toEqual([200, 409]) + const grants = await db + .select() + .from(knowledgeConnectorPermissionGrant) + .where(eq(knowledgeConnectorPermissionGrant.connectorId, connector.id)) + expect(grants).toHaveLength(1) + let winner = + grants[0].subjectToken === `u:${people.reporter.email}` ? people.reporter : people.guest + await assertReads(winner, true) + expect(fixture.embeddingCalls).toBe(before) + await db.update(user).set({ emailVerified: false }).where(eq(user.id, winner.simId)) + await assertReads(winner, false) + await db.update(user).set({ emailVerified: true }).where(eq(user.id, winner.simId)) + const removedMember = winner + const newlyMappedMember = winner === people.reporter ? people.guest : people.reporter + const remapped = await connectorRequest( + knowledgeBaseId, + { + permissionConfig: { + provider: 'gitlab', + mode: 'csv', + expectedRevision: 3, + userMapping: { + filename: 'replacement-users.csv', + content: `${winner.id},${newlyMappedMember.email}`, + }, + }, + }, + connector.id + ) + expect(remapped.status).toBe(200) + await assertReads(removedMember, false) + winner = newlyMappedMember + await assertReads(winner, true) + expect(fixture.embeddingCalls).toBe(before) + const crossOwner = await connectorRequest( + ids.knowledgeBaseId, + { + permissionConfig: { + provider: 'gitlab', + mode: 'csv', + expectedRevision: 3, + projectPermissions: projectPermissions(people.reporter.id), + }, + }, + connector.id + ) + expect(crossOwner.status).toBe(404) + await api(`/projects/${projectId}/issues/${issueIid}`, 'PUT', { confidential: true }) + const syncResult = await executeSync(connector.id, { + billingAttribution: attribution, + fullSync: true, + }) + expect(syncResult.docsFailed).toBe(0) + await assertReads(winner, false) + const [removed] = await db.select().from(document).where(eq(document.id, ordinary.id)) + expect(removed.storageKey).toBeNull() + expect(removed.acl).toEqual([]) + expect( + await db.select().from(embedding).where(eq(embedding.documentId, ordinary.id)) + ).toEqual([]) + const [snapshot] = await db + .select() + .from(knowledgeConnectorPermissionSnapshot) + .where(eq(knowledgeConnectorPermissionSnapshot.connectorId, connector.id)) + expect(snapshot.revision).toBe(4) + await connectorRequest(knowledgeBaseId, { status: 'paused' }, connector.id) + const switched = await connectorRequest( + knowledgeBaseId, + { + apiKey: adminToken, + permissionConfig: { provider: 'gitlab', mode: 'administrator', expectedRevision: 4 }, + }, + connector.id + ) + expect(switched.status).toBe(200) + expect((await switched.json()).data.accessRewritePending).toBe(true) + await assertReads(winner, false) + await connectorRequest(knowledgeBaseId, { status: 'active' }, connector.id) + await executeSync(connector.id, { + billingAttribution: attribution, + fullSync: true, + }) + const [restored] = await db + .select() + .from(knowledgeConnector) + .where(eq(knowledgeConnector.id, connector.id)) + expect(restored.accessRewritePending).toBe(false) + }, + 180000 + ) }) diff --git a/apps/sim/lib/knowledge/access/connector-permissions.ts b/apps/sim/lib/knowledge/access/connector-permissions.ts new file mode 100644 index 00000000000..f6ec99eee99 --- /dev/null +++ b/apps/sim/lib/knowledge/access/connector-permissions.ts @@ -0,0 +1,35 @@ +import { db } from '@sim/db' +import { + knowledgeBase, + knowledgeConnector, + knowledgeConnectorPermissionGrant, +} from '@sim/db/schema' +import { and, eq, isNull } from 'drizzle-orm' +import type { ResourceScope } from '@/lib/core/resource-scope' +import { resourceScopeCondition } from '@/lib/core/resource-scope.server' +import { connectorPermissionGroupToken } from '@/lib/knowledge/connectors/permission-tokens' + +/** The caller has already verified this email and current membership in the canonical owner. */ +export async function loadConnectorPermissionGroupTokens( + subjectToken: string, + scope: ResourceScope +): Promise { + const grant = knowledgeConnectorPermissionGrant + const rows = await db + .select({ connectorId: grant.connectorId, groupKey: grant.groupKey }) + .from(grant) + .innerJoin(knowledgeConnector, eq(knowledgeConnector.id, grant.connectorId)) + .innerJoin(knowledgeBase, eq(knowledgeBase.id, knowledgeConnector.knowledgeBaseId)) + .where( + and( + eq(grant.subjectToken, subjectToken), + eq(knowledgeConnector.accessMode, 'admin'), + eq(knowledgeConnector.accessRewritePending, false), + resourceScopeCondition(knowledgeBase, scope), + isNull(knowledgeBase.deletedAt), + isNull(knowledgeConnector.deletedAt), + isNull(knowledgeConnector.archivedAt) + ) + ) + return rows.map((row) => connectorPermissionGroupToken(row.connectorId, row.groupKey)) +} diff --git a/apps/sim/lib/knowledge/access/predicate.ts b/apps/sim/lib/knowledge/access/predicate.ts index 8de2cb47f79..c2bdf6d6c41 100644 --- a/apps/sim/lib/knowledge/access/predicate.ts +++ b/apps/sim/lib/knowledge/access/predicate.ts @@ -217,6 +217,7 @@ function storedKnowledgeAccessCondition( OR EXISTS ( SELECT 1 FROM ${knowledgeConnector} WHERE ${knowledgeConnector.id} = ${document.connectorId} + AND ${knowledgeConnector.accessRewritePending} = false AND ${searchIntegrationAccessCondition()} AND ${liveSourceAccess} AND ( diff --git a/apps/sim/lib/knowledge/access/scope.test.ts b/apps/sim/lib/knowledge/access/scope.test.ts index bb46c448f15..0b1ecc25723 100644 --- a/apps/sim/lib/knowledge/access/scope.test.ts +++ b/apps/sim/lib/knowledge/access/scope.test.ts @@ -11,11 +11,13 @@ const { mockCheckWorkspaceAccess, mockGitHubReadGrants, mockConfluenceReadGrants, + mockCsvGrants, } = vi.hoisted(() => ({ mockAvailability: vi.fn(async () => ({ memberScoped: true, sourceMirrored: true })), mockCheckWorkspaceAccess: vi.fn(async () => ({ hasAccess: true })), mockGitHubReadGrants: vi.fn(async () => []), mockConfluenceReadGrants: vi.fn(async () => []), + mockCsvGrants: vi.fn(async () => [] as string[]), })) vi.mock('@/lib/knowledge/access/availability', () => ({ @@ -30,6 +32,9 @@ vi.mock('@/lib/knowledge/access/confluence-site', () => ({ vi.mock('@/lib/knowledge/access/github-installation', () => ({ resolveGitHubInstallationReadGrants: mockGitHubReadGrants, })) +vi.mock('@/lib/knowledge/access/connector-permissions', () => ({ + loadConnectorPermissionGroupTokens: mockCsvGrants, +})) import { createKnowledgeAccessProvider, diff --git a/apps/sim/lib/knowledge/access/scope.ts b/apps/sim/lib/knowledge/access/scope.ts index 0fa1a187299..e70c62854ff 100644 --- a/apps/sim/lib/knowledge/access/scope.ts +++ b/apps/sim/lib/knowledge/access/scope.ts @@ -24,6 +24,7 @@ import { type ConfluenceReaderCredential, resolveConfluenceSiteReadGrants, } from '@/lib/knowledge/access/confluence-site' +import { loadConnectorPermissionGroupTokens } from '@/lib/knowledge/access/connector-permissions' import { domainMemberWildcard, EXTERNAL_GROUP_STALE_AFTER_MS, @@ -274,6 +275,10 @@ async function loadUserAccess( const email = rows[0]?.email const own = userToken(email) if (own) identityTokens.add(own) + if (own) { + for (const token of await loadConnectorPermissionGroupTokens(own, scope)) + identityTokens.add(token) + } const groupMemberTokens = [...identityTokens] if (own && email) groupMemberTokens.push(domainMemberWildcard(emailDomain(email))) if (groupMemberTokens.length > 0) { diff --git a/apps/sim/lib/knowledge/application/connector-access.ts b/apps/sim/lib/knowledge/application/connector-access.ts index 3090096a08e..518d5123eeb 100644 --- a/apps/sim/lib/knowledge/application/connector-access.ts +++ b/apps/sim/lib/knowledge/application/connector-access.ts @@ -34,6 +34,7 @@ import { knowledgeOperations } from '@/lib/knowledge/application/operations' import { type ConnectorAccessMode, mirrorsSourceAcls, + supportsConnectorAccessMode, } from '@/lib/knowledge/connectors/access-modes' import { validateKnowledgeConnectorMembersBinding } from '@/lib/knowledge/connectors/member-access' import { @@ -226,6 +227,12 @@ export const updateKnowledgeConnectorAccess = defineAuthorizedKnowledgeUseCase({ ) } + if (!supportsConnectorAccessMode(connectorMeta, input.accessMode)) { + throw new OrchestrationError( + 'validation', + `${connectorMeta.name} requires source permission access.` + ) + } if ( context.knowledgeBase.isSearchIndex && (!connectorMeta.search || input.accessMode === 'workspace') diff --git a/apps/sim/lib/knowledge/application/connectors.ts b/apps/sim/lib/knowledge/application/connectors.ts index ab8f4a2ff5a..dbe6747d077 100644 --- a/apps/sim/lib/knowledge/application/connectors.ts +++ b/apps/sim/lib/knowledge/application/connectors.ts @@ -49,6 +49,7 @@ import { type ConnectorAccessMode, isConnectorAccessMode, mirrorsSourceAcls, + supportsConnectorAccessMode, } from '@/lib/knowledge/connectors/access-modes' import { type ConnectorAccessToken, @@ -61,6 +62,16 @@ import { type ViewerConnectorMembership, } from '@/lib/knowledge/connectors/member-provisioning' import { assertConnectorMirrorsSourceAcls } from '@/lib/knowledge/connectors/mirrored-access' +import type { + ConnectorPermissionConfig, + PreparedConnectorPermissions, +} from '@/lib/knowledge/connectors/permission-config' +import { + hasConnectorPermissionConfig, + prepareConnectorPermissions, + readConnectorPermissionSummaries, + readConnectorPermissionSummary, +} from '@/lib/knowledge/connectors/permission-config.server' import { MEMBER_OBSERVATION_STALE_AFTER_HOURS } from '@/lib/knowledge/connectors/sync-limits' import { DEFAULT_KNOWLEDGE_CONNECTOR_DOCUMENT_PAGE_SIZE, @@ -129,6 +140,7 @@ export interface CreateKnowledgeConnectorInput extends KnowledgeConnectorApplica connectorType: string credentialId?: string apiKey?: string + permissionConfig?: ConnectorPermissionConfig sourceConfig: Record syncIntervalMinutes: number /** @@ -144,6 +156,8 @@ export interface CreateKnowledgeConnectorInput extends KnowledgeConnectorApplica export interface UpdateKnowledgeConnectorInput extends KnowledgeConnectorApplicationInput { connectorId: string updates: { + apiKey?: string + permissionConfig?: ConnectorPermissionConfig sourceConfig?: Record syncIntervalMinutes?: number status?: 'active' | 'paused' @@ -320,6 +334,7 @@ export async function validateConnectorSourceConfig(input: { organizationId?: string actingUserId: string requestId: string + permissionChange?: PreparedConnectorPermissions }): Promise { const accessMode = input.connector.accessMode if (!isConnectorAccessMode(accessMode)) { @@ -413,14 +428,25 @@ export async function validateConnectorSourceConfig(input: { } } + const validationContext = { + ...syncContextForToken(resolved), + mirrorsSourceAcls: mirrorsSourceAcls(input.connector.accessMode), + ...(input.connector.accessMode === 'members' ? PER_MEMBER_LISTING_CONTEXT : {}), + } + if (validationContext.mirrorsSourceAcls) { + if (input.permissionChange) { + input.permissionChange.populateSyncContext(validationContext, input.connector.id) + } else { + await connectorConfig.permissionConfig?.populateSyncContext( + input.connector.id, + validationContext + ) + } + } const validation = await connectorConfig.validateConfig( resolved.accessToken, input.sourceConfig, - { - ...syncContextForToken(resolved), - mirrorsSourceAcls: mirrorsSourceAcls(input.connector.accessMode), - ...(input.connector.accessMode === 'members' ? PER_MEMBER_LISTING_CONTEXT : {}), - } + validationContext ) return validation.valid ? null @@ -462,6 +488,7 @@ export const listKnowledgeConnectors = defineAuthorizedKnowledgeUseCase({ : await orderedQuery.limit(input.limit + 1).offset(offset) const hasMore = input.limit !== undefined && rows.length > input.limit const page = input.limit === undefined ? rows : rows.slice(0, input.limit) + const permissionSummaries = await readConnectorPermissionSummaries(page) const viewerUserId = principal.kind === 'session' ? principal.userId : null const memberships = viewerUserId && (context.workspaceId || context.organizationId) @@ -475,6 +502,7 @@ export const listKnowledgeConnectors = defineAuthorizedKnowledgeUseCase({ return { connectors: page.map(({ encryptedApiKey: _encryptedApiKey, ...rest }) => ({ ...rest, + permissionConfig: permissionSummaries.get(rest.id), viewerMembership: memberships.get(rest.id) ?? null, })), hasMore, @@ -647,6 +675,10 @@ export const readKnowledgeConnector = defineAuthorizedKnowledgeUseCase({ return { connector: { ...connectorData, + permissionConfig: await readConnectorPermissionSummary( + connector.connectorType, + connector.id + ), viewerMembership: memberships.get(connector.id) ?? null, syncLogs, memberSyncLogs, @@ -713,6 +745,12 @@ async function executeCreateKnowledgeConnector( if (!connectorMeta) { throw new OrchestrationError('validation', `Unknown connector type: ${input.connectorType}`) } + if (!supportsConnectorAccessMode(connectorMeta, input.accessMode ?? 'workspace')) { + throw new OrchestrationError( + 'validation', + `${connectorMeta.name} requires source permission access.` + ) + } if ( input.apiKey && (!getConnectorApiKeyConfig(connectorMeta.auth) || input.accessMode === 'members') @@ -792,11 +830,20 @@ async function executeCreateKnowledgeConnector( sourceConfig: membersBinding?.sourceConfig ?? input.sourceConfig, }) if (membersBinding) membersBinding = { ...membersBinding, sourceConfig } + const permissionChange = input.permissionConfig + ? await prepareConnectorPermissions(input.connectorType, { + accessMode: input.accessMode ?? 'workspace', + sourceConfig, + permissionConfig: input.permissionConfig, + apiKey: input.apiKey, + }) + : undefined const outcome = await performCreateKnowledgeConnector({ knowledgeBase: connectorTarget(context), connectorType: input.connectorType, credentialId: input.credentialId, apiKey: input.apiKey, + permissionChange, /** Members mode stores the config with its listing caps cleared. */ sourceConfig, syncIntervalMinutes: input.syncIntervalMinutes, @@ -826,7 +873,13 @@ async function executeCreateKnowledgeConnector( }) requireSuccessfulOutcome(outcome, 'Knowledge connector creation failed') return { - connector: outcome.connector, + connector: { + ...outcome.connector, + permissionConfig: await readConnectorPermissionSummary( + outcome.connector.connectorType, + outcome.connector.id + ), + }, workspaceId, ...(outcome.reused ? { reused: true } : {}), } @@ -952,10 +1005,64 @@ export const updateKnowledgeConnector = defineAuthorizedKnowledgeUseCase({ async execute({ principal, input, context, request }) { const requestId = generateRequestId() const actingUserId = resolveKnowledgeAttributedUserId(principal, context) + const { apiKey, permissionConfig, ...updates } = input.updates + let permissionChange: PreparedConnectorPermissions | undefined + let expectedUpdatedAt: Date | undefined + if ( + permissionConfig || + apiKey !== undefined || + (updates.sourceConfig !== undefined && + (await hasConnectorPermissionConfig(context.connector.connectorType))) + ) { + if (permissionConfig || apiKey !== undefined) { + const subjectUserId = resolvePrincipalSubjectUserId(principal) + if (!subjectUserId) + throw new OrchestrationError( + 'forbidden', + 'Permission settings require a signed-in administrator.' + ) + if (context.organizationId) + await requireOrganizationMembership( + principal, + context.organizationId, + 'admin', + 'knowledge.use' + ) + else if (context.workspaceId) await requireCurrentHumanRole(subjectUserId, context, 'admin') + } + const connector = await getKnowledgeConnector(context.knowledgeBaseId, context.connectorId) + if (!connector) throw new OrchestrationError('not_found', 'Connector not found') + expectedUpdatedAt = connector.updatedAt + permissionChange = await prepareConnectorPermissions(connector.connectorType, { + accessMode: connector.accessMode, + sourceConfig: updates.sourceConfig ?? (connector.sourceConfig as Record), + permissionConfig, + apiKey, + existing: connector, + }) + if (permissionChange && !permissionConfig && apiKey === undefined) { + const subjectUserId = resolvePrincipalSubjectUserId(principal) + if (!subjectUserId) + throw new OrchestrationError( + 'forbidden', + 'Permission settings require a signed-in administrator.' + ) + if (context.organizationId) + await requireOrganizationMembership( + principal, + context.organizationId, + 'admin', + 'knowledge.use' + ) + else if (context.workspaceId) await requireCurrentHumanRole(subjectUserId, context, 'admin') + } + } const outcome = await performUpdateKnowledgeConnector({ knowledgeBase: connectorTarget(context), connectorId: context.connectorId, - updates: input.updates, + updates, + permissionChange, + expectedUpdatedAt, prepareSourceConfig: (connector, sourceConfig) => prepareGitHubInstallationSource({ principal, @@ -981,7 +1088,10 @@ export const updateKnowledgeConnector = defineAuthorizedKnowledgeUseCase({ const owner = resourceScopeFields(resourceScopeFromOwner(context)) return validateConnectorSourceConfig({ principal, - connector, + connector: permissionChange?.encryptedApiKey + ? { ...connector, encryptedApiKey: permissionChange.encryptedApiKey } + : connector, + permissionChange, sourceConfig, ...owner, actingUserId, @@ -995,7 +1105,15 @@ export const updateKnowledgeConnector = defineAuthorizedKnowledgeUseCase({ recordSemanticAudit: false, }) requireSuccessfulOutcome(outcome, 'Knowledge connector update failed') - return { connector: outcome.connector } + return { + connector: { + ...outcome.connector, + permissionConfig: await readConnectorPermissionSummary( + outcome.connector.connectorType, + outcome.connector.id + ), + }, + } }, projectAudit: ({ input, context, result }) => ({ action: AuditAction.CONNECTOR_UPDATED, diff --git a/apps/sim/lib/knowledge/connectors/access-modes.ts b/apps/sim/lib/knowledge/connectors/access-modes.ts index 4293150e5a0..4c57b41f09a 100644 --- a/apps/sim/lib/knowledge/connectors/access-modes.ts +++ b/apps/sim/lib/knowledge/connectors/access-modes.ts @@ -93,3 +93,20 @@ export function effectiveConnectorSyncIntervalMinutes( ? Math.min(configuredMinutes, MAX_PERMISSION_REFRESH_INTERVAL_MINUTES) : configuredMinutes } + +/** Provider restrictions apply consistently to setup and explicit access changes. */ +export function supportsConnectorAccessMode( + connector: { supportedAccessModes?: readonly ConnectorAccessMode[] }, + mode: ConnectorAccessMode +): boolean { + return !connector.supportedAccessModes || connector.supportedAccessModes.includes(mode) +} + +export function initialConnectorAccessMode( + connector: { supportedAccessModes?: readonly ConnectorAccessMode[] } | undefined, + preferred: ConnectorAccessMode +): ConnectorAccessMode { + return connector && !supportsConnectorAccessMode(connector, preferred) + ? (connector.supportedAccessModes?.[0] ?? preferred) + : preferred +} diff --git a/apps/sim/lib/knowledge/connectors/external-group-sync.ts b/apps/sim/lib/knowledge/connectors/external-group-sync.ts index 02e6e7fad4b..230a5f92280 100644 --- a/apps/sim/lib/knowledge/connectors/external-group-sync.ts +++ b/apps/sim/lib/knowledge/connectors/external-group-sync.ts @@ -481,11 +481,13 @@ export async function refreshConnectorDirectory( ) } try { + const syncContext = syncContextForToken(token) + await connectorConfig.permissionConfig?.populateSyncContext(connector.id, syncContext) const outcome = await refreshMirroredDirectory({ ...resourceScopeFields(resourceScopeFromOwner(connector)), connectorConfig, sourceConfig, - syncContext: syncContextForToken(token), + syncContext, accessToken: token.accessToken, force: connector.lastSyncError?.startsWith(DIRECTORY_ERROR_PREFIX), }) diff --git a/apps/sim/lib/knowledge/connectors/permission-config.server.ts b/apps/sim/lib/knowledge/connectors/permission-config.server.ts new file mode 100644 index 00000000000..67f769b17bb --- /dev/null +++ b/apps/sim/lib/knowledge/connectors/permission-config.server.ts @@ -0,0 +1,59 @@ +import { OrchestrationError } from '@/lib/core/orchestration/types' +import type { + ConnectorPermissionSummary, + PrepareConnectorPermissionsInput, +} from '@/lib/knowledge/connectors/permission-config' + +export async function hasConnectorPermissionConfig(connectorType: string): Promise { + const { CONNECTOR_REGISTRY } = await import('@/connectors/registry.server') + return Boolean(CONNECTOR_REGISTRY[connectorType]?.permissionConfig) +} + +export async function prepareConnectorPermissions( + connectorType: string, + input: PrepareConnectorPermissionsInput +) { + const { CONNECTOR_REGISTRY } = await import('@/connectors/registry.server') + const capability = CONNECTOR_REGISTRY[connectorType]?.permissionConfig + if (input.permissionConfig?.provider && input.permissionConfig.provider !== connectorType) { + throw new OrchestrationError( + 'validation', + 'The permission configuration does not match the connector provider.' + ) + } + if (!capability) { + if (input.permissionConfig || (input.existing && input.apiKey !== undefined)) { + throw new OrchestrationError( + 'validation', + 'This connector does not support private permission settings.' + ) + } + return undefined + } + return capability.prepare(input) +} + +export async function readConnectorPermissionSummary(connectorType: string, connectorId: string) { + return (await readConnectorPermissionSummaries([{ connectorType, id: connectorId }])).get( + connectorId + ) +} + +export async function readConnectorPermissionSummaries( + connectors: readonly { connectorType: string; id: string }[] +) { + const { CONNECTOR_REGISTRY } = await import('@/connectors/registry.server') + const groups = new Map() + for (const row of connectors) { + if (!CONNECTOR_REGISTRY[row.connectorType]?.permissionConfig) continue + const ids = groups.get(row.connectorType) ?? [] + ids.push(row.id) + groups.set(row.connectorType, ids) + } + const summaries = new Map() + for (const [type, ids] of groups) { + const values = await CONNECTOR_REGISTRY[type].permissionConfig!.readSummaries(ids) + for (const [id, summary] of values) summaries.set(id, summary) + } + return summaries +} diff --git a/apps/sim/lib/knowledge/connectors/permission-config.ts b/apps/sim/lib/knowledge/connectors/permission-config.ts new file mode 100644 index 00000000000..828fd7ef0c4 --- /dev/null +++ b/apps/sim/lib/knowledge/connectors/permission-config.ts @@ -0,0 +1,39 @@ +import type { DbTransaction } from '@/lib/db/types' +import type { + GitLabPermissionInput, + GitLabPermissionSummary, +} from '@/connectors/gitlab/permission-config/types' + +/** Provider-discriminated private input; it is never persisted in sourceConfig. */ +export type ConnectorPermissionConfig = { provider: 'gitlab' } & GitLabPermissionInput +export type ConnectorPermissionSummary = { provider: 'gitlab' } & GitLabPermissionSummary + +export interface PrepareConnectorPermissionsInput { + accessMode: string + sourceConfig: Record + permissionConfig?: ConnectorPermissionConfig + apiKey?: string + existing?: { + id: string + encryptedApiKey: string | null + sourceConfig: unknown + } +} + +/** Server-created transaction participant; request data can never supply these callbacks. */ +export interface PreparedConnectorPermissions { + requiresAclReset: boolean + requiresContentSync: boolean + encryptedApiKey?: string + populateSyncContext(context: Record, connectorId: string): void + write(tx: DbTransaction, connectorId: string): Promise +} + +/** Providers own private configuration and grants; orchestration owns the surrounding transaction. */ +export interface ConnectorPermissionConfigCapability { + prepare( + input: PrepareConnectorPermissionsInput + ): Promise + readSummaries(connectorIds: readonly string[]): Promise> + populateSyncContext(connectorId: string, context: Record): Promise +} diff --git a/apps/sim/lib/knowledge/connectors/permission-store.ts b/apps/sim/lib/knowledge/connectors/permission-store.ts new file mode 100644 index 00000000000..c6f4a389165 --- /dev/null +++ b/apps/sim/lib/knowledge/connectors/permission-store.ts @@ -0,0 +1,96 @@ +import { db } from '@sim/db' +import { + knowledgeConnectorPermissionGrant, + knowledgeConnectorPermissionSnapshot, +} from '@sim/db/schema' +import { eq, inArray } from 'drizzle-orm' +import { OrchestrationError } from '@/lib/core/orchestration/types' +import type { DbTransaction } from '@/lib/db/types' + +export type ConnectorPermissionSnapshot = typeof knowledgeConnectorPermissionSnapshot.$inferSelect + +/** Call only after authorizing the connector; this materializes its private normalized input. */ +export async function loadConnectorPermissionSnapshot(connectorId: string) { + const [row] = await db + .select() + .from(knowledgeConnectorPermissionSnapshot) + .where(eq(knowledgeConnectorPermissionSnapshot.connectorId, connectorId)) + .limit(1) + return row ?? null +} + +/** Metadata and worker reads leave the potentially large payload in PostgreSQL. */ +export async function readConnectorPermissionMetadata(connectorIds: readonly string[]) { + const table = knowledgeConnectorPermissionSnapshot + const result: Array> = + [] + for (let offset = 0; offset < connectorIds.length; offset += 1000) { + result.push( + ...(await db + .select({ + connectorId: table.connectorId, + revision: table.revision, + metadata: table.metadata, + }) + .from(table) + .where(inArray(table.connectorId, connectorIds.slice(offset, offset + 1000)))) + ) + } + return result +} + +/** The caller holds the connector row lock and commits configuration, credentials and grants together. */ +export async function writeConnectorPermissions( + tx: DbTransaction, + connectorId: string, + input: { + expectedRevision: number + metadata: Record + payload: Record + groups: readonly { groupKey: string; subjects: readonly string[] }[] + } +) { + const table = knowledgeConnectorPermissionSnapshot + const [current] = await tx + .select({ revision: table.revision }) + .from(table) + .where(eq(table.connectorId, connectorId)) + .limit(1) + if ((current?.revision ?? 0) !== input.expectedRevision) { + throw new OrchestrationError( + 'conflict', + 'Permissions changed. Reload the connection before saving.' + ) + } + const values = { + revision: input.expectedRevision + 1, + metadata: input.metadata, + payload: input.payload, + } + try { + await tx + .insert(table) + .values({ connectorId, ...values }) + .onConflictDoUpdate({ target: table.connectorId, set: values }) + await tx + .delete(knowledgeConnectorPermissionGrant) + .where(eq(knowledgeConnectorPermissionGrant.connectorId, connectorId)) + for (const group of input.groups) { + for (let offset = 0; offset < group.subjects.length; offset += 1000) { + await tx + .insert(knowledgeConnectorPermissionGrant) + .values( + group.subjects + .slice(offset, offset + 1000) + .map((subjectToken) => ({ connectorId, groupKey: group.groupKey, subjectToken })) + ) + } + } + } catch { + /** Query exceptions may contain bind parameters from the private payload. */ + throw new OrchestrationError( + 'internal', + 'Could not save permissions. The previous configuration was preserved.' + ) + } +} diff --git a/apps/sim/lib/knowledge/connectors/permission-tokens.ts b/apps/sim/lib/knowledge/connectors/permission-tokens.ts new file mode 100644 index 00000000000..d30d3b55a32 --- /dev/null +++ b/apps/sim/lib/knowledge/connectors/permission-tokens.ts @@ -0,0 +1,4 @@ +/** A private connector group cannot grant access to another connector or a provider directory group. */ +export function connectorPermissionGroupToken(connectorId: string, groupKey: string): string { + return `g:connector:${encodeURIComponent(connectorId)}:${encodeURIComponent(groupKey)}` +} diff --git a/apps/sim/lib/knowledge/connectors/sync-engine.ts b/apps/sim/lib/knowledge/connectors/sync-engine.ts index 5cfb6a2d08a..98348acc60e 100644 --- a/apps/sim/lib/knowledge/connectors/sync-engine.ts +++ b/apps/sim/lib/knowledge/connectors/sync-engine.ts @@ -950,6 +950,8 @@ export async function executeSync( /** Tells a connector to carry permissions with its listing; without it, none are read. */ ...(mirrored ? { mirrorsSourceAcls: true } : {}), } + if (mirrored) + await connectorConfig.permissionConfig?.populateSyncContext(connectorId, syncContext) // Shared cutoff for both the tombstone-retry bound below and the stuck-document // retry near the end of this sync — same RETRY_WINDOW_DAYS window, one computation. diff --git a/apps/sim/lib/knowledge/connectors/sync-primitives.ts b/apps/sim/lib/knowledge/connectors/sync-primitives.ts index 5dc93a8cc4a..719144ae011 100644 --- a/apps/sim/lib/knowledge/connectors/sync-primitives.ts +++ b/apps/sim/lib/knowledge/connectors/sync-primitives.ts @@ -339,6 +339,13 @@ export function mergeHydratedSkippedDocument( ): ExternalDocument { return { ...stub, + ...(hydrated.skippedExistingDisposition === 'replace' + ? { + title: hydrated.title, + sourceUrl: hydrated.sourceUrl, + acl: hydrated.acl, + } + : {}), content: '', contentHash: hydrated.skippedRetryContentHash ?? @@ -346,7 +353,10 @@ export function mergeHydratedSkippedDocument( contentDeferred: false, skippedReason: hydrated.skippedReason, skippedExistingDisposition: hydrated.skippedExistingDisposition, - metadata: { ...stub.metadata, ...hydrated.metadata }, + metadata: + hydrated.skippedExistingDisposition === 'replace' + ? hydrated.metadata + : { ...stub.metadata, ...hydrated.metadata }, } } diff --git a/apps/sim/lib/knowledge/orchestration/connectors.ts b/apps/sim/lib/knowledge/orchestration/connectors.ts index 8c8d44d4087..eda94d80cc6 100644 --- a/apps/sim/lib/knowledge/orchestration/connectors.ts +++ b/apps/sim/lib/knowledge/orchestration/connectors.ts @@ -50,6 +50,7 @@ import { revokeKnowledgeConnectorCredentialAccess, stripListingCapFields, } from '@/lib/knowledge/connectors/member-access' +import type { PreparedConnectorPermissions } from '@/lib/knowledge/connectors/permission-config' import { allocateTagSlots } from '@/lib/knowledge/constants' import { enqueueKnowledgeStorageCleanup } from '@/lib/knowledge/documents/storage-cleanup' import { @@ -171,6 +172,7 @@ async function assertLiveSyncAllowed( } export interface PerformCreateKnowledgeConnectorParams extends KnowledgeOperationContext { + permissionChange?: PreparedConnectorPermissions knowledgeBase: ConnectorKnowledgeBase connectorType: string credentialId?: string @@ -320,11 +322,17 @@ export async function performCreateKnowledgeConnector( } if (accessToken !== null) { - const configValidation = await connectorConfig.validateConfig(accessToken, sourceConfig, { + const validationContext = { ...tokenContext, mirrorsSourceAcls: accessMode === 'admin', ...(accessMode === 'members' ? PER_MEMBER_LISTING_CONTEXT : {}), - }) + } + params.permissionChange?.populateSyncContext(validationContext, 'setup') + const configValidation = await connectorConfig.validateConfig( + accessToken, + sourceConfig, + validationContext + ) if (!configValidation.valid) { return fail( configValidation.error || @@ -539,6 +547,7 @@ export async function performCreateKnowledgeConnector( }) .returning() + await params.permissionChange?.write(tx, connectorId) return row }) } catch (error) { @@ -641,6 +650,8 @@ export async function performCreateKnowledgeConnector( } export interface PerformUpdateKnowledgeConnectorParams extends KnowledgeOperationContext { + permissionChange?: PreparedConnectorPermissions + expectedUpdatedAt?: Date knowledgeBase: ConnectorKnowledgeBase connectorId: string updates: { @@ -711,6 +722,8 @@ export async function performUpdateKnowledgeConnector( const updatedFields = Object.keys(updates).filter( (key) => updates[key as keyof typeof updates] !== undefined ) + const changedFields: string[] = updatedFields + if (params.permissionChange) changedFields.push('permissionConfig') if (updatedFields.length === 0) { return fail( 'At least one of sourceConfig, syncIntervalMinutes, or status is required', @@ -722,8 +735,14 @@ export async function performUpdateKnowledgeConnector( if (!existing) { return fail('Connector not found', 'not_found') } + if ( + params.expectedUpdatedAt && + params.expectedUpdatedAt.getTime() !== existing.updatedAt.getTime() + ) { + return fail('Connector changed during the update; reload before saving.', 'conflict') + } /** - * A running sync owns the row, so no edit is applied while it holds the lock. + * A running sync owns the content configuration; membership-only updates may still commit. * * `performSyncKnowledgeConnector` already refuses on the same condition; this * is the other half. `status: 'active'` sets `nextSyncAt = new Date()`, which @@ -732,7 +751,7 @@ export async function performUpdateKnowledgeConnector( * only two controls the UI leaves enabled on a wedged connector both pushed * its recovery out by another full TTL. * - * A non-status edit is refused too, not just a status flip. `sourceConfig` is + * Source-config and sync-interval edits are refused too. `sourceConfig` is * read once at the start of a run and threaded through it, so changing it * mid-flight yields a pass that lists against one config and reconciles * against another — and reconciliation hard-deletes. `syncIntervalMinutes` @@ -740,7 +759,14 @@ export async function performUpdateKnowledgeConnector( * so allowing it would silently discard the change. Refusing is the only * answer that is honest about either. */ - if (existing.status === 'syncing') { + const membershipOnly = Boolean( + params.permissionChange && + !params.permissionChange.requiresContentSync && + updates.sourceConfig === undefined && + updates.syncIntervalMinutes === undefined && + updates.status === undefined + ) + if (existing.status === 'syncing' && !membershipOnly) { return fail('Sync already in progress', 'conflict') } /** @@ -754,7 +780,9 @@ export async function performUpdateKnowledgeConnector( */ if ( existing.status === 'pending' && - (updates.sourceConfig !== undefined || updates.syncIntervalMinutes !== undefined) + (updates.sourceConfig !== undefined || + updates.syncIntervalMinutes !== undefined || + params.permissionChange?.requiresContentSync) ) { return fail('Sync already in progress', 'conflict') } @@ -825,9 +853,21 @@ export async function performUpdateKnowledgeConnector( } } + if ( + params.permissionChange?.requiresContentSync && + updates.sourceConfig === undefined && + validateSourceConfig + ) { + const rejection = await validateSourceConfig( + existing, + existing.sourceConfig as Record + ) + if (rejection) return fail(rejection.message, rejection.errorCode) + } + const resultingStatus = updates.status ?? existing.status const shouldDispatchSourceSync = - updates.sourceConfig !== undefined && + (updates.sourceConfig !== undefined || params.permissionChange?.requiresContentSync === true) && resultingStatus !== 'paused' && resultingStatus !== 'disabled' /** @@ -855,6 +895,14 @@ export async function performUpdateKnowledgeConnector( const values: Partial = { updatedAt: updateTimestamp, } + if (params.permissionChange?.encryptedApiKey) + values.encryptedApiKey = params.permissionChange.encryptedApiKey + if (params.permissionChange?.requiresAclReset) values.accessRewritePending = true + if (params.permissionChange?.requiresContentSync) { + values.lastSyncAt = null + values.listingCheckpoint = null + values.directoryCheckpoint = null + } if (sourceConfigToStore !== undefined) { values.sourceConfig = sourceConfigToStore values.lastSyncAt = null @@ -916,7 +964,7 @@ export async function performUpdateKnowledgeConnector( isNull(knowledgeConnector.deletedAt), ] updateConditions.push(eq(knowledgeConnector.status, existing.status)) - if (sourceConfigToStore !== undefined) + if (sourceConfigToStore !== undefined || params.permissionChange) updateConditions.push(eq(knowledgeConnector.updatedAt, existing.updatedAt)) if (syncsPerMember) { updateConditions.push(eq(knowledgeConnector.memberSyncStatus, existing.memberSyncStatus)) @@ -935,6 +983,7 @@ export async function performUpdateKnowledgeConnector( .set(values) .where(and(...updateConditions)) .returning() + if (updatedConnector) await params.permissionChange?.write(tx, connectorId) if (updatedConnector && syncsPerMember && sourceConfigToStore !== undefined) { await tx .update(knowledgeConnectorMember) diff --git a/packages/db/migrations/0339_connector_permissions.sql b/packages/db/migrations/0339_connector_permissions.sql new file mode 100644 index 00000000000..cd2b9a9b95d --- /dev/null +++ b/packages/db/migrations/0339_connector_permissions.sql @@ -0,0 +1,21 @@ +-- migration-safe: Additive private connector permission tables only; existing connector and worker schemas remain unchanged. Deploy before compatible workers and application UI. +CREATE TABLE "knowledge_connector_permission_grant" ( + "connector_id" text NOT NULL, + "group_key" text NOT NULL, + "subject_token" text NOT NULL, + CONSTRAINT "kcpg_pk" PRIMARY KEY("connector_id","group_key","subject_token"), + CONSTRAINT "kcpg_group_check" CHECK (length("knowledge_connector_permission_grant"."group_key") BETWEEN 1 AND 255), + CONSTRAINT "kcpg_subject_check" CHECK ("knowledge_connector_permission_grant"."subject_token" ~ '^u:[^[:space:]A-Z]+@[^[:space:]A-Z]+$') +); +--> statement-breakpoint +CREATE TABLE "knowledge_connector_permission_snapshot" ( + "connector_id" text PRIMARY KEY NOT NULL, + "revision" integer NOT NULL, + "metadata" jsonb NOT NULL, + "payload" jsonb NOT NULL, + CONSTRAINT "kcps_revision_check" CHECK ("knowledge_connector_permission_snapshot"."revision" > 0) +); +--> statement-breakpoint +ALTER TABLE "knowledge_connector_permission_grant" ADD CONSTRAINT "kcpg_snapshot_fk" FOREIGN KEY ("connector_id") REFERENCES "public"."knowledge_connector_permission_snapshot"("connector_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "knowledge_connector_permission_snapshot" ADD CONSTRAINT "kcps_connector_fk" FOREIGN KEY ("connector_id") REFERENCES "public"."knowledge_connector"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "kcpg_subject_idx" ON "knowledge_connector_permission_grant" USING btree ("subject_token","connector_id","group_key"); \ No newline at end of file diff --git a/packages/db/migrations/meta/0339_snapshot.json b/packages/db/migrations/meta/0339_snapshot.json new file mode 100644 index 00000000000..dd5dd20b27c --- /dev/null +++ b/packages/db/migrations/meta/0339_snapshot.json @@ -0,0 +1,26297 @@ +{ + "id": "1bdee29d-c55a-4de9-a0a3-03a6c6aa68aa", + "prevId": "980173df-14ec-401b-89a6-53d1999bc12d", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.academy_certificate": { + "name": "academy_certificate", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "course_id": { + "name": "course_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "academy_cert_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "issued_at": { + "name": "issued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "certificate_number": { + "name": "certificate_number", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "academy_certificate_user_id_idx": { + "name": "academy_certificate_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_course_id_idx": { + "name": "academy_certificate_course_id_idx", + "columns": [ + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_user_course_unique": { + "name": "academy_certificate_user_course_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_status_idx": { + "name": "academy_certificate_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "academy_certificate_user_id_user_id_fk": { + "name": "academy_certificate_user_id_user_id_fk", + "tableFrom": "academy_certificate", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "academy_certificate_certificate_number_unique": { + "name": "academy_certificate_certificate_number_unique", + "nullsNotDistinct": false, + "columns": ["certificate_number"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_config": { + "name": "oauth_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_user_id_idx": { + "name": "account_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_account_on_account_id_provider_id": { + "name": "idx_account_on_account_id_provider_id", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_key": { + "name": "api_key", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'personal'" + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "api_key_workspace_type_idx": { + "name": "api_key_workspace_type_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_key_user_type_idx": { + "name": "api_key_user_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_key_key_hash_idx": { + "name": "api_key_key_hash_idx", + "columns": [ + { + "expression": "key_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "api_key_user_id_user_id_fk": { + "name": "api_key_user_id_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_key_workspace_id_workspace_id_fk": { + "name": "api_key_workspace_id_workspace_id_fk", + "tableFrom": "api_key", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_key_created_by_user_id_fk": { + "name": "api_key_created_by_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_key_key_unique": { + "name": "api_key_key_unique", + "nullsNotDistinct": false, + "columns": ["key"] + } + }, + "policies": {}, + "checkConstraints": { + "workspace_type_check": { + "name": "workspace_type_check", + "value": "(type = 'workspace' AND workspace_id IS NOT NULL) OR (type = 'personal' AND workspace_id IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.async_jobs": { + "name": "async_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "run_at": { + "name": "run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_attempts": { + "name": "max_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "output": { + "name": "output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "async_jobs_status_started_at_idx": { + "name": "async_jobs_status_started_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_status_completed_at_idx": { + "name": "async_jobs_status_completed_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "completed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_schedule_pending_run_at_idx": { + "name": "async_jobs_schedule_pending_run_at_idx", + "columns": [ + { + "expression": "run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"async_jobs\".\"type\" = 'schedule-execution' AND \"async_jobs\".\"status\" = 'pending'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_schedule_processing_started_at_idx": { + "name": "async_jobs_schedule_processing_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"async_jobs\".\"type\" = 'schedule-execution' AND \"async_jobs\".\"status\" = 'processing'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_schedule_unreconciled_terminal_idx": { + "name": "async_jobs_schedule_unreconciled_terminal_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"async_jobs\".\"type\" = 'schedule-execution' AND \"async_jobs\".\"status\" IN ('completed', 'failed', 'cancelled') AND COALESCE(\"async_jobs\".\"metadata\" ->> 'scheduleReconciled', 'false') <> 'true'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_name": { + "name": "actor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_email": { + "name": "actor_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_name": { + "name": "resource_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "audit_log_workspace_created_idx": { + "name": "audit_log_workspace_created_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_workspace_created_at_id_idx": { + "name": "audit_log_workspace_created_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"created_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_actor_created_idx": { + "name": "audit_log_actor_created_idx", + "columns": [ + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_resource_idx": { + "name": "audit_log_resource_idx", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_action_idx": { + "name": "audit_log_action_idx", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_log_workspace_id_workspace_id_fk": { + "name": "audit_log_workspace_id_workspace_id_fk", + "tableFrom": "audit_log", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_actor_id_user_id_fk": { + "name": "audit_log_actor_id_user_id_fk", + "tableFrom": "audit_log", + "tableTo": "user", + "columnsFrom": ["actor_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.background_work_status": { + "name": "background_work_status", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "background_work_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "background_work_status_value", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "background_work_status_workspace_status_idx": { + "name": "background_work_status_workspace_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_workflow_status_idx": { + "name": "background_work_status_workflow_status_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_meta_child_ws_idx": { + "name": "background_work_status_meta_child_ws_idx", + "columns": [ + { + "expression": "(\"metadata\" ->> 'childWorkspaceId')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_meta_other_ws_idx": { + "name": "background_work_status_meta_other_ws_idx", + "columns": [ + { + "expression": "(\"metadata\" ->> 'otherWorkspaceId')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "background_work_status_workspace_id_workspace_id_fk": { + "name": "background_work_status_workspace_id_workspace_id_fk", + "tableFrom": "background_work_status", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "background_work_status_workflow_id_workflow_id_fk": { + "name": "background_work_status_workflow_id_workflow_id_fk", + "tableFrom": "background_work_status", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat": { + "name": "chat", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "customizations": { + "name": "customizations", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "output_configs": { + "name": "output_configs", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "include_thinking": { + "name": "include_thinking", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "include_tool_calls": { + "name": "include_tool_calls", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "identifier_idx": { + "name": "identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"chat\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "chat_archived_at_partial_idx": { + "name": "chat_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"chat\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_chat_on_workflow_id_archived_at": { + "name": "idx_chat_on_workflow_id_archived_at", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chat_workflow_id_workflow_id_fk": { + "name": "chat_workflow_id_workflow_id_fk", + "tableFrom": "chat", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_user_id_user_id_fk": { + "name": "chat_user_id_user_id_fk", + "tableFrom": "chat", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_async_tool_calls": { + "name": "copilot_async_tool_calls", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "checkpoint_id": { + "name": "checkpoint_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "tool_call_id": { + "name": "tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "args": { + "name": "args", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "status": { + "name": "status", + "type": "copilot_async_tool_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "result": { + "name": "result", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission_decision": { + "name": "permission_decision", + "type": "copilot_tool_permission_decision", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "permission_decided_at": { + "name": "permission_decided_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "claimed_by": { + "name": "claimed_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_async_tool_calls_run_id_idx": { + "name": "copilot_async_tool_calls_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_checkpoint_id_idx": { + "name": "copilot_async_tool_calls_checkpoint_id_idx", + "columns": [ + { + "expression": "checkpoint_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_status_idx": { + "name": "copilot_async_tool_calls_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_run_status_idx": { + "name": "copilot_async_tool_calls_run_status_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_tool_call_id_unique": { + "name": "copilot_async_tool_calls_tool_call_id_unique", + "columns": [ + { + "expression": "tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_async_tool_calls_run_id_copilot_runs_id_fk": { + "name": "copilot_async_tool_calls_run_id_copilot_runs_id_fk", + "tableFrom": "copilot_async_tool_calls", + "tableTo": "copilot_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_async_tool_calls_checkpoint_id_copilot_run_checkpoints_id_fk": { + "name": "copilot_async_tool_calls_checkpoint_id_copilot_run_checkpoints_id_fk", + "tableFrom": "copilot_async_tool_calls", + "tableTo": "copilot_run_checkpoints", + "columnsFrom": ["checkpoint_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_chats": { + "name": "copilot_chats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "chat_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'copilot'" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'claude-3-7-sonnet-latest'" + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_conversation_key": { + "name": "external_conversation_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_conversation_metadata": { + "name": "external_conversation_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "preview_yaml": { + "name": "preview_yaml", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan_artifact": { + "name": "plan_artifact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "resources": { + "name": "resources", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "auto_allowed_tools": { + "name": "auto_allowed_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "pinned": { + "name": "pinned", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_chats_organization_id_idx": { + "name": "copilot_chats_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_external_conversation_unique": { + "name": "copilot_chats_external_conversation_unique", + "columns": [ + { + "expression": "external_conversation_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"copilot_chats\".\"external_conversation_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_org_created_idx": { + "name": "copilot_chats_user_org_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_id_idx": { + "name": "copilot_chats_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_workflow_id_idx": { + "name": "copilot_chats_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workflow_idx": { + "name": "copilot_chats_user_workflow_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workspace_idx": { + "name": "copilot_chats_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_created_at_idx": { + "name": "copilot_chats_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_updated_at_idx": { + "name": "copilot_chats_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_workspace_created_at_id_idx": { + "name": "copilot_chats_workspace_created_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"created_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workspace_deleted_partial_idx": { + "name": "copilot_chats_user_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_chats\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_chats_user_id_user_id_fk": { + "name": "copilot_chats_user_id_user_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_workflow_id_workflow_id_fk": { + "name": "copilot_chats_workflow_id_workflow_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_workspace_id_workspace_id_fk": { + "name": "copilot_chats_workspace_id_workspace_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_organization_id_organization_id_fk": { + "name": "copilot_chats_organization_id_organization_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "copilot_chats_owner_check": { + "name": "copilot_chats_owner_check", + "value": "num_nonnulls(\"copilot_chats\".\"workspace_id\", \"copilot_chats\".\"organization_id\") <= 1" + }, + "copilot_chats_organization_workflow_check": { + "name": "copilot_chats_organization_workflow_check", + "value": "\"copilot_chats\".\"organization_id\" IS NULL OR \"copilot_chats\".\"workflow_id\" IS NULL" + } + }, + "isRLSEnabled": false + }, + "public.copilot_feedback": { + "name": "copilot_feedback", + "schema": "", + "columns": { + "feedback_id": { + "name": "feedback_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_query": { + "name": "user_query", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_response": { + "name": "agent_response", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_positive": { + "name": "is_positive", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "feedback": { + "name": "feedback", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_yaml": { + "name": "workflow_yaml", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_feedback_user_id_idx": { + "name": "copilot_feedback_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_chat_id_idx": { + "name": "copilot_feedback_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_user_chat_idx": { + "name": "copilot_feedback_user_chat_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_is_positive_idx": { + "name": "copilot_feedback_is_positive_idx", + "columns": [ + { + "expression": "is_positive", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_created_at_idx": { + "name": "copilot_feedback_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_feedback_user_id_user_id_fk": { + "name": "copilot_feedback_user_id_user_id_fk", + "tableFrom": "copilot_feedback", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_feedback_chat_id_copilot_chats_id_fk": { + "name": "copilot_feedback_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_feedback", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_messages": { + "name": "copilot_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "stream_id": { + "name": "stream_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parent_message_id": { + "name": "parent_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokens_in": { + "name": "tokens_in", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "tokens_out": { + "name": "tokens_out", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "seq": { + "name": "seq", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_messages_chat_message_unique": { + "name": "copilot_messages_chat_message_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_created_at_idx": { + "name": "copilot_messages_chat_created_at_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_seq_idx": { + "name": "copilot_messages_chat_seq_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "seq", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_stream_idx": { + "name": "copilot_messages_chat_stream_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "stream_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"stream_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_user_created_at_idx": { + "name": "copilot_messages_user_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"role\" = 'user' AND \"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_messages_chat_id_copilot_chats_id_fk": { + "name": "copilot_messages_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_messages", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_run_checkpoints": { + "name": "copilot_run_checkpoints", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "pending_tool_call_id": { + "name": "pending_tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conversation_snapshot": { + "name": "conversation_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "agent_state": { + "name": "agent_state", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "provider_request": { + "name": "provider_request", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_run_checkpoints_run_id_idx": { + "name": "copilot_run_checkpoints_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_run_checkpoints_pending_tool_call_id_idx": { + "name": "copilot_run_checkpoints_pending_tool_call_id_idx", + "columns": [ + { + "expression": "pending_tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_run_checkpoints_run_pending_tool_unique": { + "name": "copilot_run_checkpoints_run_pending_tool_unique", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pending_tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_run_checkpoints_run_id_copilot_runs_id_fk": { + "name": "copilot_run_checkpoints_run_id_copilot_runs_id_fk", + "tableFrom": "copilot_run_checkpoints", + "tableTo": "copilot_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_runs": { + "name": "copilot_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_run_id": { + "name": "parent_run_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stream_id": { + "name": "stream_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent": { + "name": "agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "copilot_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "request_context": { + "name": "request_context", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "copilot_runs_execution_id_idx": { + "name": "copilot_runs_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_parent_run_id_idx": { + "name": "copilot_runs_parent_run_id_idx", + "columns": [ + { + "expression": "parent_run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_chat_id_idx": { + "name": "copilot_runs_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_user_id_idx": { + "name": "copilot_runs_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workflow_id_idx": { + "name": "copilot_runs_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workspace_id_idx": { + "name": "copilot_runs_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_status_idx": { + "name": "copilot_runs_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_chat_execution_idx": { + "name": "copilot_runs_chat_execution_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_execution_started_at_idx": { + "name": "copilot_runs_execution_started_at_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workspace_completed_at_id_idx": { + "name": "copilot_runs_workspace_completed_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"completed_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_stream_id_unique": { + "name": "copilot_runs_stream_id_unique", + "columns": [ + { + "expression": "stream_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_runs_chat_id_copilot_chats_id_fk": { + "name": "copilot_runs_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_user_id_user_id_fk": { + "name": "copilot_runs_user_id_user_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_workflow_id_workflow_id_fk": { + "name": "copilot_runs_workflow_id_workflow_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_workspace_id_workspace_id_fk": { + "name": "copilot_runs_workspace_id_workspace_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_workflow_read_hashes": { + "name": "copilot_workflow_read_hashes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hash": { + "name": "hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_workflow_read_hashes_chat_id_idx": { + "name": "copilot_workflow_read_hashes_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_workflow_read_hashes_workflow_id_idx": { + "name": "copilot_workflow_read_hashes_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_workflow_read_hashes_chat_workflow_unique": { + "name": "copilot_workflow_read_hashes_chat_workflow_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_workflow_read_hashes_chat_id_copilot_chats_id_fk": { + "name": "copilot_workflow_read_hashes_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_workflow_read_hashes", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_workflow_read_hashes_workflow_id_workflow_id_fk": { + "name": "copilot_workflow_read_hashes_workflow_id_workflow_id_fk", + "tableFrom": "copilot_workflow_read_hashes", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential": { + "name": "credential", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slack_app_id": { + "name": "slack_app_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "credential_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unredacted": { + "name": "unredacted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_key": { + "name": "env_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_owner_user_id": { + "name": "env_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_service_account_key": { + "name": "encrypted_service_account_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_personal_token": { + "name": "encrypted_personal_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "authorization_app_id": { + "name": "authorization_app_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_group_enrollment_id": { + "name": "credential_group_enrollment_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_group_option_id": { + "name": "credential_group_option_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_server_id": { + "name": "mcp_server_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_oauth_config_version": { + "name": "mcp_oauth_config_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "managed_oauth_scope_version": { + "name": "managed_oauth_scope_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "provider_subject_id": { + "name": "provider_subject_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_tenant_id": { + "name": "provider_tenant_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "managed_oauth_status": { + "name": "managed_oauth_status", + "type": "managed_oauth_credential_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "granted_scopes": { + "name": "granted_scopes", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "provider_metadata": { + "name": "provider_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "encrypted_oauth_token_set": { + "name": "encrypted_oauth_token_set", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_tools": { + "name": "mcp_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "mcp_tools_refreshed_at": { + "name": "mcp_tools_refreshed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "granted_at": { + "name": "granted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_refreshed_at": { + "name": "last_refreshed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_organization_id_idx": { + "name": "credential_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_organization_account_unique": { + "name": "credential_organization_account_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential\".\"account_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_org_personal_token_unique": { + "name": "credential_org_personal_token_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_subject_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential\".\"type\" = 'personal_token'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_id_idx": { + "name": "credential_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_type_idx": { + "name": "credential_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_provider_id_idx": { + "name": "credential_provider_id_idx", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_account_id_idx": { + "name": "credential_account_id_idx", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_env_owner_user_id_idx": { + "name": "credential_env_owner_user_id_idx", + "columns": [ + { + "expression": "env_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_idx": { + "name": "credential_group_enrollment_idx", + "columns": [ + { + "expression": "credential_group_enrollment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_mcp_server_idx": { + "name": "credential_mcp_server_idx", + "columns": [ + { + "expression": "mcp_server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_option_unique": { + "name": "credential_group_option_unique", + "columns": [ + { + "expression": "credential_group_enrollment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "credential_group_option_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential\".\"type\" = 'managed_oauth'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_managed_mcp_enrollment_server_unique": { + "name": "credential_managed_mcp_enrollment_server_unique", + "columns": [ + { + "expression": "credential_group_enrollment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "mcp_server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential\".\"type\" = 'managed_mcp'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_account_unique": { + "name": "credential_workspace_account_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "account_id IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_env_unique": { + "name": "credential_workspace_env_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'env_workspace'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_personal_env_unique": { + "name": "credential_workspace_personal_env_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'env_personal'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_personal_token_identity_unique": { + "name": "credential_personal_token_identity_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_subject_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'personal_token'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_workspace_id_workspace_id_fk": { + "name": "credential_workspace_id_workspace_id_fk", + "tableFrom": "credential", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_organization_id_organization_id_fk": { + "name": "credential_organization_id_organization_id_fk", + "tableFrom": "credential", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_slack_app_id_slack_app_id_fk": { + "name": "credential_slack_app_id_slack_app_id_fk", + "tableFrom": "credential", + "tableTo": "slack_app", + "columnsFrom": ["slack_app_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "credential_account_id_account_id_fk": { + "name": "credential_account_id_account_id_fk", + "tableFrom": "credential", + "tableTo": "account", + "columnsFrom": ["account_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_env_owner_user_id_user_id_fk": { + "name": "credential_env_owner_user_id_user_id_fk", + "tableFrom": "credential", + "tableTo": "user", + "columnsFrom": ["env_owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_credential_group_enrollment_id_credential_group_enrollment_id_fk": { + "name": "credential_credential_group_enrollment_id_credential_group_enrollment_id_fk", + "tableFrom": "credential", + "tableTo": "credential_group_enrollment", + "columnsFrom": ["credential_group_enrollment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_mcp_server_id_mcp_servers_id_fk": { + "name": "credential_mcp_server_id_mcp_servers_id_fk", + "tableFrom": "credential", + "tableTo": "mcp_servers", + "columnsFrom": ["mcp_server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_created_by_user_id_fk": { + "name": "credential_created_by_user_id_fk", + "tableFrom": "credential", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_owner_check": { + "name": "credential_owner_check", + "value": "num_nonnulls(\"credential\".\"workspace_id\", \"credential\".\"organization_id\") = 1" + }, + "credential_organization_type_check": { + "name": "credential_organization_type_check", + "value": "\"credential\".\"organization_id\" IS NULL OR \"credential\".\"type\" IN ('oauth', 'managed_oauth', 'managed_mcp', 'service_account', 'personal_token')" + }, + "credential_personal_token_source_check": { + "name": "credential_personal_token_source_check", + "value": "(type::text <> 'personal_token') OR (\n created_by IS NOT NULL\n AND provider_id IS NOT NULL\n AND provider_id = 'gitlab'\n AND provider_subject_id IS NOT NULL\n AND provider_tenant_id IS NOT NULL\n AND encrypted_personal_token IS NOT NULL\n AND granted_scopes IS NOT NULL\n AND cardinality(granted_scopes) > 0\n AND account_id IS NULL\n AND env_key IS NULL\n AND env_owner_user_id IS NULL\n AND authorization_app_id IS NULL\n AND encrypted_oauth_token_set IS NULL\n AND encrypted_service_account_key IS NULL\n AND unredacted = false\n )" + }, + "credential_oauth_source_check": { + "name": "credential_oauth_source_check", + "value": "(type <> 'oauth') OR (account_id IS NOT NULL AND provider_id IS NOT NULL)" + }, + "credential_managed_oauth_source_check": { + "name": "credential_managed_oauth_source_check", + "value": "(type::text <> 'managed_oauth') OR (\n account_id IS NULL\n AND provider_id IS NOT NULL\n AND authorization_app_id IS NOT NULL\n AND provider_subject_id IS NOT NULL\n AND managed_oauth_status IS NOT NULL\n AND granted_scopes IS NOT NULL\n AND encrypted_oauth_token_set IS NOT NULL\n AND granted_at IS NOT NULL\n )" + }, + "credential_managed_oauth_group_binding_check": { + "name": "credential_managed_oauth_group_binding_check", + "value": "(type::text <> 'managed_oauth') OR (\n credential_group_enrollment_id IS NOT NULL\n AND credential_group_option_id IS NOT NULL\n AND managed_oauth_scope_version IS NOT NULL\n AND managed_oauth_scope_version > 0\n )" + }, + "credential_managed_mcp_source_check": { + "name": "credential_managed_mcp_source_check", + "value": "(type::text <> 'managed_mcp') OR (\n id LIKE 'mcp-cg-%'\n AND account_id IS NULL\n AND provider_id IS NULL\n AND authorization_app_id IS NULL\n AND credential_group_enrollment_id IS NOT NULL\n AND credential_group_option_id IS NULL\n AND mcp_server_id IS NOT NULL\n AND managed_oauth_status IS NOT NULL\n AND (managed_oauth_status <> 'active' OR (\n encrypted_oauth_token_set IS NOT NULL\n AND mcp_tools IS NOT NULL\n ))\n AND granted_at IS NOT NULL\n AND managed_oauth_scope_version IS NULL\n AND provider_subject_id IS NULL\n AND provider_tenant_id IS NULL\n AND granted_scopes IS NULL\n AND provider_metadata IS NULL\n AND created_by IS NULL\n AND env_key IS NULL\n AND env_owner_user_id IS NULL\n AND encrypted_service_account_key IS NULL\n AND unredacted = false\n )" + }, + "credential_creator_source_check": { + "name": "credential_creator_source_check", + "value": "(type::text = 'managed_mcp') OR created_by IS NOT NULL" + }, + "credential_workspace_env_source_check": { + "name": "credential_workspace_env_source_check", + "value": "(type <> 'env_workspace') OR (env_key IS NOT NULL AND env_owner_user_id IS NULL)" + }, + "credential_personal_env_source_check": { + "name": "credential_personal_env_source_check", + "value": "(type <> 'env_personal') OR (env_key IS NOT NULL AND env_owner_user_id IS NOT NULL)" + } + }, + "isRLSEnabled": false + }, + "public.credential_group": { + "name": "credential_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "public_id": { + "name": "public_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "options": { + "name": "options", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "encrypted_provider_configuration": { + "name": "encrypted_provider_configuration", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "credential_group_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_group_organization_id_idx": { + "name": "credential_group_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_organization_unique": { + "name": "credential_group_organization_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_public_id_unique": { + "name": "credential_group_public_id_unique", + "columns": [ + { + "expression": "public_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_workspace_unique": { + "name": "credential_group_workspace_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_group_workspace_id_workspace_id_fk": { + "name": "credential_group_workspace_id_workspace_id_fk", + "tableFrom": "credential_group", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_group_organization_id_organization_id_fk": { + "name": "credential_group_organization_id_organization_id_fk", + "tableFrom": "credential_group", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_group_created_by_user_id_fk": { + "name": "credential_group_created_by_user_id_fk", + "tableFrom": "credential_group", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_group_owner_check": { + "name": "credential_group_owner_check", + "value": "num_nonnulls(\"credential_group\".\"workspace_id\", \"credential_group\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.credential_group_enrollment": { + "name": "credential_group_enrollment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "credential_group_id": { + "name": "credential_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "credential_group_enrollment_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'invited'" + }, + "invitation_token_hash": { + "name": "invitation_token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "invitation_expires_at": { + "name": "invitation_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "invited_at": { + "name": "invited_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "sent_at": { + "name": "sent_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_delivery_error": { + "name": "last_delivery_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_group_enrollment_group_user_unique": { + "name": "credential_group_enrollment_group_user_unique", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential_group_enrollment\".\"user_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_user_id_idx": { + "name": "credential_group_enrollment_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_group_email_unique": { + "name": "credential_group_enrollment_group_email_unique", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_invitation_token_hash_unique": { + "name": "credential_group_enrollment_invitation_token_hash_unique", + "columns": [ + { + "expression": "invitation_token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_group_status_idx": { + "name": "credential_group_enrollment_group_status_idx", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_group_invited_at_id_idx": { + "name": "credential_group_enrollment_group_invited_at_id_idx", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "invited_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_group_enrollment_credential_group_id_credential_group_id_fk": { + "name": "credential_group_enrollment_credential_group_id_credential_group_id_fk", + "tableFrom": "credential_group_enrollment", + "tableTo": "credential_group", + "columnsFrom": ["credential_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_group_enrollment_user_id_user_id_fk": { + "name": "credential_group_enrollment_user_id_user_id_fk", + "tableFrom": "credential_group_enrollment", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_group_enrollment_created_by_user_id_fk": { + "name": "credential_group_enrollment_created_by_user_id_fk", + "tableFrom": "credential_group_enrollment", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_group_enrollment_normalized_email_check": { + "name": "credential_group_enrollment_normalized_email_check", + "value": "\"credential_group_enrollment\".\"email\" = lower(btrim(\"credential_group_enrollment\".\"email\")) AND length(\"credential_group_enrollment\".\"email\") BETWEEN 3 AND 320" + }, + "credential_group_enrollment_invitation_token_hash_length_check": { + "name": "credential_group_enrollment_invitation_token_hash_length_check", + "value": "length(\"credential_group_enrollment\".\"invitation_token_hash\") = 64" + } + }, + "isRLSEnabled": false + }, + "public.credential_member": { + "name": "credential_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "credential_member_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "status": { + "name": "status", + "type": "credential_member_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "joined_at": { + "name": "joined_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_member_user_id_idx": { + "name": "credential_member_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_role_idx": { + "name": "credential_member_role_idx", + "columns": [ + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_status_idx": { + "name": "credential_member_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_unique": { + "name": "credential_member_unique", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_member_credential_id_credential_id_fk": { + "name": "credential_member_credential_id_credential_id_fk", + "tableFrom": "credential_member", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_member_user_id_user_id_fk": { + "name": "credential_member_user_id_user_id_fk", + "tableFrom": "credential_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_member_invited_by_user_id_fk": { + "name": "credential_member_invited_by_user_id_fk", + "tableFrom": "credential_member", + "tableTo": "user", + "columnsFrom": ["invited_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_block": { + "name": "custom_block", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "outputs": { + "name": "outputs", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "trace_child_runs": { + "name": "trace_child_runs", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "custom_block_organization_id_idx": { + "name": "custom_block_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_block_workflow_id_idx": { + "name": "custom_block_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_block_organization_type_unique": { + "name": "custom_block_organization_type_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "custom_block_organization_id_organization_id_fk": { + "name": "custom_block_organization_id_organization_id_fk", + "tableFrom": "custom_block", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_block_workflow_id_workflow_id_fk": { + "name": "custom_block_workflow_id_workflow_id_fk", + "tableFrom": "custom_block", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_block_created_by_user_id_fk": { + "name": "custom_block_created_by_user_id_fk", + "tableFrom": "custom_block", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_tools": { + "name": "custom_tools", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schema": { + "name": "schema", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "custom_tools_workspace_id_idx": { + "name": "custom_tools_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_tools_workspace_title_unique": { + "name": "custom_tools_workspace_title_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "custom_tools_workspace_id_workspace_id_fk": { + "name": "custom_tools_workspace_id_workspace_id_fk", + "tableFrom": "custom_tools", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_tools_user_id_user_id_fk": { + "name": "custom_tools_user_id_user_id_fk", + "tableFrom": "custom_tools", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_drain_runs": { + "name": "data_drain_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "drain_id": { + "name": "drain_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "data_drain_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "trigger": { + "name": "trigger", + "type": "data_drain_run_trigger", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "finished_at": { + "name": "finished_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "rows_exported": { + "name": "rows_exported", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "bytes_written": { + "name": "bytes_written", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "cursor_before": { + "name": "cursor_before", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cursor_after": { + "name": "cursor_after", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "locators": { + "name": "locators", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + } + }, + "indexes": { + "data_drain_runs_drain_started_idx": { + "name": "data_drain_runs_drain_started_idx", + "columns": [ + { + "expression": "drain_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "data_drain_runs_drain_id_data_drains_id_fk": { + "name": "data_drain_runs_drain_id_data_drains_id_fk", + "tableFrom": "data_drain_runs", + "tableTo": "data_drains", + "columnsFrom": ["drain_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_drains": { + "name": "data_drains", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "data_drain_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "destination_type": { + "name": "destination_type", + "type": "data_drain_destination", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "destination_config": { + "name": "destination_config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "destination_credentials": { + "name": "destination_credentials", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schedule_cadence": { + "name": "schedule_cadence", + "type": "data_drain_cadence", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "cursor": { + "name": "cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_success_at": { + "name": "last_success_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "data_drains_org_idx": { + "name": "data_drains_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "data_drains_due_idx": { + "name": "data_drains_due_idx", + "columns": [ + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "data_drains_org_name_unique": { + "name": "data_drains_org_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "data_drains_organization_id_organization_id_fk": { + "name": "data_drains_organization_id_organization_id_fk", + "tableFrom": "data_drains", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "data_drains_created_by_user_id_fk": { + "name": "data_drains_created_by_user_id_fk", + "tableFrom": "data_drains", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.docs_embeddings": { + "name": "docs_embeddings", + "schema": "", + "columns": { + "chunk_id": { + "name": "chunk_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chunk_text": { + "name": "chunk_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_document": { + "name": "source_document", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_link": { + "name": "source_link", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_text": { + "name": "header_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_level": { + "name": "header_level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "embedding": { + "name": "embedding", + "type": "vector(1536)", + "primaryKey": false, + "notNull": true + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "chunk_text_tsv": { + "name": "chunk_text_tsv", + "type": "tsvector", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "to_tsvector('english', \"docs_embeddings\".\"chunk_text\")", + "type": "stored" + } + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "docs_emb_source_document_idx": { + "name": "docs_emb_source_document_idx", + "columns": [ + { + "expression": "source_document", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_header_level_idx": { + "name": "docs_emb_header_level_idx", + "columns": [ + { + "expression": "header_level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_source_header_idx": { + "name": "docs_emb_source_header_idx", + "columns": [ + { + "expression": "source_document", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "header_level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_model_idx": { + "name": "docs_emb_model_idx", + "columns": [ + { + "expression": "embedding_model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_created_at_idx": { + "name": "docs_emb_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_embedding_vector_hnsw_idx": { + "name": "docs_embedding_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "docs_emb_metadata_gin_idx": { + "name": "docs_emb_metadata_gin_idx", + "columns": [ + { + "expression": "metadata", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "docs_emb_chunk_text_fts_idx": { + "name": "docs_emb_chunk_text_fts_idx", + "columns": [ + { + "expression": "chunk_text_tsv", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "docs_embedding_not_null_check": { + "name": "docs_embedding_not_null_check", + "value": "\"embedding\" IS NOT NULL" + }, + "docs_header_level_check": { + "name": "docs_header_level_check", + "value": "\"header_level\" >= 1 AND \"header_level\" <= 6" + } + }, + "isRLSEnabled": false + }, + "public.document": { + "name": "document", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_url": { + "name": "file_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chunk_count": { + "name": "chunk_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "character_count": { + "name": "character_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "processing_status": { + "name": "processing_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "processing_attempts": { + "name": "processing_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "processing_queued_at": { + "name": "processing_queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_queue_token": { + "name": "processing_queue_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_deferred_until": { + "name": "processing_deferred_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_completed_at": { + "name": "processing_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_error": { + "name": "processing_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processing_recovery_after": { + "name": "processing_recovery_after", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "user_excluded": { + "name": "user_excluded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "tag1": { + "name": "tag1", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag2": { + "name": "tag2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag3": { + "name": "tag3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag4": { + "name": "tag4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag5": { + "name": "tag5", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag6": { + "name": "tag6", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag7": { + "name": "tag7", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number1": { + "name": "number1", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number2": { + "name": "number2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number3": { + "name": "number3", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number4": { + "name": "number4", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number5": { + "name": "number5", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "date1": { + "name": "date1", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date2": { + "name": "date2", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boolean1": { + "name": "boolean1", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean2": { + "name": "boolean2", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean3": { + "name": "boolean3", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "acl": { + "name": "acl", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{ws}'::text[]" + }, + "acl_requirements": { + "name": "acl_requirements", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "acl_verified_at": { + "name": "acl_verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_modified_at": { + "name": "source_modified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_seen_at": { + "name": "source_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "doc_kb_id_idx": { + "name": "doc_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_acl_gin_idx": { + "name": "doc_acl_gin_idx", + "columns": [ + { + "expression": "acl", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "array_ops" + } + ], + "isUnique": false, + "where": "\"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "gin", + "with": {} + }, + "doc_filename_idx": { + "name": "doc_filename_idx", + "columns": [ + { + "expression": "filename", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_processing_status_idx": { + "name": "doc_processing_status_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "processing_status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_processing_recovery_idx": { + "name": "doc_processing_recovery_idx", + "columns": [ + { + "expression": "uploaded_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"processing_status\" IN ('pending', 'processing', 'failed') AND \"document\".\"connector_id\" IS NOT NULL AND \"document\".\"content_hash\" IS NOT NULL AND \"document\".\"storage_key\" IS NOT NULL AND \"document\".\"user_excluded\" = false AND \"document\".\"archived_at\" IS NULL AND \"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_external_id_idx": { + "name": "doc_connector_external_id_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_source_lookup_idx": { + "name": "doc_connector_source_lookup_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_reconciliation_idx": { + "name": "doc_connector_reconciliation_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "COALESCE(\"source_seen_at\", '-infinity'::timestamp)", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"user_excluded\" = false AND \"document\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_active_kb_token_count_idx": { + "name": "doc_active_kb_token_count_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "token_count", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"user_excluded\" = false AND \"document\".\"archived_at\" IS NULL AND \"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_storage_key_idx": { + "name": "doc_storage_key_idx", + "columns": [ + { + "expression": "storage_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"storage_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_archived_at_partial_idx": { + "name": "doc_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_deleted_at_partial_idx": { + "name": "doc_deleted_at_partial_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag1_lower_idx": { + "name": "doc_kb_tag1_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag1\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag2_lower_idx": { + "name": "doc_kb_tag2_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag2\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag3_lower_idx": { + "name": "doc_kb_tag3_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag3\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag4_lower_idx": { + "name": "doc_kb_tag4_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag4\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag5_lower_idx": { + "name": "doc_kb_tag5_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag5\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag6_lower_idx": { + "name": "doc_kb_tag6_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag6\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag7_lower_idx": { + "name": "doc_kb_tag7_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag7\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number1_idx": { + "name": "doc_number1_idx", + "columns": [ + { + "expression": "number1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number2_idx": { + "name": "doc_number2_idx", + "columns": [ + { + "expression": "number2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number3_idx": { + "name": "doc_number3_idx", + "columns": [ + { + "expression": "number3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number4_idx": { + "name": "doc_number4_idx", + "columns": [ + { + "expression": "number4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number5_idx": { + "name": "doc_number5_idx", + "columns": [ + { + "expression": "number5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_date1_idx": { + "name": "doc_date1_idx", + "columns": [ + { + "expression": "date1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_date2_idx": { + "name": "doc_date2_idx", + "columns": [ + { + "expression": "date2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean1_idx": { + "name": "doc_boolean1_idx", + "columns": [ + { + "expression": "boolean1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean2_idx": { + "name": "doc_boolean2_idx", + "columns": [ + { + "expression": "boolean2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean3_idx": { + "name": "doc_boolean3_idx", + "columns": [ + { + "expression": "boolean3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "document_knowledge_base_id_knowledge_base_id_fk": { + "name": "document_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "document", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "document_connector_id_knowledge_connector_id_fk": { + "name": "document_connector_id_knowledge_connector_id_fk", + "tableFrom": "document", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "document_uploaded_by_user_id_fk": { + "name": "document_uploaded_by_user_id_fk", + "tableFrom": "document", + "tableTo": "user", + "columnsFrom": ["uploaded_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "doc_acl_token_shape_check": { + "name": "doc_acl_token_shape_check", + "value": "array_position(\"document\".\"acl\", NULL) IS NULL AND (cardinality(\"document\".\"acl\") = 0 OR (cardinality(\"document\".\"acl\") = array_length(string_to_array(array_to_string(\"document\".\"acl\", E'\\n'), E'\\n'), 1) AND array_to_string(\"document\".\"acl\", E'\\n') ~ '^((ws|pub|link|u:[^\\nA-Z]+@[^\\nA-Z]+|[gs]:[^\\n:]+:[^\\n:]+:[^\\n]+)(\\n(ws|pub|link|u:[^\\nA-Z]+@[^\\nA-Z]+|[gs]:[^\\n:]+:[^\\n:]+:[^\\n]+))*)$'))" + } + }, + "isRLSEnabled": false + }, + "public.document_secret_provenance": { + "name": "document_secret_provenance", + "schema": "", + "columns": { + "document_id": { + "name": "document_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "source_hash": { + "name": "source_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "document_secret_provenance_document_id_document_id_fk": { + "name": "document_secret_provenance_document_id_document_id_fk", + "tableFrom": "document_secret_provenance", + "tableTo": "document", + "columnsFrom": ["document_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "document_secret_provenance_status_check": { + "name": "document_secret_provenance_status_check", + "value": "\"document_secret_provenance\".\"status\" IN ('exact', 'unknown')" + } + }, + "isRLSEnabled": false + }, + "public.embedding": { + "name": "embedding", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "document_id": { + "name": "document_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chunk_index": { + "name": "chunk_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "chunk_hash": { + "name": "chunk_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "content_length": { + "name": "content_length", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "embedding": { + "name": "embedding", + "type": "vector(1536)", + "primaryKey": false, + "notNull": false + }, + "embedding_384": { + "name": "embedding_384", + "type": "vector(384)", + "primaryKey": false, + "notNull": false + }, + "embedding_768": { + "name": "embedding_768", + "type": "vector(768)", + "primaryKey": false, + "notNull": false + }, + "embedding_1024": { + "name": "embedding_1024", + "type": "vector(1024)", + "primaryKey": false, + "notNull": false + }, + "embedding_3072": { + "name": "embedding_3072", + "type": "vector(3072)", + "primaryKey": false, + "notNull": false + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "start_offset": { + "name": "start_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "end_offset": { + "name": "end_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "tag1": { + "name": "tag1", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag2": { + "name": "tag2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag3": { + "name": "tag3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag4": { + "name": "tag4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag5": { + "name": "tag5", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag6": { + "name": "tag6", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag7": { + "name": "tag7", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number1": { + "name": "number1", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number2": { + "name": "number2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number3": { + "name": "number3", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number4": { + "name": "number4", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number5": { + "name": "number5", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "date1": { + "name": "date1", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date2": { + "name": "date2", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boolean1": { + "name": "boolean1", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean2": { + "name": "boolean2", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean3": { + "name": "boolean3", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "content_tsv": { + "name": "content_tsv", + "type": "tsvector", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "to_tsvector('english', \"embedding\".\"content\")", + "type": "stored" + } + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "emb_kb_id_idx": { + "name": "emb_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_id_idx": { + "name": "emb_doc_id_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_chunk_idx": { + "name": "emb_doc_chunk_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chunk_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_model_idx": { + "name": "emb_kb_model_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "embedding_model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_enabled_idx": { + "name": "emb_kb_enabled_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_enabled_idx": { + "name": "emb_doc_enabled_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "embedding_vector_hnsw_idx": { + "name": "embedding_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "embedding_384_vector_hnsw_idx": { + "name": "embedding_384_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding_384", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "embedding_768_vector_hnsw_idx": { + "name": "embedding_768_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding_768", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "embedding_1024_vector_hnsw_idx": { + "name": "embedding_1024_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding_1024", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "embedding_3072_vector_hnsw_idx": { + "name": "embedding_3072_vector_hnsw_idx", + "columns": [ + { + "expression": "(\"embedding_3072\"::halfvec(3072)) halfvec_cosine_ops", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "emb_kb_tag1_lower_idx": { + "name": "emb_kb_tag1_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag1\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag2_lower_idx": { + "name": "emb_kb_tag2_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag2\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag3_lower_idx": { + "name": "emb_kb_tag3_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag3\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag4_lower_idx": { + "name": "emb_kb_tag4_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag4\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag5_lower_idx": { + "name": "emb_kb_tag5_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag5\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag6_lower_idx": { + "name": "emb_kb_tag6_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag6\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag7_lower_idx": { + "name": "emb_kb_tag7_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag7\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number1_idx": { + "name": "emb_number1_idx", + "columns": [ + { + "expression": "number1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number2_idx": { + "name": "emb_number2_idx", + "columns": [ + { + "expression": "number2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number3_idx": { + "name": "emb_number3_idx", + "columns": [ + { + "expression": "number3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number4_idx": { + "name": "emb_number4_idx", + "columns": [ + { + "expression": "number4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number5_idx": { + "name": "emb_number5_idx", + "columns": [ + { + "expression": "number5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_date1_idx": { + "name": "emb_date1_idx", + "columns": [ + { + "expression": "date1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_date2_idx": { + "name": "emb_date2_idx", + "columns": [ + { + "expression": "date2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean1_idx": { + "name": "emb_boolean1_idx", + "columns": [ + { + "expression": "boolean1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean2_idx": { + "name": "emb_boolean2_idx", + "columns": [ + { + "expression": "boolean2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean3_idx": { + "name": "emb_boolean3_idx", + "columns": [ + { + "expression": "boolean3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_content_fts_idx": { + "name": "emb_content_fts_idx", + "columns": [ + { + "expression": "content_tsv", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "embedding_knowledge_base_id_knowledge_base_id_fk": { + "name": "embedding_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "embedding", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "embedding_document_id_document_id_fk": { + "name": "embedding_document_id_document_id_fk", + "tableFrom": "embedding", + "tableTo": "document", + "columnsFrom": ["document_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "embedding_width_check": { + "name": "embedding_width_check", + "value": "num_nonnulls(\"embedding\", \"embedding_384\", \"embedding_768\", \"embedding_1024\", \"embedding_3072\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.embedding_secret_provenance": { + "name": "embedding_secret_provenance", + "schema": "", + "columns": { + "embedding_id": { + "name": "embedding_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "embedding_secret_provenance_embedding_id_embedding_id_fk": { + "name": "embedding_secret_provenance_embedding_id_embedding_id_fk", + "tableFrom": "embedding_secret_provenance", + "tableTo": "embedding", + "columnsFrom": ["embedding_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "embedding_secret_provenance_status_check": { + "name": "embedding_secret_provenance_status_check", + "value": "\"embedding_secret_provenance\".\"status\" IN ('exact', 'unknown')" + } + }, + "isRLSEnabled": false + }, + "public.environment": { + "name": "environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "environment_user_id_user_id_fk": { + "name": "environment_user_id_user_id_fk", + "tableFrom": "environment", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environment_user_id_unique": { + "name": "environment_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_value_dependencies": { + "name": "execution_large_value_dependencies", + "schema": "", + "columns": { + "parent_key": { + "name": "parent_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_key": { + "name": "child_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "execution_large_value_dependencies_workspace_parent_key_idx": { + "name": "execution_large_value_dependencies_workspace_parent_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_value_dependencies_workspace_child_key_idx": { + "name": "execution_large_value_dependencies_workspace_child_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_value_dependencies_workspace_id_workspace_id_fk": { + "name": "execution_large_value_dependencies_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_value_dependencies", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "execution_large_value_dependencies_parent_key_child_key_pk": { + "name": "execution_large_value_dependencies_parent_key_child_key_pk", + "columns": ["parent_key", "child_key"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_value_references": { + "name": "execution_large_value_references", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "execution_large_value_reference_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "execution_large_value_references_workspace_execution_source_idx": { + "name": "execution_large_value_references_workspace_execution_source_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_value_references_workflow_id_idx": { + "name": "execution_large_value_references_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_value_references_workspace_id_workspace_id_fk": { + "name": "execution_large_value_references_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_value_references", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "execution_large_value_references_workflow_id_workflow_id_fk": { + "name": "execution_large_value_references_workflow_id_workflow_id_fk", + "tableFrom": "execution_large_value_references", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "execution_large_value_references_key_execution_id_source_pk": { + "name": "execution_large_value_references_key_execution_id_source_pk", + "columns": ["key", "execution_id", "source"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_values": { + "name": "execution_large_values", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_execution_id": { + "name": "owner_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "execution_large_values_owner_execution_id_idx": { + "name": "execution_large_values_owner_execution_id_idx", + "columns": [ + { + "expression": "owner_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_values_cleanup_idx": { + "name": "execution_large_values_cleanup_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"execution_large_values\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_values_tombstone_cleanup_idx": { + "name": "execution_large_values_tombstone_cleanup_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"execution_large_values\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_values_workflow_id_idx": { + "name": "execution_large_values_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_values_workspace_id_workspace_id_fk": { + "name": "execution_large_values_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_values", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "execution_large_values_workflow_id_workflow_id_fk": { + "name": "execution_large_values_workflow_id_workflow_id_fk", + "tableFrom": "execution_large_values", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.folder": { + "name": "folder", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "folder_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "folder_user_idx": { + "name": "folder_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_workspace_resource_parent_idx": { + "name": "folder_workspace_resource_parent_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_parent_sort_idx": { + "name": "folder_parent_sort_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_deleted_at_idx": { + "name": "folder_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_workspace_deleted_partial_idx": { + "name": "folder_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"folder\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_workspace_resource_parent_name_active_unique": { + "name": "folder_workspace_resource_parent_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"parent_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"folder\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "folder_user_id_user_id_fk": { + "name": "folder_user_id_user_id_fk", + "tableFrom": "folder", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "folder_workspace_id_workspace_id_fk": { + "name": "folder_workspace_id_workspace_id_fk", + "tableFrom": "folder", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "folder_parent_id_folder_id_fk": { + "name": "folder_parent_id_folder_id_fk", + "tableFrom": "folder", + "tableTo": "folder", + "columnsFrom": ["parent_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.idempotency_key": { + "name": "idempotency_key", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "result": { + "name": "result", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idempotency_key_created_at_idx": { + "name": "idempotency_key_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "invitation_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'organization'" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "membership_intent": { + "name": "membership_intent", + "type": "invitation_membership_intent", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'internal'" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "invitation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_organization_id_idx": { + "name": "invitation_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_status_idx": { + "name": "invitation_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_pending_email_org_unique": { + "name": "invitation_pending_email_org_unique", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"invitation\".\"status\" = 'pending' AND \"invitation\".\"organization_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": ["inviter_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "invitation_token_unique": { + "name": "invitation_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation_workspace_grant": { + "name": "invitation_workspace_grant", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "invitation_id": { + "name": "invitation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "invitation_workspace_grant_unique": { + "name": "invitation_workspace_grant_unique", + "columns": [ + { + "expression": "invitation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_workspace_grant_workspace_id_idx": { + "name": "invitation_workspace_grant_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_workspace_grant_invitation_id_invitation_id_fk": { + "name": "invitation_workspace_grant_invitation_id_invitation_id_fk", + "tableFrom": "invitation_workspace_grant", + "tableTo": "invitation", + "columnsFrom": ["invitation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_workspace_grant_workspace_id_workspace_id_fk": { + "name": "invitation_workspace_grant_workspace_id_workspace_id_fk", + "tableFrom": "invitation_workspace_grant", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.job_execution_logs": { + "name": "job_execution_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule_id": { + "name": "schedule_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_duration_ms": { + "name": "total_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "execution_data": { + "name": "execution_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "cost": { + "name": "cost", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "job_execution_logs_schedule_id_idx": { + "name": "job_execution_logs_schedule_id_idx", + "columns": [ + { + "expression": "schedule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_workspace_started_at_idx": { + "name": "job_execution_logs_workspace_started_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_workspace_ended_at_id_idx": { + "name": "job_execution_logs_workspace_ended_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"ended_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_execution_id_unique": { + "name": "job_execution_logs_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_trigger_idx": { + "name": "job_execution_logs_trigger_idx", + "columns": [ + { + "expression": "trigger", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "job_execution_logs_schedule_id_workflow_schedule_id_fk": { + "name": "job_execution_logs_schedule_id_workflow_schedule_id_fk", + "tableFrom": "job_execution_logs", + "tableTo": "workflow_schedule", + "columnsFrom": ["schedule_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "job_execution_logs_workspace_id_workspace_id_fk": { + "name": "job_execution_logs_workspace_id_workspace_id_fk", + "tableFrom": "job_execution_logs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_base": { + "name": "knowledge_base", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_search_index": { + "name": "is_search_index", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "embedding_dimension": { + "name": "embedding_dimension", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1536 + }, + "chunking_config": { + "name": "chunking_config", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{\"maxSize\": 1024, \"minSize\": 1, \"overlap\": 200}'" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kb_organization_id_idx": { + "name": "kb_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_organization_search_index_unique": { + "name": "kb_organization_search_index_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"is_search_index\" = true AND \"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_organization_name_active_unique": { + "name": "kb_organization_name_active_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_user_id_idx": { + "name": "kb_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_id_idx": { + "name": "kb_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_user_workspace_idx": { + "name": "kb_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_folder_id_idx": { + "name": "kb_folder_id_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_deleted_at_idx": { + "name": "kb_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_deleted_partial_idx": { + "name": "kb_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_base\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_name_active_unique": { + "name": "kb_workspace_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_search_index_unique": { + "name": "kb_workspace_search_index_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"is_search_index\" = true AND \"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_base_user_id_user_id_fk": { + "name": "knowledge_base_user_id_user_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_base_workspace_id_workspace_id_fk": { + "name": "knowledge_base_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_base_organization_id_organization_id_fk": { + "name": "knowledge_base_organization_id_organization_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_base_folder_id_folder_id_fk": { + "name": "knowledge_base_folder_id_folder_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kb_owner_check": { + "name": "kb_owner_check", + "value": "num_nonnulls(\"knowledge_base\".\"workspace_id\", \"knowledge_base\".\"organization_id\") = 1" + }, + "kb_organization_search_index_check": { + "name": "kb_organization_search_index_check", + "value": "\"knowledge_base\".\"organization_id\" IS NULL OR \"knowledge_base\".\"is_search_index\"" + }, + "kb_organization_folder_check": { + "name": "kb_organization_folder_check", + "value": "\"knowledge_base\".\"organization_id\" IS NULL OR \"knowledge_base\".\"folder_id\" IS NULL" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_base_tag_definitions": { + "name": "knowledge_base_tag_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag_slot": { + "name": "tag_slot", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "field_type": { + "name": "field_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kb_tag_definitions_kb_slot_idx": { + "name": "kb_tag_definitions_kb_slot_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag_slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_tag_definitions_kb_display_name_idx": { + "name": "kb_tag_definitions_kb_display_name_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_tag_definitions_kb_id_idx": { + "name": "kb_tag_definitions_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_base_tag_definitions_knowledge_base_id_knowledge_base_id_fk": { + "name": "knowledge_base_tag_definitions_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "knowledge_base_tag_definitions", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_connector": { + "name": "knowledge_connector", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connector_type": { + "name": "connector_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_config": { + "name": "source_config", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "sync_mode": { + "name": "sync_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'full'" + }, + "sync_interval_minutes": { + "name": "sync_interval_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1440 + }, + "access_mode": { + "name": "access_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'workspace'" + }, + "credential_group_id": { + "name": "credential_group_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_group_option_id": { + "name": "credential_group_option_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "member_sync_status": { + "name": "member_sync_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "member_sync_lock_token": { + "name": "member_sync_lock_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "member_sync_lock_lease_at": { + "name": "member_sync_lock_lease_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_member_sync_at": { + "name": "next_member_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_member_sync_at": { + "name": "last_member_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_member_sync_error": { + "name": "last_member_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "member_sync_consecutive_failures": { + "name": "member_sync_consecutive_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "access_rewrite_pending": { + "name": "access_rewrite_pending", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_sync_error": { + "name": "last_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_doc_count": { + "name": "last_sync_doc_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "listing_checkpoint": { + "name": "listing_checkpoint", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "directory_checkpoint": { + "name": "directory_checkpoint", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "next_sync_at": { + "name": "next_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_directory_sync_at": { + "name": "next_directory_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "consecutive_failures": { + "name": "consecutive_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "sync_lock_token": { + "name": "sync_lock_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sync_lock_lease_at": { + "name": "sync_lock_lease_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kc_knowledge_base_id_idx": { + "name": "kc_knowledge_base_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_status_next_sync_idx": { + "name": "kc_status_next_sync_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_archived_at_partial_idx": { + "name": "kc_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_deleted_at_partial_idx": { + "name": "kc_deleted_at_partial_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_member_sync_due_idx": { + "name": "kc_member_sync_due_idx", + "columns": [ + { + "expression": "member_sync_status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_member_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"access_mode\" = 'members' AND \"knowledge_connector\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_directory_sync_due_idx": { + "name": "kc_directory_sync_due_idx", + "columns": [ + { + "expression": "next_directory_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"access_mode\" = 'admin' AND \"knowledge_connector\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_knowledge_base_id_knowledge_base_id_fk": { + "name": "knowledge_connector_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "knowledge_connector", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_connector_credential_group_id_credential_group_id_fk": { + "name": "knowledge_connector_credential_group_id_credential_group_id_fk", + "tableFrom": "knowledge_connector", + "tableTo": "credential_group", + "columnsFrom": ["credential_group_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kc_access_mode_check": { + "name": "kc_access_mode_check", + "value": "\"knowledge_connector\".\"access_mode\" IN ('workspace', 'members', 'admin')" + }, + "kc_member_sync_status_check": { + "name": "kc_member_sync_status_check", + "value": "\"knowledge_connector\".\"member_sync_status\" IN ('idle', 'pending', 'running', 'error', 'disabled')" + }, + "kc_sync_lock_exclusive_check": { + "name": "kc_sync_lock_exclusive_check", + "value": "NOT (\"knowledge_connector\".\"sync_lock_token\" IS NOT NULL AND \"knowledge_connector\".\"member_sync_lock_token\" IS NOT NULL)" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_connector_member": { + "name": "knowledge_connector_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subject_token": { + "name": "subject_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "consecutive_failures": { + "name": "consecutive_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "next_attempt_at": { + "name": "next_attempt_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_started_at": { + "name": "last_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_complete_listing_at": { + "name": "last_complete_listing_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_listed_count": { + "name": "last_listed_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "member_synced_through": { + "name": "member_synced_through", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "change_cursor": { + "name": "change_cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listing_checkpoint": { + "name": "listing_checkpoint", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "suspended_at": { + "name": "suspended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kcm_organization_id_idx": { + "name": "kcm_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcm_connector_credential_unique": { + "name": "kcm_connector_credential_unique", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcm_connector_queue_idx": { + "name": "kcm_connector_queue_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_attempt_at", + "isExpression": false, + "asc": true, + "nulls": "first" + }, + { + "expression": "last_started_at", + "isExpression": false, + "asc": true, + "nulls": "first" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcm_credential_idx": { + "name": "kcm_credential_idx", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_member_workspace_id_workspace_id_fk": { + "name": "knowledge_connector_member_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_connector_member", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_connector_member_organization_id_organization_id_fk": { + "name": "knowledge_connector_member_organization_id_organization_id_fk", + "tableFrom": "knowledge_connector_member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_connector_member_connector_id_knowledge_connector_id_fk": { + "name": "knowledge_connector_member_connector_id_knowledge_connector_id_fk", + "tableFrom": "knowledge_connector_member", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_connector_member_credential_id_credential_id_fk": { + "name": "knowledge_connector_member_credential_id_credential_id_fk", + "tableFrom": "knowledge_connector_member", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kcm_owner_check": { + "name": "kcm_owner_check", + "value": "num_nonnulls(\"knowledge_connector_member\".\"workspace_id\", \"knowledge_connector_member\".\"organization_id\") = 1" + }, + "kcm_status_check": { + "name": "kcm_status_check", + "value": "\"knowledge_connector_member\".\"status\" IN ('active', 'suspended', 'disabled')" + }, + "kcm_subject_token_shape_check": { + "name": "kcm_subject_token_shape_check", + "value": "\"knowledge_connector_member\".\"subject_token\" ~ '^s:[^:]+:[^:]+:.+$'" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_connector_member_sync_log": { + "name": "knowledge_connector_member_sync_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "members_claimed": { + "name": "members_claimed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "members_completed": { + "name": "members_completed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "members_incomplete": { + "name": "members_incomplete", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "members_failed": { + "name": "members_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_listed": { + "name": "docs_listed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_added": { + "name": "docs_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_updated": { + "name": "docs_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_unchanged": { + "name": "docs_unchanged", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_hydrated_once": { + "name": "docs_hydrated_once", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "observations_added": { + "name": "observations_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "observations_removed": { + "name": "observations_removed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_tombstoned": { + "name": "docs_tombstoned", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_resurrected": { + "name": "docs_resurrected", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_purged": { + "name": "docs_purged", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "credentials_audited": { + "name": "credentials_audited", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kcmsl_connector_started_at_idx": { + "name": "kcmsl_connector_started_at_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"started_at\" DESC", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcmsl_started_at_partial_idx": { + "name": "kcmsl_started_at_partial_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector_member_sync_log\".\"status\" = 'started'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_member_sync_log_connector_id_knowledge_connector_id_fk": { + "name": "knowledge_connector_member_sync_log_connector_id_knowledge_connector_id_fk", + "tableFrom": "knowledge_connector_member_sync_log", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kcmsl_status_check": { + "name": "kcmsl_status_check", + "value": "\"knowledge_connector_member_sync_log\".\"status\" IN ('started', 'partial', 'completed', 'failed')" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_connector_permission_grant": { + "name": "knowledge_connector_permission_grant", + "schema": "", + "columns": { + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "group_key": { + "name": "group_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subject_token": { + "name": "subject_token", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "kcpg_subject_idx": { + "name": "kcpg_subject_idx", + "columns": [ + { + "expression": "subject_token", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "group_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "kcpg_snapshot_fk": { + "name": "kcpg_snapshot_fk", + "tableFrom": "knowledge_connector_permission_grant", + "tableTo": "knowledge_connector_permission_snapshot", + "columnsFrom": ["connector_id"], + "columnsTo": ["connector_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "kcpg_pk": { + "name": "kcpg_pk", + "columns": ["connector_id", "group_key", "subject_token"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kcpg_group_check": { + "name": "kcpg_group_check", + "value": "length(\"knowledge_connector_permission_grant\".\"group_key\") BETWEEN 1 AND 255" + }, + "kcpg_subject_check": { + "name": "kcpg_subject_check", + "value": "\"knowledge_connector_permission_grant\".\"subject_token\" ~ '^u:[^[:space:]A-Z]+@[^[:space:]A-Z]+$'" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_connector_permission_snapshot": { + "name": "knowledge_connector_permission_snapshot", + "schema": "", + "columns": { + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "kcps_connector_fk": { + "name": "kcps_connector_fk", + "tableFrom": "knowledge_connector_permission_snapshot", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kcps_revision_check": { + "name": "kcps_revision_check", + "value": "\"knowledge_connector_permission_snapshot\".\"revision\" > 0" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_connector_sync_log": { + "name": "knowledge_connector_sync_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "docs_added": { + "name": "docs_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_updated": { + "name": "docs_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_deleted": { + "name": "docs_deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_unchanged": { + "name": "docs_unchanged", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_skipped": { + "name": "docs_skipped", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_failed": { + "name": "docs_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "listed_count": { + "name": "listed_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kcsl_connector_started_at_idx": { + "name": "kcsl_connector_started_at_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"started_at\" DESC", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcsl_started_at_partial_idx": { + "name": "kcsl_started_at_partial_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector_sync_log\".\"status\" = 'started'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_sync_log_connector_id_knowledge_connector_id_fk": { + "name": "knowledge_connector_sync_log_connector_id_knowledge_connector_id_fk", + "tableFrom": "knowledge_connector_sync_log", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_document_observation": { + "name": "knowledge_document_observation", + "schema": "", + "columns": { + "document_id": { + "name": "document_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "member_id": { + "name": "member_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "kdo_member_idx": { + "name": "kdo_member_idx", + "columns": [ + { + "expression": "member_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_document_observation_document_id_document_id_fk": { + "name": "knowledge_document_observation_document_id_document_id_fk", + "tableFrom": "knowledge_document_observation", + "tableTo": "document", + "columnsFrom": ["document_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_document_observation_member_id_knowledge_connector_member_id_fk": { + "name": "knowledge_document_observation_member_id_knowledge_connector_member_id_fk", + "tableFrom": "knowledge_document_observation", + "tableTo": "knowledge_connector_member", + "columnsFrom": ["member_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "knowledge_document_observation_document_id_member_id_pk": { + "name": "knowledge_document_observation_document_id_member_id_pk", + "columns": ["document_id", "member_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_external_directory": { + "name": "knowledge_external_directory", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tenant_id": { + "name": "tenant_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sync_lock_token": { + "name": "sync_lock_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sync_lock_lease_at": { + "name": "sync_lock_lease_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_started_at": { + "name": "last_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_complete_sync_at": { + "name": "last_complete_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ked_organization_id_idx": { + "name": "ked_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ked_workspace_identity_unique": { + "name": "ked_workspace_identity_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ked_organization_identity_unique": { + "name": "ked_organization_identity_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_external_directory_workspace_id_workspace_id_fk": { + "name": "knowledge_external_directory_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_external_directory", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_external_directory_organization_id_organization_id_fk": { + "name": "knowledge_external_directory_organization_id_organization_id_fk", + "tableFrom": "knowledge_external_directory", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "ked_owner_check": { + "name": "ked_owner_check", + "value": "num_nonnulls(\"knowledge_external_directory\".\"workspace_id\", \"knowledge_external_directory\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_external_group": { + "name": "knowledge_external_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tenant_id": { + "name": "tenant_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_group_id": { + "name": "external_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_synced_at": { + "name": "last_synced_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "keg_organization_id_idx": { + "name": "keg_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keg_organization_identity_unique": { + "name": "keg_organization_identity_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keg_organization_synced_idx": { + "name": "keg_organization_synced_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_synced_at", + "isExpression": false, + "asc": true, + "nulls": "first" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keg_identity_unique": { + "name": "keg_identity_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keg_workspace_synced_idx": { + "name": "keg_workspace_synced_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_synced_at", + "isExpression": false, + "asc": true, + "nulls": "first" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_external_group_organization_id_organization_id_fk": { + "name": "knowledge_external_group_organization_id_organization_id_fk", + "tableFrom": "knowledge_external_group", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "keg_workspace_fk": { + "name": "keg_workspace_fk", + "tableFrom": "knowledge_external_group", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "keg_owner_check": { + "name": "keg_owner_check", + "value": "num_nonnulls(\"knowledge_external_group\".\"workspace_id\", \"knowledge_external_group\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_external_group_member": { + "name": "knowledge_external_group_member", + "schema": "", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subject_token": { + "name": "subject_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kegm_subject_token_idx": { + "name": "kegm_subject_token_idx", + "columns": [ + { + "expression": "subject_token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "kegm_group_fk": { + "name": "kegm_group_fk", + "tableFrom": "knowledge_external_group_member", + "tableTo": "knowledge_external_group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "knowledge_external_group_member_group_id_subject_token_pk": { + "name": "knowledge_external_group_member_group_id_subject_token_pk", + "columns": ["group_id", "subject_token"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_server_oauth": { + "name": "mcp_server_oauth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "mcp_server_id": { + "name": "mcp_server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_information": { + "name": "client_information", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokens": { + "name": "tokens", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "code_verifier": { + "name": "code_verifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state_created_at": { + "name": "state_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_refreshed_at": { + "name": "last_refreshed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "mcp_server_oauth_server_unique": { + "name": "mcp_server_oauth_server_unique", + "columns": [ + { + "expression": "mcp_server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_server_oauth_state_idx": { + "name": "mcp_server_oauth_state_idx", + "columns": [ + { + "expression": "state", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_server_oauth_mcp_server_id_mcp_servers_id_fk": { + "name": "mcp_server_oauth_mcp_server_id_mcp_servers_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "mcp_servers", + "columnsFrom": ["mcp_server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_server_oauth_user_id_user_id_fk": { + "name": "mcp_server_oauth_user_id_user_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "mcp_server_oauth_workspace_id_workspace_id_fk": { + "name": "mcp_server_oauth_workspace_id_workspace_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_server_oauth_organization_id_organization_id_fk": { + "name": "mcp_server_oauth_organization_id_organization_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "mcp_server_oauth_owner_check": { + "name": "mcp_server_oauth_owner_check", + "value": "num_nonnulls(\"mcp_server_oauth\".\"workspace_id\", \"mcp_server_oauth\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.mcp_servers": { + "name": "mcp_servers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_group_id": { + "name": "credential_group_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "managed_connector_id": { + "name": "managed_connector_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_config_version": { + "name": "oauth_config_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transport": { + "name": "transport", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'headers'" + }, + "oauth_client_id": { + "name": "oauth_client_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_client_secret": { + "name": "oauth_client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "headers": { + "name": "headers", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "timeout": { + "name": "timeout", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 30000 + }, + "retries": { + "name": "retries", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_connected": { + "name": "last_connected", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "connection_status": { + "name": "connection_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'disconnected'" + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status_config": { + "name": "status_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "tool_count": { + "name": "tool_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_tools_refresh": { + "name": "last_tools_refresh", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_requests": { + "name": "total_requests", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "mcp_servers_organization_id_idx": { + "name": "mcp_servers_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_workspace_enabled_idx": { + "name": "mcp_servers_workspace_enabled_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_credential_group_idx": { + "name": "mcp_servers_credential_group_idx", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_credential_group_managed_connector_unique": { + "name": "mcp_servers_credential_group_managed_connector_unique", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "managed_connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"mcp_servers\".\"credential_group_id\" IS NOT NULL AND \"mcp_servers\".\"managed_connector_id\" IS NOT NULL AND \"mcp_servers\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_workspace_deleted_partial_idx": { + "name": "mcp_servers_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"mcp_servers\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_servers_workspace_id_workspace_id_fk": { + "name": "mcp_servers_workspace_id_workspace_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_servers_organization_id_organization_id_fk": { + "name": "mcp_servers_organization_id_organization_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_servers_credential_group_id_credential_group_id_fk": { + "name": "mcp_servers_credential_group_id_credential_group_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "credential_group", + "columnsFrom": ["credential_group_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "mcp_servers_created_by_user_id_fk": { + "name": "mcp_servers_created_by_user_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "mcp_servers_owner_check": { + "name": "mcp_servers_owner_check", + "value": "num_nonnulls(\"mcp_servers\".\"workspace_id\", \"mcp_servers\".\"organization_id\") = 1" + }, + "mcp_servers_organization_managed_check": { + "name": "mcp_servers_organization_managed_check", + "value": "\"mcp_servers\".\"organization_id\" IS NULL OR \"mcp_servers\".\"credential_group_id\" IS NOT NULL" + }, + "mcp_servers_credential_group_managed_connector_check": { + "name": "mcp_servers_credential_group_managed_connector_check", + "value": "\"mcp_servers\".\"credential_group_id\" IS NULL OR \"mcp_servers\".\"managed_connector_id\" IS NOT NULL" + }, + "mcp_servers_managed_connector_oauth_check": { + "name": "mcp_servers_managed_connector_oauth_check", + "value": "\"mcp_servers\".\"managed_connector_id\" IS NULL OR \"mcp_servers\".\"auth_type\" = 'oauth'" + } + }, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "member_user_id_unique": { + "name": "member_user_id_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "member_organization_id_idx": { + "name": "member_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory": { + "name": "memory", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "memory_key_idx": { + "name": "memory_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_idx": { + "name": "memory_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_key_idx": { + "name": "memory_workspace_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_deleted_partial_idx": { + "name": "memory_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"memory\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "memory_workspace_id_workspace_id_fk": { + "name": "memory_workspace_id_workspace_id_fk", + "tableFrom": "memory", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory_secret_provenance": { + "name": "memory_secret_provenance", + "schema": "", + "columns": { + "memory_id": { + "name": "memory_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "memory_secret_provenance_memory_id_memory_id_fk": { + "name": "memory_secret_provenance_memory_id_memory_id_fk", + "tableFrom": "memory_secret_provenance", + "tableTo": "memory", + "columnsFrom": ["memory_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "memory_secret_provenance_status_check": { + "name": "memory_secret_provenance_status_check", + "value": "\"memory_secret_provenance\".\"status\" IN ('exact', 'unknown')" + } + }, + "isRLSEnabled": false + }, + "public.mothership_inbox_allowed_sender": { + "name": "mothership_inbox_allowed_sender", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "added_by": { + "name": "added_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "inbox_sender_ws_email_idx": { + "name": "inbox_sender_ws_email_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_inbox_allowed_sender_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_allowed_sender_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_allowed_sender", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mothership_inbox_allowed_sender_added_by_user_id_fk": { + "name": "mothership_inbox_allowed_sender_added_by_user_id_fk", + "tableFrom": "mothership_inbox_allowed_sender", + "tableTo": "user", + "columnsFrom": ["added_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_task": { + "name": "mothership_inbox_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_email": { + "name": "from_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_name": { + "name": "from_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body_preview": { + "name": "body_preview", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body_text": { + "name": "body_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body_html": { + "name": "body_html", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_message_id": { + "name": "email_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "in_reply_to": { + "name": "in_reply_to", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "response_message_id": { + "name": "response_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agentmail_message_id": { + "name": "agentmail_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'received'" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "trigger_job_id": { + "name": "trigger_job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result_summary": { + "name": "result_summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rejection_reason": { + "name": "rejection_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "has_attachments": { + "name": "has_attachments", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cc_recipients": { + "name": "cc_recipients", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "inbox_task_ws_created_at_idx": { + "name": "inbox_task_ws_created_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_ws_status_idx": { + "name": "inbox_task_ws_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_response_msg_id_idx": { + "name": "inbox_task_response_msg_id_idx", + "columns": [ + { + "expression": "response_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_email_msg_id_idx": { + "name": "inbox_task_email_msg_id_idx", + "columns": [ + { + "expression": "email_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_inbox_task_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_task_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_task", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mothership_inbox_task_chat_id_copilot_chats_id_fk": { + "name": "mothership_inbox_task_chat_id_copilot_chats_id_fk", + "tableFrom": "mothership_inbox_task", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_webhook": { + "name": "mothership_inbox_webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "webhook_id": { + "name": "webhook_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "mothership_inbox_webhook_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_webhook_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_webhook", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mothership_inbox_webhook_workspace_id_unique": { + "name": "mothership_inbox_webhook_workspace_id_unique", + "nullsNotDistinct": false, + "columns": ["workspace_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_settings": { + "name": "mothership_settings", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "mcp_tool_refs": { + "name": "mcp_tool_refs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "custom_tool_refs": { + "name": "custom_tool_refs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "skill_refs": { + "name": "skill_refs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "mothership_settings_workspace_id_workspace_id_fk": { + "name": "mothership_settings_workspace_id_workspace_id_fk", + "tableFrom": "mothership_settings", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_access_token": { + "name": "oauth_access_token", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_id": { + "name": "refresh_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "resource": { + "name": "resource", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "oauth_access_token_client_id_idx": { + "name": "oauth_access_token_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_session_id_idx": { + "name": "oauth_access_token_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_refresh_id_idx": { + "name": "oauth_access_token_refresh_id_idx", + "columns": [ + { + "expression": "refresh_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_user_client_idx": { + "name": "oauth_access_token_user_client_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_expires_at_idx": { + "name": "oauth_access_token_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_access_token_client_id_oauth_client_client_id_fk": { + "name": "oauth_access_token_client_id_oauth_client_client_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "oauth_client", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_access_token_session_id_session_id_fk": { + "name": "oauth_access_token_session_id_session_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "session", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauth_access_token_user_id_user_id_fk": { + "name": "oauth_access_token_user_id_user_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_access_token_refresh_id_oauth_refresh_token_id_fk": { + "name": "oauth_access_token_refresh_id_oauth_refresh_token_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "oauth_refresh_token", + "columnsFrom": ["refresh_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_access_token_token_unique": { + "name": "oauth_access_token_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": { + "oauth_access_token_search_resource_check": { + "name": "oauth_access_token_search_resource_check", + "value": "NOT ('search:read' = ANY(\"oauth_access_token\".\"scopes\")) OR \"oauth_access_token\".\"resource\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.oauth_client": { + "name": "oauth_client", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "skip_consent": { + "name": "skip_consent", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "enable_end_session": { + "name": "enable_end_session", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subject_type": { + "name": "subject_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contacts": { + "name": "contacts", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "tos": { + "name": "tos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "policy": { + "name": "policy", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "software_id": { + "name": "software_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "software_version": { + "name": "software_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "software_statement": { + "name": "software_statement", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uris": { + "name": "redirect_uris", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "post_logout_redirect_uris": { + "name": "post_logout_redirect_uris", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "token_endpoint_auth_method": { + "name": "token_endpoint_auth_method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "grant_types": { + "name": "grant_types", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "response_types": { + "name": "response_types", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "public": { + "name": "public", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "require_pkce": { + "name": "require_pkce", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "oauth_client_user_id_idx": { + "name": "oauth_client_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_client_user_id_user_id_fk": { + "name": "oauth_client_user_id_user_id_fk", + "tableFrom": "oauth_client", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_client_client_id_unique": { + "name": "oauth_client_client_id_unique", + "nullsNotDistinct": false, + "columns": ["client_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_consent": { + "name": "oauth_consent", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_consent_client_id_idx": { + "name": "oauth_consent_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_consent_client_id_oauth_client_client_id_fk": { + "name": "oauth_consent_client_id_oauth_client_client_id_fk", + "tableFrom": "oauth_consent", + "tableTo": "oauth_client", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_consent_user_id_user_id_fk": { + "name": "oauth_consent_user_id_user_id_fk", + "tableFrom": "oauth_consent", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_consent_user_client_reference_unique": { + "name": "oauth_consent_user_client_reference_unique", + "nullsNotDistinct": true, + "columns": ["user_id", "client_id", "reference_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_refresh_token": { + "name": "oauth_refresh_token", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "revoked": { + "name": "revoked", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "auth_time": { + "name": "auth_time", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "resource": { + "name": "resource", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "family_id": { + "name": "family_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_refresh_token_client_id_idx": { + "name": "oauth_refresh_token_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_refresh_token_session_id_idx": { + "name": "oauth_refresh_token_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_refresh_token_user_client_idx": { + "name": "oauth_refresh_token_user_client_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_refresh_token_expires_at_idx": { + "name": "oauth_refresh_token_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_refresh_token_client_id_oauth_client_client_id_fk": { + "name": "oauth_refresh_token_client_id_oauth_client_client_id_fk", + "tableFrom": "oauth_refresh_token", + "tableTo": "oauth_client", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_refresh_token_session_id_session_id_fk": { + "name": "oauth_refresh_token_session_id_session_id_fk", + "tableFrom": "oauth_refresh_token", + "tableTo": "session", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauth_refresh_token_user_id_user_id_fk": { + "name": "oauth_refresh_token_user_id_user_id_fk", + "tableFrom": "oauth_refresh_token", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_refresh_token_family_id_oauth_token_family_id_fk": { + "name": "oauth_refresh_token_family_id_oauth_token_family_id_fk", + "tableFrom": "oauth_refresh_token", + "tableTo": "oauth_token_family", + "columnsFrom": ["family_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_refresh_token_token_unique": { + "name": "oauth_refresh_token_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + }, + "oauth_refresh_token_family_generation_unique": { + "name": "oauth_refresh_token_family_generation_unique", + "nullsNotDistinct": false, + "columns": ["family_id", "generation"] + } + }, + "policies": {}, + "checkConstraints": { + "oauth_refresh_token_generation_check": { + "name": "oauth_refresh_token_generation_check", + "value": "\"oauth_refresh_token\".\"generation\" BETWEEN 0 AND 1000" + }, + "oauth_refresh_token_search_resource_check": { + "name": "oauth_refresh_token_search_resource_check", + "value": "NOT ('search:read' = ANY(\"oauth_refresh_token\".\"scopes\")) OR \"oauth_refresh_token\".\"resource\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.oauth_token_family": { + "name": "oauth_token_family", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "consent_id": { + "name": "consent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current_generation": { + "name": "current_generation", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_token_family_client_id_idx": { + "name": "oauth_token_family_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_token_family_session_id_idx": { + "name": "oauth_token_family_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_token_family_user_client_idx": { + "name": "oauth_token_family_user_client_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_token_family_consent_id_idx": { + "name": "oauth_token_family_consent_id_idx", + "columns": [ + { + "expression": "consent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_token_family_expires_at_idx": { + "name": "oauth_token_family_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_token_family_client_id_oauth_client_client_id_fk": { + "name": "oauth_token_family_client_id_oauth_client_client_id_fk", + "tableFrom": "oauth_token_family", + "tableTo": "oauth_client", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_token_family_session_id_session_id_fk": { + "name": "oauth_token_family_session_id_session_id_fk", + "tableFrom": "oauth_token_family", + "tableTo": "session", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauth_token_family_user_id_user_id_fk": { + "name": "oauth_token_family_user_id_user_id_fk", + "tableFrom": "oauth_token_family", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_token_family_consent_id_oauth_consent_id_fk": { + "name": "oauth_token_family_consent_id_oauth_consent_id_fk", + "tableFrom": "oauth_token_family", + "tableTo": "oauth_consent", + "columnsFrom": ["consent_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "oauth_token_family_generation_check": { + "name": "oauth_token_family_generation_check", + "value": "\"oauth_token_family\".\"current_generation\" BETWEEN 0 AND 1000" + } + }, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "session_policy_settings": { + "name": "session_policy_settings", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "security_policy_version": { + "name": "security_policy_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "whitelabel_settings": { + "name": "whitelabel_settings", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "data_retention_settings": { + "name": "data_retention_settings", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "org_usage_limit": { + "name": "org_usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "limit_notifications": { + "name": "limit_notifications", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "departed_member_usage": { + "name": "departed_member_usage", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_byok_keys": { + "name": "organization_byok_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "organization_byok_organization_provider_idx": { + "name": "organization_byok_organization_provider_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "organization_byok_keys_organization_id_organization_id_fk": { + "name": "organization_byok_keys_organization_id_organization_id_fk", + "tableFrom": "organization_byok_keys", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_byok_keys_created_by_user_id_fk": { + "name": "organization_byok_keys_created_by_user_id_fk", + "tableFrom": "organization_byok_keys", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_member_usage_limit": { + "name": "organization_member_usage_limit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_limit": { + "name": "usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "set_by": { + "name": "set_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "org_member_usage_limit_org_user_unique": { + "name": "org_member_usage_limit_org_user_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "org_member_usage_limit_organization_id_idx": { + "name": "org_member_usage_limit_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "organization_member_usage_limit_organization_id_organization_id_fk": { + "name": "organization_member_usage_limit_organization_id_organization_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_member_usage_limit_user_id_user_id_fk": { + "name": "organization_member_usage_limit_user_id_user_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_member_usage_limit_set_by_user_id_fk": { + "name": "organization_member_usage_limit_set_by_user_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "user", + "columnsFrom": ["set_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_search_integration": { + "name": "organization_search_integration", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connector_type": { + "name": "connector_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "approved": { + "name": "approved", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "organization_search_integration_organization_id_organization_id_fk": { + "name": "organization_search_integration_organization_id_organization_id_fk", + "tableFrom": "organization_search_integration", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "organization_search_integration_organization_id_connector_type_pk": { + "name": "organization_search_integration_organization_id_connector_type_pk", + "columns": ["organization_id", "connector_type"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_search_invocation": { + "name": "organization_search_invocation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surface": { + "name": "surface", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_types": { + "name": "source_types", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "result_count": { + "name": "result_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "organization_search_invocation_org_created_idx": { + "name": "organization_search_invocation_org_created_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "organization_search_invocation_user_idx": { + "name": "organization_search_invocation_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "organization_search_invocation_organization_id_organization_id_fk": { + "name": "organization_search_invocation_organization_id_organization_id_fk", + "tableFrom": "organization_search_invocation", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_search_invocation_user_id_user_id_fk": { + "name": "organization_search_invocation_user_id_user_id_fk", + "tableFrom": "organization_search_invocation", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "organization_search_invocation_result_count_bounds": { + "name": "organization_search_invocation_result_count_bounds", + "value": "\"organization_search_invocation\".\"result_count\" BETWEEN 0 AND 100" + }, + "organization_search_invocation_source_types_bounds": { + "name": "organization_search_invocation_source_types_bounds", + "value": "cardinality(\"organization_search_invocation\".\"source_types\") <= 100" + } + }, + "isRLSEnabled": false + }, + "public.outbox_event": { + "name": "outbox_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_attempts": { + "name": "max_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 10 + }, + "available_at": { + "name": "available_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "locked_at": { + "name": "locked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "outbox_event_status_available_idx": { + "name": "outbox_event_status_available_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "available_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "outbox_event_pending_type_available_idx": { + "name": "outbox_event_pending_type_available_idx", + "columns": [ + { + "expression": "event_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "available_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"outbox_event\".\"status\" = 'pending'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "outbox_event_locked_at_idx": { + "name": "outbox_event_locked_at_idx", + "columns": [ + { + "expression": "locked_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "outbox_event_type_created_idx": { + "name": "outbox_event_type_created_idx", + "columns": [ + { + "expression": "event_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.paused_executions": { + "name": "paused_executions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_snapshot": { + "name": "execution_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "pause_points": { + "name": "pause_points", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "total_pause_count": { + "name": "total_pause_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "resumed_count": { + "name": "resumed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "automatic_resume_retry_count": { + "name": "automatic_resume_retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'paused'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "paused_at": { + "name": "paused_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_resume_at": { + "name": "next_resume_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "paused_executions_workflow_id_idx": { + "name": "paused_executions_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_status_idx": { + "name": "paused_executions_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_execution_id_unique": { + "name": "paused_executions_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_next_resume_at_idx": { + "name": "paused_executions_next_resume_at_idx", + "columns": [ + { + "expression": "next_resume_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'paused' AND next_resume_at IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "paused_executions_workflow_id_workflow_id_fk": { + "name": "paused_executions_workflow_id_workflow_id_fk", + "tableFrom": "paused_executions", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pending_credential_draft": { + "name": "pending_credential_draft", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_config": { + "name": "oauth_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pending_draft_organization_id_idx": { + "name": "pending_draft_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pending_draft_user_provider_org": { + "name": "pending_draft_user_provider_org", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pending_draft_user_provider_ws": { + "name": "pending_draft_user_provider_ws", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pending_credential_draft_user_id_user_id_fk": { + "name": "pending_credential_draft_user_id_user_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_workspace_id_workspace_id_fk": { + "name": "pending_credential_draft_workspace_id_workspace_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_organization_id_organization_id_fk": { + "name": "pending_credential_draft_organization_id_organization_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_credential_id_credential_id_fk": { + "name": "pending_credential_draft_credential_id_credential_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "pending_draft_owner_check": { + "name": "pending_draft_owner_check", + "value": "num_nonnulls(\"pending_credential_draft\".\"workspace_id\", \"pending_credential_draft\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.permission_group": { + "name": "permission_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "membership_mode": { + "name": "membership_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'inherit'" + } + }, + "indexes": { + "permission_group_created_by_idx": { + "name": "permission_group_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_organization_name_unique": { + "name": "permission_group_organization_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_organization_default_unique": { + "name": "permission_group_organization_default_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_organization_id_organization_id_fk": { + "name": "permission_group_organization_id_organization_id_fk", + "tableFrom": "permission_group", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_created_by_user_id_fk": { + "name": "permission_group_created_by_user_id_fk", + "tableFrom": "permission_group", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group_member": { + "name": "permission_group_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "assigned_by": { + "name": "assigned_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permission_group_member_group_id_idx": { + "name": "permission_group_member_group_id_idx", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_member_group_user_unique": { + "name": "permission_group_member_group_user_unique", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_member_organization_user_idx": { + "name": "permission_group_member_organization_user_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_member_permission_group_id_permission_group_id_fk": { + "name": "permission_group_member_permission_group_id_permission_group_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_organization_id_organization_id_fk": { + "name": "permission_group_member_organization_id_organization_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_user_id_user_id_fk": { + "name": "permission_group_member_user_id_user_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_assigned_by_user_id_fk": { + "name": "permission_group_member_assigned_by_user_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "user", + "columnsFrom": ["assigned_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group_workspace": { + "name": "permission_group_workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permission_group_workspace_workspace_id_idx": { + "name": "permission_group_workspace_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_workspace_group_workspace_unique": { + "name": "permission_group_workspace_group_workspace_unique", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_workspace_permission_group_id_permission_group_id_fk": { + "name": "permission_group_workspace_permission_group_id_permission_group_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_workspace_workspace_id_workspace_id_fk": { + "name": "permission_group_workspace_workspace_id_workspace_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_workspace_organization_id_organization_id_fk": { + "name": "permission_group_workspace_organization_id_organization_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permissions": { + "name": "permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_type": { + "name": "permission_type", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permissions_user_id_idx": { + "name": "permissions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_entity_idx": { + "name": "permissions_entity_idx", + "columns": [ + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_type_idx": { + "name": "permissions_user_entity_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_permission_idx": { + "name": "permissions_user_entity_permission_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "permission_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_unique_constraint": { + "name": "permissions_unique_constraint", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permissions_user_id_user_id_fk": { + "name": "permissions_user_id_user_id_fk", + "tableFrom": "permissions", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pinned_item": { + "name": "pinned_item", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pinned_at": { + "name": "pinned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pinned_item_user_workspace_idx": { + "name": "pinned_item_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pinned_item_resource_idx": { + "name": "pinned_item_resource_idx", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pinned_item_user_resource_unique": { + "name": "pinned_item_user_resource_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pinned_item_user_id_user_id_fk": { + "name": "pinned_item_user_id_user_id_fk", + "tableFrom": "pinned_item", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pinned_item_workspace_id_workspace_id_fk": { + "name": "pinned_item_workspace_id_workspace_id_fk", + "tableFrom": "pinned_item", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.public_share": { + "name": "public_share", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "public_share_token_unique": { + "name": "public_share_token_unique", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_resource_unique": { + "name": "public_share_resource_unique", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_resource_id_idx": { + "name": "public_share_resource_id_idx", + "columns": [ + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_workspace_id_idx": { + "name": "public_share_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "public_share_workspace_id_workspace_id_fk": { + "name": "public_share_workspace_id_workspace_id_fk", + "tableFrom": "public_share", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "public_share_created_by_user_id_fk": { + "name": "public_share_created_by_user_id_fk", + "tableFrom": "public_share", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rate_limit_bucket": { + "name": "rate_limit_bucket", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "tokens": { + "name": "tokens", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "blocked_until": { + "name": "blocked_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity_state": { + "name": "capacity_state", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resource_policy": { + "name": "resource_policy", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "document": { + "name": "document", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "resource_policy_organization_id_idx": { + "name": "resource_policy_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resource_policy_resource_unique": { + "name": "resource_policy_resource_unique", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resource_policy_workspace_id_idx": { + "name": "resource_policy_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "resource_policy_workspace_id_workspace_id_fk": { + "name": "resource_policy_workspace_id_workspace_id_fk", + "tableFrom": "resource_policy", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "resource_policy_organization_id_organization_id_fk": { + "name": "resource_policy_organization_id_organization_id_fk", + "tableFrom": "resource_policy", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "resource_policy_created_by_user_id_fk": { + "name": "resource_policy_created_by_user_id_fk", + "tableFrom": "resource_policy", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "resource_policy_updated_by_user_id_fk": { + "name": "resource_policy_updated_by_user_id_fk", + "tableFrom": "resource_policy", + "tableTo": "user", + "columnsFrom": ["updated_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "resource_policy_owner_check": { + "name": "resource_policy_owner_check", + "value": "num_nonnulls(\"resource_policy\".\"workspace_id\", \"resource_policy\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.resume_queue": { + "name": "resume_queue", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "paused_execution_id": { + "name": "paused_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_execution_id": { + "name": "parent_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "new_execution_id": { + "name": "new_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "context_id": { + "name": "context_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resume_input": { + "name": "resume_input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "queued_at": { + "name": "queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "failure_reason": { + "name": "failure_reason", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "resume_queue_parent_status_idx": { + "name": "resume_queue_parent_status_idx", + "columns": [ + { + "expression": "parent_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resume_queue_new_execution_idx": { + "name": "resume_queue_new_execution_idx", + "columns": [ + { + "expression": "new_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "resume_queue_paused_execution_id_paused_executions_id_fk": { + "name": "resume_queue_paused_execution_id_paused_executions_id_fk", + "tableFrom": "resume_queue", + "tableTo": "paused_executions", + "columnsFrom": ["paused_execution_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sandbox_image": { + "name": "sandbox_image", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "spec_hash": { + "name": "spec_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "spec": { + "name": "spec", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "sandbox_image_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "image_ref": { + "name": "image_ref", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_image_id": { + "name": "provider_image_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_id": { + "name": "build_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "materialization_generation": { + "name": "materialization_generation", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_detail": { + "name": "error_detail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sandbox_image_provider_spec_unique": { + "name": "sandbox_image_provider_spec_unique", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "spec_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sandbox_image_status_idx": { + "name": "sandbox_image_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sandbox_image_last_used_idx": { + "name": "sandbox_image_last_used_idx", + "columns": [ + { + "expression": "last_used_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_connection": { + "name": "scim_connection", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "last_request_at": { + "name": "last_request_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "reconcile_lock_token": { + "name": "reconcile_lock_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reconcile_lease_at": { + "name": "reconcile_lease_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "reconciled_at": { + "name": "reconciled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_connection_organization_unique": { + "name": "scim_connection_organization_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_connection_reconcile_due_idx": { + "name": "scim_connection_reconcile_due_idx", + "columns": [ + { + "expression": "reconciled_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_connection_organization_id_organization_id_fk": { + "name": "scim_connection_organization_id_organization_id_fk", + "tableFrom": "scim_connection", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_connection_created_by_user_id_fk": { + "name": "scim_connection_created_by_user_id_fk", + "tableFrom": "scim_connection", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_credential": { + "name": "scim_credential", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_prefix": { + "name": "token_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_by": { + "name": "revoked_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_credential_token_hash_unique": { + "name": "scim_credential_token_hash_unique", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_credential_connection_idx": { + "name": "scim_credential_connection_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_credential_connection_id_scim_connection_id_fk": { + "name": "scim_credential_connection_id_scim_connection_id_fk", + "tableFrom": "scim_credential", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_credential_revoked_by_user_id_fk": { + "name": "scim_credential_revoked_by_user_id_fk", + "tableFrom": "scim_credential", + "tableTo": "user", + "columnsFrom": ["revoked_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "scim_credential_created_by_user_id_fk": { + "name": "scim_credential_created_by_user_id_fk", + "tableFrom": "scim_credential", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_group": { + "name": "scim_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name_key": { + "name": "display_name_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "order_key": { + "name": "order_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_group_connection_display_name_unique": { + "name": "scim_group_connection_display_name_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_connection_external_id_unique": { + "name": "scim_group_connection_external_id_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "external_id is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_connection_order_idx": { + "name": "scim_group_connection_order_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_group_connection_id_scim_connection_id_fk": { + "name": "scim_group_connection_id_scim_connection_id_fk", + "tableFrom": "scim_group", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_group_mapping": { + "name": "scim_group_mapping", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_kind": { + "name": "target_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission_type": { + "name": "permission_type", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'manual'" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_group_mapping_group_idx": { + "name": "scim_group_mapping_group_idx", + "columns": [ + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_mapping_permission_group_idx": { + "name": "scim_group_mapping_permission_group_idx", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_mapping_workspace_idx": { + "name": "scim_group_mapping_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_mapping_group_target_unique": { + "name": "scim_group_mapping_group_target_unique", + "columns": [ + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"permission_group_id\", \"workspace_id\", \"role\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_group_mapping_group_id_scim_group_id_fk": { + "name": "scim_group_mapping_group_id_scim_group_id_fk", + "tableFrom": "scim_group_mapping", + "tableTo": "scim_group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_group_mapping_permission_group_id_permission_group_id_fk": { + "name": "scim_group_mapping_permission_group_id_permission_group_id_fk", + "tableFrom": "scim_group_mapping", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_group_mapping_workspace_id_workspace_id_fk": { + "name": "scim_group_mapping_workspace_id_workspace_id_fk", + "tableFrom": "scim_group_mapping", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_group_mapping_created_by_user_id_fk": { + "name": "scim_group_mapping_created_by_user_id_fk", + "tableFrom": "scim_group_mapping", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "scim_group_mapping_target_shape": { + "name": "scim_group_mapping_target_shape", + "value": "(\n (\"scim_group_mapping\".\"target_kind\" = 'permission_group' AND \"scim_group_mapping\".\"permission_group_id\" IS NOT NULL AND \"scim_group_mapping\".\"workspace_id\" IS NULL AND \"scim_group_mapping\".\"permission_type\" IS NULL AND \"scim_group_mapping\".\"role\" IS NULL)\n OR (\"scim_group_mapping\".\"target_kind\" = 'workspace' AND \"scim_group_mapping\".\"workspace_id\" IS NOT NULL AND \"scim_group_mapping\".\"permission_type\" IS NOT NULL AND \"scim_group_mapping\".\"permission_group_id\" IS NULL AND \"scim_group_mapping\".\"role\" IS NULL)\n OR (\"scim_group_mapping\".\"target_kind\" = 'org_role' AND \"scim_group_mapping\".\"role\" IS NOT NULL AND \"scim_group_mapping\".\"permission_group_id\" IS NULL AND \"scim_group_mapping\".\"workspace_id\" IS NULL AND \"scim_group_mapping\".\"permission_type\" IS NULL)\n )" + } + }, + "isRLSEnabled": false + }, + "public.scim_group_member": { + "name": "scim_group_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scim_user_id": { + "name": "scim_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_group_member_group_user_unique": { + "name": "scim_group_member_group_user_unique", + "columns": [ + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scim_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_member_scim_user_idx": { + "name": "scim_group_member_scim_user_idx", + "columns": [ + { + "expression": "scim_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_group_member_group_id_scim_group_id_fk": { + "name": "scim_group_member_group_id_scim_group_id_fk", + "tableFrom": "scim_group_member", + "tableTo": "scim_group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_group_member_scim_user_id_scim_user_id_fk": { + "name": "scim_group_member_scim_user_id_scim_user_id_fk", + "tableFrom": "scim_group_member", + "tableTo": "scim_user", + "columnsFrom": ["scim_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_projection_grant": { + "name": "scim_projection_grant", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scim_user_id": { + "name": "scim_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_kind": { + "name": "target_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_type": { + "name": "permission_type", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "baseline_permission": { + "name": "baseline_permission", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'directory'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_projection_grant_user_target_unique": { + "name": "scim_projection_grant_user_target_unique", + "columns": [ + { + "expression": "scim_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_projection_grant_connection_idx": { + "name": "scim_projection_grant_connection_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_projection_grant_connection_id_scim_connection_id_fk": { + "name": "scim_projection_grant_connection_id_scim_connection_id_fk", + "tableFrom": "scim_projection_grant", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_projection_grant_scim_user_id_scim_user_id_fk": { + "name": "scim_projection_grant_scim_user_id_scim_user_id_fk", + "tableFrom": "scim_projection_grant", + "tableTo": "scim_user", + "columnsFrom": ["scim_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_request_log": { + "name": "scim_request_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "scim_type": { + "name": "scim_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "detail": { + "name": "detail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_request_log_connection_created_idx": { + "name": "scim_request_log_connection_created_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_request_log_connection_id_scim_connection_id_fk": { + "name": "scim_request_log_connection_id_scim_connection_id_fk", + "tableFrom": "scim_request_log", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_user": { + "name": "scim_user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_name": { + "name": "user_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "attributes": { + "name": "attributes", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "order_key": { + "name": "order_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_user_connection_user_unique": { + "name": "scim_user_connection_user_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_connection_user_name_unique": { + "name": "scim_user_connection_user_name_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_connection_external_id_unique": { + "name": "scim_user_connection_external_id_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "external_id is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_connection_order_idx": { + "name": "scim_user_connection_order_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_user_idx": { + "name": "scim_user_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_user_connection_id_scim_connection_id_fk": { + "name": "scim_user_connection_id_scim_connection_id_fk", + "tableFrom": "scim_user", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_user_user_id_user_id_fk": { + "name": "scim_user_user_id_user_id_fk", + "tableFrom": "scim_user", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_user_tombstone": { + "name": "scim_user_tombstone", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_user_tombstone_connection_external_id_unique": { + "name": "scim_user_tombstone_connection_external_id_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_tombstone_user_idx": { + "name": "scim_user_tombstone_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_user_tombstone_connection_id_scim_connection_id_fk": { + "name": "scim_user_tombstone_connection_id_scim_connection_id_fk", + "tableFrom": "scim_user_tombstone", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_user_tombstone_user_id_user_id_fk": { + "name": "scim_user_tombstone_user_id_user_id_fk", + "tableFrom": "scim_user_tombstone", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.secret_usage": { + "name": "secret_usage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret_name": { + "name": "secret_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret_scope": { + "name": "secret_scope", + "type": "secret_usage_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "secret_owner_user_id": { + "name": "secret_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "source": { + "name": "source", + "type": "secret_usage_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "actor_user_id": { + "name": "actor_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "usage_date": { + "name": "usage_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "use_count": { + "name": "use_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "last_execution_id": { + "name": "last_execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_trigger": { + "name": "last_trigger", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "secret_usage_bucket_unique": { + "name": "secret_usage_bucket_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_name", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_scope", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "usage_date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "secret_usage_secret_recent_idx": { + "name": "secret_usage_secret_recent_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_name", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_scope", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_used_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "secret_usage_workspace_id_workspace_id_fk": { + "name": "secret_usage_workspace_id_workspace_id_fk", + "tableFrom": "secret_usage", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_user_id_idx": { + "name": "session_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_active_organization_id_organization_id_fk": { + "name": "session_active_organization_id_organization_id_fk", + "tableFrom": "session", + "tableTo": "organization", + "columnsFrom": ["active_organization_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'system'" + }, + "auto_connect": { + "name": "auto_connect", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "email_preferences": { + "name": "email_preferences", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "billing_usage_notifications_enabled": { + "name": "billing_usage_notifications_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "show_training_controls": { + "name": "show_training_controls", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "super_user_mode_enabled": { + "name": "super_user_mode_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "mothership_environment": { + "name": "mothership_environment", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "error_notifications_enabled": { + "name": "error_notifications_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "snap_to_grid_size": { + "name": "snap_to_grid_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "show_action_bar": { + "name": "show_action_bar", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auto_focus_on_click": { + "name": "auto_focus_on_click", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "copilot_enabled_models": { + "name": "copilot_enabled_models", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "copilot_auto_allowed_tools": { + "name": "copilot_auto_allowed_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "last_active_workspace_id": { + "name": "last_active_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "settings_user_id_user_id_fk": { + "name": "settings_user_id_user_id_fk", + "tableFrom": "settings", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "settings_user_id_unique": { + "name": "settings_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sim_trigger_state": { + "name": "sim_trigger_state", + "schema": "", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope_key": { + "name": "scope_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "last_fired_at": { + "name": "last_fired_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sim_trigger_state_workflow_id_workflow_id_fk": { + "name": "sim_trigger_state_workflow_id_workflow_id_fk", + "tableFrom": "sim_trigger_state", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "sim_trigger_state_workflow_id_block_id_scope_key_pk": { + "name": "sim_trigger_state_workflow_id_block_id_scope_key_pk", + "columns": ["workflow_id", "block_id", "scope_key"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.skill": { + "name": "skill", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "skill_workspace_name_unique": { + "name": "skill_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "skill_workspace_id_workspace_id_fk": { + "name": "skill_workspace_id_workspace_id_fk", + "tableFrom": "skill", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "skill_user_id_user_id_fk": { + "name": "skill_user_id_user_id_fk", + "tableFrom": "skill", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.skill_member": { + "name": "skill_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "skill_id": { + "name": "skill_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "skill_member_user_id_idx": { + "name": "skill_member_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "skill_member_unique": { + "name": "skill_member_unique", + "columns": [ + { + "expression": "skill_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "skill_member_skill_id_skill_id_fk": { + "name": "skill_member_skill_id_skill_id_fk", + "tableFrom": "skill_member", + "tableTo": "skill", + "columnsFrom": ["skill_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "skill_member_user_id_user_id_fk": { + "name": "skill_member_user_id_user_id_fk", + "tableFrom": "skill_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "skill_member_invited_by_user_id_fk": { + "name": "skill_member_invited_by_user_id_fk", + "tableFrom": "skill_member", + "tableTo": "user", + "columnsFrom": ["invited_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_app": { + "name": "slack_app", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_client_secret": { + "name": "encrypted_client_secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_signing_secret": { + "name": "encrypted_signing_secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "slack_app_organization_id_organization_id_fk": { + "name": "slack_app_organization_id_organization_id_fk", + "tableFrom": "slack_app", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "slack_app_owner_check": { + "name": "slack_app_owner_check", + "value": "(\"slack_app\".\"kind\" = 'custom' AND \"slack_app\".\"organization_id\" IS NOT NULL) OR (\"slack_app\".\"kind\" = 'shared' AND \"slack_app\".\"organization_id\" IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.slack_search_installation": { + "name": "slack_search_installation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_app_id": { + "name": "slack_app_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "team_name": { + "name": "team_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bot_user_id": { + "name": "bot_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enterprise_id": { + "name": "enterprise_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "credential_version": { + "name": "credential_version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_outcome": { + "name": "last_outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_event_at": { + "name": "last_event_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_search_installation_organization_idx": { + "name": "slack_search_installation_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_installation_credential_unique": { + "name": "slack_search_installation_credential_unique", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_installation_app_team_unique": { + "name": "slack_search_installation_app_team_unique", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "team_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_installation_active_team_unique": { + "name": "slack_search_installation_active_team_unique", + "columns": [ + { + "expression": "team_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"slack_search_installation\".\"enabled\" = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_search_installation_organization_id_organization_id_fk": { + "name": "slack_search_installation_organization_id_organization_id_fk", + "tableFrom": "slack_search_installation", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "slack_search_installation_credential_id_credential_id_fk": { + "name": "slack_search_installation_credential_id_credential_id_fk", + "tableFrom": "slack_search_installation", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "slack_search_installation_slack_app_id_slack_app_id_fk": { + "name": "slack_search_installation_slack_app_id_slack_app_id_fk", + "tableFrom": "slack_search_installation", + "tableTo": "slack_app", + "columnsFrom": ["slack_app_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_search_turn": { + "name": "slack_search_turn", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "ordinal": { + "name": "ordinal", + "type": "integer", + "primaryKey": false, + "notNull": true, + "identity": { + "type": "always", + "name": "slack_search_turn_ordinal_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "2147483647", + "cache": "1", + "cycle": false + } + }, + "installation_id": { + "name": "installation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conversation_key": { + "name": "conversation_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "lease_id": { + "name": "lease_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_search_turn_event_unique": { + "name": "slack_search_turn_event_unique", + "columns": [ + { + "expression": "installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_turn_pending_idx": { + "name": "slack_search_turn_pending_idx", + "columns": [ + { + "expression": "installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_turn_thread_idx": { + "name": "slack_search_turn_thread_idx", + "columns": [ + { + "expression": "conversation_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_turn_active_thread_unique": { + "name": "slack_search_turn_active_thread_unique", + "columns": [ + { + "expression": "conversation_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"slack_search_turn\".\"status\" = 'running'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_search_turn_installation_id_slack_search_installation_id_fk": { + "name": "slack_search_turn_installation_id_slack_search_installation_id_fk", + "tableFrom": "slack_search_turn", + "tableTo": "slack_search_installation", + "columnsFrom": ["installation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sso_domain": { + "name": "sso_domain", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "verification_token": { + "name": "verification_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "verified_at": { + "name": "verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sso_domain_organization_id_idx": { + "name": "sso_domain_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_domain_domain_idx": { + "name": "sso_domain_domain_idx", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_domain_org_domain_unique": { + "name": "sso_domain_org_domain_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_domain_verified_unique": { + "name": "sso_domain_verified_unique", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "status = 'verified'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sso_domain_organization_id_organization_id_fk": { + "name": "sso_domain_organization_id_organization_id_fk", + "tableFrom": "sso_domain", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sso_domain_created_by_user_id_fk": { + "name": "sso_domain_created_by_user_id_fk", + "tableFrom": "sso_domain", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sso_provider": { + "name": "sso_provider", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "oidc_config": { + "name": "oidc_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "saml_config": { + "name": "saml_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domain_verified": { + "name": "domain_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "jit_provisioning_enabled": { + "name": "jit_provisioning_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "sso_provider_provider_id_unique": { + "name": "sso_provider_provider_id_unique", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_org_domain_unique": { + "name": "sso_provider_org_domain_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(regexp_replace(btrim(\"domain\"), '^\\*\\.', ''))", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"sso_provider\".\"organization_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_domain_idx": { + "name": "sso_provider_domain_idx", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_user_id_idx": { + "name": "sso_provider_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_organization_id_idx": { + "name": "sso_provider_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sso_provider_user_id_user_id_fk": { + "name": "sso_provider_user_id_user_id_fk", + "tableFrom": "sso_provider", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sso_provider_organization_id_organization_id_fk": { + "name": "sso_provider_organization_id_organization_id_fk", + "tableFrom": "sso_provider", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.subscription": { + "name": "subscription", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_subscription_id": { + "name": "stripe_subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "period_start": { + "name": "period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "period_end": { + "name": "period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "cancel_at": { + "name": "cancel_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "canceled_at": { + "name": "canceled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "seats": { + "name": "seats", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trial_start": { + "name": "trial_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trial_end": { + "name": "trial_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "billing_interval": { + "name": "billing_interval", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_schedule_id": { + "name": "stripe_schedule_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "last_closed_period_start": { + "name": "last_closed_period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "subscription_reference_status_idx": { + "name": "subscription_reference_status_idx", + "columns": [ + { + "expression": "reference_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "subscription_cycle_close_lagging_idx": { + "name": "subscription_cycle_close_lagging_idx", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"subscription\".\"status\" in ('active', 'past_due') and \"subscription\".\"period_start\" is not null and (\"subscription\".\"last_closed_period_start\" is null or \"subscription\".\"last_closed_period_start\" < \"subscription\".\"period_start\")", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "check_enterprise_metadata": { + "name": "check_enterprise_metadata", + "value": "plan != 'enterprise' OR metadata IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.table_jobs": { + "name": "table_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "rows_processed": { + "name": "rows_processed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "table_jobs_one_active_per_table": { + "name": "table_jobs_one_active_per_table", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"table_jobs\".\"status\" = 'running' AND \"table_jobs\".\"type\" <> 'export'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_jobs_watchdog_idx": { + "name": "table_jobs_watchdog_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_jobs_table_started_idx": { + "name": "table_jobs_table_started_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_jobs_table_id_user_table_definitions_id_fk": { + "name": "table_jobs_table_id_user_table_definitions_id_fk", + "tableFrom": "table_jobs", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_jobs_workspace_id_workspace_id_fk": { + "name": "table_jobs_workspace_id_workspace_id_fk", + "tableFrom": "table_jobs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.table_row_executions": { + "name": "table_row_executions", + "schema": "", + "columns": { + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "row_id": { + "name": "row_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "job_id": { + "name": "job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "running_block_ids": { + "name": "running_block_ids", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "block_errors": { + "name": "block_errors", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "cancelled_at": { + "name": "cancelled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capability_governed_user_id": { + "name": "capability_governed_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enrichment_details": { + "name": "enrichment_details", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "table_row_executions_table_status_idx": { + "name": "table_row_executions_table_status_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"table_row_executions\".\"status\" IN ('queued', 'running', 'pending')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_row_executions_execution_id_idx": { + "name": "table_row_executions_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"table_row_executions\".\"execution_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_row_executions_table_group_idx": { + "name": "table_row_executions_table_group_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_row_executions_table_id_user_table_definitions_id_fk": { + "name": "table_row_executions_table_id_user_table_definitions_id_fk", + "tableFrom": "table_row_executions", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_row_executions_row_id_user_table_rows_id_fk": { + "name": "table_row_executions_row_id_user_table_rows_id_fk", + "tableFrom": "table_row_executions", + "tableTo": "user_table_rows", + "columnsFrom": ["row_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_row_executions_capability_governed_user_id_user_id_fk": { + "name": "table_row_executions_capability_governed_user_id_user_id_fk", + "tableFrom": "table_row_executions", + "tableTo": "user", + "columnsFrom": ["capability_governed_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "table_row_executions_row_id_group_id_pk": { + "name": "table_row_executions_row_id_group_id_pk", + "columns": ["row_id", "group_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.table_run_dispatches": { + "name": "table_run_dispatches", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mode": { + "name": "mode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope": { + "name": "scope", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "cursor": { + "name": "cursor", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "limit": { + "name": "limit", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "processed_count": { + "name": "processed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "is_manual_run": { + "name": "is_manual_run", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "triggered_by_user_id": { + "name": "triggered_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "capability_governed_user_id": { + "name": "capability_governed_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "heartbeat_at": { + "name": "heartbeat_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancelled_at": { + "name": "cancelled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "table_run_dispatches_active_idx": { + "name": "table_run_dispatches_active_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_run_dispatches_watchdog_idx": { + "name": "table_run_dispatches_watchdog_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "requested_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_run_dispatches_governed_active_idx": { + "name": "table_run_dispatches_governed_active_idx", + "columns": [ + { + "expression": "capability_governed_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"table_run_dispatches\".\"status\" IN ('pending', 'dispatching')", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_run_dispatches_table_id_user_table_definitions_id_fk": { + "name": "table_run_dispatches_table_id_user_table_definitions_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_run_dispatches_workspace_id_workspace_id_fk": { + "name": "table_run_dispatches_workspace_id_workspace_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_run_dispatches_triggered_by_user_id_user_id_fk": { + "name": "table_run_dispatches_triggered_by_user_id_user_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "user", + "columnsFrom": ["triggered_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "table_run_dispatches_capability_governed_user_id_user_id_fk": { + "name": "table_run_dispatches_capability_governed_user_id_user_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "user", + "columnsFrom": ["capability_governed_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.table_views": { + "name": "table_views", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "table_views_table_created_idx": { + "name": "table_views_table_created_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_views_workspace_created_idx": { + "name": "table_views_workspace_created_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_views_table_default_unique": { + "name": "table_views_table_default_unique", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_views_table_id_user_table_definitions_id_fk": { + "name": "table_views_table_id_user_table_definitions_id_fk", + "tableFrom": "table_views", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_views_workspace_id_workspace_id_fk": { + "name": "table_views_workspace_id_workspace_id_fk", + "tableFrom": "table_views", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_views_created_by_user_id_fk": { + "name": "table_views_created_by_user_id_fk", + "tableFrom": "table_views", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.upload_session": { + "name": "upload_session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "purpose": { + "name": "purpose", + "type": "upload_session_purpose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "method": { + "name": "method", + "type": "upload_session_method", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "storage_context": { + "name": "storage_context", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "final_key": { + "name": "final_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_provider": { + "name": "storage_provider", + "type": "upload_session_provider", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "provider_upload_id": { + "name": "provider_upload_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_object_version": { + "name": "provider_object_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_name": { + "name": "file_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "part_size": { + "name": "part_size", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "part_count": { + "name": "part_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "upload_session_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'uploading'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "processing_lease_id": { + "name": "processing_lease_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processing_lease_expires_at": { + "name": "processing_lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_file_id": { + "name": "completed_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "upload_session_token_hash_unique": { + "name": "upload_session_token_hash_unique", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "upload_session_final_key_unique": { + "name": "upload_session_final_key_unique", + "columns": [ + { + "expression": "final_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "upload_session_status_expires_at_idx": { + "name": "upload_session_status_expires_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.usage_log": { + "name": "usage_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "usage_log_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "usage_log_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_entity_type": { + "name": "billing_entity_type", + "type": "billing_entity_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "billing_entity_id": { + "name": "billing_entity_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_period_start": { + "name": "billing_period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "billing_period_end": { + "name": "billing_period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "usage_log_user_created_at_idx": { + "name": "usage_log_user_created_at_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_source_idx": { + "name": "usage_log_source_idx", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workspace_id_idx": { + "name": "usage_log_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workflow_id_idx": { + "name": "usage_log_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_event_key_unique": { + "name": "usage_log_event_key_unique", + "columns": [ + { + "expression": "event_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"usage_log\".\"event_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_billing_entity_period_idx": { + "name": "usage_log_billing_entity_period_idx", + "columns": [ + { + "expression": "billing_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_start", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_end", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"usage_log\".\"billing_entity_type\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_billing_period_cost_idx": { + "name": "usage_log_billing_period_cost_idx", + "columns": [ + { + "expression": "billing_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_start", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_end", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"usage_log\".\"billing_entity_type\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_billing_entity_created_at_cost_idx": { + "name": "usage_log_billing_entity_created_at_cost_idx", + "columns": [ + { + "expression": "billing_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"usage_log\".\"billing_entity_type\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workspace_created_at_idx": { + "name": "usage_log_workspace_created_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_execution_id_idx": { + "name": "usage_log_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "usage_log_user_id_user_id_fk": { + "name": "usage_log_user_id_user_id_fk", + "tableFrom": "usage_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "usage_log_workspace_id_workspace_id_fk": { + "name": "usage_log_workspace_id_workspace_id_fk", + "tableFrom": "usage_log", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "usage_log_workflow_id_workflow_id_fk": { + "name": "usage_log_workflow_id_workflow_id_fk", + "tableFrom": "usage_log", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "usage_log_billing_scope_all_or_none": { + "name": "usage_log_billing_scope_all_or_none", + "value": "(\n (\"usage_log\".\"billing_entity_type\" IS NULL AND \"usage_log\".\"billing_entity_id\" IS NULL AND \"usage_log\".\"billing_period_start\" IS NULL AND \"usage_log\".\"billing_period_end\" IS NULL)\n OR\n (\"usage_log\".\"billing_entity_type\" IS NOT NULL AND \"usage_log\".\"billing_entity_id\" IS NOT NULL AND \"usage_log\".\"billing_period_start\" IS NOT NULL AND \"usage_log\".\"billing_period_end\" IS NOT NULL AND \"usage_log\".\"billing_period_start\" < \"usage_log\".\"billing_period_end\")\n )" + } + }, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "normalized_email": { + "name": "normalized_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "suspended_at": { + "name": "suspended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "suspension_source": { + "name": "suspension_source", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "user_email_lower_idx": { + "name": "user_email_lower_idx", + "columns": [ + { + "expression": "lower(btrim(\"email\"))", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + }, + "user_normalized_email_unique": { + "name": "user_normalized_email_unique", + "nullsNotDistinct": false, + "columns": ["normalized_email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_stats": { + "name": "user_stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_manual_executions": { + "name": "total_manual_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_api_calls": { + "name": "total_api_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_webhook_triggers": { + "name": "total_webhook_triggers", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_scheduled_executions": { + "name": "total_scheduled_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_chat_executions": { + "name": "total_chat_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_executions": { + "name": "total_mcp_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_tokens_used": { + "name": "total_tokens_used", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_cost": { + "name": "total_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_usage_limit": { + "name": "current_usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'5'" + }, + "usage_limit_updated_at": { + "name": "usage_limit_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "current_period_cost": { + "name": "current_period_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_period_cost": { + "name": "last_period_cost", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "billed_overage_this_period": { + "name": "billed_overage_this_period", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "pro_period_cost_snapshot": { + "name": "pro_period_cost_snapshot", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "pro_period_cost_snapshot_at": { + "name": "pro_period_cost_snapshot_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "total_copilot_cost": { + "name": "total_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_period_copilot_cost": { + "name": "current_period_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_period_copilot_cost": { + "name": "last_period_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "total_copilot_tokens": { + "name": "total_copilot_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_copilot_calls": { + "name": "total_copilot_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_copilot_calls": { + "name": "total_mcp_copilot_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_copilot_cost": { + "name": "total_mcp_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_period_mcp_copilot_cost": { + "name": "current_period_mcp_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_active": { + "name": "last_active", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "billing_blocked": { + "name": "billing_blocked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "billing_blocked_reason": { + "name": "billing_blocked_reason", + "type": "billing_blocked_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "limit_notifications": { + "name": "limit_notifications", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": { + "user_stats_user_id_user_id_fk": { + "name": "user_stats_user_id_user_id_fk", + "tableFrom": "user_stats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_stats_user_id_unique": { + "name": "user_stats_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_table_definitions": { + "name": "user_table_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema": { + "name": "schema", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "max_rows": { + "name": "max_rows", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 10000 + }, + "row_count": { + "name": "row_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "rows_version": { + "name": "rows_version", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "schema_locked": { + "name": "schema_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "insert_locked": { + "name": "insert_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "update_locked": { + "name": "update_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "delete_locked": { + "name": "delete_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_table_def_workspace_id_idx": { + "name": "user_table_def_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_folder_id_idx": { + "name": "user_table_def_folder_id_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_workspace_name_unique": { + "name": "user_table_def_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"user_table_definitions\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_archived_at_idx": { + "name": "user_table_def_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_workspace_archived_partial_idx": { + "name": "user_table_def_workspace_archived_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"user_table_definitions\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_table_definitions_workspace_id_workspace_id_fk": { + "name": "user_table_definitions_workspace_id_workspace_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_definitions_folder_id_folder_id_fk": { + "name": "user_table_definitions_folder_id_folder_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "user_table_definitions_created_by_user_id_fk": { + "name": "user_table_definitions_created_by_user_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_table_row_secret_provenance": { + "name": "user_table_row_secret_provenance", + "schema": "", + "columns": { + "row_id": { + "name": "row_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content_updated_at": { + "name": "content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_table_row_secret_provenance_row_id_user_table_rows_id_fk": { + "name": "user_table_row_secret_provenance_row_id_user_table_rows_id_fk", + "tableFrom": "user_table_row_secret_provenance", + "tableTo": "user_table_rows", + "columnsFrom": ["row_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "user_table_row_secret_provenance_status_check": { + "name": "user_table_row_secret_provenance_status_check", + "value": "\"user_table_row_secret_provenance\".\"status\" IN ('exact', 'unknown')" + } + }, + "isRLSEnabled": false + }, + "public.user_table_rows": { + "name": "user_table_rows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "order_key": { + "name": "order_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "user_table_rows_tenant_data_gin_idx": { + "name": "user_table_rows_tenant_data_gin_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"data\" jsonb_path_ops", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "user_table_rows_workspace_table_idx": { + "name": "user_table_rows_workspace_table_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_position_idx": { + "name": "user_table_rows_table_position_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_order_key_idx": { + "name": "user_table_rows_table_order_key_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_created_id_idx": { + "name": "user_table_rows_table_created_id_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_id_id_idx": { + "name": "user_table_rows_table_id_id_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_table_rows_table_id_user_table_definitions_id_fk": { + "name": "user_table_rows_table_id_user_table_definitions_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_rows_workspace_id_workspace_id_fk": { + "name": "user_table_rows_workspace_id_workspace_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_rows_created_by_user_id_fk": { + "name": "user_table_rows_created_by_user_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "verification_expires_at_idx": { + "name": "verification_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.waitlist": { + "name": "waitlist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "waitlist_email_unique": { + "name": "waitlist_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhook": { + "name": "webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registration_status": { + "name": "registration_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registration_generation": { + "name": "registration_generation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "config_fingerprint": { + "name": "config_fingerprint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prepared_at": { + "name": "prepared_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "routing_key": { + "name": "routing_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_config": { + "name": "provider_config", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "failed_count": { + "name": "failed_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "path_deployment_unique": { + "name": "path_deployment_unique", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_workflow_deployment_idx": { + "name": "webhook_workflow_deployment_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_routing_key_active_idx": { + "name": "webhook_routing_key_active_idx", + "columns": [ + { + "expression": "routing_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"webhook\".\"archived_at\" IS NULL AND \"webhook\".\"routing_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_archived_at_partial_idx": { + "name": "webhook_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"webhook\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_webhook_on_provider_is_active_workflow_id_deploym_bdeed5468": { + "name": "idx_webhook_on_provider_is_active_workflow_id_deploym_bdeed5468", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_webhook_on_workflow_id_block_id_updated_at_desc": { + "name": "idx_webhook_on_workflow_id_block_id_updated_at_desc", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_active_registration_unique": { + "name": "webhook_active_registration_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"registration_status\" = 'active' AND \"webhook\".\"block_id\" IS NOT NULL AND \"webhook\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_candidate_registration_unique": { + "name": "webhook_candidate_registration_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"registration_status\" = 'candidate' AND \"webhook\".\"block_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_registration_status_generation_idx": { + "name": "webhook_registration_status_generation_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "registration_status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "registration_generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_workflow_id_workflow_id_fk": { + "name": "webhook_workflow_id_workflow_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "webhook_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "webhook_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "webhook_registration_status_check": { + "name": "webhook_registration_status_check", + "value": "\"webhook\".\"registration_status\" IS NULL OR \"webhook\".\"registration_status\" IN ('active', 'candidate', 'retired', 'orphaned')" + }, + "webhook_registration_generation_check": { + "name": "webhook_registration_generation_check", + "value": "\"webhook\".\"registration_generation\" IS NULL OR \"webhook\".\"registration_generation\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.webhook_path_claim": { + "name": "webhook_path_claim", + "schema": "", + "columns": { + "path": { + "name": "path", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "webhook_path_claim_workflow_idx": { + "name": "webhook_path_claim_workflow_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_path_claim_workflow_id_workflow_id_fk": { + "name": "webhook_path_claim_workflow_id_workflow_id_fk", + "tableFrom": "webhook_path_claim", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "webhook_path_claim_generation_check": { + "name": "webhook_path_claim_generation_check", + "value": "\"webhook_path_claim\".\"generation\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_synced": { + "name": "last_synced", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "is_deployed": { + "name": "is_deployed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deployed_at": { + "name": "deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_public_api": { + "name": "is_public_api", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "fork_sync_excluded": { + "name": "fork_sync_excluded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_user_id_idx": { + "name": "workflow_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_id_idx": { + "name": "workflow_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_user_workspace_idx": { + "name": "workflow_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_folder_name_active_unique": { + "name": "workflow_workspace_folder_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"folder_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_sort_idx": { + "name": "workflow_folder_sort_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_active_workspace_sort_idx": { + "name": "workflow_active_workspace_sort_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_archived_at_idx": { + "name": "workflow_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_archived_partial_idx": { + "name": "workflow_workspace_archived_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_user_id_user_id_fk": { + "name": "workflow_user_id_user_id_fk", + "tableFrom": "workflow", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_folder_id_folder_id_fk": { + "name": "workflow_folder_id_folder_id_fk", + "tableFrom": "workflow", + "tableTo": "folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_blocks": { + "name": "workflow_blocks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position_x": { + "name": "position_x", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "position_y": { + "name": "position_y", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "horizontal_handles": { + "name": "horizontal_handles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_wide": { + "name": "is_wide", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "advanced_mode": { + "name": "advanced_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "trigger_mode": { + "name": "trigger_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "error_enabled": { + "name": "error_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "retry": { + "name": "retry", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "height": { + "name": "height", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "sub_blocks": { + "name": "sub_blocks", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "outputs": { + "name": "outputs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_blocks_workflow_id_idx": { + "name": "workflow_blocks_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_blocks_type_idx": { + "name": "workflow_blocks_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_blocks_workflow_id_workflow_id_fk": { + "name": "workflow_blocks_workflow_id_workflow_id_fk", + "tableFrom": "workflow_blocks", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_checkpoints": { + "name": "workflow_checkpoints", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_state": { + "name": "workflow_state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_checkpoints_user_id_idx": { + "name": "workflow_checkpoints_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_workflow_id_idx": { + "name": "workflow_checkpoints_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_chat_id_idx": { + "name": "workflow_checkpoints_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_message_id_idx": { + "name": "workflow_checkpoints_message_id_idx", + "columns": [ + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_user_workflow_idx": { + "name": "workflow_checkpoints_user_workflow_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_workflow_chat_idx": { + "name": "workflow_checkpoints_workflow_chat_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_created_at_idx": { + "name": "workflow_checkpoints_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_chat_created_at_idx": { + "name": "workflow_checkpoints_chat_created_at_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_checkpoints_user_id_user_id_fk": { + "name": "workflow_checkpoints_user_id_user_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_checkpoints_workflow_id_workflow_id_fk": { + "name": "workflow_checkpoints_workflow_id_workflow_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_checkpoints_chat_id_copilot_chats_id_fk": { + "name": "workflow_checkpoints_chat_id_copilot_chats_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_deployment_operation": { + "name": "workflow_deployment_operation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "previous_active_version_id": { + "name": "previous_active_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "protocol_version": { + "name": "protocol_version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'preparing'" + }, + "component_readiness": { + "name": "component_readiness", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "request_hash": { + "name": "request_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_deployment_operation_workflow_generation_unique": { + "name": "workflow_deployment_operation_workflow_generation_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_idempotency_unique": { + "name": "workflow_deployment_operation_workflow_idempotency_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "idempotency_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_deployment_operation\".\"idempotency_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_in_flight_unique": { + "name": "workflow_deployment_operation_workflow_in_flight_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_deployment_operation\".\"status\" IN ('preparing', 'activating')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_status_idx": { + "name": "workflow_deployment_operation_workflow_status_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_deployment_version_idx": { + "name": "workflow_deployment_operation_deployment_version_idx", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_version_generation_idx": { + "name": "workflow_deployment_operation_workflow_version_generation_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_deployment_operation_workflow_id_workflow_id_fk": { + "name": "workflow_deployment_operation_workflow_id_workflow_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_deployment_operation_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_deployment_operation_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_deployment_operation_previous_active_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_deployment_operation_previous_active_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["previous_active_version_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workflow_deployment_operation_action_check": { + "name": "workflow_deployment_operation_action_check", + "value": "\"workflow_deployment_operation\".\"action\" IN ('deploy', 'activate')" + }, + "workflow_deployment_operation_status_check": { + "name": "workflow_deployment_operation_status_check", + "value": "\"workflow_deployment_operation\".\"status\" IN ('preparing', 'activating', 'active', 'failed', 'superseded')" + }, + "workflow_deployment_operation_generation_check": { + "name": "workflow_deployment_operation_generation_check", + "value": "\"workflow_deployment_operation\".\"generation\" > 0" + }, + "workflow_deployment_operation_protocol_version_check": { + "name": "workflow_deployment_operation_protocol_version_check", + "value": "\"workflow_deployment_operation\".\"protocol_version\" > 0" + } + }, + "isRLSEnabled": false + }, + "public.workflow_deployment_version": { + "name": "workflow_deployment_version", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_deployment_version_workflow_version_unique": { + "name": "workflow_deployment_version_workflow_version_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_version_workflow_active_idx": { + "name": "workflow_deployment_version_workflow_active_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_version_created_at_idx": { + "name": "workflow_deployment_version_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_deployment_version_workflow_id_workflow_id_fk": { + "name": "workflow_deployment_version_workflow_id_workflow_id_fk", + "tableFrom": "workflow_deployment_version", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_edges": { + "name": "workflow_edges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_block_id": { + "name": "source_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_block_id": { + "name": "target_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_handle": { + "name": "source_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target_handle": { + "name": "target_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_edges_workflow_id_idx": { + "name": "workflow_edges_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_edges_workflow_source_idx": { + "name": "workflow_edges_workflow_source_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_edges_workflow_target_idx": { + "name": "workflow_edges_workflow_target_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_edges_workflow_id_workflow_id_fk": { + "name": "workflow_edges_workflow_id_workflow_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_edges_source_block_id_workflow_blocks_id_fk": { + "name": "workflow_edges_source_block_id_workflow_blocks_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow_blocks", + "columnsFrom": ["source_block_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_edges_target_block_id_workflow_blocks_id_fk": { + "name": "workflow_edges_target_block_id_workflow_blocks_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow_blocks", + "columnsFrom": ["target_block_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_execution_logs": { + "name": "workflow_execution_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_snapshot_id": { + "name": "state_snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "execution_deadline_at": { + "name": "execution_deadline_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_duration_ms": { + "name": "total_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "execution_data": { + "name": "execution_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "cost": { + "name": "cost", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "cost_total": { + "name": "cost_total", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "models_used": { + "name": "models_used", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "files": { + "name": "files", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_execution_logs_workflow_id_idx": { + "name": "workflow_execution_logs_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_state_snapshot_id_idx": { + "name": "workflow_execution_logs_state_snapshot_id_idx", + "columns": [ + { + "expression": "state_snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_deployment_version_id_idx": { + "name": "workflow_execution_logs_deployment_version_id_idx", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_trigger_idx": { + "name": "workflow_execution_logs_trigger_idx", + "columns": [ + { + "expression": "trigger", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_level_idx": { + "name": "workflow_execution_logs_level_idx", + "columns": [ + { + "expression": "level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_started_at_idx": { + "name": "workflow_execution_logs_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_execution_id_unique": { + "name": "workflow_execution_logs_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workflow_started_at_idx": { + "name": "workflow_execution_logs_workflow_started_at_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_started_at_idx": { + "name": "workflow_execution_logs_workspace_started_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_started_at_id_desc_idx": { + "name": "workflow_execution_logs_workspace_started_at_id_desc_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"started_at\" DESC NULLS LAST", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "\"id\" DESC", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_cost_total_idx": { + "name": "workflow_execution_logs_workspace_cost_total_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cost_total", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_models_used_idx": { + "name": "workflow_execution_logs_models_used_idx", + "columns": [ + { + "expression": "models_used", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "workflow_execution_logs_workspace_ended_at_id_idx": { + "name": "workflow_execution_logs_workspace_ended_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"ended_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_running_started_at_idx": { + "name": "workflow_execution_logs_running_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'running'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_running_deadline_idx": { + "name": "workflow_execution_logs_running_deadline_idx", + "columns": [ + { + "expression": "execution_deadline_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_execution_logs\".\"status\" = 'running' AND \"workflow_execution_logs\".\"execution_deadline_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_redacting_started_at_idx": { + "name": "workflow_execution_logs_redacting_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'redacting'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_redacting_deadline_idx": { + "name": "workflow_execution_logs_redacting_deadline_idx", + "columns": [ + { + "expression": "execution_deadline_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_execution_logs\".\"status\" = 'redacting' AND \"workflow_execution_logs\".\"execution_deadline_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_completed_ended_at_idx": { + "name": "workflow_execution_logs_completed_ended_at_idx", + "columns": [ + { + "expression": "ended_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_execution_logs\".\"status\" = 'completed' AND \"workflow_execution_logs\".\"level\" = 'info' AND \"workflow_execution_logs\".\"ended_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_execution_logs_workflow_id_workflow_id_fk": { + "name": "workflow_execution_logs_workflow_id_workflow_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_execution_logs_workspace_id_workspace_id_fk": { + "name": "workflow_execution_logs_workspace_id_workspace_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_execution_logs_state_snapshot_id_workflow_execution_snapshots_id_fk": { + "name": "workflow_execution_logs_state_snapshot_id_workflow_execution_snapshots_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow_execution_snapshots", + "columnsFrom": ["state_snapshot_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_execution_snapshots": { + "name": "workflow_execution_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state_hash": { + "name": "state_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_data": { + "name": "state_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_snapshots_workflow_id_idx": { + "name": "workflow_snapshots_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_hash_idx": { + "name": "workflow_snapshots_hash_idx", + "columns": [ + { + "expression": "state_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_workflow_hash_idx": { + "name": "workflow_snapshots_workflow_hash_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "state_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_created_at_idx": { + "name": "workflow_snapshots_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_execution_snapshots_workflow_id_workflow_id_fk": { + "name": "workflow_execution_snapshots_workflow_id_workflow_id_fk", + "tableFrom": "workflow_execution_snapshots", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_mcp_server": { + "name": "workflow_mcp_server", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_mcp_server_workspace_id_idx": { + "name": "workflow_mcp_server_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_created_by_idx": { + "name": "workflow_mcp_server_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_deleted_at_idx": { + "name": "workflow_mcp_server_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_workspace_deleted_partial_idx": { + "name": "workflow_mcp_server_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_mcp_server\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_mcp_server_workspace_id_workspace_id_fk": { + "name": "workflow_mcp_server_workspace_id_workspace_id_fk", + "tableFrom": "workflow_mcp_server", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_mcp_server_created_by_user_id_fk": { + "name": "workflow_mcp_server_created_by_user_id_fk", + "tableFrom": "workflow_mcp_server", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_mcp_tool": { + "name": "workflow_mcp_tool", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "server_id": { + "name": "server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_description": { + "name": "tool_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parameter_schema": { + "name": "parameter_schema", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "parameter_description_overrides": { + "name": "parameter_description_overrides", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'::json" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_mcp_tool_server_id_idx": { + "name": "workflow_mcp_tool_server_id_idx", + "columns": [ + { + "expression": "server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_workflow_id_idx": { + "name": "workflow_mcp_tool_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_server_workflow_unique": { + "name": "workflow_mcp_tool_server_workflow_unique", + "columns": [ + { + "expression": "server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_mcp_tool\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_archived_at_partial_idx": { + "name": "workflow_mcp_tool_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_mcp_tool\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_mcp_tool_server_id_workflow_mcp_server_id_fk": { + "name": "workflow_mcp_tool_server_id_workflow_mcp_server_id_fk", + "tableFrom": "workflow_mcp_tool", + "tableTo": "workflow_mcp_server", + "columnsFrom": ["server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_mcp_tool_workflow_id_workflow_id_fk": { + "name": "workflow_mcp_tool_workflow_id_workflow_id_fk", + "tableFrom": "workflow_mcp_tool", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_schedule": { + "name": "workflow_schedule", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_operation_id": { + "name": "deployment_operation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_ran_at": { + "name": "last_ran_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_queued_at": { + "name": "last_queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trigger_type": { + "name": "trigger_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'UTC'" + }, + "failed_count": { + "name": "failed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "infra_retry_count": { + "name": "infra_retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'workflow'" + }, + "job_title": { + "name": "job_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lifecycle": { + "name": "lifecycle", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'persistent'" + }, + "success_condition": { + "name": "success_condition", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_runs": { + "name": "max_runs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "source_chat_id": { + "name": "source_chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_task_name": { + "name": "source_task_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_user_id": { + "name": "source_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_workspace_id": { + "name": "source_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_scope": { + "name": "secret_scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'all'" + }, + "mounted_secrets": { + "name": "mounted_secrets", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "job_history": { + "name": "job_history", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "contexts": { + "name": "contexts", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "excluded_dates": { + "name": "excluded_dates", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ends_at": { + "name": "ends_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_schedule_workflow_block_deployment_unique": { + "name": "workflow_schedule_workflow_block_deployment_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_workflow_deployment_idx": { + "name": "workflow_schedule_workflow_deployment_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_archived_at_partial_idx": { + "name": "workflow_schedule_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_workflow_schedule_on_source_workspace_id_source_t_c07f3bba6": { + "name": "idx_workflow_schedule_on_source_workspace_id_source_t_c07f3bba6", + "columns": [ + { + "expression": "source_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_due_workflow_idx": { + "name": "workflow_schedule_due_workflow_idx", + "columns": [ + { + "expression": "next_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL AND \"workflow_schedule\".\"status\" NOT IN ('disabled', 'completed') AND (\"workflow_schedule\".\"source_type\" = 'workflow' OR \"workflow_schedule\".\"source_type\" IS NULL)", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_due_job_idx": { + "name": "workflow_schedule_due_job_idx", + "columns": [ + { + "expression": "next_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL AND \"workflow_schedule\".\"status\" NOT IN ('disabled', 'completed') AND \"workflow_schedule\".\"source_type\" = 'job'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_schedule_workflow_id_workflow_id_fk": { + "name": "workflow_schedule_workflow_id_workflow_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_deployment_operation_id_workflow_deployment_operation_id_fk": { + "name": "workflow_schedule_deployment_operation_id_workflow_deployment_operation_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow_deployment_operation", + "columnsFrom": ["deployment_operation_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_schedule_source_user_id_user_id_fk": { + "name": "workflow_schedule_source_user_id_user_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "user", + "columnsFrom": ["source_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_source_workspace_id_workspace_id_fk": { + "name": "workflow_schedule_source_workspace_id_workspace_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workspace", + "columnsFrom": ["source_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_subflows": { + "name": "workflow_subflows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_subflows_workflow_id_idx": { + "name": "workflow_subflows_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_subflows_workflow_type_idx": { + "name": "workflow_subflows_workflow_type_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_subflows_workflow_id_workflow_id_fk": { + "name": "workflow_subflows_workflow_id_workflow_id_fk", + "tableFrom": "workflow_subflows", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace": { + "name": "workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#33C482'" + }, + "logo_url": { + "name": "logo_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_mode": { + "name": "workspace_mode", + "type": "workspace_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'grandfathered_shared'" + }, + "billed_account_user_id": { + "name": "billed_account_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "allow_personal_api_keys": { + "name": "allow_personal_api_keys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "inbox_enabled": { + "name": "inbox_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "inbox_address": { + "name": "inbox_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inbox_provider_id": { + "name": "inbox_provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inbox_secret_scope": { + "name": "inbox_secret_scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'all'" + }, + "inbox_mounted_secrets": { + "name": "inbox_mounted_secrets", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "organization_assigned_at": { + "name": "organization_assigned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "forked_from_workspace_id": { + "name": "forked_from_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_owner_id_idx": { + "name": "workspace_owner_id_idx", + "columns": [ + { + "expression": "owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_organization_id_idx": { + "name": "workspace_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_mode_idx": { + "name": "workspace_mode_idx", + "columns": [ + { + "expression": "workspace_mode", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_forked_from_workspace_id_idx": { + "name": "workspace_forked_from_workspace_id_idx", + "columns": [ + { + "expression": "forked_from_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_inbox_provider_id_idx": { + "name": "workspace_inbox_provider_id_idx", + "columns": [ + { + "expression": "inbox_provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace\".\"inbox_provider_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_owner_id_user_id_fk": { + "name": "workspace_owner_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_organization_id_organization_id_fk": { + "name": "workspace_organization_id_organization_id_fk", + "tableFrom": "workspace", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workspace_billed_account_user_id_user_id_fk": { + "name": "workspace_billed_account_user_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": ["billed_account_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workspace_forked_from_workspace_id_workspace_id_fk": { + "name": "workspace_forked_from_workspace_id_workspace_id_fk", + "tableFrom": "workspace", + "tableTo": "workspace", + "columnsFrom": ["forked_from_workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workspace_storage_used_bytes_non_negative": { + "name": "workspace_storage_used_bytes_non_negative", + "value": "\"workspace\".\"storage_used_bytes\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.workspace_byok_keys": { + "name": "workspace_byok_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_byok_workspace_provider_idx": { + "name": "workspace_byok_workspace_provider_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_byok_keys_workspace_id_workspace_id_fk": { + "name": "workspace_byok_keys_workspace_id_workspace_id_fk", + "tableFrom": "workspace_byok_keys", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_byok_keys_created_by_user_id_fk": { + "name": "workspace_byok_keys_created_by_user_id_fk", + "tableFrom": "workspace_byok_keys", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_environment": { + "name": "workspace_environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_environment_workspace_unique": { + "name": "workspace_environment_workspace_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_environment_workspace_id_workspace_id_fk": { + "name": "workspace_environment_workspace_id_workspace_id_fk", + "tableFrom": "workspace_environment", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file": { + "name": "workspace_file", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_file_workspace_id_idx": { + "name": "workspace_file_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_deleted_at_idx": { + "name": "workspace_file_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_workspace_deleted_partial_idx": { + "name": "workspace_file_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_file\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_workspace_id_workspace_id_fk": { + "name": "workspace_file_workspace_id_workspace_id_fk", + "tableFrom": "workspace_file", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_uploaded_by_user_id_fk": { + "name": "workspace_file_uploaded_by_user_id_fk", + "tableFrom": "workspace_file", + "tableTo": "user", + "columnsFrom": ["uploaded_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_file_key_unique": { + "name": "workspace_file_key_unique", + "nullsNotDistinct": false, + "columns": ["key"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_collab_state": { + "name": "workspace_file_collab_state", + "schema": "", + "columns": { + "file_id": { + "name": "file_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "doc_state": { + "name": "doc_state", + "type": "bytea", + "primaryKey": false, + "notNull": true + }, + "source_hash": { + "name": "source_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_file_collab_state_file_id_workspace_files_id_fk": { + "name": "workspace_file_collab_state_file_id_workspace_files_id_fk", + "tableFrom": "workspace_file_collab_state", + "tableTo": "workspace_files", + "columnsFrom": ["file_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_search_backfill": { + "name": "workspace_file_search_backfill", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "after_workspace_id": { + "name": "after_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "after_file_id": { + "name": "after_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_search_dispatch_queue": { + "name": "workspace_file_search_dispatch_queue", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "enqueued_at": { + "name": "enqueued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_dispatched_at": { + "name": "last_dispatched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_file_search_dispatch_queue_schedule_idx": { + "name": "workspace_file_search_dispatch_queue_schedule_idx", + "columns": [ + { + "expression": "last_dispatched_at", + "isExpression": false, + "asc": true, + "nulls": "first" + }, + { + "expression": "enqueued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_search_queue_workspace_fk": { + "name": "workspace_file_search_queue_workspace_fk", + "tableFrom": "workspace_file_search_dispatch_queue", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_search_index": { + "name": "workspace_file_search_index", + "schema": "", + "columns": { + "file_id": { + "name": "file_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_content_updated_at": { + "name": "source_content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "workspace_file_search_index_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "partial": { + "name": "partial", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "failure_reason": { + "name": "failure_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "line_count": { + "name": "line_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "indexed_bytes": { + "name": "indexed_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "dispatched_at": { + "name": "dispatched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_file_search_index_workspace_status_idx": { + "name": "workspace_file_search_index_workspace_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_content_updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_search_index_pending_dispatch_idx": { + "name": "workspace_file_search_index_pending_dispatch_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "file_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_content_updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_file_search_index\".\"status\" = 'pending' AND \"workspace_file_search_index\".\"dispatched_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_search_index_active_dispatch_idx": { + "name": "workspace_file_search_index_active_dispatch_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "dispatched_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_file_search_index\".\"status\" = 'pending' AND \"workspace_file_search_index\".\"dispatched_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_search_index_file_fk": { + "name": "workspace_file_search_index_file_fk", + "tableFrom": "workspace_file_search_index", + "tableTo": "workspace_files", + "columnsFrom": ["file_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_search_index_workspace_fk": { + "name": "workspace_file_search_index_workspace_fk", + "tableFrom": "workspace_file_search_index", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "workspace_file_search_index_pk": { + "name": "workspace_file_search_index_pk", + "columns": ["file_id", "source_content_updated_at"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_search_segment": { + "name": "workspace_file_search_segment", + "schema": "", + "columns": { + "file_id": { + "name": "file_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_content_updated_at": { + "name": "source_content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "line_number": { + "name": "line_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "segment_number": { + "name": "segment_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "segment_start": { + "name": "segment_start", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "line_length": { + "name": "line_length", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "workspace_file_search_segment_workspace_revision_idx": { + "name": "workspace_file_search_segment_workspace_revision_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "file_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_content_updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_search_segment_workspace_content_trgm_idx": { + "name": "workspace_file_search_segment_workspace_content_trgm_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + }, + { + "expression": "content", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "gin_trgm_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_search_segment_file_fk": { + "name": "workspace_file_search_segment_file_fk", + "tableFrom": "workspace_file_search_segment", + "tableTo": "workspace_files", + "columnsFrom": ["file_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_search_segment_workspace_fk": { + "name": "workspace_file_search_segment_workspace_fk", + "tableFrom": "workspace_file_search_segment", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "workspace_file_search_segment_pk": { + "name": "workspace_file_search_segment_pk", + "columns": ["file_id", "source_content_updated_at", "line_number", "segment_number"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_secret_provenance": { + "name": "workspace_file_secret_provenance", + "schema": "", + "columns": { + "file_id": { + "name": "file_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content_updated_at": { + "name": "content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_file_secret_provenance_file_id_workspace_files_id_fk": { + "name": "workspace_file_secret_provenance_file_id_workspace_files_id_fk", + "tableFrom": "workspace_file_secret_provenance", + "tableTo": "workspace_files", + "columnsFrom": ["file_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workspace_file_secret_provenance_status_check": { + "name": "workspace_file_secret_provenance_status_check", + "value": "\"workspace_file_secret_provenance\".\"status\" IN ('exact', 'unknown', 'unrecorded')" + } + }, + "isRLSEnabled": false + }, + "public.workspace_files": { + "name": "workspace_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "context": { + "name": "context", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "size_bytes": { + "name": "size_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "content_updated_at": { + "name": "content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workspace_files_key_active_unique": { + "name": "workspace_files_key_active_unique", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_folder_name_active_unique": { + "name": "workspace_files_workspace_folder_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"folder_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "original_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"deleted_at\" IS NULL AND \"workspace_files\".\"context\" = 'workspace' AND \"workspace_files\".\"workspace_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_chat_display_name_unique": { + "name": "workspace_files_chat_display_name_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"context\" = 'mothership' AND \"workspace_files\".\"chat_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_organization_id_idx": { + "name": "workspace_files_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_key_idx": { + "name": "workspace_files_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_user_id_idx": { + "name": "workspace_files_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_id_idx": { + "name": "workspace_files_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_folder_id_idx": { + "name": "workspace_files_folder_id_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_context_idx": { + "name": "workspace_files_context_idx", + "columns": [ + { + "expression": "context", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_chat_id_idx": { + "name": "workspace_files_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_deleted_at_idx": { + "name": "workspace_files_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_deleted_partial_idx": { + "name": "workspace_files_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_files\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_files_user_id_user_id_fk": { + "name": "workspace_files_user_id_user_id_fk", + "tableFrom": "workspace_files", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_workspace_id_workspace_id_fk": { + "name": "workspace_files_workspace_id_workspace_id_fk", + "tableFrom": "workspace_files", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_organization_id_organization_id_fk": { + "name": "workspace_files_organization_id_organization_id_fk", + "tableFrom": "workspace_files", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_folder_id_folder_id_fk": { + "name": "workspace_files_folder_id_folder_id_fk", + "tableFrom": "workspace_files", + "tableTo": "folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workspace_files_chat_id_copilot_chats_id_fk": { + "name": "workspace_files_chat_id_copilot_chats_id_fk", + "tableFrom": "workspace_files", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workspace_files_organization_binding_check": { + "name": "workspace_files_organization_binding_check", + "value": "\"workspace_files\".\"organization_id\" IS NULL OR (\"workspace_files\".\"workspace_id\" IS NULL AND \"workspace_files\".\"context\" = 'knowledge-base' AND \"workspace_files\".\"folder_id\" IS NULL AND \"workspace_files\".\"chat_id\" IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.workspace_fork_block_map": { + "name": "workspace_fork_block_map", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_workflow_id": { + "name": "parent_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_block_id": { + "name": "parent_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_workflow_id": { + "name": "child_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_block_id": { + "name": "child_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_block_map_child_ws_parent_unique": { + "name": "workspace_fork_block_map_child_ws_parent_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_child_unique": { + "name": "workspace_fork_block_map_child_ws_child_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_parent_wf_idx": { + "name": "workspace_fork_block_map_child_ws_parent_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_child_wf_idx": { + "name": "workspace_fork_block_map_child_ws_child_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_block_map_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_block_map_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_block_map", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_dependent_value": { + "name": "workspace_fork_dependent_value", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_workflow_id": { + "name": "target_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_block_id": { + "name": "target_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sub_block_key": { + "name": "sub_block_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_dependent_value_child_ws_wf_idx": { + "name": "workspace_fork_dependent_value_child_ws_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_dependent_value_field_unique": { + "name": "workspace_fork_dependent_value_field_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sub_block_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_dependent_value_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_dependent_value_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_dependent_value", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_promote_run": { + "name": "workspace_fork_promote_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_workspace_id": { + "name": "source_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_workspace_id": { + "name": "target_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "direction": { + "name": "direction", + "type": "workspace_fork_promote_direction", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_promote_run_child_ws_target_unique": { + "name": "workspace_fork_promote_run_child_ws_target_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_promote_run_target_ws_idx": { + "name": "workspace_fork_promote_run_target_ws_idx", + "columns": [ + { + "expression": "target_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_promote_run_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_promote_run_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_promote_run", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_fork_promote_run_created_by_user_id_fk": { + "name": "workspace_fork_promote_run_created_by_user_id_fk", + "tableFrom": "workspace_fork_promote_run", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_resource_map": { + "name": "workspace_fork_resource_map", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "workspace_fork_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "parent_resource_id": { + "name": "parent_resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_resource_id": { + "name": "child_resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_resource_map_child_ws_idx": { + "name": "workspace_fork_resource_map_child_ws_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_resource_map_child_ws_type_idx": { + "name": "workspace_fork_resource_map_child_ws_type_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_resource_map_child_type_parent_unique": { + "name": "workspace_fork_resource_map_child_type_parent_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_resource_map_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_resource_map_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_resource_map", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_fork_resource_map_created_by_user_id_fk": { + "name": "workspace_fork_resource_map_created_by_user_id_fk", + "tableFrom": "workspace_fork_resource_map", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_operation_receipt": { + "name": "workspace_operation_receipt", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_hash": { + "name": "request_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "report": { + "name": "report", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_operation_receipt_request_unique": { + "name": "workspace_operation_receipt_request_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "request_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_operation_receipt_workspace_created_idx": { + "name": "workspace_operation_receipt_workspace_created_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_operation_receipt_workspace_id_workspace_id_fk": { + "name": "workspace_operation_receipt_workspace_id_workspace_id_fk", + "tableFrom": "workspace_operation_receipt", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_sandbox": { + "name": "workspace_sandbox", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "language": { + "name": "language", + "type": "sandbox_language", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "dependencies": { + "name": "dependencies", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "cli_tools": { + "name": "cli_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "system_packages": { + "name": "system_packages", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "spec_hash": { + "name": "spec_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_sandbox_workspace_name_unique": { + "name": "workspace_sandbox_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_sandbox_workspace_idx": { + "name": "workspace_sandbox_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_sandbox_spec_hash_idx": { + "name": "workspace_sandbox_spec_hash_idx", + "columns": [ + { + "expression": "spec_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_sandbox_workspace_id_workspace_id_fk": { + "name": "workspace_sandbox_workspace_id_workspace_id_fk", + "tableFrom": "workspace_sandbox", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_sandbox_created_by_user_id_fk": { + "name": "workspace_sandbox_created_by_user_id_fk", + "tableFrom": "workspace_sandbox", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.academy_cert_status": { + "name": "academy_cert_status", + "schema": "public", + "values": ["active", "revoked", "expired"] + }, + "public.background_work_kind": { + "name": "background_work_kind", + "schema": "public", + "values": ["deployment_side_effects", "fork_content_copy", "fork_sync", "fork_rollback"] + }, + "public.background_work_status_value": { + "name": "background_work_status_value", + "schema": "public", + "values": ["pending", "processing", "completed", "completed_with_warnings", "failed"] + }, + "public.billing_blocked_reason": { + "name": "billing_blocked_reason", + "schema": "public", + "values": ["payment_failed", "dispute"] + }, + "public.billing_entity_type": { + "name": "billing_entity_type", + "schema": "public", + "values": ["user", "organization"] + }, + "public.chat_type": { + "name": "chat_type", + "schema": "public", + "values": ["mothership", "copilot"] + }, + "public.copilot_async_tool_status": { + "name": "copilot_async_tool_status", + "schema": "public", + "values": ["pending", "running", "completed", "failed", "cancelled", "delivered"] + }, + "public.copilot_run_status": { + "name": "copilot_run_status", + "schema": "public", + "values": ["active", "paused_waiting_for_tool", "resuming", "complete", "error", "cancelled"] + }, + "public.copilot_tool_permission_decision": { + "name": "copilot_tool_permission_decision", + "schema": "public", + "values": ["allow", "allow_chat", "always_allow", "skip"] + }, + "public.credential_group_enrollment_status": { + "name": "credential_group_enrollment_status", + "schema": "public", + "values": ["invited", "delivery_failed", "in_progress", "completed", "revoked"] + }, + "public.credential_group_status": { + "name": "credential_group_status", + "schema": "public", + "values": ["active", "disabled"] + }, + "public.credential_member_role": { + "name": "credential_member_role", + "schema": "public", + "values": ["admin", "member"] + }, + "public.credential_member_status": { + "name": "credential_member_status", + "schema": "public", + "values": ["active", "pending", "revoked"] + }, + "public.credential_type": { + "name": "credential_type", + "schema": "public", + "values": [ + "oauth", + "managed_oauth", + "managed_mcp", + "env_workspace", + "env_personal", + "service_account", + "personal_token" + ] + }, + "public.data_drain_cadence": { + "name": "data_drain_cadence", + "schema": "public", + "values": ["hourly", "daily"] + }, + "public.data_drain_destination": { + "name": "data_drain_destination", + "schema": "public", + "values": ["s3", "gcs", "azure_blob", "datadog", "bigquery", "snowflake", "webhook"] + }, + "public.data_drain_run_status": { + "name": "data_drain_run_status", + "schema": "public", + "values": ["running", "success", "failed"] + }, + "public.data_drain_run_trigger": { + "name": "data_drain_run_trigger", + "schema": "public", + "values": ["cron", "manual"] + }, + "public.data_drain_source": { + "name": "data_drain_source", + "schema": "public", + "values": ["workflow_logs", "job_logs", "audit_logs", "copilot_chats", "copilot_runs"] + }, + "public.execution_large_value_reference_source": { + "name": "execution_large_value_reference_source", + "schema": "public", + "values": ["execution_log", "paused_snapshot"] + }, + "public.folder_resource_type": { + "name": "folder_resource_type", + "schema": "public", + "values": ["workflow", "file", "knowledge_base", "table"] + }, + "public.invitation_kind": { + "name": "invitation_kind", + "schema": "public", + "values": ["organization", "workspace"] + }, + "public.invitation_membership_intent": { + "name": "invitation_membership_intent", + "schema": "public", + "values": ["internal", "external"] + }, + "public.invitation_status": { + "name": "invitation_status", + "schema": "public", + "values": ["pending", "accepted", "rejected", "cancelled", "expired"] + }, + "public.managed_oauth_credential_status": { + "name": "managed_oauth_credential_status", + "schema": "public", + "values": ["active", "needs_reauth", "revoked"] + }, + "public.permission_type": { + "name": "permission_type", + "schema": "public", + "values": ["admin", "write", "read"] + }, + "public.sandbox_image_status": { + "name": "sandbox_image_status", + "schema": "public", + "values": ["pending", "building", "ready", "failed"] + }, + "public.sandbox_language": { + "name": "sandbox_language", + "schema": "public", + "values": ["javascript", "python"] + }, + "public.secret_usage_scope": { + "name": "secret_usage_scope", + "schema": "public", + "values": ["workspace", "personal"] + }, + "public.secret_usage_source": { + "name": "secret_usage_source", + "schema": "public", + "values": ["workflow", "copilot", "mcp"] + }, + "public.upload_session_method": { + "name": "upload_session_method", + "schema": "public", + "values": ["put", "multipart"] + }, + "public.upload_session_provider": { + "name": "upload_session_provider", + "schema": "public", + "values": ["local", "s3", "blob", "gcs"] + }, + "public.upload_session_purpose": { + "name": "upload_session_purpose", + "schema": "public", + "values": [ + "workspace_file", + "table_import", + "knowledge_document", + "profile_picture", + "workspace_logo", + "mothership_attachment", + "execution_attachment" + ] + }, + "public.upload_session_status": { + "name": "upload_session_status", + "schema": "public", + "values": [ + "uploading", + "completing", + "finalizing", + "completed", + "aborting", + "aborted", + "failed", + "expired" + ] + }, + "public.usage_log_category": { + "name": "usage_log_category", + "schema": "public", + "values": ["model", "fixed", "tool", "model_unbilled"] + }, + "public.usage_log_source": { + "name": "usage_log_source", + "schema": "public", + "values": [ + "workflow", + "wand", + "copilot", + "workspace-chat", + "mcp_copilot", + "mothership_block", + "knowledge-base", + "voice-input", + "enrichment", + "voice-output", + "api-tool" + ] + }, + "public.workspace_file_search_index_status": { + "name": "workspace_file_search_index_status", + "schema": "public", + "values": ["pending", "ready", "skipped", "failed"] + }, + "public.workspace_fork_promote_direction": { + "name": "workspace_fork_promote_direction", + "schema": "public", + "values": ["push", "pull"] + }, + "public.workspace_fork_resource_type": { + "name": "workspace_fork_resource_type", + "schema": "public", + "values": [ + "workflow", + "oauth_credential", + "service_account_credential", + "env_var", + "table", + "knowledge_base", + "knowledge_document", + "file", + "file_folder", + "mcp_server", + "workflow_mcp_server", + "custom_block", + "custom_tool", + "skill", + "sandbox" + ] + }, + "public.workspace_mode": { + "name": "workspace_mode", + "schema": "public", + "values": ["personal", "organization", "grandfathered_shared"] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index f8f91eff92f..de9faaffd08 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -2367,6 +2367,13 @@ "when": 1789076658450, "tag": "0338_organization_search_activity", "breakpoints": true + }, + { + "idx": 339, + "version": "7", + "when": 1789084655493, + "tag": "0339_connector_permissions", + "breakpoints": true } ] } diff --git a/packages/db/schema.ts b/packages/db/schema.ts index 8d1b2746844..d8d8342ebe2 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -5531,6 +5531,52 @@ export const knowledgeConnector = pgTable( }) ) +/** Private provider configuration; metadata reads never materialize the larger normalized payload. */ +export const knowledgeConnectorPermissionSnapshot = pgTable( + 'knowledge_connector_permission_snapshot', + { + connectorId: text('connector_id').primaryKey(), + revision: integer('revision').notNull(), + metadata: jsonb('metadata').$type>().notNull(), + payload: jsonb('payload').$type>().notNull(), + }, + (table) => ({ + revisionCheck: check('kcps_revision_check', sql`${table.revision} > 0`), + connectorFk: foreignKey({ + name: 'kcps_connector_fk', + columns: [table.connectorId], + foreignColumns: [knowledgeConnector.id], + }).onDelete('cascade'), + }) +) + +/** Administrator-managed connector groups; provider directory crawls never write these grants. */ +export const knowledgeConnectorPermissionGrant = pgTable( + 'knowledge_connector_permission_grant', + { + connectorId: text('connector_id').notNull(), + groupKey: text('group_key').notNull(), + subjectToken: text('subject_token').notNull(), + }, + (table) => ({ + pk: primaryKey({ + name: 'kcpg_pk', + columns: [table.connectorId, table.groupKey, table.subjectToken], + }), + subjectIdx: index('kcpg_subject_idx').on(table.subjectToken, table.connectorId, table.groupKey), + snapshotFk: foreignKey({ + name: 'kcpg_snapshot_fk', + columns: [table.connectorId], + foreignColumns: [knowledgeConnectorPermissionSnapshot.connectorId], + }).onDelete('cascade'), + groupCheck: check('kcpg_group_check', sql`length(${table.groupKey}) BETWEEN 1 AND 255`), + subjectCheck: check( + 'kcpg_subject_check', + sql`${table.subjectToken} ~ '^u:[^[:space:]A-Z]+@[^[:space:]A-Z]+$'` + ), + }) +) + /** * One row per (members-mode connector, member credential). Membership is * derived from the credential-group option on every run: `active` while the From 1254d0bbee7a3c6d0b1bea5bb09e8047558b0987 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Thu, 10 Sep 2026 18:13:09 -0700 Subject: [PATCH 2/2] fix(gitlab): address setup review and test expectations --- .../use-connector-settings-form.ts | 45 ++++++++++++++---- .../components/search-source-setup.test.tsx | 22 +++++---- .../gitlab/permission-config/parser.test.ts | 4 +- .../permission-config/use-permission-form.ts | 35 +++++++------- .../orchestration/connectors.test.ts | 46 +++++++++++++++++++ .../lib/knowledge/orchestration/connectors.ts | 8 +--- 6 files changed, 119 insertions(+), 41 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/use-connector-settings-form.ts b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/use-connector-settings-form.ts index 0e153777489..15744d583ba 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/use-connector-settings-form.ts +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/use-connector-settings-form.ts @@ -316,20 +316,28 @@ export function useConnectorSettingsForm({ !hiddenCapFieldIds.has(key) && !valuesEqual(connector.sourceConfig[key], value) ) - const handleSave = () => { + const { + apiKey: permissionApiKey, + complete: permissionsComplete, + dirty: permissionsDirty, + input: permissionInput, + reset: resetPermissions, + } = gitlabPermissions + + const handleSave = useCallback(() => { if ( !searchSettingsAllowed || !settingsComplete || accessDirty || - (showGitLabPermissions && !gitlabPermissions.complete) + (showGitLabPermissions && !permissionsComplete) ) return setError(null) const updates: UpdateConnectorBody = {} - if (showGitLabPermissions && gitlabPermissions.dirty) { - updates.permissionConfig = gitlabPermissions.input - if (gitlabPermissions.apiKey.trim()) updates.apiKey = gitlabPermissions.apiKey + if (showGitLabPermissions && permissionsDirty) { + updates.permissionConfig = permissionInput + if (permissionApiKey.trim()) updates.apiKey = permissionApiKey } if (syncInterval !== connector.syncIntervalMinutes) { @@ -338,8 +346,9 @@ export function useConnectorSettingsForm({ const resolved = resolveSourceConfig() const changedEntries: Record = {} + const saveHiddenFieldIds = derivedAclCapFieldIds(connectorConfig, access.accessMode) for (const [key, value] of Object.entries(resolved)) { - if (hiddenCapFieldIds.has(key)) continue + if (saveHiddenFieldIds.has(key)) continue if (!valuesEqual(connector.sourceConfig[key], value)) changedEntries[key] = value } @@ -365,7 +374,7 @@ export function useConnectorSettingsForm({ { knowledgeBaseId, connectorId: connector.id, updates }, { onSuccess: (updated) => { - gitlabPermissions.reset(updated.permissionConfig) + resetPermissions(updated.permissionConfig) onSaved(updated) }, onError: (err) => { @@ -374,7 +383,27 @@ export function useConnectorSettingsForm({ }, } ) - } + }, [ + access.accessMode, + accessDirty, + canonicalModes, + connector, + connectorConfig, + knowledgeBaseId, + onSaved, + permissionApiKey, + permissionInput, + permissionsComplete, + permissionsDirty, + persistedCanonicalModes, + resetPermissions, + resolveSourceConfig, + searchSettingsAllowed, + settingsComplete, + showGitLabPermissions, + syncInterval, + updateConnector, + ]) /** * The mode switch is its own admin operation: it rewrites document access diff --git a/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.test.tsx b/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.test.tsx index 90bb6dafcf2..6074aab20ea 100644 --- a/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.test.tsx @@ -1026,9 +1026,11 @@ describe('Search source setup with real connector dialogs', () => { ) }) - it('opens GitLab with its single central method and submits the custom host and PAT', async () => { + it('opens GitLab token tabs and submits the custom host and PAT with managed access', async () => { await render(setup(), '?addConnector=gitlab') - expect(document.body.textContent).toContain('Admin or service account') + expect(button('Administrator token')).toHaveAttribute('aria-checked', 'true') + expect(button('Non-admin token')).toHaveAttribute('aria-checked', 'false') + expect(document.body.textContent).not.toContain('Connection method') expect(document.body.textContent).not.toContain('Member accounts') expect(button('Connect & Sync')).toBeDisabled() await fill('Enter your GitLab PAT', 'test-pat') @@ -1197,14 +1199,16 @@ describe('member content credentials in real add and edit dialogs', () => { ) await click(card!) expect(document.body.textContent).not.toContain('Connected members') - expect(button('Workspace')).toHaveAttribute('aria-checked', 'true') + expect(button('Administrator token')).toHaveAttribute('aria-checked', 'true') + expect(document.body.textContent).not.toContain('Connection method') await fill('Enter your GitLab PAT', 'new-pat') + await fill('gitlab.example.com', 'gitlab.example.test') await fill('group/project or numeric ID', '1') expect(button('Connect & Sync')).toBeEnabled() await click(button('Connect & Sync')) expect(mocks.create.mock.calls[1][0]).toMatchObject({ connectorType: 'gitlab', - accessMode: 'workspace', + accessMode: 'admin', apiKey: 'new-pat', }) expect(mocks.create.mock.calls[1][0].sourceConfig).not.toHaveProperty('excludeChannels') @@ -1978,8 +1982,9 @@ describe('canonical Search connector safety', () => { ) expect(gitlab).toBeDefined() await click(gitlab!) - expect(document.body.textContent).toContain('Admin or service account') - expect(document.querySelector('[role="radio"][aria-checked="true"]')).toBeNull() + expect(button('Administrator token')).toHaveAttribute('aria-checked', 'true') + expect(button('Non-admin token')).toHaveAttribute('aria-checked', 'false') + expect(document.body.textContent).not.toContain('Connection method') expect( Array.from(document.querySelectorAll('button')).some( (node) => node.textContent === 'Workspace' @@ -2027,8 +2032,9 @@ describe('resuming Search source setup', () => { it('reopens the source from the URL even when the source filter hides its row', async () => { await render(setup(), '?search=nothing-matches&addConnector=gitlab&credentialDraftId=draft-1') - expect(document.body.textContent).toContain('Admin or service account') - expect(document.querySelector('[role="radio"][aria-checked="true"]')).toBeNull() + expect(button('Administrator token')).toHaveAttribute('aria-checked', 'true') + expect(button('Non-admin token')).toHaveAttribute('aria-checked', 'false') + expect(document.body.textContent).not.toContain('Connection method') expect(document.body.textContent).toContain('Add GitLab project') expect(document.body.textContent).not.toContain('Sync Frequency') expect(document.body.textContent).not.toContain('Sync automatically') diff --git a/apps/sim/connectors/gitlab/permission-config/parser.test.ts b/apps/sim/connectors/gitlab/permission-config/parser.test.ts index 097f700b692..1cd929df9eb 100644 --- a/apps/sim/connectors/gitlab/permission-config/parser.test.ts +++ b/apps/sim/connectors/gitlab/permission-config/parser.test.ts @@ -80,13 +80,11 @@ describe('GitLab CSV permission uploads', () => { ) ).toThrow('4 MiB') }) - it('accepts 100,000 rows within a bounded parsing budget and rejects the next row', () => { + it('accepts 100,000 rows and rejects the next row', () => { const content = Array.from({ length: 100_000 }, (_, i) => `${i + 1},u${i}@example.com`).join( '\n' ) - const start = performance.now() expect(parseGitLabCsv({ filename: 'users.csv', content }, 'userMapping')).toHaveLength(100_000) - expect(performance.now() - start).toBeLessThan(5000) expect(() => parseGitLabCsv( { filename: 'users.csv', content: `${content}\n100001,last@example.com` }, diff --git a/apps/sim/connectors/gitlab/permission-config/use-permission-form.ts b/apps/sim/connectors/gitlab/permission-config/use-permission-form.ts index 99a3d0cc6f0..60437b22259 100644 --- a/apps/sim/connectors/gitlab/permission-config/use-permission-form.ts +++ b/apps/sim/connectors/gitlab/permission-config/use-permission-form.ts @@ -1,6 +1,6 @@ 'use client' -import { useRef, useState } from 'react' +import { useCallback, useMemo, useRef, useState } from 'react' import { getErrorMessage } from '@sim/utils/errors' import type { GitLabPermissionData, @@ -41,18 +41,21 @@ export function useGitLabPermissionForm(initial?: GitLabPermissionData) { Boolean(apiKey) || (mode === 'csv' && Object.values(files).some((file) => file.upload || file.error || file.loading)) - const input: GitLabPermissionUploadInput = { - provider: 'gitlab', - mode, - ...(saved ? { expectedRevision: saved.revision } : {}), - ...(mode === 'csv' - ? { - userMapping: files.userMapping?.upload, - projectPermissions: files.projectPermissions?.upload, - } - : {}), - } - async function selectFile(kind: GitLabCsvKind, file: File) { + const input = useMemo( + () => ({ + provider: 'gitlab', + mode, + ...(saved ? { expectedRevision: saved.revision } : {}), + ...(mode === 'csv' + ? { + userMapping: files.userMapping?.upload, + projectPermissions: files.projectPermissions?.upload, + } + : {}), + }), + [files, mode, saved] + ) + const selectFile = useCallback(async (kind: GitLabCsvKind, file: File) => { const generation = ++generations.current[kind] setFiles((previous) => ({ ...previous, [kind]: { loading: true } })) let selected: SelectedFile @@ -69,15 +72,15 @@ export function useGitLabPermissionForm(initial?: GitLabPermissionData) { } if (generation === generations.current[kind]) setFiles((previous) => ({ ...previous, [kind]: selected })) - } - function reset(next?: GitLabPermissionData) { + }, []) + const reset = useCallback((next?: GitLabPermissionData) => { generations.current.userMapping++ generations.current.projectPermissions++ setFiles({}) setApiKey('') setSaved(next) setMode(next?.mode ?? 'administrator') - } + }, []) return { mode, setMode, diff --git a/apps/sim/lib/knowledge/orchestration/connectors.test.ts b/apps/sim/lib/knowledge/orchestration/connectors.test.ts index bc9baa09a74..177adbe52d6 100644 --- a/apps/sim/lib/knowledge/orchestration/connectors.test.ts +++ b/apps/sim/lib/knowledge/orchestration/connectors.test.ts @@ -430,6 +430,52 @@ describe('performUpdateKnowledgeConnector', () => { expect(dbChainMockFns.select).not.toHaveBeenCalled() }) + it.each(['permissions', 'token'] as const)( + 'commits a %s-only change without dispatching a content sync', + async (change) => { + const existing = { + id: 'conn-1', + connectorType: 'gitlab', + accessMode: 'admin', + status: 'active', + updatedAt: new Date('2026-01-01T00:00:00Z'), + } + dbChainMockFns.limit.mockResolvedValueOnce([existing]) + dbChainMockFns.returning.mockResolvedValueOnce([existing]) + const write = vi.fn().mockResolvedValue(undefined) + const outcome = await performUpdateKnowledgeConnector({ + ...ACTOR, + knowledgeBase: KB, + connectorId: existing.id, + updates: {}, + permissionChange: { + requiresAclReset: false, + requiresContentSync: false, + ...(change === 'token' ? { encryptedApiKey: 'encrypted-fixture-pat' } : {}), + populateSyncContext: vi.fn(), + write, + }, + resolveBillingAttribution, + }) + + expect(outcome).toMatchObject({ success: true }) + expect(write).toHaveBeenCalledWith(expect.anything(), existing.id) + expect(mockRecordAudit).toHaveBeenCalledWith( + expect.objectContaining({ + metadata: expect.objectContaining({ updatedFields: ['permissionConfig'] }), + }) + ) + expect(mockDispatchSync).not.toHaveBeenCalled() + expect(mockDispatchMemberSync).not.toHaveBeenCalled() + expect(resolveBillingAttribution).not.toHaveBeenCalled() + if (change === 'token') { + expect(dbChainMockFns.set).toHaveBeenCalledWith( + expect.objectContaining({ encryptedApiKey: 'encrypted-fixture-pat' }) + ) + } + } + ) + it('classifies a sub-hourly interval on an unentitled workspace as forbidden', async () => { dbChainMockFns.limit.mockResolvedValueOnce([ { id: 'conn-1', connectorType: 'notion', accessMode: 'workspace' }, diff --git a/apps/sim/lib/knowledge/orchestration/connectors.ts b/apps/sim/lib/knowledge/orchestration/connectors.ts index eda94d80cc6..9648b040758 100644 --- a/apps/sim/lib/knowledge/orchestration/connectors.ts +++ b/apps/sim/lib/knowledge/orchestration/connectors.ts @@ -722,13 +722,9 @@ export async function performUpdateKnowledgeConnector( const updatedFields = Object.keys(updates).filter( (key) => updates[key as keyof typeof updates] !== undefined ) - const changedFields: string[] = updatedFields - if (params.permissionChange) changedFields.push('permissionConfig') + if (params.permissionChange) updatedFields.push('permissionConfig') if (updatedFields.length === 0) { - return fail( - 'At least one of sourceConfig, syncIntervalMinutes, or status is required', - 'validation' - ) + return fail('At least one connector setting or permission change is required', 'validation') } const existing = await getKnowledgeConnector(kb.id, connectorId)