motir.co serves /p/[identifier] — the layout, the tab nav, the Overview and the page's own entity signal
motir.co answers for /p/[identifier] for the first time. This card ships the page's shell and its first screen: the route segment, the layout, the tab bar, the Overview, and the page's own entity signal.
Measured on the live hosts while planning: https://motir.co/p/MOTIR → 404, and https://motir.co/explore → 200 with cards rendering href="/p/MOTIR". This is the card that makes that link resolve.
What ships:
app/p/[identifier]/layout.tsx— the project shell insidemotir.co's existing chrome (SiteHeader/SiteFooter): the hero from the subject read, and the tab bar with its five destinations rendered as links, current-state included. The tab bar ships here even though its tabs land in the tabs card — a shell with no navigation is not a shell; the tab routes it points at arrive next.app/p/[identifier]/page.tsx— the Overview: the authored README as Markdown, the tags, the stats, the empty state for a project with no overview.lib/publicProject.ts— the data layer, followinglib/explore.tsexactly: the DTO shapes restated frommotir-core's contract, onefetchagainst${APP_ORIGIN}/api/public,next: { revalidate: 0 }, andfailed-style error handling — an unreachable API is a real state of this surface, not a crash. No database client (the standing repository rule).- 404 vs error, distinguished. A
404 { code }from the subject read isnotFound(); an unreachable API is the error state the design draws. Conflating them turns an outage into "this project does not exist", which is worse than an error page. - The entity signal:
metadatawith a canonical onSITE_ORIGIN(lib/siteOrigin.ts),og:urlnaming this host, and JSON-LD in the shapeapp/explore/_components/JsonLd.tsxestablished. The OpenGraph IMAGE and the sitemap entries are the crawl-surface card's — this card sets the metadata that names them.
Out of scope, and each named to its owner: the five tabs' own routes (tabs), the detail pages and the request form (detail pages), every act affordance including follow/vote/edit (act affordances), the OG image, sitemap and Atom route (crawl surface). The tab bar renders links to routes that do not exist yet; that is expected and is why the tabs card is blocked_by this one rather than the reverse.
Build to the design asset, not to the deleted page: motir-marketing/design/public-projects/.
Acceptance criteria
motir.co/p/<identifier>renders, for a logged-out visitor, a public project's hero and its overview README, insidemotir.co's own header/nav/footer chrome.- An unknown or non-public identifier renders a 404; an unreachable public API renders the design's error state, and the two are distinguishable in the code and in a test.
- The tab bar renders all five destinations with the current one marked, and the page's own tab reads as current.
- Every read goes through
lib/publicProject.tsto${APP_ORIGIN}/api/public/...; no@prisma/client, no database URL, and no direct database import appears anywhere in this repository after this card (asserted by the standing guard). canonical,og:urland the JSON-LD@idall nameSITE_ORIGIN— neverAPP_ORIGIN— and a test asserts it.- The empty state (a public project with no authored overview) renders as the design draws it.
- The page matches
design/public-projects/'s Overview board; any deviation is recorded on the asset, not left in the code. - No file outside
motir-marketingis touched.
Context refs
motir-marketing/lib/explore.ts— the data-layer pattern to follow, including thefailedstate and the no-database-client commentmotir-marketing/lib/appOrigin.ts·lib/siteOrigin.ts— which origin answers which questionmotir-marketing/app/explore/page.tsx·app/explore/_components/JsonLd.tsx·app/legal/[slug]/page.tsx— the closest shipped precedentsmotir-marketing/app/_components/SiteHeader.tsx·SiteFooter.tsxmotir-core/app/api/public/p/[identifier]/route.ts— the subject read (PublicProjectOverviewDto), shipped by MOTIR-3945motir-core/app/(public)/p/[identifier]/page.tsx@95a2d4468^— the deleted page, as prior art onlymotir-marketing/design/public-projects/— the asset this builds to