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:
@@ -25,6 +25,11 @@ func TestProtectedRoutes_RequireAuth(t *testing.T) {
|
||||
}{
|
||||
{http.MethodGet, "/api/auth/me"},
|
||||
{http.MethodPost, "/api/auth/logout"},
|
||||
{http.MethodPost, "/api/desktop/clients/register"},
|
||||
{http.MethodPost, "/api/tenant/accounts/:id/request-delete"},
|
||||
{http.MethodPost, "/api/tenant/tasks/:id/reconcile"},
|
||||
{http.MethodPost, "/api/tenant/tasks/:id/cancel"},
|
||||
{http.MethodPost, "/api/tenant/publish-jobs"},
|
||||
{http.MethodGet, "/api/tenant/workspace/overview"},
|
||||
{http.MethodGet, "/api/tenant/templates"},
|
||||
{http.MethodGet, "/api/tenant/articles"},
|
||||
@@ -52,11 +57,6 @@ func TestPublicRoutes_NoAuth(t *testing.T) {
|
||||
}{
|
||||
{http.MethodPost, "/api/auth/login"},
|
||||
{http.MethodPost, "/api/auth/refresh"},
|
||||
{http.MethodPost, "/api/plugin/monitoring/heartbeat"},
|
||||
{http.MethodPost, "/api/plugin/monitoring/tasks/lease"},
|
||||
{http.MethodPost, "/api/plugin/monitoring/tasks/resume"},
|
||||
{http.MethodPost, "/api/plugin/monitoring/tasks/:id/result"},
|
||||
{http.MethodPost, "/api/plugin/monitoring/tasks/:id/skip"},
|
||||
{http.MethodGet, "/api/health/live"},
|
||||
{http.MethodGet, "/api/health/ready"},
|
||||
}
|
||||
@@ -68,6 +68,24 @@ func TestPublicRoutes_NoAuth(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDesktopClientRoutes_ClientTokenAuth(t *testing.T) {
|
||||
routes := []struct {
|
||||
method string
|
||||
path string
|
||||
}{
|
||||
{http.MethodGet, "/api/desktop/events"},
|
||||
{http.MethodGet, "/api/desktop/accounts"},
|
||||
{http.MethodPost, "/api/desktop/tasks/lease"},
|
||||
{http.MethodPost, "/api/desktop/tasks/:id/result"},
|
||||
}
|
||||
|
||||
for _, rt := range routes {
|
||||
t.Run(rt.method+" "+rt.path, func(t *testing.T) {
|
||||
assert.NotEmpty(t, rt.path)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHealthEndpoint_Live(t *testing.T) {
|
||||
r := gin.New()
|
||||
r.GET("/api/health/live", func(c *gin.Context) {
|
||||
|
||||
Reference in New Issue
Block a user