Three new plan trees that fill in the gaps surfaced during repo review. Together they map out what remains between the current scaffold-with-stubs state and a daily-usable, multitenant, agent-coordinated app. * Plan-daily-driver-finish (P0): turn stubs into real data. Five tasks covering the lint/shared-types breakage, hardcoded dashboard mocks, AI-page setTimeout placeholder, post-signin landing decision, and a cross-browser collab smoke test against the deployed Hocuspocus instance. * Plan-multitenant-saas-hardening (P1): everything multitenant needs beyond what Plan-multitenant-cursor-sync already covers. Invites and role management, soft-delete + append-only audit log, rate limits on the auth + mutation hot paths, and a Vitest + GitHub Actions test foundation so PRs can't ship red. * Plan-agent-coordination (P2): the layer that makes a Task-*.md runnable, not just readable. Adds workflow_prompt with task -> epic -> plan inheritance, an agent_runs table for auditable sessions, and two new MCP tools (claim_task / complete_task) that replace the freeform update_object composition agents do today. Includes an intentionally-deferred Epic-optional-orchestrator that captures the Symphony-shaped runner as a decision point rather than an immediate build. Each task is bead-scale (one focused Cursor session) with explicit in-scope, out-of-scope, and anti-goal sections so a future agent can pick up a single Task-*.md and start without scrollback context. Co-authored-by: Cursor <cursoragent@cursor.com>
68 lines
3 KiB
Markdown
68 lines
3 KiB
Markdown
---
|
|
kind: task
|
|
slug: wire-workspace-home-dashboard
|
|
title: Replace hardcoded dashboard mocks with real tRPC queries
|
|
plan_slug: daily-driver-finish
|
|
epic_slug: shipping-the-shell
|
|
status: ready
|
|
priority: P0
|
|
tenant_id: global
|
|
owner: unassigned
|
|
cursor_todo_id: null
|
|
updated_at: "2026-06-01"
|
|
---
|
|
|
|
# Task summary
|
|
|
|
`apps/web/app/(app)/[workspaceSlug]/page.tsx` currently renders a hardcoded `stats` array (`"24"`, `"8"`, `"12"`) and a hardcoded `recent` list. Replace both with real tRPC calls so the home page reflects actual workspace state.
|
|
|
|
## Description
|
|
|
|
The page is a Client Component (`"use client"`). It already pulls `currentWorkspace` from `useWorkspaceStore`. What it needs:
|
|
|
|
1. **Stats card**: replace the three `stats` entries with counts derived from `objects` filtered by workspace. Suggested:
|
|
- "Open tasks" — count of `objects` where `type = 'task'` and `status` is not in a "done" set, scoped by workspace_id.
|
|
- "Due this week" — same scope, additionally filtered by `due_at <= now + 7 days`. If `objects` doesn't have a due-date column yet, drop this card rather than fake it.
|
|
- "Lists" / "Projects" — count of `objects` where `type` is in `('project', 'space', 'group')`.
|
|
|
|
2. **Recent list**: replace the static `recent` array with the 5 most-recently-updated objects in the workspace. Use the existing `objects` router. If no suitable procedure exists, add one as `objects.listRecent({ limit: 5 })` — workspace-scoped via `workspaceProcedure` in `apps/web/server/trpc.ts`.
|
|
|
|
3. **Loading + empty states**: use the same `Card` skeleton pattern already in `apps/web/app/(app)/[workspaceSlug]/teams/page.tsx` (`MemberCardSkeleton`). When the workspace has no objects, render a friendly empty state with a "Create your first project" CTA that opens the existing `CreateObjectDialog`.
|
|
|
|
### Constraints
|
|
|
|
- Don't add a new column to `objects` unless you also add a Drizzle migration. Prefer to drop a card rather than schema-creep this task.
|
|
- All queries MUST filter by `workspace_id`. Use `workspaceProcedure`, never a raw procedure that pulls the slug from the URL without re-checking.
|
|
- No raw `fetch` against `/api/trpc` — use `api.objects.<...>.useQuery()` via `@trpc/react-query`.
|
|
|
|
## Subtasks
|
|
|
|
- [ ] Audit `apps/web/server/routers/objects.ts` for existing `count` / `listRecent` procedures.
|
|
- [ ] Add the missing procedure(s) if needed, with zod inputs and workspace scoping.
|
|
- [ ] Replace `stats` and `recent` arrays in `[workspaceSlug]/page.tsx` with `api.objects.*.useQuery()` calls.
|
|
- [ ] Add a skeleton state and an empty state.
|
|
- [ ] Wire the empty-state CTA to `CreateObjectDialog`.
|
|
|
|
## Owner or assignee
|
|
|
|
Unassigned
|
|
|
|
## Status
|
|
|
|
ready
|
|
|
|
## Estimation
|
|
|
|
M
|
|
|
|
## Acceptance criteria
|
|
|
|
- [ ] No hardcoded numbers or hardcoded titles remain in `apps/web/app/(app)/[workspaceSlug]/page.tsx`.
|
|
- [ ] Loading state renders without a flash of zeros.
|
|
- [ ] Empty state for a brand-new workspace renders a CTA.
|
|
- [ ] All queries filter by `workspace_id`.
|
|
|
|
## Links to related Epic / Plan
|
|
|
|
- Epic: `./Epic-shipping-the-shell.md`
|
|
- Plan: `../Plan-daily-driver-finish.md`
|