feat(passport): public share URL + OG image + copy-link button#58
Merged
Conversation
Turns every passport into a shareable social artifact. Any passport is now visitable by its public id (e.g. /passport/TP-2026-000042) with proper OG + Twitter card metadata so pasting the link into Twitter/Slack/Discord previews as a real card. - `/passport/[passportId]` — public server component. Case-insensitive. Renders the same book-style SVG the private page uses, plus a Download PDF button. 404 for unknown ids and for guests (guests share a placeholder `TP-GUEST` id and don't have a public page). - `/passport/[passportId]/og.png` — 1200×630 PNG generated by rasterizing the first spread SVG with `sharp` (already in deps). The page-color background letterboxes the ~1.6:1 spread inside the ~1.9:1 OG aspect. 5-minute cache to keep scrapers happy without letting the card go stale for long. - `/passport/[passportId]/pdf` — public download route colocated with the page. Same renderer, keyed by URL segment instead of session. - `generateMetadata()` on the public page emits title / description / OG / Twitter tags with absolute URLs resolved from x-forwarded-host, mirroring the pattern in /[town]/page.tsx. - `loadPassportDataByPassportId(passportId)` — shared loader used by the page, OG image, and PDF routes. Normalises to uppercase. - On the private /passport page, a **Copy share link** button now appears next to Download PDF for authed users with an assigned id. Related: #50 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #57 (merged). Turns every Town passport into a shareable social artifact — any passport is now visitable by its public id, with proper OG + Twitter card metadata so pasted links preview as real cards on X, Slack, Discord, LinkedIn.
Related
What's new
Public passport URL
/passport/[passportId]— public server component. Example:town.getcore.me/passport/TP-2026-000042. Case-insensitive; renders the same book-style SVG the private page uses, plus a Download PDF button.TP-GUESTid and don't have a public page — by design).OG image
/passport/[passportId]/og.png— 1200×630 PNG generated by rasterizing the first spread SVG withsharp(already in deps). The page-color background letterboxes the ~1.6:1 spread inside the ~1.9:1 OG aspect. 5-minute CDN cache — keeps scrapers happy without letting the card go too stale.Metadata
generateMetadata()on the public page emits title / description / OG / Twitter tags with absolute URLs resolved fromx-forwarded-host, mirroring the pattern already in/[town]/page.tsx.<name> · Town Passport. Description:TP-<id> · N stamps · N towns owned · ….summary_large_image. Canonical URL set.Public PDF download
/passport/[passportId]/pdf— colocated public download route. Same renderer, keyed by URL segment instead of session cookie.Data
loadPassportDataByPassportId(passportId)— shared loader used by the page, OG image, and PDF routes. Normalises to uppercase.Copy share link (private page)
/passport(the signed-in user's own page), a new Copy share link button appears next to Download PDF. Only shown for authed users with an assignedpassportId. Usesnavigator.clipboard.writeText()with awindow.promptfallback for clipboard-denied browsers. ShowsCopied ✓for 1.5 s.Test plan
/passport→ Copy share link button appears next to Download PDF; click copieshttps://<host>/passport/TP-<year>-<seq>to clipboard.og:title,og:description,og:image,twitter:cardall present with absolute URLs./passport/<id>/og.pngdirectly → 1200×630 PNG with the identity spread letterboxed on the page color./passport/<id>/pdfwhile signed out → downloads a valid PDF of that user's passport./passport/DOES-NOT-EXIST→ 404./passport/tp-2026-000042also works).Not in this PR (follow-ups)
/passport/@harshith) — needsUser.handlecolumn + backfill + settings UI. Cleaner social share when it lands; passport-id URLs keep working alongside.User.passportPublicif privacy becomes a concern.🤖 Generated with Claude Code