feat(desktop): implement workspace foundation + desktop-client skeleton
Plan 0 (workspaces): add workspaces + workspace_memberships schema, extend JWT/Actor/claims with primary_workspace_id, seed default workspace per tenant, thread workspace_id through tenant monitoring quota. Plan A (desktop skeleton): new Electron app (apps/desktop-client) with main/ preload/renderer, shared Vue component package (packages/ui-shared), and server surface — desktop client registration + token rotation + heartbeat, SSE task event stream, desktop accounts/tasks/content handlers, publish job endpoint, and supporting repositories, services, sqlc queries, and migrations. Hard cutover per plan: remove browser-extension monitoring callback endpoints, stub legacy media API in admin-web, and delete monitoring_callback_handler.go.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
CREATE TABLE workspaces (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
tenant_id BIGINT NOT NULL REFERENCES tenants(id),
|
||||
name TEXT NOT NULL,
|
||||
slug TEXT NOT NULL,
|
||||
is_default BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (tenant_id, slug)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_workspaces_tenant_default
|
||||
ON workspaces (tenant_id)
|
||||
WHERE is_default = TRUE;
|
||||
|
||||
CREATE TABLE workspace_memberships (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
workspace_id BIGINT NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
tenant_id BIGINT NOT NULL REFERENCES tenants(id),
|
||||
role TEXT NOT NULL DEFAULT 'member',
|
||||
is_primary BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (workspace_id, user_id)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_memberships_user_primary
|
||||
ON workspace_memberships (user_id)
|
||||
WHERE is_primary = TRUE;
|
||||
|
||||
INSERT INTO workspaces (tenant_id, name, slug, is_default)
|
||||
SELECT id, 'Default', 'default', TRUE
|
||||
FROM tenants
|
||||
ON CONFLICT (tenant_id, slug) DO NOTHING;
|
||||
|
||||
INSERT INTO workspace_memberships (workspace_id, user_id, tenant_id, role, is_primary)
|
||||
SELECT w.id, tm.user_id, tm.tenant_id, 'member', TRUE
|
||||
FROM tenant_memberships tm
|
||||
JOIN workspaces w
|
||||
ON w.tenant_id = tm.tenant_id
|
||||
AND w.is_default = TRUE
|
||||
WHERE tm.deleted_at IS NULL
|
||||
ON CONFLICT (workspace_id, user_id) DO NOTHING;
|
||||
Reference in New Issue
Block a user