Echo/Docs

CLI command

announcements

Release announcements: a changelog entry announced in the product's in-product feed and emailed to every subscriber, with every delivery recorded, and the widget a product's page embeds to show the feed.

Invocation#

Shell
echo-cli announcements publish --entry <entry-id> --by <name>
echo-cli announcements list --product <id>
echo-cli announcements subscribers --product <id>
echo-cli announcements deliveries --announcement <announcement-id>
echo-cli announcements feed --product <id>
echo-cli announcements widget --product <id>

Inputs and output#

publish writes announcement (id, product_id, entry_id, title, body, published_by, published_at) and deliveries, one per subscriber still subscribed, each with id, announcement_id, subscriber_id, email, error (null when it was sent), sent_from (the ECHO_ANNOUNCEMENT_FROM address it went out from, null when it was not sent; a sending identity with that address counts it against its daily cap, as email warmup list shows) and attempted_at. list writes the product's announcements, newest first; subscribers writes its subscribers with subscribed_at and unsubscribed_at (null while subscribed); deliveries writes an announcement's deliveries. feed writes the public feed as a product's users read it: id, title, body and published_at of each announcement, newest first. widget writes script_url, snippet (the HTML a product's page pastes: the script tag with data-product and the element the feed is shown in) and script_bytes, the size of the script Echo Web serves now.

State effect#

Every verb calls Echo Web's authenticated /api/analytics/announcements or /api/analytics/announcements/audience with ECHO_INTERNAL_BEARER at ECHO_WEB_BASE_URL, except feed and widget, which read the public /api/public/announcements and /api/public/announcements/widget without a bearer as a product's page does; the Release announcements section of the tracking screen and the Announcements section of Echo Desktop's GEO screen call the same operations (Desktop's Embed in product prints the widget HTML), and echo-mcp reads announcements (echo_list_announcements), deliveries (echo_announcement_deliveries) and the widget (echo_announcement_widget) but publishes nothing. publish titles the announcement with the product's name and the entry's version (entries come from echo-cli changelog, read again daily by /api/cron/changelog-sync), and from then on the product's feed at GET /api/public/announcements?product_id=<id> serves it, answering only each announcement's id, title, body and published_at, signed in or not, to a browser on an origin the deployment allows (NEXT_PUBLIC_SITE_URL and CORS_ALLOWED_ORIGINS). The widget script, loaded from Echo Web with data-product, reads that feed from the origin it came from and writes each title, publication day and body as text into the page's element carrying data-echo-announcements; a missing element, a script without data-product or a refused feed is written into the element, or to the console without one, with its reason. It emails the announcement once to every subscriber still subscribed, from the address in Echo Web's ECHO_ANNOUNCEMENT_FROM through Echo's Resend integration, and records each delivery with the send's error or none; a failed send never stops the others. Every email ends with the recipient's signed preference link, where they stop announcements without signing in; a withdrawn address is recorded as such instead of emailed. A signed-in user subscribes with POST /api/public/announcements { product_id } and unsubscribes with DELETE and the same body, using the email Echo's sign-in holds for them, stored in lower case; subscribing again takes back one who left.

Refusals#

  • A wrong invocation is refused before anything is sent: "announcements takes <every usage, separated by semicolons>; got <word>", "announcements <verb> does not take <flag>; it takes …", "<flag> needs a value" and "announcements <verb> needs <flag>" for each flag the verb needs.
  • Echo Web answers a bad request with "entry_id is required: …", "product_id is required: …", "published_by is required: an internal caller has no signed-in user, so it names who is acting" or "product_id or announcement_id is required: …"; not found with "no changelog entry has id <id>; echo-cli changelog entries --product <id> lists them" or "product <id> of changelog entry <id> no longer exists"; a conflict with "changelog entry <id> was already announced as <announcement id> at <time>". Publishing on a deployment without ECHO_ANNOUNCEMENT_FROM is refused naming that setting.
  • The public route refuses subscribing without a signed-in user ("sign in to subscribe: announcements are emailed to a signed-in user") and an account with no email ("your account has no email address, so announcements cannot be emailed to it"); unsubscribing an email that is not subscribed is not found with "<email> is not subscribed to the announcements of product <id>".