feat: workspaces v1#1012
Open
raivieiraadriano92 wants to merge 19 commits into
Open
Conversation
Semgrep Security ScanNo security issues found. |
PR Metrics
Updated Mon, 29 Jun 2026 19:38:26 GMT · run #2108 |
|
Preview environment deployed 🚀
Stack: Auto-destroys on PR close/merge. Login via the bundled Keycloak realm — |
d44392e to
ec2f63c
Compare
7e1dd71 to
b404270
Compare
* feat(THU-549): serverId + extended /v1/config payload * feat(THU-549): trust-domain registry + namespaced auth/device/keys * feat(THU-549): boot env vars + trust-domain decision tree * feat(THU-549): scope DB filename by trust domain + lifecycle broadcast * feat(THU-549): logout = unconditional wipe * feat(THU-549): scope cloud URL by active server * refactor(THU-549): collapse registry actions into activateServer/activateStandalone * feat(THU-549): persist per-server session on ServerEntry + wire mirror * refactor(THU-549): drop unused db-reopened event + subscribeDbLifecycle * refactor(THU-549): extract shared sync-worker-name format * fix(THU-549): pin SERVER_ID for e2e backends * fix(THU-549): address PR review — timeout, Tauri OPFS, logout loading state, test SERVER_ID, auth-token let * fix(THU-549): wipe IDB databases on logout + fix SSO redirect race + delete E2EE keys IDB * fix(THU-549): use getActiveCloudUrl in getSystemTinfoilClient * fix(THU-550): fix BE/FE tests broken by THU-549 trust-domain rebase * feat(THU-550): Workspaces data layer (#944) * feat(THU-550): BE workspaces tables + post-create bootstrap hook * feat(THU-550): PowerSync upload handler factory + workspace handlers * feat(THU-550): workspace_id on scoped tables + sync rules + ws handler * feat(THU-550): encrypt workspaces.name * feat(THU-550): shared deterministic personal-workspace id helpers * feat(THU-550): BE — FE-owned personal workspace creation * feat(THU-550): FE — workspace-aware DAL + post-auth bootstrap + gate * fix(THU-550): log permanently rejected upload ops * fix(THU-550): pin workspace_id in PATCH/DELETE WHERE clause * fix(THU-550): scope reconcile-defaults lookups and updates by workspace_id * fix(THU-550): force personal workspace name + shared workspace admin bootstrap * fix(THU-550): throw bootstrap error + update stale 400 upload test assertions * fix(THU-550): add workspaceId to model profile defaults + fix getSystemTinfoilClient cloud URL * fix(THU-550): restore BE test isolation broken by upload handler transactions * ci(THU-550): install root deps before BE type-check (shared/ uses uuid) * feat(THU-578): scope all FE DAL methods to active workspaceId (#951) * feat(THU-578): scope all FE DAL methods to active workspaceId * fix(THU-578): seed trust domain in eval CLI + scope model-profile upsert by workspace * fix(THU-578): retry hydration when workspaceId resolves after WorkspaceGate * fix(THU-578): evict stale chat session on workspace switch * fix(THU-578): scope prompt join in getTriggerPromptForThread to active workspace * fix(THU-578): fix random test failures from workspaceId resolution races * feat(THU-553): mode picker UI — layout, selection state, and connectivity (#958) * feat(THU-553): polish mode-picker UI — layout, selection state, and connectivity * fix(THU-553): DI for mode-picker, drop mock.module('@/lib/http') leakage * feat(THU-551): workspace selector in sidebar + URL-based active workspace (#961) * feat(THU-551): reactive active-workspace + URL helpers * feat(THU-551): useWorkspacesQuery hook + DAL test * feat(THU-551): WorkspaceMembershipGate + live membership query * feat(THU-551): mount workspace routes under /w/:workspaceId prefix * feat(THU-551): workspace selector in sidebar header * feat(THU-551): thread workspace prefix through navigation call sites * feat(THU-552): create workspace modal — name + invite by email (#965) * feat(THU-552): promote pending membership to active on email match * feat(THU-552): createSharedWorkspace DAL function * feat(THU-552): useCanCreateWorkspace hook * feat(THU-552): EmailChipInput component * feat(THU-552): CreateWorkspaceModal component * feat(THU-552): Create workspace button in sidebar selector footer * feat(THU-552): seed defaults into newly-created shared workspace * fix(THU-552): scope cleanupRemovedDefaults to a workspace * feat(THU-552): split create + invite into two modals, single Create CTA * feat(THU-552): workspace selector design polish * fix(THU-552): rename SCREAMING_SNAKE constants to camelCase * feat(THU-554): Settings → Workspace → General (rename, slug, icon, duplicate) (#971) * fix(THU-554): align PageHeader actions with content padding * feat(THU-554): allow personal workspace rename via upload handler * feat(THU-554): updateWorkspaceName DAL, default name, createdAt stamps * feat(THU-554): useActiveWorkspaceMembership hook * feat(THU-554): split settings sidebar into Account Settings and Workspace groups * feat(THU-554): Workspace Settings page with autosave rename * feat(THU-554): add slug + icon columns to workspaces * feat(THU-554): workspace slug input with auto-derive from name * feat(THU-554): workspace icon picker (emoji or image upload) * feat(THU-554): render workspace icon in the sidebar selector * feat(THU-554): share WorkspaceFormFields between settings and create modal * feat(THU-554): duplicate workspace action * feat(THU-555): Settings → Workspace → Members (add / remove / role / pending) (#974) * feat(THU-555): add user_name/user_email to workspace_memberships * feat(THU-555): enrich membership upload handler with user display info * feat(THU-555): propagate user name/email changes to memberships * feat(THU-555): mirror userName/userEmail on FE workspace_memberships * feat(THU-555): reactive members + pending queries * feat(THU-555): membership mutation DAL * feat(THU-555): useWorkspacePermission hook * feat(THU-555): RequireWorkspacePermission route wrapper * feat(THU-555): Members page scaffold + route * feat(THU-555): Members sidebar entry gated by manage_members * feat(THU-555): render members table with role dropdown * feat(THU-555): wire Remove member with confirmation * feat(THU-555): use globe icon for General sidebar entry * fix(THU-555): rename SCREAMING_SNAKE constant to camelCase * feat(THU-593): gate member management on E2EE-enabled servers * fix(chat-store): dedupe concurrent hydrateChatStore calls * feat(THU-556): Settings → Workspace → Permissions page + resource-CRUD enforcement (#978) * feat(THU-556): setWorkspacePermissionRequiredRole DAL * feat(THU-556): RequireWorkspaceAdmin route guard * refactor(THU-556): consolidate workspace permission keys into shared/workspaces.ts * feat(THU-556): Permissions page (11 keys, labels only) * feat(THU-556): Permissions sidebar entry * feat(THU-556): mount Permissions route * feat(THU-556): refine Permissions page copy and layout * feat(THU-556): scope Permissions to agents/skills/models/mcps * feat(THU-556): use Lock icon for Permissions sidebar entry * feat(THU-556): permissionAllows + BE permission lookup helpers * feat(THU-556): permission-key gating in workspace-scoped handler * feat(THU-556): enforce add_agents/remove_agents permissions * feat(THU-556): treat soft-delete PATCH as remove for permission gating * feat(THU-556): enforce add_skills/remove_skills permissions * feat(THU-556): enforce add_models/remove_models permissions * feat(THU-556): enforce add_mcp_servers/remove_mcp_servers permissions * feat(THU-556): gate edit + chat bypasses, add permission gating tests * fix(workspaces): address review comments across stacked PRs (#988) * fix(THU-549): clear auth token after signOut so server can revoke session * fix(THU-549): clear registry before db-closing so reloaded tabs land at ModePicker * fix(THU-549): guard LogoutModal handleLogout against rapid double-click * fix(THU-549): friendlier ZodError for unset/invalid SERVER_ID * fix(THU-549): remove Cloud URL dev-settings input (use ModePicker flow instead) * fix(THU-552): preserve existing membership role on promote-on-insert * fix(THU-552): delete pending row by (workspace_id, email) after promote-on-insert * fix(THU-552): skip onCreated when create-workspace modal dismissed mid-flight * fix(THU-554): preserve slug/icon on PUT when payload omits them * fix(THU-554): reflect remote workspace updates into settings form * fix(THU-554): append random suffix to duplicate workspace slug * fix(THU-555): resolve workspace permission state when user has no membership * fix(THU-555): gate member actions on granular permission keys * fix(THU-551): expose URL workspace id immediately + collapse chat-id on workspace switch * fix(THU-550): wrap BrowserRouter in ErrorBoundary so bootstrap throws surface a screen * chore: strip PR-ref noise from review-followup comments * fix(THU-578): reset isReady before chat session eviction on workspace switch * fix(THU-553): dedupe ModePicker validation between blur and Continue * fix(THU-552): force ctx.userId for invitedByUserId in pending memberships * fix(THU-552): reject malformed emails on pending membership writes * fix(THU-578): persist selectedAgent against session.workspaceId not thread * fix(THU-556): hide chat-skills-bar when no edit perm and no pinned chips * docs: refresh workspace-memberships handler docstring for permission-key model * test(THU-578): seed workspace context in LinkPreviewWidget fallback tests * fix(THU-553): reset isValidating on SET_URL to unstick Continue after stale blur * fix(THU-553): reset stage to picker on stale-URL bail-out in handleContinue * fix(THU-549): pass captured serverId to handleFullWipe after registry clear * fix(THU-555): align pending-row gates + block admin escalation via invite * refactor(THU-555): use isResolved for membership loading distinction * refactor(THU-555): assign openRef in render body, drop useEffect * fix(THU-555): widen duplicate-slug suffix to 8 chars for collision resistance * docs(THU-555): refresh stale comments referencing removed manage_members guard * fix(THU-555): mirror serverUrl ref synchronously in mode-picker onChange * fix(THU-555): sync pending memberships to all workspace members * fix(THU-555): require change_roles for membership PUT that changes existing role * fix(THU-549): keep getAuthToken resolvable through signOut after registry clear * fix(THU-555): add last-admin guard to membership PUT apply path * fix(THU-555): gate pending-row Admin option on change_roles
* chore(THU-603): add scope column to workspace resource schemas * feat(THU-603): split sync rules by resource scope * feat(THU-603): scope-aware upload handler + config flag * feat(THU-603): thread scope through FE config and DAL * feat(THU-603): add scope picker primitive and gate hook * feat(THU-603): expose scope picker in resource UIs * feat(THU-603): accept user scope in workspace upload handler * fix(THU-603): skip default tasks when seeding new workspaces * fix(THU-603): honor composite PK in upload-handler row lookup * fix: stabilize logout-modal and skills-view flaky tests * refactor: split settings sidebar into Account / Extensions / Workspace * feat: open Workspace > General to members; read-only for non-admins * fix: reset useConfigStore between test suites to prevent leak * fix(THU-603): enforce allowUserScopedResources + INVALID_SCOPE on PUT and PATCH
* feat(THU-622): backfill workspace_id in BE 0020/0021 instead of truncating * feat(THU-622): unblock pre-Workspaces clients during rollout * feat(THU-622): FE pre-Workspaces attach migration + boot wiring * feat(THU-579): add api_key column to models schema (revert THU-505) * refactor(THU-579): read api_key directly from models, drop models_secrets * feat(THU-579): copy api_key from legacy models_secrets without clobbering * feat(THU-622): redirect to / after first-time migration * fix(THU-579): stamp api_key via Drizzle so PowerSync uploads it * fix(THU-622): rewrite pre-Workspaces local DB migration via separate wa-sqlite engine * chore: merge BE migrations * fix(THU-622): gate destructive migration steps on data-completion flag * docs(THU-622): move pre-workspaces-attach README to docs/architecture * fix(THU-622): warn on dropped legacy rows during table copy * docs(THU-622): mark PowerSync internal-schema coupling in ps_crud import * fix(THU-622): assert non-null user_id before backfill in 0021 migration * refactor(THU-622): rename ranAttach to ranMigration on migration result * fix(THU-622): defer pre-Workspaces telemetry until after PostHog init * fix(THU-622): preserve legacy localStorage and IDB keys for rollback * fix(THU-622): device-global migration flag, ps_crud wipe, drop tripwire * fix(THU-622): post-merge test and DAL fallout
2fb0814 to
223a07e
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e6210f8. Configure here.
7 tasks
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 free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.

Lands Workspaces v1 — multi-user support for enterprise deployments where members share AI configuration (models, modes, prompts, MCP servers, agents, skills) inside a workspace while keeping chats, messages, and tasks private per user.
What's in
serverId+ extended/v1/config, trust-domain registry, per-server scoped SQLite, namespaced auth/device/keys, logout = wipe.workspaceId, post-auth bootstrap + gate./w/:workspaceIdrouting for shared workspaces (personal stays at unprefixed URLs).createWorkspaceScopedHandler+useWorkspacePermission.modelsrow again, copied over from the oldmodels_secretstable.Out of scope (post-v1)
Standalone UX polish, anon entry button, workspace delete, multi-server UI, surfacing rejected sync ops (THU-557, THU-592, THU-598, THU-599, THU-590).
Note
High Risk
Large one-shot schema migration on published PowerSync tables (PK swaps and backfills) plus changed upload semantics affect every synced client; SERVER_ID is a breaking deploy requirement that resets client trust domains if mis-set.
Overview
Introduces Workspaces v1 on the backend: a consolidated migration adds workspace identity tables, backfills a personal workspace per user, threads
workspace_id(and optionalscope) through PowerSync data tables, reshapes composite PKs/FKs, and restoresmodels.api_key.Deployment identity and policy —
SERVER_IDis now required (validated UUID);GET /v1/configexposesserverId, anonymous-user allowance, workspace-creation flags, andallowUserScopedResources. Env examples and CI install root deps soshared/workspaces.tscan resolveuuidduring backend type-check.PowerSync uploads — the monolithic
applyOperationDAL is replaced byapplyUploadBatchand per-table handlers (workspace-scoped vs user-scoped). Successful uploads return{ success, rejected[] }with per-op codes (e.g.ROW_NOT_FOUND,UNKNOWN_TABLE) instead of failing the whole batch with HTTP 400; transient failures use 503.Auth lifecycle — on user create,
promotePendingMembershipsturns email invites into memberships; on profile update,syncMembershipDisplayInfokeeps denormalized member display fields in sync. New workspace DAL powers upload enforcement and tests cover these flows.Reviewed by Cursor Bugbot for commit e5b89ab. Bugbot is set up for automated code reviews on this repo. Configure here.