You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
organization_role_assignments — which roles each WorkOS user has within an org. role_urn encodes scope+id (role:global:<uuid> or role:organization:<uuid>); no FK on role_urn, deletes handled in app. user_id nullable so membership events can land before the Gram user exists.
workos_organization_syncs — per-org event cursor for organization.* / organization_role.* events.
workos_user_syncs — singleton cursor for organization_membership.* events. CHECK (id = 1) enforces single row.
Schema decisions
workos_organization_syncs.id is uuid DEFAULT generate_uuidv7() (multi-row, matches schema convention elsewhere).
workos_user_syncs.id stays bigint identity with CHECK (id = 1) — UUID adds nothing to a singleton.
organization_role_assignments: unique on (organization_id, workos_user_id, role_urn); partial index on (organization_id, user_id) WHERE user_id IS NOT NULL.
organization_roles: unique on (organization_id, workos_slug) — slugs are immutable in WorkOS.
global_roles: unique on workos_slug.
eventual consistency: every WorkOS-driven row tracks workos_updated_at separately from updated_at so re-replayed events don't clobber newer state.
Sample data (from local instance after webhook traffic)
Note: local rows show bigint ids on workos_organization_syncs because the dev DB pre-dates the UUID switch in this PR. New deployments / db:reset will produce UUIDs. Format of every other column is identical.
id | workos_slug | workos_name | workos_description | workos_created_at | workos_deleted
--------------------------------------+-------------+-------------+------------------------------+----------------------------+----------------
019ddddc-fa21-7297-af91-1bf9c2b6baea | member | Member | The default user role | 2024-08-15 21:49:46.159+00 | f
019ddddc-fa23-7995-9fd3-3a85d1f4fb05 | admin | Admin | The default super-admin role | 2026-03-24 15:24:49.149+00 | f
organization_roles:
id | organization_id | workos_slug | workos_name | workos_description | workos_created_at | workos_deleted
--------------------------------------+--------------------------------------+---------------------------------------+-----------------------------------+------------------------------------------------------------------+----------------------------+----------------
019ddddc-fa25-7e39-b12a-b99ca05ab26a | 8f782a9f-2bbb-e641-80eb-6cf47c3ad3ac | org-api-key-role-test-20260401-181104 | API key role test 20260401-181104 | Fresh role created via API key | 2026-04-01 17:11:04.449+00 | f
019ddddc-fa27-7e3a-a7d0-f5c04c991ad1 | 8f782a9f-2bbb-e641-80eb-6cf47c3ad3ac | org-local-assign-test-20260402-1622 | Local Assign Test 20260402-1622 | Created to test assigning an existing local user to a fresh role | 2026-04-02 16:22:54.767+00 | f
019ddddc-fa27-7048-8678-dceba84bbe29 | 8f782a9f-2bbb-e641-80eb-6cf47c3ad3ac | org-mcp-user | MCP User | An MCP user for ecommerce | 2026-04-15 14:38:36.026+00 | f
The reason will be displayed to describe this comment to others. Learn more.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Labels
None yet
2 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First chunk of the WorkOS sync split (originally #2093). Schema only — no consumers, no behavior change. Safe to apply ahead of subsequent PRs.
Adds five tables that downstream PRs (handlers, activities, workflows, webhook) will populate from WorkOS events:
global_roles— environment-level WorkOS roles (e.g.admin,member).organization_roles— per-org WorkOS roles.organization_role_assignments— which roles each WorkOS user has within an org.role_urnencodes scope+id (role:global:<uuid>orrole:organization:<uuid>); no FK onrole_urn, deletes handled in app.user_idnullable so membership events can land before the Gram user exists.workos_organization_syncs— per-org event cursor fororganization.*/organization_role.*events.workos_user_syncs— singleton cursor fororganization_membership.*events.CHECK (id = 1)enforces single row.Schema decisions
workos_organization_syncs.idisuuid DEFAULT generate_uuidv7()(multi-row, matches schema convention elsewhere).workos_user_syncs.idstaysbigint identitywithCHECK (id = 1)— UUID adds nothing to a singleton.organization_role_assignments: unique on(organization_id, workos_user_id, role_urn); partial index on(organization_id, user_id) WHERE user_id IS NOT NULL.organization_roles: unique on(organization_id, workos_slug)— slugs are immutable in WorkOS.global_roles: unique onworkos_slug.eventual consistency: every WorkOS-driven row tracksworkos_updated_atseparately fromupdated_atso re-replayed events don't clobber newer state.Sample data (from local instance after webhook traffic)
workos_organization_syncs:workos_user_syncs(singleton):global_roles:organization_roles:organization_role_assignments:(
user_idempty because membership events have so far arrived for users who are not yet in the localuserstable. Linked on first login or backfill.)Follow-ups (subsequent PRs)
/rpc/external.receiveWorkOSWebhookendpoint