Repository navigation
feat(web): public web pages for broadcasts, team archive, RSS and sitemap - #97
Merged
Merged
Conversation
…emap
Broadcasts can be published to the web (dashboard, REST, MCP). Once sent,
a published broadcast gets a public page at /w/<handle>/p/<slug> without
personal data, tracking or an unsubscribe link, with title, description,
canonical, Open Graph/Twitter tags and Article JSON-LD (noindex on
request). The team archive at /w/<handle> lists issues with a signup form,
plus an RSS feed and a sitemap. {{ web_version_url }} and the footer's
"view in browser" link point to the public page once published.
Platforms can turn hosting off and render issues from GET /web/issues and
GET /web/issues/:slug instead.
Closes #63
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.
Part of #79. Closes #63.
What
sequences:web_published,web_slug(unique per team), SEO title and description, OG image,web_noindex,web_canonical_url.settings:web_enabled,web_handle(unique), title, description, and the archive's signup form.GET/PATCH /sequences/:id/web, broadcasts only.GET/PATCH /settings/web. Turning hosting on picks a unique handle from the team name and creates a "Web archive" signup form.GET /web/issues(paginated: excerpt from the text blocks, plus SEO fields) andGET /web/issues/:slug(sanitised HTML). Both work with hosting off.web/public-routes.ts):/w/:handle: the archive, newest first, with a subscribe form and pagination./w/:handle/p/:slug: one issue, with title, description, canonical (or the sender's), OG and Twitter tags,ArticleJSON-LD andnoindex./w/:handle/feed.xml: RSS 2.0 withcontent:encoded. An issue that fails to render is skipped rather than failing the feed./w/:handle/sitemap.xml: leaves out noindex issues and issues with an external canonical.default-src 'none',form-action 'self'; scripts and handlers stripped;Cache-Control: public, max-age=300.renderCampaignHtml(web: "public")renders with no subscriber data, no tracking, and the unsubscribe link removed.{{ web_version_url }}and the footer's "view in browser" link go to the public page once the issue is published, otherwise to the reader's own web version. The tag is reserved, like the other platform variables.get/update_broadcast_web_publishing,get/update_web_settings,list_web_issues,get_web_issue.email-marketing/web-archive, plus updates to the broadcasts, transactional and MCP docs.Verification
check.sh(format, lint, typecheck, 715 API tests incl. 9 new, web tests),check:drift,test:conformance.web_version_urlpointing to the public page.web_version_urland has title, description, OG, canonical and JSON-LD.web-archivetag after double opt-in./web/issuesand/web/issues/:slugreturn it.Found along the way (not changed here)
A quoted Liquid filter in a marketing text block, e.g.
{{ subscriber.name | default: "there" }}, fails the send: the text is HTML-escaped (") before Liquid runs. This already happened before this PR, and the docs here avoid recommending that syntax.