*PR Created by the Glary-Bot Agent* --- ## Summary Replaces the `tos.*` i18n keys in `apps/website/src/i18n/translations.ts` with the legal-approved Terms of Service copy from `Comfy - Terms of Service (GP 5.12.26).docx` and surfaces an effective date below the hero on `/terms-of-service`. - Restructures the ToS into 14 sections (intro + 13 numbered sections) to match the new legal-approved structure. - Adds two new keys, `tos.effectiveDateLabel` and `tos.effectiveDate`, rendered as a centered `Effective Date: May 13, 2026` line between the hero and the content (matches the pattern used on the Affiliate Program Terms page). - Subsection labels (*Right to Access and Use Comfy Products.*, *Customer Data.*, etc.) render as h3 headings via the existing `block.N.heading` shape — no changes to `ContentSection.vue` or `contentSections.ts`. - English page meta description tightened to reflect the new scope (Comfy Products: Cloud, API, Enterprise — explicitly excluding Comfy OSS). ## Verbatim legal copy Per request, the copy is **verbatim from the legal-approved `.docx`**, including: - `[URL]` placeholder in §2.7 (Data Retention) where the legal doc has a placeholder pending the real docs page. - `[Address]` placeholder in §12.8 (Notices) where the legal doc has a placeholder pending the finalized mailing address. - Mixed casing in §8 (Disclaimer) and §9 (Limitation of Liability) — e.g. `THE Comfy Products AND OUTPUT…`, `…TOTAL LIABILITY OF Comfy…` — preserved exactly as the legal doc presents it. - §11(c) cross-reference left as written. These are intentional and flagged for follow-up with legal/docs before publishing. I have **not** silently substituted real values for the placeholders or normalized casing — that would be editing legal-approved text. ## Chinese (zh-CN) handling The legal-approved copy was provided in English only. To avoid serving English text under a Chinese page shell: - `apps/website/src/pages/zh-CN/terms-of-service.astro` is **removed**. - `getRoutes()` in `apps/website/src/config/routes.ts` treats `termsOfService` as locale-invariant, so the Chinese footer link emits `/terms-of-service` directly — no redirect hop. - `astro.config.ts` adds a redirect from `/zh-CN/terms-of-service` → `/terms-of-service` as a safety net for any stale external/cached links. - All `zh-CN` values on the new `tos.*` keys are filler (mirrored from English) so the `Record<Locale, string>` type contract holds; they are never served. ## Files changed - `apps/website/src/i18n/translations.ts` — 73 old `tos.*` keys removed, 136 new keys added matching the .docx structure. - `apps/website/src/pages/terms-of-service.astro` — imports `t`, renders effective date, updates meta description. - `apps/website/src/pages/zh-CN/terms-of-service.astro` — **removed**. - `apps/website/astro.config.ts` — adds `/zh-CN/terms-of-service` → `/terms-of-service` redirect. - `apps/website/src/config/routes.ts` — `termsOfService` route stays un-prefixed in non-English locales. ## Verification - `pnpm --filter=@comfyorg/website typecheck` — 0 errors (2 pre-existing hints in unrelated files). - `pnpm --filter=@comfyorg/website build` — 279 pages built, `/terms-of-service/` (English page) and `/zh-CN/terms-of-service/` (redirect stub with `noindex` + `canonical`) both emitted. - Pre-commit lint-staged ran `oxfmt`, `oxlint --type-aware`, `eslint --fix`, and `pnpm typecheck` on every commit — all green. - Rendered HTML spot-checked: English `/terms-of-service` contains the new content with verbatim `[URL]` and `[Address]` placeholders; zh-CN homepage footer now links directly to `/terms-of-service` (no redirect hop); `/zh-CN/privacy-policy` and other locale routes still correctly emit `/zh-CN/…` prefixes. - Manual visual check via `astro preview` + Playwright — sidebar nav, h2 section titles, h3 subsection headings, paragraph wrapping, and inline mailto/href anchors all render correctly. Screenshots attached. ## Code-review follow-ups addressed - **zh-CN regression** — Page removed, route override added, redirect kept as safety net. - **Page description mismatch** — Updated meta description to reflect new scope. - **`docs.comfy.org/data-retention` 404** — Now matches the docx placeholder `[URL]`; flagged to legal/docs. - **Disclaimer / Liability casing** — Restored to match docx verbatim. - **Mailing address** — Now matches the docx placeholder `[Address]`; flagged to legal. - **Section 11(c) cross-reference** — Left verbatim per legal doc. ## Scope notes - English-only legal update per request — no Chinese rewrite, no schema changes, no acceptance-tracking infrastructure. - The signup-flow link on `platform.comfy.org` (`website` repo) already points at `https://www.comfy.org/terms-of-service` and renders the new copy at the same URL — no change needed there. ## Screenshots   ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-12286-feat-website-update-Terms-of-Service-to-legal-approved-2026-05-13-copy-3616d73d3650815b9262f84d12655dfa) by [Unito](https://www.unito.io) --------- Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
@comfyorg/website
Marketing/brand website built with Astro + Vue.
Ashby careers integration
/careers and /zh-CN/careers are rendered from Ashby's public job board
API at build time. Data flow:
src/pages/careers.astroawaitsfetchRolesForBuild()during the Astro build.src/utils/ashby.tscallsGET https://api.ashbyhq.com/posting-api/job-board/{board}?includeCompensation=false, validates the envelope and each posting with Zod (src/utils/ashby.schema.ts), and maps to the domain type insrc/data/roles.ts.- On any failure (network, HTTP 4xx/5xx, envelope schema drift),
the fetcher falls back to the committed JSON snapshot at
src/data/ashby-roles.snapshot.json. src/utils/ashby.ci.tsemits GitHub Actions annotations and a$GITHUB_STEP_SUMMARYblock so stale fetches are visible on green builds.
Required environment variables
Both are build-time only. Never prefix with PUBLIC_ (Astro would
inline that into the client bundle).
| Name | Purpose | Default (when unset) |
|---|---|---|
WEBSITE_ASHBY_API_KEY |
Ashby API key (Basic auth) | Build uses the committed snapshot |
WEBSITE_ASHBY_JOB_BOARD_NAME |
Ashby public job board slug | Build uses the committed snapshot |
CI wiring (manual step — required)
This repo's .github/workflows/*.yaml changes cannot be pushed by a
GitHub App. A maintainer must apply the following edits once:
.github/workflows/ci-website-build.yaml — pass the env into the
build step and run the unit tests before it:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup frontend
uses: ./.github/actions/setup-frontend
- name: Run website unit tests
run: pnpm --filter @comfyorg/website test:unit
- name: Build website
env:
WEBSITE_ASHBY_API_KEY: ${{ secrets.WEBSITE_ASHBY_API_KEY }}
WEBSITE_ASHBY_JOB_BOARD_NAME: ${{ vars.WEBSITE_ASHBY_JOB_BOARD_NAME || 'comfy-org' }}
run: pnpm --filter @comfyorg/website build
- name: Verify API key is not leaked into build output
env:
WEBSITE_ASHBY_API_KEY: ${{ secrets.WEBSITE_ASHBY_API_KEY }}
run: |
set +x
if [ -z "${WEBSITE_ASHBY_API_KEY:-}" ]; then
echo "Secret not available in this run; skipping leak check."
exit 0
fi
# grep -rlF prints only file paths (never match content).
MATCHES=$(grep -rlF --exclude-dir=node_modules --null \
-e "$WEBSITE_ASHBY_API_KEY" apps/website/dist/ 2>/dev/null \
| tr '\0' '\n' || true)
if [ -n "$MATCHES" ]; then
echo "::error title=Ashby API key leaked into build output::$MATCHES"
exit 1
fi
.github/workflows/ci-vercel-website-preview.yaml — add the
two env vars to the top-level env: block so vercel build (both
deploy-preview and deploy-production jobs) sees them:
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_WEBSITE_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_WEBSITE_PROJECT_ID }}
VERCEL_TOKEN: ${{ secrets.VERCEL_WEBSITE_TOKEN }}
VERCEL_SCOPE: comfyui
WEBSITE_ASHBY_API_KEY: ${{ secrets.WEBSITE_ASHBY_API_KEY }}
WEBSITE_ASHBY_JOB_BOARD_NAME: ${{ vars.WEBSITE_ASHBY_JOB_BOARD_NAME || 'comfy-org' }}
The secret must also be added to the Vercel project environment
(vercel env add WEBSITE_ASHBY_API_KEY … or via the Vercel UI) so
that vercel build in the preview job has access to it.
Fork PRs do not exercise this path: ci-vercel-website-preview.yaml
receives an empty VERCEL_TOKEN for forks and fails at vercel pull
before the build runs. Fork-safe PR interactions (the preview-URL
comment) are handled by pr-vercel-website-preview.yaml.
Refreshing the snapshot
When a maintainer wants to update the committed snapshot (e.g. after onboarding/offboarding roles):
WEBSITE_ASHBY_API_KEY=… WEBSITE_ASHBY_JOB_BOARD_NAME=comfy-org \
pnpm --filter @comfyorg/website ashby:refresh-snapshot
git commit apps/website/src/data/ashby-roles.snapshot.json
The script exits non-zero on any non-fresh outcome so stale/empty snapshots can't be accidentally committed.
Cloud nodes integration
/cloud/supported-nodes (and /zh-CN/) lists custom-node packs preinstalled on Comfy Cloud, joined with public metadata from the ComfyUI Custom Node Registry (api.comfy.org). See src/pages/cloud/supported-nodes/AGENTS.md for the build pipeline, source-file map, and key invariants.
Build-time env var: WEBSITE_CLOUD_API_KEY (Cloud /api/object_info auth; the build falls back to the committed snapshot when unset). Must also be set in the Vercel project environment.
Production strictness
src/utils/cloudNodes.build.ts throws when fetchCloudNodesForBuild() returns
{ status: 'stale' } and process.env.VERCEL_ENV === 'production'. This
prevents the production deploy from silently shipping an out-of-date snapshot
when the Cloud API is unreachable or WEBSITE_CLOUD_API_KEY is missing. Preview
and local builds continue to use the committed snapshot with a warning
annotation.
Required GitHub Actions / Vercel secrets
| Name | Where | Purpose |
|---|---|---|
WEBSITE_CLOUD_API_KEY |
GitHub Actions repo secret + Vercel project env | Auth for Cloud /api/object_info. Required for fresh production data. |
The Release: Website workflow uses the GitHub Actions secret to regenerate
apps/website/src/data/cloud-nodes.snapshot.json via
.github/actions/cloud-nodes-pull/action.yaml. The Vercel environment value is
read at build time by vercel build in ci-vercel-website-preview.yaml; the
deploy-production job hard-fails before vercel build --prod if the secret
is missing.
Refreshing the snapshot
To update the committed snapshot manually (e.g. after onboarding new packs to Comfy Cloud):
WEBSITE_CLOUD_API_KEY=… \
pnpm --filter @comfyorg/website cloud-nodes:refresh-snapshot
git commit apps/website/src/data/cloud-nodes.snapshot.json
The script exits non-zero on any non-fresh outcome so stale/empty snapshots
can't be accidentally committed. Otherwise the Release: Website GitHub
Actions workflow runs the same step on every manual dispatch and opens a PR
with the refreshed snapshot.
HubSpot contact form
The contact page uses HubSpot's hosted form embed for the interest form:
<script
src="https://js-na2.hsforms.net/forms/embed/developer/244637579.js"
defer
></script>
<div
class="hs-form-html"
data-region="na2"
data-form-id="94e05eab-1373-47f7-ab5e-d84f9e6aa262"
data-portal-id="244637579"
></div>
The localized /zh-CN/contact page uses the same portal and script with form
ID 6885750c-02ef-4aa2-ba0d-213be9cccf93.
This keeps submission handling, validation, anti-spam updates, and field
configuration in HubSpot. The local implementation in
src/components/contact/HubspotFormEmbed.vue only loads the hosted script and
renders the documented embed container.
Scripts
pnpm dev— Astro dev serverpnpm build— production build todist/pnpm typecheck—astro checkpnpm test:unit— Vitest unit testspnpm test:e2e— Playwright E2E tests (requirespnpm buildfirst)pnpm ashby:refresh-snapshot— refresh the committed careers snapshotpnpm cloud-nodes:refresh-snapshot— refresh the committed cloud nodes snapshot