Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions components/locale-switch.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { usePathname, useSearchParams } from "next/navigation";
import type { Locale } from "@/lib/types";
import { subscriptionLocaleHref } from "@/lib/news/subscription-ui";

export function LocaleSwitch({ locale, alternate }: { locale: Locale; alternate: Locale }) {
const pathname = usePathname();
const href = pathname?.startsWith(`/${locale}`) ? pathname.replace(`/${locale}`, `/${alternate}`) : `/${alternate}`;
return <Link className="locale-switch" data-testid="locale-switch" href={href} hrefLang={alternate}>{alternate === "zh" ? "中文" : "EN"}</Link>;
const query = useSearchParams();
const href = subscriptionLocaleHref(pathname, locale, alternate, query.toString());
return <Link className="locale-switch" data-testid="locale-switch" href={href} hrefLang={alternate} prefetch={pathname === `/${locale}/subscribe` ? false : undefined}>{alternate === "zh" ? "中文" : "EN"}</Link>;
}
4 changes: 2 additions & 2 deletions components/news/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ export function SubscribeBand({ locale }: { locale: Locale }) {
</h2>
<p>
{locale === "zh"
? "用一份精选,串起生成式 UI 的一周。RSS 已开放,邮件周报待启用。"
: "A considered view of the week in Generative UI. RSS is live; email delivery is coming."}
? "用一份精选,串起生成式 UI 的一周。通过 RSS 阅读,或确认邮箱后接收周报。"
: "A considered view of the week in Generative UI. Read with RSS, or confirm your email for the digest."}
</p>
</div>
<Link className="n-button" href={`/${locale}/subscribe`}>
Expand Down
107 changes: 64 additions & 43 deletions components/news/subscription.tsx

Large diffs are not rendered by default.

64 changes: 54 additions & 10 deletions docs/CURRENT_STATE.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"documentsAndCodeIntegrityVerified": true
},
"production": {
"evidence": "Verified handoff and user statement; not re-read in this synchronization",
"evidence": "Sites metadata and source refreshed on 2026-10-13; private environment values were not read",
"url": "https://ag-ui.ai",
"publishedVersion": 12,
"deploymentStatusAtHandoff": "succeeded",
Expand All @@ -25,15 +25,16 @@
"confirmedSubscriberCapacity": 250,
"dailySubmissionLimitAtHandoff": 300,
"weeklySubmissionBudgetAtHandoff": 250,
"existingSchedulesPreserved": true
"existingSchedulesPreserved": true,
"metadataObservedAt": "2026-10-13T10:10:32Z"
},
"github": {
"observedAt": "2026-10-13T09:18:00Z",
"observedAt": "2026-10-13T10:10:32Z",
"repository": "AutoGenUI/ag-ui.ai",
"defaultBranch": "main",
"mainAtObservation": "24edc498f5c135e283d773d946fcab3e99d239bd",
"mainAtObservation": "f670b23d32e6de1e4497f46113ef277fc3fc97cc",
"syncBranch": null,
"pullRequest": "https://github.com/AutoGenUI/ag-ui.ai/pull/3",
"pullRequest": "https://github.com/AutoGenUI/ag-ui.ai/pull/4",
"draftAtObservation": false,
"mergedAtObservation": true,
"codeAndCiVerificationCommit": "b0f0a40748474e3ce1f5918a7f9c4acff6f1a4f3",
Expand All @@ -44,11 +45,11 @@
"requiredCheck": "verify",
"branchProtectionPreserved": true,
"historicalSyncBranch": "codex/ag-ui-ai-v12-sync",
"mergedAt": "2026-10-13T09:03:38Z",
"validatedPullRequestHead": "800cf6202bffc2ce2952b65bb813377f5398169b",
"validatedTree": "46d9bda9cead65231bb02bf7bded7792374a5b44",
"mergedAt": "2026-10-13T09:47:47Z",
"validatedPullRequestHead": "219dd12bbac3662662f942257c6c6b292f37f577",
"validatedTree": "e36d9422315db154c01f4f9eaa44ac0230506ded",
"primaryMainBeforeSynchronization": "525ec78904ab7e2b97717adc7ac13bfd3f5f3db0",
"primaryMainAtObservation": "24edc498f5c135e283d773d946fcab3e99d239bd",
"primaryMainAtObservation": "f670b23d32e6de1e4497f46113ef277fc3fc97cc",
"branchPolicy": "Keep only main after completed iterations; temporary PR branches allowed and cleaned after verified merge",
"branchesAtLastCompletedCleanup": [
"main"
Expand Down Expand Up @@ -260,7 +261,7 @@
},
"openEngineeringWork": [
"Track 8 moderate dependencies without weakening the audit gate",
"Preserve bundle budgets; baseline raw JavaScript margin is 1169 bytes",
"Preserve bundle budgets; raw JavaScript remains close to the unchanged 920000-byte gate",
"Verify complete Brevo tracking disablement and keep bilingual disclosures accurate",
"Recheck restricted-network accessibility without promising global access",
"Observe real queued cancellation and additional bounce scenarios only under authorized acceptance",
Expand All @@ -283,5 +284,48 @@
"accountDnsInventoryAndDkimSelectorVerified": false,
"managedD1BackupRestoreCapabilitiesVerified": false,
"documentationCommit": "Query GitHub; this snapshot does not self-reference its own commit"
},
"releaseCandidate": {
"version": "1.0.0",
"phase": "local-verification-complete-awaiting-required-CI-and-publication",
"baseMain": "f670b23d32e6de1e4497f46113ef277fc3fc97cc",
"recordedAt": "2026-10-13T10:10:32Z",
"notes": "docs/releases/v1.0.0.md",
"formalReleaseEvidence": "Query the remote annotated v1.0.0 tag and GitHub Release; this dated candidate record does not assert deployment completion",
"tests": {
"base": 35,
"newsAndMail": 42,
"subscriptionUi": 10,
"localHttp": 8,
"total": 95
},
"browser": {
"viewports": [
"390x844",
"1440x900"
],
"syntheticLocalFlows": [
"GET remains pending",
"language switch preserves signed confirmation and management links",
"active public confirmation 0 to 1",
"replayed confirmation does not allocate another place",
"test confirmation does not allocate a public place",
"expired confirmation shows error",
"preferences save",
"unsubscribe releases place",
"focus event refreshes previous tab aggregate"
],
"focusTest": "Temporary CDP focus emulation; restored after verification",
"realMailSent": false,
"productionSubscriberDataRead": false
},
"userConfirmationReport": {
"date": "2026-10-13",
"evidence": "User reported a new inbox and active webpage confirmation with public count 1; no email or signed URL retained"
},
"schemaChanged": false,
"productionSecretsRead": false,
"productionConfigurationChanges": false,
"rolloutLimit": "New client requires subscriptionType; use matching client and Worker and refresh open pages after rollback"
}
}
6 changes: 6 additions & 0 deletions docs/PROJECT_CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

本说明用于在同一个项目中持续迭代。它仅保留可公开的工程事实,未复制私人运营审计、账户、验收邮箱、生产数据或秘密值。机器可读记录见 [CURRENT_STATE.json](CURRENT_STATE.json)。

## v1.0.0 发布接续

2026-10-13 用户报告已在邮件落地页主动确认,新邮箱正式人数显示 1。本轮修复最后一步可见性、邮件两步说明、签名页语言切换与回到原页刷新,并以隔离 D1/合成身份完成 95 项测试及手机/桌面浏览器验收。发布候选从 main `f670b23d32e6de1e4497f46113ef277fc3fc97cc`(维护 PR #4 已合并)继续,尚需 required CI、正常 PR 合并及 Sites 终态成功。

[版本说明](releases/v1.0.0.md) 规定最终凭据:GitHub 的带注释 `v1.0.0` tag/Release 与实际 Sites deployment。文档为时间快照,不能将候选版本号解释为已上线。旧章节中的“本轮”“尚未部署”描述此前 GitHub 同步/维护阶段;本次用户已授权正式发布,生产秘密、DNS、现有邮件开关/任务均保留,不额外发送验收邮件。Sites 元数据已重新核对生产仍为数字版本 12,源码 `6027589c…`;没有读取私有环境值。

## 证据时间与状态区分

- **生产交接快照**:2026-10-13 05:26:10 UTC(新加坡时间 13:26:10),来自交接版本 28。本轮读取了经过校验的上下文文件,没有重新读取生产环境或邮件账户。
Expand Down
2 changes: 2 additions & 0 deletions docs/operations/deployment-maintenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ Sites 在上传新 Worker 前应用未执行的托管 schema 迁移。**部署

代码回退优先选择该项目已有、带完整 archive 的已知成功版本,由 Sites 正常部署;source-only 旧版本需先恢复其匹配产物。回退前验证它与当前 schema、测试隔离字段、队列状态、签名 generation 和邮件门槛兼容。现有两份 SQL 没有 down migration,切换 Worker **不会回滚 D1**。

v1.0.0 候选没有 schema 迁移,但签名订阅响应新增 `subscriptionType`,新客户端遇到旧 API 缺少字段会保守拒绝成功提示。正式发布与回退都应使用同一个已验证版本的客户端和 Worker,完成后刷新浏览器再验收;混用缓存中的新客户端与旧 Worker 可能显示“未能确认结果”,并不证明数据库未更新。不要为了兼容提示解除测试隔离或恢复 GET 自动确认。GitHub `v1.0.0` tag 与 Sites 的递增数字版本是独立标识,按 [发布记录](../releases/v1.0.0.md) 查询实际部署,不能由 tag 名推断生产版本。

对于不兼容 schema,优先追加兼容修复并向前发布;确需恢复数据库时,由 owner 授权协调停止受影响的写入/投递任务、恢复与版本配套的数据、核对抑制和已提交邮件状态,再恢复运行。不得盲目清库、回放旧投递或恢复旧签名链接;不确定邮件必须向 provider 对账。切勿以“回滚”为理由应用 [2026-07-20 首发记录](2026-07-20-public-launch.md) 中删除域名、恢复私有 audience 的历史首发撤销流程。正常源码回退应保留现有域名、公开权限和生产配置。

## 部署后与日常验收
Expand Down
12 changes: 10 additions & 2 deletions docs/operations/email-subscriptions.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 邮件订阅与投递维护

核对日期:2026-10-13;实现依据 main `24edc498f5c135e283d773d946fcab3e99d239bd`。2026-10-13 05:26 UTC 的 v12 交接记录公众邮件、发信域名认证和真实验收已完成,发件地址 `news@ag-ui.ai`。本次只读代码/官方资料和文档更新没有重验收、发真实邮件或读取生产秘密。交接状态不是实时账户状态;不要用早期“待启用”示例把生产邮件关掉,也不要重复开启。
核对日期:2026-10-13;历史维护基线为 main `24edc498f5c135e283d773d946fcab3e99d239bd`,本文同时说明从 `f670b23d32e6de1e4497f46113ef277fc3fc97cc` 继续的 [v1.0.0 候选修复](../releases/v1.0.0.md)。2026-10-13 05:26 UTC 的 v12 交接记录公众邮件、发信域名认证和真实验收已完成,发件地址 `news@ag-ui.ai`。本次文档更新没有读取生产秘密或代发真实邮件;用户后续确认反馈见下文。交接状态不是实时账户状态;不要用早期“待启用”示例把生产邮件关掉,也不要重复开启。

先读 [维护入口](README.md)、[owner 管理](owner-management.md);域名认证记录见 [DNS 维护](dns-maintenance.md),构建、绑定与发布见 [部署维护](deployment-maintenance.md)。

Expand All @@ -27,6 +27,12 @@

持有签名链接的读者通过同源 `POST /api/subscription/manage` 执行 `confirm/preferences/unsubscribe/read`。打开 GET 页面或邮箱扫描不确认、不退订;读者主动点击动作才提交。确认原子取得名额,确认成功后改为管理链接;偏好只允许 confirmed 保存;退订取消仍为 queued 的邮件并释放名额。管理链接目前不设独立到期时间,其签名绑定 subscriber ID、创建时间与密钥;不能把真实链接放进日志、截图、工单或公开文档。

v1.0.0 候选将中英邮件按钮明确为“打开确认页”,HTML/纯文本都说明两步:打开链接,再在页面点击“确认订阅”并等待成功提示。页面把主动确认按钮放在状态说明旁,确认前不展示偏好编辑大表单;成功后再展示服务器保存的偏好。签名不绑定原设备、IP 或登录会话,可在另一设备操作;仅打开链接不代表完成确认。

返回原标签页时,focus/visibility 事件只重新读取公开容量接口,不能自动确认、退订或发信。中英切换在订阅页保留 `id/token/action` 查询参数,不将这些参数带到新闻等其他路由。保留原网址文本后备和 24 小时确认时限,不因本次界面修复改变签名或代际。

有效签名管理/确认响应新增 `subscriptionType: "public"|"test"`,仅向对应链接持有人解释身份,不改变公开聚合或暴露邮箱。public 确认占正式名额;test 确认明确显示“测试邮箱已确认”,不占名额、不进入正式周报。新客户端要求身份字段合法,遇到旧 API 缺少字段时保守显示未能确认结果,不把测试确认说成正式订阅。发布或回退后应刷新页面,使客户端与 Worker 来自匹配版本;错误提示不代表数据库操作一定没有执行,重试前按有效管理链接核对状态,不重复申请来绕过测试隔离。

已确认重放保持幂等。pending 有效确认代际和到期时间不因重复申请跨日改变;已知到期代际允许开始下一周期并取消旧 queued,`sending/uncertain` 阻止自动轮换。测试 restart 改变创建 epoch 和代际,旧确认、偏好、退订请求不能覆盖新代际;前端 generation/abort 也防止旧请求覆盖现页面。维护时保留这些检查,不通过删除记录、换 run ID 或新建订阅来解除抑制。

## 容量、免费额度与看板
Expand Down Expand Up @@ -61,7 +67,7 @@

提供商事务回调目标 `https://ag-ui.ai/api/brevo/webhook`,认证方式 Bearer,与服务端 `BREVO_WEBHOOK_SECRET` 一致。官方 [安全 webhook 文档](https://developers.brevo.com/docs/secured-webhooks) 支持这一配置;回调事件名和 payload 以 [事务 webhook 文档](https://developers.brevo.com/docs/transactional-webhooks) 为准(2026-10-13 核对)。不把回调密钥写入 URL,不将 Brevo API key 复用为 webhook 认证。

现有代码归一化大小写/下划线及 `invalid_email`,处理 Delivered、hardBounce、softBounce、spam、invalid、blocked、unsubscribed(也识别 error)。hard bounce、spam、invalid 立即 suppressed;unsubscribed 设置退订;取消相应 queued。soft bounce、blocked、error 标失败但不自动将订阅者永久抑制。原始 mailbox 与 provider message ID 或 `X-Mailin-custom: delivery:…` 必须关联既有记录,不凭任意 Delivered 建新记录;失败状态不能被迟到 Delivered 覆盖。回调处理在 [mail.ts](../../lib/news/mail.ts) 的 `mailWebhook`(第 550 行)。
现有代码归一化大小写/下划线及 `invalid_email`,处理 Delivered、hardBounce、softBounce、spam、invalid、blocked、unsubscribed(也识别 error)。hard bounce、spam、invalid 立即 suppressed;unsubscribed 设置退订;取消相应 queued。soft bounce、blocked、error 标失败但不自动将订阅者永久抑制。原始 mailbox 与 provider message ID 或 `X-Mailin-custom: delivery:…` 必须关联既有记录,不凭任意 Delivered 建新记录;失败状态不能被迟到 Delivered 覆盖。回调处理见 [mail.ts](../../lib/news/mail.ts) 的 `mailWebhook`。

回调 401 先查安全认证配置是否匹配及近期轮换,不关闭验证;400 查事件格式;503 查 D1/运行故障。不要向正式 endpoint 投递人工“Delivered”去伪造验收。重复回调、回调早于 API 响应、错误拼写、错配记录等可用本地 fixture 测试;真实投诉/退信和带邮箱原始 payload 只留在安全运营记录。

Expand All @@ -77,6 +83,8 @@

交接记录两轮真人验收、4 封测试邮件、用户退订、鉴权 Delivered 与退订后停发已通过;本轮没有重复,也没有真实 queued cancellation 或全部退信场景的证据。仓库 fixture 通过不能补成真实验收。需保持 [项目上下文](../PROJECT_CONTEXT.md) 中这些边界。

2026-10-13 用户另行报告:用新邮箱完成公众确认后,页面已确认人数为 1。这是用户提供的生产行为证据,不是本次 agent 读取私有订阅库的结果,也不证明候选代码已部署或周报/全部回调已复验;不保存该邮箱、签名链接或邮件内容。

## 隐私、密钥轮换与故障处理

邮件记录含个人信息;管理员聚合不等于数据库匿名。签名管理链接本身具有访问权限,所有公开记录、PR、任务提示、截图和日志必须排除邮箱、密钥、会话与真实签名 URL。浏览统计和邮箱不关联;不利用 opens/clicks 作阅读证明或是否继续发信依据。交接接受并公开披露了 Brevo 匿名跟踪;匿名化不证明像素或改写链接已关闭。HTML/纯文本提供原网址文本可复制,但直接点击/自动识别仍可能经跟踪。全面关闭尚未验证,修改跟踪须同步中英订阅及隐私披露并重新验证,不能只删说明。
Expand Down
Loading
Loading