FE-553: Multi-project routing#16
Conversation
FE-553 Multi-project routing
Install tanstack/react-router. Three client routes: project list ( Part of slice 3d in PLAN.md. Depends on slice 3c (Drizzle + core extraction). |
🤖 Augment PR SummarySummary: Adds multi-project support by introducing project-scoped routing and API endpoints, so each interview session is tied to a specific project and can be revisited via a stable URL. Changes:
Technical Notes: Chat streaming is translated into the AI SDK UI message stream protocol via an SSE adapter that emits text, reasoning, and tool-call events. 🤖 Was this summary useful? React with 👍 or 👎 |
| const isLoading = status === 'submitted' || status === 'streaming'; | ||
|
|
||
| // Hydrate turns into useChat messages on mount | ||
| useEffect(() => { |
There was a problem hiding this comment.
useEffect only calls setMessages when turns?.length > 0, so navigating from a project with turns to a project with zero turns can leave the previous project’s messages visible. Also, the effect depends only on project.id, so if turns changes for the same project (e.g. loader revalidation) the chat hydration won’t rerun.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| res.status(400).json({ error: 'name is required' }); | ||
| return; | ||
| } | ||
| const project = createNewProject(db, name.trim()); |
There was a problem hiding this comment.
The project name validation happens before trimming, so a request like { "name": " " } will pass the !name check and create a project with an empty name after trim(). That can lead to blank entries in the project list.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
|
|
||
| const project = getProjectState(db).project; | ||
| const prompt = extractPrompt(req.body.messages ?? []); |
There was a problem hiding this comment.
If extractPrompt(req.body.messages ?? []) returns an empty string (e.g., empty messages or no text parts), this route still calls conductTurn and persists a turn with an empty answer. Consider rejecting empty prompts to avoid creating “empty” turns in the active path.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| assistantText += delta.text; | ||
| yield { type: 'text-delta', delta: delta.text }; | ||
| } else if (delta.type === 'input_json_delta' && delta.partial_json) { | ||
| const toolBlock = toolUseBlocks.get(event.index!); |
There was a problem hiding this comment.
When handling input_json_delta, if toolUseBlocks.get(event.index!) is missing, this code still yields a tool-call-delta event with toolCallId: ''. Emitting tool-call events with an empty id can break client/tool-stream state machines, so it may be safer to drop or explicitly handle the missing-tool-block case.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| if (assistantText) { | ||
| updateTurn(db, turn.id, { question: assistantText }); | ||
| } | ||
| advanceHead(db, projectId, turn.id); |
There was a problem hiding this comment.
advanceHead(db, projectId, turn.id) runs even if the streaming/query path throws and no assistant question was persisted, which can advance the project’s HEAD to a turn with an empty question. If errors are transient, this can leave the active path/UI in a confusing state where the latest turn has no assistant content.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
5cd25b7 to
edd3dc7
Compare
231bff6 to
1e4e403
Compare
Add project-scoped API routes (GET/POST /api/projects, GET /api/projects/:id, POST /api/projects/:id/chat), TanStack Router with three client routes (project list, interview workspace, export preview placeholder), and new db/core functions for project listing and creation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… App.tsx InterviewWorkspace was missing dynamic-tool part rendering that 3b added to App.tsx (merge gap from parallel builds). App.tsx is now dead code — main.tsx uses RouterProvider. Also removes unused getOrCreateProject import from core. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mark 3b (FE-541) and 3d (FE-553) done in PLAN.md. Update SPEC.md: A16 partially validated, invariants I14/I15 established, coverage table updated to 72 tests across 4 files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ness Install oxlint (lint + type-aware + type-check via tsgolint), oxfmt (formatting: single quotes, 110 width, sorted imports). Remove eslint. Add npm scripts: lint, lint:fix, fmt, fmt:check, verify (full pipeline). Update SPEC.md verification commands. Fix all lint warnings (unused vars, floating promises, await-thenable). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
npm run fix (lint:fix + fmt) is the fast inner loop — auto-fixes and formats. npm run verify (check + test + build) is the commit gate. CLAUDE.md documents the two-tier workflow. SPEC.md verification commands updated to match. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SPEC.md: update D8 (Express is now thin adapter, not SDK iterator), D14 (AI Elements deferred, hand-built rendering), D19 (full DomainEvent list: 9 types implemented + 2 future), lexicon domain event entry, add D21 (oxlint+oxfmt tooling decision). PLAN.md: update parallelism section (3b/3d done, spike+4 now parallel). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Port arc-oracle's diagnostic framework and oracle taxonomy into a self-contained ln-oracles skill. Update SPEC.md with three-tier oracle strategy, diagnostic assessment, observer history projection design, and acknowledged blind spots. Annotate PLAN.md slices 4/5/6 and observer spike with verification approaches. Sharpen ln-spec (delegates middle/outer loop to ln-oracles), ln-scope (requires verification approach per slice), ln-build (oracle strategy informs test design), and ln-review (audits oracle coverage). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Delete pre-v2 code and config superseded by src/ over slices 1-3d: - server/ (Dolt/mysql2 JS server) → src/server/ (Express + SQLite + Drizzle) - client/ (Preact/React UI) → src/client/ (React + TanStack Router) - config.yaml (Dolt server config), opencode.json (OpenCode MCP sidecar) - test-opencode.js, test-sse-raw.js (manual test scripts) - scripts/kill-port.js (unused utility) - docs/design/schema.dbml, schema.dbdiagram (superseded by drizzle/schema.ts) - @types/cors devDependency (cors not imported in src/) - HANDOFF.md (session state captured in memory) Update SPEC.md references to removed schema.dbml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Slim CLAUDE.md to always-loaded essentials, extract operational protocols into docs/praxis/: - graphite-workflow.md: gt-vs-git boundary, branch lifecycle, parallel work reintegration - worktree-agents.md: isolation protocol, known limitations, merge gap risk - manual-testing.md: outer-loop verification, fixture capture Add explicit git-vs-gt rule to CLAUDE.md. Remove inline manual testing section (now in praxis). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Trim project name before empty check to reject whitespace-only names - Reject empty prompt in chat endpoint instead of creating empty turns - Always call setMessages on project change (including for 0 turns) and add turns to dependency array for revalidation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1e4e403 to
8bdf9df
Compare

feat: add multi-project routing with TanStack Router (FE-553)
Add project-scoped API routes (GET/POST /api/projects, GET /api/projects/:id,
POST /api/projects/:id/chat), TanStack Router with three client routes
(project list, interview workspace, export preview placeholder), and new
db/core functions for project listing and creation.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
refactor: port tool-call rendering to InterviewWorkspace, delete dead App.tsx
InterviewWorkspace was missing dynamic-tool part rendering that 3b added to
App.tsx (merge gap from parallel builds). App.tsx is now dead code — main.tsx
uses RouterProvider. Also removes unused getOrCreateProject import from core.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
docs: traceability updates for slices 3b and 3d
Mark 3b (FE-541) and 3d (FE-553) done in PLAN.md. Update SPEC.md:
A16 partially validated, invariants I14/I15 established, coverage
table updated to 72 tests across 4 files.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
chore: replace eslint+tsc with oxlint+oxfmt+tsgolint verification harness
Install oxlint (lint + type-aware + type-check via tsgolint), oxfmt
(formatting: single quotes, 110 width, sorted imports). Remove eslint.
Add npm scripts: lint, lint:fix, fmt, fmt:check, verify (full pipeline).
Update SPEC.md verification commands. Fix all lint warnings (unused vars,
floating promises, await-thenable).
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
chore: add fix/check/verify scripts, document inner loop in CLAUDE.md
npm run fix (lint:fix + fmt) is the fast inner loop — auto-fixes and
formats. npm run verify (check + test + build) is the commit gate.
CLAUDE.md documents the two-tier workflow. SPEC.md verification
commands updated to match.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com