nexus/.planning/phases/21-chat-foundation/21-00-PLAN.md

9.3 KiB

phase plan type wave depends_on files_modified autonomous requirements must_haves
21-chat-foundation 00 execute 0
server/src/__tests__/chat-service.test.ts
server/src/__tests__/chat-routes.test.ts
ui/src/components/ChatMarkdownMessage.test.tsx
ui/src/components/ChatInput.test.tsx
true
HIST-01
CHAT-02
CHAT-03
CHAT-04
CHAT-05
CHAT-06
INPUT-07
truths artifacts key_links
Test stubs exist and can be executed by vitest without errors
Each stub has describe blocks with placeholder tests that skip or pass trivially
path provides contains
server/src/__tests__/chat-service.test.ts Test scaffold for chat service (HIST-01, CHAT-04, CHAT-05, CHAT-06) describe.*chatService
path provides contains
server/src/__tests__/chat-routes.test.ts Test scaffold for chat routes (POST conversation, GET list, POST message) describe.*chatRoutes
path provides contains
ui/src/components/ChatMarkdownMessage.test.tsx Test scaffold for markdown rendering (CHAT-02, CHAT-03) describe.*ChatMarkdownMessage
path provides contains
ui/src/components/ChatInput.test.tsx Test scaffold for keyboard shortcuts (INPUT-07) describe.*ChatInput
Create Wave 0 test stubs for the four key test files needed by Plans 01-05.

Purpose: Satisfy the Nyquist rule — every implementation task must have a pre-existing test file with describe blocks and placeholder expectations. Plans 01 and 02 depend on these stubs existing before they execute. Output: Four test files with describe/it blocks that vitest can discover and run.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/21-chat-foundation/21-RESEARCH.md From server/src/__tests__/activity-routes.test.ts (reference pattern for server tests): ```typescript import express from "express"; import request from "supertest"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { errorHandler } from "../middleware/index.js";

const mockService = vi.hoisted(() => ({ list: vi.fn(), create: vi.fn() })); vi.mock("../services/activity.js", () => ({ activityService: () => mockService }));

function createApp() { const app = express(); app.use(express.json()); // ... mock actor middleware }


From ui/src/components/MarkdownBody.test.tsx (reference pattern for UI component tests):
```typescript
// @vitest-environment node
import { describe, expect, it } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
import { ThemeProvider } from "../context/ThemeContext";
Task 1: Create server-side test stubs (chat-service + chat-routes) server/src/__tests__/chat-service.test.ts, server/src/__tests__/chat-routes.test.ts - server/src/__tests__/activity-routes.test.ts (full file — reference for mock pattern, createApp, supertest usage) Create `server/src/__tests__/chat-service.test.ts`:
import { describe, it, expect } from "vitest";

describe("chatService", () => {
  describe("createConversation", () => {
    it.todo("creates a conversation row with companyId");
    it.todo("returns the created conversation with id and timestamps");
  });

  describe("listConversations", () => {
    it.todo("returns conversations sorted by updatedAt DESC");
    it.todo("excludes soft-deleted conversations");
    it.todo("supports cursor-based pagination with hasMore");
    it.todo("limits results to max 100");
  });

  describe("getConversation", () => {
    it.todo("returns conversation by id");
    it.todo("throws notFound for non-existent conversation");
    it.todo("throws notFound for soft-deleted conversation");
  });

  describe("updateConversation", () => {
    it.todo("updates title");
    it.todo("sets pinnedAt timestamp");
    it.todo("clears pinnedAt when set to null");
    it.todo("sets archivedAt timestamp");
    it.todo("bumps updatedAt on every update");
  });

  describe("softDeleteConversation", () => {
    it.todo("sets deletedAt timestamp");
    it.todo("throws notFound if already deleted");
  });

  describe("addMessage", () => {
    it.todo("inserts a message row with conversationId and role");
    it.todo("bumps conversation updatedAt after insert");
    it.todo("auto-sets title from first user message when title is null");
    it.todo("does not overwrite existing title on subsequent messages");
  });

  describe("listMessages", () => {
    it.todo("returns messages for conversation sorted by createdAt DESC");
    it.todo("supports cursor-based pagination");
  });
});

Create server/src/__tests__/chat-routes.test.ts:

import { describe, it, expect } from "vitest";

describe("chatRoutes", () => {
  describe("POST /companies/:companyId/conversations", () => {
    it.todo("creates a conversation and returns 201");
    it.todo("accepts optional title and agentId");
  });

  describe("GET /companies/:companyId/conversations", () => {
    it.todo("returns paginated conversation list");
    it.todo("supports cursor query param");
  });

  describe("GET /conversations/:id", () => {
    it.todo("returns conversation by id");
    it.todo("returns 404 for non-existent conversation");
  });

  describe("PATCH /conversations/:id", () => {
    it.todo("updates conversation fields");
  });

  describe("DELETE /conversations/:id", () => {
    it.todo("soft-deletes and returns 204");
  });

  describe("POST /conversations/:id/messages", () => {
    it.todo("creates a message and returns 201");
    it.todo("rejects invalid role");
  });

  describe("GET /conversations/:id/messages", () => {
    it.todo("returns paginated message list");
  });
});

Both files use it.todo() which vitest marks as skipped — they run without error and serve as scaffolds for implementation tasks to fill in. cd /opt/nexus && pnpm vitest run server/src/tests/chat-service.test.ts server/src/tests/chat-routes.test.ts --reporter=verbose 2>&1 | tail -5 Server test stubs exist with describe/it.todo blocks covering all chatService methods and chatRoutes endpoints. Vitest runs them without error.

Task 2: Create UI test stubs (ChatMarkdownMessage + ChatInput) ui/src/components/ChatMarkdownMessage.test.tsx, ui/src/components/ChatInput.test.tsx - ui/src/components/MarkdownBody.test.tsx (reference for UI component test pattern — renderToStaticMarkup, ThemeProvider wrapper) - ui/src/components/IssueRow.test.tsx (reference for component test with RTL if used) Create `ui/src/components/ChatMarkdownMessage.test.tsx`:
// @vitest-environment node
import { describe, it, expect } from "vitest";

describe("ChatMarkdownMessage", () => {
  describe("markdown rendering (CHAT-02)", () => {
    it.todo("renders plain text as paragraph");
    it.todo("renders code blocks with hljs classes for syntax highlighting");
    it.todo("renders GFM tables");
    it.todo("renders headings, lists, and links");
  });

  describe("code block features (CHAT-03)", () => {
    it.todo("renders language label from code fence");
    it.todo("renders copy button with aria-label");
    it.todo("extracts code text content for clipboard");
  });
});

Create ui/src/components/ChatInput.test.tsx:

// @vitest-environment node
import { describe, it, expect } from "vitest";

describe("ChatInput", () => {
  describe("keyboard shortcuts (INPUT-07)", () => {
    it.todo("calls onSend when Enter is pressed without Shift");
    it.todo("inserts newline when Shift+Enter is pressed");
    it.todo("clears input when Escape is pressed");
    it.todo("does not send when input is empty");
  });

  describe("auto-resize (INPUT-01)", () => {
    it.todo("textarea has max-height constraint");
  });

  describe("submit state", () => {
    it.todo("disables send button when isSubmitting is true");
  });
});

Both files use it.todo() for the same reason as the server stubs. cd /opt/nexus && pnpm vitest run ui/src/components/ChatMarkdownMessage.test.tsx ui/src/components/ChatInput.test.tsx --reporter=verbose 2>&1 | tail -5 UI test stubs exist with describe/it.todo blocks covering ChatMarkdownMessage rendering and ChatInput keyboard shortcuts. Vitest runs them without error.

- All four test files exist and vitest discovers them - `pnpm vitest run server/src/__tests__/chat-service.test.ts` exits 0 - `pnpm vitest run server/src/__tests__/chat-routes.test.ts` exits 0 - `pnpm vitest run ui/src/components/ChatMarkdownMessage.test.tsx` exits 0 - `pnpm vitest run ui/src/components/ChatInput.test.tsx` exits 0

<success_criteria>

  • Four test stub files created with describe blocks matching the requirements they cover
  • Vitest runs all four files without errors (todo tests are skipped, not failed)
  • Implementation plans (01-05) can reference these files in their verify commands </success_criteria>
After completion, create `.planning/phases/21-chat-foundation/21-00-SUMMARY.md`