Skip to content

✨ feat(device): add structured working_dirs column to devices#15356

Closed
arvinxx wants to merge 1 commit into
canaryfrom
feat/device-working-dirs-schema
Closed

✨ feat(device): add structured working_dirs column to devices#15356
arvinxx wants to merge 1 commit into
canaryfrom
feat/device-working-dirs-schema

Conversation

@arvinxx

@arvinxx arvinxx commented May 31, 2026

Copy link
Copy Markdown
Member

💻 Change Type

  • ✨ feat

🔗 Related Issue

🔀 Description of Change

DB layer for structured device working directories. Adds a working_dirs jsonb column to the devices table and the WorkingDirEntry type ({ path, repoType?: 'git' | 'github' }).

A remote client viewing a device can't re-probe that device's filesystem, so the detected repo type must be captured at the source — a bare path string loses it.

Additive migration (0105_device_add_working_dirs): ALTER TABLE "devices" ADD COLUMN IF NOT EXISTS "working_dirs" jsonb DEFAULT '[]'::jsonb. The column is nullable (defaults to []). The legacy recent_cwds column is kept (now @deprecated) and no data is converted — no destructive SQL. A later cleanup can drop recent_cwds once nothing reads it.

This is the lower layer of a stacked pair — it merges first. The consumers (model / tRPC / UI) follow in #15353.

🧪 How to Test

  • Tested locally
  • Added/updated tests
  • No tests needed

Existing device model tests pass unchanged against the additive migration (backward compatible):

cd packages/database && bunx vitest run src/models/__tests__/device.test.ts   # 7 passed

📝 Additional Information

@arvinxx arvinxx requested review from nekomeowww and tjx666 as code owners May 31, 2026 12:08
@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label May 31, 2026
@vercel

vercel Bot commented May 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lobehub Canceled Canceled May 31, 2026 12:40pm

Request Review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've reviewed this pull request using the Sourcery rules engine

Introduce a `working_dirs` `jsonb` column on the `devices` table plus the
`WorkingDirEntry` type (`{ path, repoType?: 'git' | 'github' }`). Structured
entries let a remote client surface a device's working directories with their
detected repo type — a bare path string would lose that, and the client can't
re-probe a remote filesystem.

Additive migration only: `recent_cwds` is kept (now `@deprecated`) and no data
is converted, so this carries no destructive SQL. Consumers switch over in a
follow-up PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@arvinxx arvinxx force-pushed the feat/device-working-dirs-schema branch from 8ee8dd8 to 0752b4e Compare May 31, 2026 12:24
@arvinxx arvinxx changed the title ✨ feat(device): add structured working_dirs column to devices ✨ feat(device): add structured working_dirs column to devices May 31, 2026
arvinxx added a commit that referenced this pull request Jun 3, 2026
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>
arvinxx added a commit that referenced this pull request Jun 4, 2026
* 🗃️ 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>
@arvinxx arvinxx closed this Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant