Files
lobe-chat/docs/development
Arvin Xu 133675adda 🗃️ db(database): add workspace_id columns to existing tables (#15446)
* 🗃️ feat(database): add workspace_id columns to existing tables

Add a nullable `workspace_id text` column to user-owned business tables
(agents, sessions, topics, messages, files, tasks, RAG/eval, RBAC, devices,
connectors, etc.) so records can later be scoped to a workspace. Workspace
tables themselves already landed on canary via 0105_add_usage_agent_share_workspace.

Also folds in the additive device schema from #15356: the structured
`working_dirs` jsonb column + `WorkingDirEntry` type (recent_cwds kept,
now @deprecated).

Scope is deliberately column-only — the lowest-risk slice:
- migration 0106 is pure `ADD COLUMN IF NOT EXISTS` (metadata-only, ~ms locks
  per table, online-safe, no app code change since columns are all NULL).
- FKs, btree indexes, and the per-user→workspace-scoped unique-constraint
  conversions are intentionally deferred to follow-up PRs so each can use the
  production-safe execution path Drizzle can't express (NOT VALID + VALIDATE,
  CREATE INDEX CONCURRENTLY, atomic unique swap).

Scoping notes:
- devices / user_connectors / user_connector_tools: scoped (user-owned resources).
- push_tokens: left user/device-level — an Expo token is one per app install and
  receives a person's notifications across all their workspaces.
- agent_shares: no workspace_id — scoped transitively via agent_id → agents.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* 🐛 fix(database): satisfy inferred row types after adding workspace_id

Adding workspace_id made it a required key in the Drizzle-inferred row types
($inferSelect), breaking call sites that build those shapes by hand:
- rbac.getUserRoles: include workspace_id in the explicit select projection
- session action: add workspaceId to the constructed chat-group literal
- test mocks (apiKey / generation / generationBatch / generationTopic): add
  workspaceId: null

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

*  test(database): use toMatchObject for topic.create row assertions

The two `expect(createdTopic).toEqual({ ...full literal })` snapshots broke
on every new column (here: workspace_id). Switch them to toMatchObject so the
returned row may carry extra columns without churning the expected literal.
The dbTopic↔createdTopic strict comparisons are left as toEqual.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 13:18:16 +08:00
..
2026-03-14 22:06:09 +08:00
2026-03-14 22:06:09 +08:00