feat(api): GET /api/workspaces/:id/stats endpoint

This commit is contained in:
2026-03-01 15:35:02 -06:00
commit fe87122179
41 changed files with 8471 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
Wire the chat interface in ~/src/mosaic-stack to the backend API.
## Context
The chat page (/chat) exists with full UI components but is NOT connected to the backend. Everything is stubbed. The old jarvis codebase had a working implementation — use it as the reference.
## Architecture Decision
Use `/api/chat/stream` (chat-proxy → OpenClaw) for LLM responses.
But ALSO wire conversation persistence using the existing brain + conversation-archive endpoints.
## Backend Endpoints Available (all authenticated, cookie-based auth):
### Chat/LLM:
- POST /api/chat/stream — SSE stream proxied from OpenClaw
- Request body: { messages: [{role, content}], model?: string }
- Response: SSE stream (pass-through from OpenClaw — handle both OpenAI format and custom format)
- OpenAI streaming format: data: {"choices":[{"delta":{"content":"token"},"finish_reason":null}]}\n\n
- Final: data: [DONE]\n\n OR data: {"choices":[{"finish_reason":"stop"}]}\n\n
- Error: event: error\ndata: {"error":"message"}\n\n
### Conversation Archive (for persistence):
- GET /api/conversation-archives — list user's archived conversations
- POST /api/conversation-archives — create/save a conversation
- Body: { title: string, summary?: string, messages: [{role, content, timestamp?}], metadata?: object }
- GET /api/conversation-archives/:id — get specific conversation
- DELETE /api/conversation-archives/:id — delete
### Brain (for context):
- POST /api/brain/query — query tasks, projects, events
- GET /api/brain/context — get summary context
## What to Change
### 1. apps/web/src/lib/api/chat.ts
Rewrite `streamChatMessage` to:
- Call `POST /api/chat/stream` (not /api/llm/chat)
- Use credentials: "include" (cookie auth)
- Add X-Workspace-Id header from workspace context
- Handle OpenAI SSE format: parse `data.choices[0].delta.content` for tokens
- Also handle `data: [DONE]` as completion
- Keep the same callback signature: onChunk(token), onComplete(), onError(err)
Add new functions:
- `saveConversation(title, messages)` → POST /api/conversation-archives
- `listConversations()` → GET /api/conversation-archives
- `getConversation(id)` → GET /api/conversation-archives/:id
- `deleteConversation(id)` → DELETE /api/conversation-archives/:id
### 2. apps/web/src/hooks/useChat.ts
- Fix `loadConversation`: load from conversation-archives API instead of ideas/brain
- Fix `sendMessage`: uses streamChatMessage correctly with the messages array
- Add `saveCurrentConversation()`: save to conversation-archives after each assistant reply
- Wire up auto-save after each successful assistant response
### 3. apps/web/src/components/chat/ConversationSidebar.tsx
Check if it loads from conversations API — if it's stubbed or uses wrong endpoint, fix to use `listConversations()`.
## Key Reference: Old Jarvis Implementation
The old jarvis at ~/src/jarvis-old/apps/web/src had:
- components/Chat.tsx (1616 lines — working SSE stream handler)
- lib/api.ts — working API client
- hooks/useConversations.ts — conversation list management
Read these for reference on SSE parsing, error handling, conversation state management patterns.
## Constraints
- Keep auth as cookie-based (credentials: "include") — NOT Bearer token for web client
- The X-Workspace-Id header must be included on all API calls
- Use useWorkspaceId() hook to get workspace ID
- Keep TypeScript strict — no `any` unless unavoidable
- Match existing chat.ts style (callbacks not promises for streaming)
## Process
1. git checkout main && git pull --ff-only origin main
2. git checkout -b feat/wire-chat-interface
3. Read the existing files: apps/web/src/lib/api/chat.ts, apps/web/src/hooks/useChat.ts, apps/web/src/components/chat/*.tsx
4. Read reference: ~/src/jarvis-old/apps/web/src/components/Chat.tsx (lines 400-550 for SSE handling)
5. Implement the changes
6. Run: pnpm turbo lint typecheck --filter=@mosaic/web
7. Commit --no-verify: "feat(web): wire chat interface to /api/chat/stream and conversation-archives"
8. Push and PR: ~/.config/mosaic/tools/git/pr-create.sh -t "feat(web): wire chat interface to backend" -b "Wires the stubbed chat page to /api/chat/stream (OpenClaw proxy) for LLM responses and /api/conversation-archives for persistence. References old jarvis implementation for SSE parsing patterns."
When done:
openclaw system event --text "Done: chat wiring PR ready" --mode now

View File

@@ -0,0 +1,29 @@
Fix the CsrfGuard in ~/src/mosaic-stack to skip CSRF validation when the request is authenticated via Bearer token (Authorization header).
## Background
CSRF attacks exploit cookie-based authentication — a malicious site tricks the browser into sending authenticated cookies. When a client uses `Authorization: Bearer <token>`, CSRF is not a valid attack vector because malicious sites cannot set or read Authorization headers. The CSRF guard should not fire for Bearer-authenticated API clients.
## File to Change
apps/api/src/common/guards/csrf.guard.ts
## What to Do
1. git checkout main && git pull --ff-only origin main
2. Create branch: fix/csrf-bearer-bypass
3. Read csrf.guard.ts carefully
4. Update `canActivate` to skip CSRF check when the request has an `Authorization: Bearer` header
- Extract the Authorization header
- If it starts with "Bearer ", return true (skip CSRF — Bearer auth is not CSRF-vulnerable)
- Otherwise, proceed with existing CSRF token validation as-is
5. Do NOT change any other logic — surgical change only
6. Read auth.guard.ts to confirm you are using the same header extraction pattern for consistency
## Completion Requirements (MANDATORY)
1. Run quality gates: pnpm turbo lint typecheck --filter=@mosaic/api
2. Run tests: pnpm --filter @mosaic/api test -- --run
3. Review the change: confirm existing CSRF tests still pass, confirm Bearer bypass is correct
4. Commit: "fix(api): skip CSRF for Bearer-authenticated requests"
5. Push branch
6. Create PR: ~/.config/mosaic/tools/git/pr-create.sh -t "fix(api): skip CSRF for Bearer-authenticated API clients" -b "CSRF protection is only relevant for cookie-based sessions. Requests using Authorization: Bearer are not CSRF-vulnerable — malicious sites cannot inject Authorization headers. This change skips CSRF validation when a Bearer token is present, enabling programmatic API access from agents and service accounts."
When completely finished, run:
openclaw system event --text "Done: CSRF Bearer bypass PR ready for review" --mode now

View File

@@ -0,0 +1,51 @@
Fix the fleet-settings "Add Provider" form in ~/src/mosaic-stack so it submits the correct field names to the API.
## Background
The Add Provider UI form (apps/web) sends these fields to POST /api/llm-providers:
- type (should be: providerType)
- baseUrl (should be nested inside config.endpoint)
- models (should be nested inside config.models)
- displayName (correct)
- apiKey (should be nested inside config.apiKey)
The API DTO (apps/api/src/llm/dto/provider-admin.dto.ts) expects:
{
providerType: "ollama" | "openai" | "claude",
displayName: string,
config: {
endpoint?: string, // the base URL
apiKey?: string,
models?: string[], // list of model IDs
timeout?: number
},
isDefault?: boolean,
isEnabled?: boolean
}
## Files to Change
- apps/web — find the Add Provider form/dialog component (search for "Add Provider" or "baseUrl" or "providerType")
- Fix the form submission to map fields correctly before POSTing
## Process
1. git checkout main && git pull --ff-only origin main
2. Create branch: fix/fleet-provider-form-dto
3. Find the form component — search: grep -r "baseUrl\|Add Provider\|providerType" apps/web/src --include="*.tsx" --include="*.ts" -l
4. Fix field mapping in the form submit handler:
- type → providerType
- baseUrl → config.endpoint
- models (textarea, newline-separated) → config.models (string array, split by newline, trim, filter empty)
- apiKey → config.apiKey
5. Also fix the models input: if it's a textarea with one model per line, split on newline before submitting
## Completion Requirements (MANDATORY)
1. Run: pnpm turbo lint typecheck --filter=@mosaic/web
2. Run: pnpm --filter @mosaic/web test -- --run (if tests exist)
3. Review: confirm form submit payload matches CreateLlmProviderDto exactly
4. Commit: "fix(web): correct Add Provider form field mapping to match API DTO"
5. Push and create PR:
~/.config/mosaic/tools/git/pr-create.sh \
-t "fix(web): correct Add Provider form DTO field mapping" \
-b "The Add Provider form was sending top-level fields (type, baseUrl, models) that do not match the API DTO. Fixed to send providerType and nest endpoint/apiKey/models inside config object. Models textarea is now split by newline into a string array."
When completely finished, run:
openclaw system event --text "Done: fleet-provider form DTO fix PR ready" --mode now

View File

@@ -0,0 +1,38 @@
Add "Add Task" functionality to the Kanban board in ~/src/mosaic-stack.
## Problem
The Kanban page (/kanban) shows tasks and allows drag-drop between columns, but there is NO way to create a new task. Users can't add tasks directly to the queue.
## What Exists
- File: apps/web/src/app/(authenticated)/kanban/page.tsx (765 lines)
- API client: apps/web/src/lib/api/tasks.ts — already has fetchTasks, updateTask, and a newly added createTask function
- API endpoint: POST /api/tasks (accepts: title, description?, status?, priority?, dueDate?, projectId?)
- Shared types: @mosaic/shared — Task, TaskStatus, TaskPriority enums
- Project fetch: fetchProjects already imported in kanban page
## What to Build
Add an "Add Task" button (+ icon) to each Kanban column header that:
1. Opens an inline form or small dialog directly in that column
2. Form fields: title (required), description (optional), priority (optional, defaults to MEDIUM), dueDate (optional)
3. On submit: calls createTask({ title, description, priority, status: <column_status>, projectId: currentProjectFilter })
4. On success: adds the new task to the column without full page reload (optimistic or refetch)
5. On cancel: dismisses form
6. Matches existing visual style (same inline styles / design tokens as rest of page — it uses CSS-in-JS inline styles with rgb(var(--color-*)) tokens)
## Key Constraints
- The page uses inline styles throughout (rgb(var(--surface-*)), rgb(var(--text-*)), rgb(var(--border-*))) — match this pattern, no Tailwind classes
- KanbanColumn component receives config and tasks — you'll need to wire the add button into it or add it at column-header level
- createTask is exported from apps/web/src/lib/api/tasks.ts — import and use it
- Use useWorkspaceId() hook (already imported) for workspace context
- Keep it minimal — a simple inline card input (like Trello's "+Add a card" at bottom of column) is perfect
## Process
1. git checkout main && git pull --ff-only origin main
2. git checkout -b feat/kanban-add-task
3. Implement the feature
4. Run: pnpm turbo lint typecheck --filter=@mosaic/web
5. Commit --no-verify: "feat(web): add task creation to Kanban board"
6. Push and PR: ~/.config/mosaic/tools/git/pr-create.sh -t "feat(web): add task creation to Kanban board" -b "Adds inline Add Task button to each Kanban column. Clicking opens a quick-add form at the bottom of the column. Uses createTask API to persist, then refreshes tasks."
When done:
openclaw system event --text "Done: kanban add-task PR ready" --mode now

View File

@@ -0,0 +1,57 @@
You are performing a mandatory code review and security audit of MS22 Phase 1 modules in ~/src/mosaic-stack.
## Objective
Audit all MS22 modules for correctness, missing dependencies, and security issues. Produce a written report regardless of findings. If nothing needs fixing, that is itself a valid result — document it.
## MS22 Modules to Audit
- apps/api/src/container-lifecycle/
- apps/api/src/crypto/
- apps/api/src/agent-config/
- apps/api/src/onboarding/
- apps/api/src/fleet-settings/
- apps/api/src/chat-proxy/
## What to Check
### 1. NestJS Module Dependency Audit
For each *.module.ts file:
- Does it import every module whose services/guards are used in its controllers/services?
- Are all providers listed that are used?
- Are exports correct?
### 2. Security Review
- fleet-settings: are admin-only routes properly guarded? Can a non-admin access provider secrets?
- agent-config: is the bearer token guard timing-safe? Is the internal route isolated?
- onboarding: can onboarding be re-run after completion?
- crypto: is AES-256-GCM implemented correctly? IV uniqueness, auth tag verification?
- chat-proxy: can a user proxy to another user's container?
### 3. Input Validation
- Are DTOs using class-validator decorators?
- Any unvalidated inputs?
### 4. Error Handling
- Are errors leaking sensitive data?
- Are Prisma errors caught before reaching HTTP layer?
## Process — MANDATORY, follow exactly
1. git checkout main && git pull --ff-only origin main
2. Read each module file carefully
3. Create branch: fix/ms22-audit
4. Write a report file at docs/audits/ms22-phase1-audit.md documenting:
- Each module reviewed
- Findings (or "no issues found") per module
- Security assessment
- Changes made (if any)
5. If you found issues: fix them, include fixes in the same commit
6. If no issues found: still commit the report file
7. Run quality gates: pnpm turbo lint typecheck --filter=@mosaic/api
8. Commit: "fix(api): MS22 Phase 1 audit report and fixes"
9. Push: git push origin fix/ms22-audit
10. Create PR: ~/.config/mosaic/tools/git/pr-create.sh -t "fix(api): MS22 Phase 1 post-coding audit" -b "Mandatory post-coding audit of all MS22 Phase 1 modules. Report at docs/audits/ms22-phase1-audit.md."
DO NOT exit without pushing and creating a PR. The audit report is required even if all modules are clean.
When completely finished:
openclaw system event --text "Done: MS22 audit PR ready — check docs/audits/ms22-phase1-audit.md" --mode now

View File

@@ -0,0 +1,42 @@
Create the missing project detail page in ~/src/mosaic-stack.
## Problem
Clicking a project card on /projects navigates to /projects/[id] but that route doesn't exist → 404.
## What to Build
Create: apps/web/src/app/(authenticated)/projects/[id]/page.tsx
The API endpoint GET /api/projects/:id returns a project with this shape:
{
id, name, description, status, priority, startDate, dueDate, createdAt, updatedAt,
creator: { id, name, email },
tasks: [{ id, title, status, priority, dueDate }],
events: [{ id, title, startTime, endTime }],
_count: { tasks, events }
}
## Page Requirements
1. Fetch the project using the existing API client pattern (look at how projects/page.tsx calls the API — follow same auth/workspace patterns)
2. Display: project name, description, status badge, priority badge, dates, creator
3. Display tasks list: title, status, priority, dueDate — empty state if none
4. Display events list: title, startTime, endTime — empty state if none
5. Back button → /projects
6. Loading state and error state (show friendly message if project not found or fetch fails)
7. Match the visual style of the existing projects/page.tsx (same component library, shadcn/ui, same spacing/layout conventions)
## API Client
Look at apps/web/src/lib/api/ for existing project fetch functions. If no getProject(id) function exists, add it following the same pattern as other functions in that file.
## Process
1. git checkout main && git pull --ff-only origin main
2. Branch: feat/project-detail-page
3. Check apps/web/src/lib/api/ for existing project API functions
4. Create the page and any needed API client functions
5. Run: pnpm turbo lint typecheck --filter=@mosaic/web
6. Run: pnpm --filter @mosaic/web test -- --run
7. Review: confirm page handles loading/error/not-found states, confirm no TypeScript errors
8. Commit --no-verify: "feat(web): add project detail page (/projects/[id])"
9. Push and PR: ~/.config/mosaic/tools/git/pr-create.sh -t "feat(web): add project detail page" -b "Clicking a project card navigated to /projects/[id] which returned 404. This adds the missing detail page showing project info, tasks, and events."
When completely finished:
openclaw system event --text "Done: project detail page PR ready" --mode now

View File

@@ -0,0 +1,31 @@
Fix two issues in ~/src/mosaic-stack related to dashboard widgets:
## Issue 1: Rate limiting on widget polling endpoints (429 errors)
The widget data endpoint POST /api/widgets/data/* is being rate-limited because the dashboard polls it frequently from the same IP. Internal dashboard polling should not be throttled like external API traffic.
Fix: Add @SkipThrottler() decorator to the widgets data controller/endpoints.
Find the controller: grep -r "widgets/data\|WidgetData\|widget.*controller" apps/api/src --include="*.ts" -l
## Issue 2: Missing /api/orchestrator/agents and /api/orchestrator/events endpoints
The AgentStatusWidget in apps/web polls GET /api/orchestrator/agents and subscribes to GET /api/orchestrator/events (SSE). These endpoints do not exist, causing "Failed to fetch agents:" errors in the UI.
Implement a minimal orchestrator controller that:
- GET /api/orchestrator/agents — returns list of active agent containers from the agents table (id, name, status, type, createdAt). Protected by AuthGuard.
- GET /api/orchestrator/events — SSE endpoint that streams agent status change events. Can be a simple implementation that polls the agents table every 5 seconds and sends updates. Protected by AuthGuard.
Reference: apps/api/src/agent-config/ for the agents table schema and existing queries.
Create: apps/api/src/orchestrator/orchestrator.controller.ts + orchestrator.module.ts
Wire into AppModule.
## Process
1. git checkout main && git pull --ff-only origin main
2. Branch: fix/orchestrator-widgets
3. Fix Issue 1 first (small change), then Issue 2
4. Run: pnpm turbo lint typecheck --filter=@mosaic/api
5. Run: pnpm --filter @mosaic/api test -- --run
6. Review: confirm @SkipThrottler only on widget endpoints, confirm orchestrator endpoints are auth-guarded
7. Commit: "fix(api): skip throttler for widget polling; add orchestrator agents/events endpoints"
8. Push + PR: ~/.config/mosaic/tools/git/pr-create.sh -t "fix(api): widget throttling and orchestrator endpoints" -b "Adds @SkipThrottler to widget data endpoints (internal polling should not be rate-limited). Implements GET /api/orchestrator/agents and GET /api/orchestrator/events SSE endpoint for AgentStatusWidget."
When completely finished:
openclaw system event --text "Done: orchestrator widgets fix PR ready" --mode now