Estimate: 16m · Depends on: 1.4.5, 1.4.7
The Story-closing E2E test that proves Story 1.4's structural invariants hold end-to-end across realistic multi-workspace, multi-project scenarios. Same shape as Story 1.2.7 (workspace isolation) and Story 1.3.6 (project isolation) — a Playwright (or Vitest-driven HTTP) test that exercises the data layer via a thin throwaway test endpoint (since Epic 2 hasn't shipped the production routes yet). The test endpoint lives under app/api/_test/work-items/ and is gated by a build-time NODE_ENV !== 'production' flag.
Scenario: User A in workspace W1 with projects P1 + P2; User B in workspace W2 with project P3. Each creates 3 work items in each of their projects. Then:
getBlockers(X) returns [Y, Z]; getBlocking(Y) returns [X]; isReady(X) returns false. Marks Y status=done; isReady(X) still false. Marks Z status=done; isReady(X) returns true. Unlinks X→Y (the link, not the item); isReady(X) stays true (only Z remained, already done).explanationMd = null, explanationSource = user_authored. PATCH with { explanationMd: "…", explanationSource: "ai_draft" } (simulating what Epic 7's AI-drafting endpoint will do); GET confirms both. PATCH with { explanationMd: "…edited" } (no explicit source); GET confirms source auto-transitioned to user_edited. Revision feed shows three rows in order with the right diffs (including the source transition on the third update).descriptionMd containing a fenced code block, a GFM table, and an inline <script> tag. GET-with-render returns sanitized HTML — script stripped, table rendered, code block with syntax-highlighting markup.What you'll do: Add the test endpoint app/api/_test/work-items/route.ts (POST = createWorkItem, GET = list/get, PATCH = update, DELETE = archive) AND app/api/_test/work-item-links/route.ts (POST = linkWorkItems, DELETE = unlinkWorkItems, GET with ?workItemId=&direction=blockers|blocking wraps getBlockers / getBlocking; GET with ?workItemId=&ready=1 wraps isReady). Wire both through the service layer (NOT raw Prisma) so the tests exercise the production code path. Add the Playwright test tests/e2e/work-items-isolation.spec.ts following the 1.2.7 / 1.3.6 pattern. CI runs E2E against the docker-compose'd Postgres + a built Next server.
app/api/_test/work-items/route.ts AND app/api/_test/work-item-links/route.ts expose CRUD + linking via the service layer; both gated behind NODE_ENV !== 'production' (return 404 in production builds).tests/e2e/work-items-isolation.spec.ts covers every bullet from the scenario list above, including the dependency / cross-project link / cycle scenarios.tests/e2e/workspaces-isolation.spec.ts from 1.2.7 — the exact patterntests/e2e/projects-isolation.spec.ts from 1.3.6 — the second pattern instanceapp/api/_test/* existing test endpoints from 1.2.7 / 1.3.6 — the gating conventionlib/services/workItemsService.ts — the service the route delegates to