MotirBuilding in public
MOTIR · moooon
onMotir
You’re viewing a public project. Anyone can view it — no account needed. Sign in to submit, upvote, or comment on requests.View-only — you can’t edit work items
MOTIR-420

6.12.12 Public request DETAIL page + comment composer/thread UI (wire the 6.12.6 backend into the public surface)

Done
Description

Estimate: 60m · Depends on: 6.12.1, 6.12.4, 6.12.6, 6.12.7

Why this exists (planning gap, found running 6.12.10): 6.12.6 shipped the upvote + public-request COMMENT backend (POST /api/public-requests/[id]/upvote and POST /api/public-requests/[id]/comments), and 6.12.7 added the roadmap upvote control (PublicRoadmapVote) — but there is NO public request DETAIL surface and NO comment UI anywhere (PublicRoadmap’s own comment notes: "there is no public request DETAIL route yet; that surface, design Panel 5, is unbuilt"; submitted roadmap cards are plain text with no link). So a public viewer cannot open a request, read its comments, or comment, and the e2e (6.12.10 step 3 "add a comment on that public request → it appears") has no real UI to drive. This card builds the missing public request detail + comment UI per the 6.12.1 Panel 4/5 design.

  • The public request detail route: add a public, server-rendered, crawlable detail page under app/(public)/ for a public request (reached from the roadmap cards — repoint PublicRoadmap titles/cards to it — and from the 6.12.11 dedupe candidates), gated by the same anonymous-read browse check the other public tabs use (non-public / unknown → 404-not-403). It renders the request title + kind + status + body through the public projection (no internal field leaks — reuse the 6.12.4 read shape).
  • Upvote on the detail: reuse the shipped PublicRoadmapVote control (one vote per account, toggle, sign-in-to-act when logged out) so the detail and the roadmap share one upvote affordance.
  • Comment composer + thread: render the public-request comment thread (the isPublic comments from 6.12.6 — the work item’s INTERNAL comments stay hidden by the projection) and a composer that POSTs to /api/public-requests/[id]/comments ({ bodyMd } → 201) for a signed-in account; a logged-out viewer sees the sign-in-to-act prompt on the composer. New comment appears on success (the composer fires from inside the thread island — optimistic local insert / authoritative refetch, per the page-state-after-mutation rule; no whole-tree refresh).
  • No new backend beyond a public-projection READ for the detail + its comment thread (a read method / DTO in the existing publicProjectsService / publicRequestsService layer if one isn’t already exposed) — the upvote + comment WRITES reuse the shipped 6.12.6 routes. Stay 4-layer; design-compliant (ONLY shipped components/ui/* + --el-* / [data-display-style] tokens).

Acceptance criteria

  • A public request detail page renders anonymously (server-rendered, crawlable) showing the request title/kind/status/body via the public projection (assignee / estimate / internal comments absent); a non-public / unknown request is 404-not-403; roadmap cards + 6.12.11 dedupe candidates link to it.
  • The detail shows the upvote control (reused PublicRoadmapVote: toggle, count, already-voted state, sign-in-to-act when logged out) and the public comment thread (only isPublic comments; internal comments never present).
  • A signed-in account (cross-org included) adds a comment → it posts (201) and appears in the thread (optimistic/refetch, no whole-tree refresh); a logged-out viewer sees a sign-in-to-act prompt on the composer.
  • ONLY --el-* + [data-display-style] tokens + shipped components/ui/*; matches the 6.12.1 Panel 4/5 design; 4-layer respected (public-projection read in the service/repository; the upvote/comment writes reuse the shipped 6.12.6 routes; no raw Prisma in the route).

Context refs

  • 6.12.1 Panel 4/5 (the public request detail + upvote + comments design) — the surface to match; design/public-projects/.
  • 6.12.6 routes (shipped): app/api/public-requests/[id]/upvote/route.ts (POST → { voted, voteCount }) + app/api/public-requests/[id]/comments/route.ts (POST { bodyMd } → 201 CommentDTO).
  • app/(public)/_components/PublicRoadmap.tsx (repoint the card links) + PublicRoadmapVote.tsx (reuse the upvote control) + the 6.12.4 public projection (lib/services/publicProjectsService.ts, lib/dto/publicProjects.ts).
  • motir-core/CLAUDE.md § 4-layer + § colour/shape tokens + § page-state-after-mutation (client-island refetch).