CRM daily workspace
Conversations and Follow-ups remain the existing CRM pages. Their heading links connect the two surfaces without adding global navigation or another inbox/backend.
Follow-ups summarizes the currently loaded queue, including its owner and Open/Completed filters. Overdue/today/later uses the shared timezone and DST-aware grouping used by its rows. A server cursor means more available even when visibility filtering produces an empty or short page. Completed work is described as completed loaded items. The independent conversation summary reports the server's counts of conversations with unread messages, open assigned to me, and open unassigned; unavailable/stale answers are labeled independently.
Conversations summarizes its loaded filtered threads: conversations, threads with unread messages, and threads with an assignee. These are not organization totals or inferred reply obligations. A separate loaded planned-follow-up summary uses the existing timeline read. Failed reads do not become zero counts.
The thread, view, status, channel, and submitted q query parameters survive reload. Thread selection adds a history entry; filter edits replace the current entry and preserve unrelated parameters. Back/Forward selects the URL's thread. Detail queries and caches include the current organization, and the page remounts the inbox when organization changes. Missing or foreign thread links show an unavailable state without resolving through another organization. Path segments are encoded before requesting detail.
Beside the selected conversation's real contact link, Create follow-up opens the existing Activity Composer with that contact linked. Choose Task and Planned, then Save. The composer currently has no public initial-kind option; this UI explains those choices instead of adding another writer or silently changing the form. Creation requires crm:create and the current CRM entitlement. Completion/rescheduling retain the existing row controls and server transition; completedAt comes from the server.
Opening a thread performs reads only. Mark read explicitly advances this person's read marker. Assignment, closing, sending, and activity creation remain human actions. Reply channel availability, suppression/do-not-contact information, practice mode, queued/unknown outcomes and request idempotency remain the existing inbox behavior.
The browser/API journey is apps/api/test/crm-daily-workspace-journey.test.ts. Build the web package with NEXT_PUBLIC_API_URL='' API_PROXY_TARGET=http://127.0.0.1:43183, then run that named suite through the approved PostgreSQL pool. It starts and closes only loopback API/web child processes, with synthetic records in the suite's disposable database. Screenshots and IDs are written under the task's .lanes evidence directory. No external transport is invoked. Each view/status/channel/search control is changed in the browser, checked against the outgoing list request and URL, then checked again after reload and Back/Forward through Follow-ups. The real-page HTTP-fixture suite apps/web/src/components/crm/daily-workspace-conversations.test.tsx independently denies creation without crm:create and with crm.enabled: false, alongside an allowed case; it also checks each filter URL write and preservation of unrelated query parameters.
MCP integration boundary: crm_get_record reads the same contact. Org API keys cannot read the CRM timeline through call_api: the API-key route allowlist excludes that route. The separate user_token_session_action tool can expose timeline reads only with its dark switches and an explicit human-granted user token; it is not registered for this fixture's org key. Inbox v1 explicitly refuses agent credentials even for reads. The journey records both exact refusals rather than claiming parity. Parent integration must decide whether these credential surfaces should support daily workspace reads; this UI does not change auth, grants or central transport.
URL implementation follows the installed Next.js documentation and Next.js useSearchParams. Browser fixtures follow Playwright BrowserContext and Route. Large local typechecks use Node's documented max-old-space-size option when the default heap is insufficient.