diff --git a/public/og/pages/de/support.jpg b/public/og/pages/de/support.jpg
new file mode 100644
index 00000000..5bde4ed0
Binary files /dev/null and b/public/og/pages/de/support.jpg differ
diff --git a/public/og/pages/en/support.jpg b/public/og/pages/en/support.jpg
new file mode 100644
index 00000000..2be14c17
Binary files /dev/null and b/public/og/pages/en/support.jpg differ
diff --git a/public/og/pages/fr/support.jpg b/public/og/pages/fr/support.jpg
new file mode 100644
index 00000000..e8731ed3
Binary files /dev/null and b/public/og/pages/fr/support.jpg differ
diff --git a/public/og/pages/ja/support.jpg b/public/og/pages/ja/support.jpg
new file mode 100644
index 00000000..fa8bd396
Binary files /dev/null and b/public/og/pages/ja/support.jpg differ
diff --git a/public/og/pages/ko/support.jpg b/public/og/pages/ko/support.jpg
new file mode 100644
index 00000000..e9fc325b
Binary files /dev/null and b/public/og/pages/ko/support.jpg differ
diff --git a/public/og/pages/zh-CN/support.jpg b/public/og/pages/zh-CN/support.jpg
new file mode 100644
index 00000000..d3866472
Binary files /dev/null and b/public/og/pages/zh-CN/support.jpg differ
diff --git a/public/og/pages/zh-TW/support.jpg b/public/og/pages/zh-TW/support.jpg
new file mode 100644
index 00000000..0244f78b
Binary files /dev/null and b/public/og/pages/zh-TW/support.jpg differ
diff --git a/src/app/[lang]/contact/page.tsx b/src/app/[lang]/contact/page.tsx
index b58d5fb7..9247c543 100644
--- a/src/app/[lang]/contact/page.tsx
+++ b/src/app/[lang]/contact/page.tsx
@@ -4,7 +4,7 @@ import Link from "next/link"
import { useLang } from "@/core/i18n/lang-provider"
import { toast } from "sonner"
import { Button } from "@/components/ui/button"
-import { Github, Mail, MessageSquare, ExternalLink, ShieldCheck, Map, ThumbsUp } from "lucide-react"
+import { Github, Mail, MessageSquare, ExternalLink, ShieldCheck, Map, ThumbsUp, HeartHandshake } from "lucide-react"
import { safeClipboardWrite } from "@/core/clipboard/clipboard"
const EMAIL_ADDRESS = "contact@byteflow.tools"
@@ -24,6 +24,7 @@ export default function ContactPage() {
{ icon: Map, title: t.common.request_tool, desc: p.contact_request_tool_desc, href: GITHUB_FEATURE_REQUEST_URL, external: true },
{ icon: ThumbsUp, title: t.common.vote_on_requests, desc: p.contact_vote_requests_desc, href: GITHUB_REQUEST_VOTING_URL, external: true },
{ icon: ShieldCheck, title: p.contact_security_title, desc: p.contact_security_desc, href: SECURITY_ADVISORY_URL, external: true },
+ { icon: HeartHandshake, title: p.support_title, desc: p.contact_support_desc, href: `/${lang}/support`, external: false },
]
const handleCopyEmail = async () => {
@@ -46,7 +47,7 @@ export default function ContactPage() {
{links.map((link) => (
-
{link.title}
{link.desc}
-
+
))}
@@ -97,6 +98,12 @@ export default function ContactPage() {
>
{p.contact_self_hosting_link}
+
+ {p.support_title}
+
diff --git a/src/app/[lang]/pricing/page.tsx b/src/app/[lang]/pricing/page.tsx
index f4e9b897..6a43718f 100644
--- a/src/app/[lang]/pricing/page.tsx
+++ b/src/app/[lang]/pricing/page.tsx
@@ -86,15 +86,12 @@ export default function PricingPage() {
{p.pricing_support_desc}
-
- {p.pricing_github_project}
-
-
+ {p.support_title}
+
@@ -110,7 +107,7 @@ export default function PricingPage() {
{p.self_hosting_title}
diff --git a/src/app/[lang]/self-hosting/page.tsx b/src/app/[lang]/self-hosting/page.tsx
index 95020806..e8ee1bf4 100644
--- a/src/app/[lang]/self-hosting/page.tsx
+++ b/src/app/[lang]/self-hosting/page.tsx
@@ -1,6 +1,6 @@
import Link from "next/link"
import { notFound } from "next/navigation"
-import { Server, ShieldCheck, WifiOff } from "lucide-react"
+import { HeartHandshake, Server, ShieldCheck, WifiOff } from "lucide-react"
import type { Locale } from "@/core/i18n/i18n"
import { isValidLocale } from "@/core/i18n/i18n"
import { getTranslation } from "@/core/i18n/translations/catalog"
@@ -160,6 +160,10 @@ export default async function SelfHostingPage({ params }: { params: Promise<{ la
{t.pages.trust_center_title}
+
+
+ {t.pages.support_title}
+
@@ -189,6 +193,10 @@ export default async function SelfHostingPage({ params }: { params: Promise<{ la
{copy.boundaryBody}
+
+
+ {t.pages.support_private_deployment_title}
+
diff --git a/src/app/[lang]/support/layout.tsx b/src/app/[lang]/support/layout.tsx
new file mode 100644
index 00000000..bef0e0f8
--- /dev/null
+++ b/src/app/[lang]/support/layout.tsx
@@ -0,0 +1,21 @@
+import type { Metadata } from "next"
+import { notFound } from "next/navigation"
+import { isValidLocale } from "@/core/i18n/i18n"
+import { getTranslation } from "@/core/i18n/translations/catalog"
+import { buildStaticPageMetadata } from "@/core/seo/seo"
+
+export async function generateMetadata({ params }: { params: Promise<{ lang: string }> }): Promise {
+ const { lang } = await params
+ if (!isValidLocale(lang)) notFound()
+ const t = getTranslation(lang)
+ return buildStaticPageMetadata({
+ lang,
+ slug: "support",
+ title: t.pages.support_title,
+ description: t.pages.support_intro,
+ })
+}
+
+export default function Layout({ children }: { children: React.ReactNode }) {
+ return <>{children}>
+}
diff --git a/src/app/[lang]/support/page.tsx b/src/app/[lang]/support/page.tsx
new file mode 100644
index 00000000..ad74e793
--- /dev/null
+++ b/src/app/[lang]/support/page.tsx
@@ -0,0 +1,89 @@
+import Link from "next/link"
+import { notFound } from "next/navigation"
+import { ArrowUpRight, CheckCircle2, HeartHandshake, Mail, ServerCog, ShieldCheck } from "lucide-react"
+import { isValidLocale } from "@/core/i18n/i18n"
+import { getTranslation } from "@/core/i18n/translations/catalog"
+
+const EMAIL_ADDRESS = "contact@byteflow.tools"
+const GITHUB_REPOSITORY_URL = "https://github.com/baixiangcpp/byteflow.tools"
+
+export default async function SupportPage({ params }: { params: Promise<{ lang: string }> }) {
+ const { lang } = await params
+ if (!isValidLocale(lang)) notFound()
+ const t = getTranslation(lang)
+ const p = t.pages
+
+ const boundaries = [
+ p.support_boundary_free,
+ p.support_boundary_no_tracking,
+ p.support_boundary_no_payload,
+ p.support_boundary_no_account,
+ ]
+
+ return (
+
+
+ {p.support_badge}
+ {p.support_title}
+
+ {p.support_intro}
+
+
+
+
+
+
+
+ {p.support_sponsor_title}
+
+ {p.support_sponsor_desc}
+
+
+
+
+ {p.support_private_deployment_title}
+
+ {p.support_private_deployment_desc}
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/layout/route-page-chrome.tsx b/src/components/layout/route-page-chrome.tsx
index 8271323e..07e893dc 100644
--- a/src/components/layout/route-page-chrome.tsx
+++ b/src/components/layout/route-page-chrome.tsx
@@ -15,7 +15,7 @@ import { getRouteToolBySlug } from "@/generated/route-tool-lookup"
import { ToolTrustHeader } from "@/features/tool-shell/tool-trust-header"
import { ToolFavoriteControl } from "./tool-favorite-control"
-const EXCLUDED_CONTENT_INTRO_SLUGS = new Set(["about", "pricing", "contact", "privacy", "terms", "install-app"])
+const EXCLUDED_CONTENT_INTRO_SLUGS = new Set(["about", "pricing", "contact", "privacy", "terms", "install-app", "support"])
type RoutePageChromeProps = {
children: React.ReactNode
diff --git a/src/components/layout/server-footer.tsx b/src/components/layout/server-footer.tsx
index 93ade2d2..27def649 100644
--- a/src/components/layout/server-footer.tsx
+++ b/src/components/layout/server-footer.tsx
@@ -27,6 +27,7 @@ export function ServerFooter({
{ key: "roadmap", slug: "roadmap", label: requireTranslationValue(translations.pages.roadmap_title, "pages.roadmap_title") },
{ key: "changelog", slug: "changelog", label: requireTranslationValue(translations.pages.changelog_title, "pages.changelog_title") },
{ key: "self-hosting", slug: "self-hosting", label: requireTranslationValue(translations.pages.self_hosting_title, "pages.self_hosting_title") },
+ { key: "support", slug: "support", label: requireTranslationValue(translations.pages.support_title, "pages.support_title") },
{ key: "terms", slug: "terms", label: requireTranslationValue(translations.pages.terms_title, "pages.terms_title") },
{ key: "contact", slug: "contact", label: requireTranslationValue(translations.pages.contact_title, "pages.contact_title") },
].map((page) => ({
diff --git a/src/core/i18n/translations/de.json b/src/core/i18n/translations/de.json
index eba12b99..dab260cf 100644
--- a/src/core/i18n/translations/de.json
+++ b/src/core/i18n/translations/de.json
@@ -3304,6 +3304,21 @@
"contact_public_planning_desc": "Nutzen Sie oeffentliche Anfragen nur mit bereinigten Beispielen. Posten Sie keine echten Secrets, privaten Payloads, HAR-Dateien, privaten URLs, Logs, Prompts, generierten Ausgaben, Request-Bodies oder Response-Bodies.",
"contact_roadmap_link": "Fahrplan",
"contact_distribution_research_link": "Erweiterungs- und Desktop-Recherche",
- "contact_self_hosting_link": "Selbsthosting"
+ "contact_self_hosting_link": "Selbsthosting",
+ "support_title": "Datenschutzsichere Unterstützung",
+ "support_intro": "Unterstützen Sie byteflow.tools über einfache Sponsoring-Anfragen oder private Deployment-Hilfe, während die Kern-Tools kostenlos, Open Source, browser-lokal und ohne Konto bleiben.",
+ "support_badge": "Unterstützung ohne Ad-Tracking",
+ "support_sponsor_title": "Sponsoring-Platzierungen",
+ "support_sponsor_desc": "Sponsoring nutzt nur Plain-Text- oder Logo-Platzierungen mit normalen Links. Es gibt keine Tracking-Pixel, personalisierte Werbung, Ad-Skripte oder Verhaltensprofile.",
+ "support_private_deployment_title": "Private Deployment-Unterstützung",
+ "support_private_deployment_desc": "Deployment-Hilfe kann statisches Hosting, interne Bereitstellung, Sicherheitsprüfung, Packaging, Wartung und Offline-Distribution abdecken, ohne ein Cloud-Konto zu verlangen.",
+ "support_boundaries_title": "Datenschutzgrenzen",
+ "support_boundary_free": "Die Kern-Tools bleiben kostenlos und Open Source.",
+ "support_boundary_no_tracking": "Sponsoring-Platzierungen verwenden keine Tracking-Pixel, keine personalisierte Werbung und keine Ad-Skripte.",
+ "support_boundary_no_payload": "Sponsoren erhalten keinen Payload-Zugriff, keine Suchtexte, keine Nutzerkennungen und keine Verhaltensprofile.",
+ "support_boundary_no_account": "Für Support oder private Deployment-Hilfe ist kein Cloud-Konto und kein gehosteter Payload-Verlauf erforderlich.",
+ "support_cta_email": "Support kontaktieren",
+ "support_cta_github": "Quellcode prüfen",
+ "contact_support_desc": "Fragen Sie zu Sponsoring, privatem Deployment, Sicherheitsprüfung, Packaging oder Wartung an, ohne private Payloads zu teilen."
}
}
diff --git a/src/core/i18n/translations/en.json b/src/core/i18n/translations/en.json
index 03aa5a81..6003b4e4 100644
--- a/src/core/i18n/translations/en.json
+++ b/src/core/i18n/translations/en.json
@@ -3304,6 +3304,21 @@
"contact_public_planning_desc": "Use public requests only with sanitized examples. Do not post real secrets, private payloads, HAR files, private URLs, logs, prompts, generated output, request bodies, or response bodies.",
"contact_roadmap_link": "Roadmap",
"contact_distribution_research_link": "Extension and desktop research",
- "contact_self_hosting_link": "Self-hosting"
+ "contact_self_hosting_link": "Self-hosting",
+ "support_title": "Privacy-safe support",
+ "support_intro": "Support byteflow.tools through plain sponsorship inquiries or private deployment help while keeping the core tools free, open source, browser-local, and account-free.",
+ "support_badge": "Support without ad tracking",
+ "support_sponsor_title": "Sponsor placements",
+ "support_sponsor_desc": "Sponsorships are plain-text or logo placements with normal links only. They do not use tracking pixels, personalized ads, ad scripts, or behavioral profiling.",
+ "support_private_deployment_title": "Private deployment support",
+ "support_private_deployment_desc": "Deployment support can cover static hosting, internal deployment, security review, packaging, maintenance, and offline distribution guidance without requiring a cloud account.",
+ "support_boundaries_title": "Privacy boundaries",
+ "support_boundary_free": "Core tools remain free and open source.",
+ "support_boundary_no_tracking": "Sponsor placements use no tracking pixels, no personalized ads, and no ad scripts.",
+ "support_boundary_no_payload": "Sponsors do not receive payload access, query text, user identifiers, or behavioral profiles.",
+ "support_boundary_no_account": "No cloud account or hosted payload history is required for support or private deployment help.",
+ "support_cta_email": "Contact support",
+ "support_cta_github": "Review the source",
+ "contact_support_desc": "Ask about sponsorship, private deployment, security review, packaging, or maintenance without sharing private payloads."
}
}
diff --git a/src/core/i18n/translations/fr.json b/src/core/i18n/translations/fr.json
index 158ddac4..c2b63180 100644
--- a/src/core/i18n/translations/fr.json
+++ b/src/core/i18n/translations/fr.json
@@ -3304,6 +3304,21 @@
"contact_public_planning_desc": "Utilisez les demandes publiques uniquement avec des exemples nettoyes. Ne publiez pas de vrais secrets, payloads prives, fichiers HAR, URL privees, logs, prompts, sorties generees, corps de requete ou corps de reponse.",
"contact_roadmap_link": "Feuille de route",
"contact_distribution_research_link": "Recherche extension et desktop",
- "contact_self_hosting_link": "Auto-hebergement"
+ "contact_self_hosting_link": "Auto-hebergement",
+ "support_title": "Soutien respectueux de la vie privée",
+ "support_intro": "Soutenez byteflow.tools avec des demandes de sponsoring simples ou une aide au deploiement prive, tout en gardant les outils principaux gratuits, open source, locaux au navigateur et sans compte.",
+ "support_badge": "Soutien sans suivi publicitaire",
+ "support_sponsor_title": "Emplacements sponsorises",
+ "support_sponsor_desc": "Les sponsors utilisent seulement du texte ou un logo avec des liens ordinaires. Aucun pixel de suivi, aucune publicite personnalisee, aucun script publicitaire ni profil comportemental.",
+ "support_private_deployment_title": "Support de deploiement prive",
+ "support_private_deployment_desc": "Le support peut couvrir hebergement statique, deploiement interne, revue de securite, packaging, maintenance et distribution hors ligne, sans exiger de compte cloud.",
+ "support_boundaries_title": "Limites de confidentialite",
+ "support_boundary_free": "Les outils principaux restent gratuits et open source.",
+ "support_boundary_no_tracking": "Les emplacements sponsorises n'utilisent aucun pixel de suivi, aucune publicite personnalisee et aucun script publicitaire.",
+ "support_boundary_no_payload": "Les sponsors ne recoivent aucun acces aux payloads, textes de requete, identifiants utilisateur ou profils comportementaux.",
+ "support_boundary_no_account": "Aucun compte cloud ni historique de payload heberge n'est requis pour le support ou le deploiement prive.",
+ "support_cta_email": "Contacter le support",
+ "support_cta_github": "Consulter le code source",
+ "contact_support_desc": "Demandez sponsoring, deploiement prive, revue de securite, packaging ou maintenance sans partager de payload prive."
}
}
diff --git a/src/core/i18n/translations/ja.json b/src/core/i18n/translations/ja.json
index 326ce9b1..e34add08 100644
--- a/src/core/i18n/translations/ja.json
+++ b/src/core/i18n/translations/ja.json
@@ -3304,6 +3304,21 @@
"pricing_internal_deployment_title": "内部デプロイの相談",
"pricing_internal_deployment_desc": "セルフホストでもクラウド履歴なしの約束を保ちます。ホスト型アカウント、payload 同期、サーバー側のツール payload 処理はありません。",
"pricing_internal_deployment_cta": "内部デプロイを相談",
- "pricing_self_hosting_guide": "セルフホストガイド"
+ "pricing_self_hosting_guide": "セルフホストガイド",
+ "support_title": "プライバシー安全なサポート",
+ "support_intro": "通常のスポンサー問い合わせやプライベート導入支援で byteflow.tools を支援できます。中核ツールは無料、オープンソース、ブラウザ内処理、アカウント不要のままです。",
+ "support_badge": "広告追跡なしの支援",
+ "support_sponsor_title": "スポンサー掲載",
+ "support_sponsor_desc": "スポンサー掲載はプレーンテキストまたはロゴと通常リンクのみです。追跡ピクセル、パーソナライズ広告、広告スクリプト、行動プロファイルは使いません。",
+ "support_private_deployment_title": "プライベート導入支援",
+ "support_private_deployment_desc": "導入支援は静的ホスティング、社内導入、セキュリティレビュー、パッケージング、保守、オフライン配布の相談を扱い、クラウドアカウントは不要です。",
+ "support_boundaries_title": "プライバシー境界",
+ "support_boundary_free": "中核ツールは無料でオープンソースのままです。",
+ "support_boundary_no_tracking": "スポンサー掲載は追跡ピクセル、パーソナライズ広告、広告スクリプトを使いません。",
+ "support_boundary_no_payload": "スポンサーは payload へのアクセス、検索文、ユーザー識別子、行動プロファイルを受け取りません。",
+ "support_boundary_no_account": "サポートやプライベート導入支援にクラウドアカウントやホストされた payload 履歴は必要ありません。",
+ "support_cta_email": "サポートに連絡",
+ "support_cta_github": "ソースを確認",
+ "contact_support_desc": "スポンサー、プライベート導入、セキュリティレビュー、パッケージング、保守について、非公開 payload を共有せずに相談できます。"
}
}
diff --git a/src/core/i18n/translations/ko.json b/src/core/i18n/translations/ko.json
index e2063ba3..d4514509 100644
--- a/src/core/i18n/translations/ko.json
+++ b/src/core/i18n/translations/ko.json
@@ -3304,6 +3304,21 @@
"pricing_internal_deployment_title": "내부 배포 안내",
"pricing_internal_deployment_desc": "자체 호스팅은 클라우드 기록 없음 약속을 유지합니다. 호스팅 계정, payload 동기화, 서버 측 도구 payload 처리가 없습니다.",
"pricing_internal_deployment_cta": "내부 배포 문의",
- "pricing_self_hosting_guide": "자체 호스팅 가이드"
+ "pricing_self_hosting_guide": "자체 호스팅 가이드",
+ "support_title": "개인정보 보호형 지원",
+ "support_intro": "일반 스폰서 문의나 비공개 배포 지원으로 byteflow.tools를 도울 수 있으며, 핵심 도구는 무료, 오픈소스, 브라우저 로컬, 계정 불필요 상태를 유지합니다.",
+ "support_badge": "광고 추적 없는 지원",
+ "support_sponsor_title": "스폰서 표시",
+ "support_sponsor_desc": "스폰서 표시는 일반 텍스트 또는 로고와 일반 링크만 사용합니다. 추적 픽셀, 개인화 광고, 광고 스크립트, 행동 프로필은 사용하지 않습니다.",
+ "support_private_deployment_title": "비공개 배포 지원",
+ "support_private_deployment_desc": "배포 지원은 정적 호스팅, 내부 배포, 보안 검토, 패키징, 유지보수, 오프라인 배포 안내를 다루며 클라우드 계정을 요구하지 않습니다.",
+ "support_boundaries_title": "개인정보 경계",
+ "support_boundary_free": "핵심 도구는 계속 무료이며 오픈소스입니다.",
+ "support_boundary_no_tracking": "스폰서 표시는 추적 픽셀, 개인화 광고, 광고 스크립트를 사용하지 않습니다.",
+ "support_boundary_no_payload": "스폰서는 payload 접근 권한, 검색 텍스트, 사용자 식별자, 행동 프로필을 받지 않습니다.",
+ "support_boundary_no_account": "지원이나 비공개 배포 도움에는 클라우드 계정 또는 호스팅된 payload 기록이 필요하지 않습니다.",
+ "support_cta_email": "지원 문의",
+ "support_cta_github": "소스 확인",
+ "contact_support_desc": "비공개 payload 공유 없이 스폰서십, 비공개 배포, 보안 검토, 패키징, 유지보수를 문의하세요."
}
}
diff --git a/src/core/i18n/translations/zh-CN.json b/src/core/i18n/translations/zh-CN.json
index e62171bd..0ec4036a 100644
--- a/src/core/i18n/translations/zh-CN.json
+++ b/src/core/i18n/translations/zh-CN.json
@@ -3304,6 +3304,21 @@
"pricing_internal_deployment_title": "内部部署指导",
"pricing_internal_deployment_desc": "自托管会保留无云端历史承诺:无托管账号、无 payload 同步,也没有服务端工具 payload 处理。",
"pricing_internal_deployment_cta": "咨询内部部署",
- "pricing_self_hosting_guide": "自托管指南"
+ "pricing_self_hosting_guide": "自托管指南",
+ "support_title": "隐私安全支持",
+ "support_intro": "通过普通赞助咨询或私有部署协助支持 byteflow.tools,同时保持核心工具免费、开源、浏览器本地处理且无需账号。",
+ "support_badge": "无广告跟踪的支持",
+ "support_sponsor_title": "赞助展示",
+ "support_sponsor_desc": "赞助展示仅使用纯文本或 logo 与普通链接,不使用跟踪像素、个性化广告、广告脚本或行为画像。",
+ "support_private_deployment_title": "私有部署支持",
+ "support_private_deployment_desc": "部署支持可覆盖静态托管、内部部署、安全审查、打包、维护和离线分发指导,且不要求云端账号。",
+ "support_boundaries_title": "隐私边界",
+ "support_boundary_free": "核心工具保持免费且开源。",
+ "support_boundary_no_tracking": "赞助展示不使用跟踪像素、个性化广告或广告脚本。",
+ "support_boundary_no_payload": "赞助方不会获得 payload 访问权、查询文本、用户标识或行为画像。",
+ "support_boundary_no_account": "支持或私有部署协助不需要云端账号或托管 payload 历史。",
+ "support_cta_email": "联系支持",
+ "support_cta_github": "查看源码",
+ "contact_support_desc": "咨询赞助、私有部署、安全审查、打包或维护,不需要分享私有 payload。"
}
}
diff --git a/src/core/i18n/translations/zh-TW.json b/src/core/i18n/translations/zh-TW.json
index c26c6fa5..0f00a554 100644
--- a/src/core/i18n/translations/zh-TW.json
+++ b/src/core/i18n/translations/zh-TW.json
@@ -3304,6 +3304,21 @@
"pricing_internal_deployment_title": "內部部署指引",
"pricing_internal_deployment_desc": "自託管會保留無雲端歷史承諾:無託管帳號、無 payload 同步,也沒有服務端工具 payload 處理。",
"pricing_internal_deployment_cta": "諮詢內部部署",
- "pricing_self_hosting_guide": "自託管指南"
+ "pricing_self_hosting_guide": "自託管指南",
+ "support_title": "隱私安全支持",
+ "support_intro": "透過普通贊助洽詢或私有部署協助支持 byteflow.tools,同時維持核心工具免費、開源、瀏覽器本地處理且無需帳號。",
+ "support_badge": "無廣告追蹤的支持",
+ "support_sponsor_title": "贊助展示",
+ "support_sponsor_desc": "贊助展示僅使用純文字或 logo 與普通連結,不使用追蹤像素、個人化廣告、廣告腳本或行為輪廓。",
+ "support_private_deployment_title": "私有部署支持",
+ "support_private_deployment_desc": "部署支持可涵蓋靜態託管、內部部署、安全審查、打包、維護和離線分發指引,且不要求雲端帳號。",
+ "support_boundaries_title": "隱私邊界",
+ "support_boundary_free": "核心工具保持免費且開源。",
+ "support_boundary_no_tracking": "贊助展示不使用追蹤像素、個人化廣告或廣告腳本。",
+ "support_boundary_no_payload": "贊助方不會取得 payload 存取權、查詢文字、使用者識別或行為輪廓。",
+ "support_boundary_no_account": "支持或私有部署協助不需要雲端帳號或託管 payload 歷史。",
+ "support_cta_email": "聯絡支持",
+ "support_cta_github": "查看原始碼",
+ "contact_support_desc": "洽詢贊助、私有部署、安全審查、打包或維護,不需要分享私有 payload。"
}
}
diff --git a/src/generated/tool-index.json b/src/generated/tool-index.json
index 4f55fb25..98a369e5 100644
--- a/src/generated/tool-index.json
+++ b/src/generated/tool-index.json
@@ -2,7 +2,7 @@
"counts": {
"canonicalTools": 131,
"aliasRoutes": 2,
- "routeDirs": 199,
+ "routeDirs": 200,
"unknownRouteDirs": 0
},
"canonicalTools": [
@@ -6994,6 +6994,14 @@
"inHubGroup": false,
"inStaticGroup": false
},
+ {
+ "slug": "support",
+ "hasPage": true,
+ "kind": "static-content",
+ "targetSlug": null,
+ "inHubGroup": false,
+ "inStaticGroup": true
+ },
{
"slug": "svg-blob-generator",
"hasPage": true,
diff --git a/src/lib/ia-stability-baseline.json b/src/lib/ia-stability-baseline.json
index fde1c889..e05cb6d6 100644
--- a/src/lib/ia-stability-baseline.json
+++ b/src/lib/ia-stability-baseline.json
@@ -94,6 +94,7 @@
"sha256-digest-generator",
"sha384-digest-generator",
"sha512-digest-generator",
+ "support",
"svg-optimization-and-conversion-best-practices",
"terms",
"trust-center",
diff --git a/src/lib/sitemap-lastmod.json b/src/lib/sitemap-lastmod.json
index c78ab5c5..38fad941 100644
--- a/src/lib/sitemap-lastmod.json
+++ b/src/lib/sitemap-lastmod.json
@@ -202,13 +202,13 @@
"fr": "2026-06-26T00:00:00.000Z"
},
"pricing": {
- "en": "2026-06-25T00:00:00.000Z",
- "zh-CN": "2026-06-25T00:00:00.000Z",
- "zh-TW": "2026-06-25T00:00:00.000Z",
- "ja": "2026-06-25T00:00:00.000Z",
- "ko": "2026-06-25T00:00:00.000Z",
- "de": "2026-06-25T00:00:00.000Z",
- "fr": "2026-06-25T00:00:00.000Z"
+ "en": "2026-06-29T00:00:00.000Z",
+ "zh-CN": "2026-06-29T00:00:00.000Z",
+ "zh-TW": "2026-06-29T00:00:00.000Z",
+ "ja": "2026-06-29T00:00:00.000Z",
+ "ko": "2026-06-29T00:00:00.000Z",
+ "de": "2026-06-29T00:00:00.000Z",
+ "fr": "2026-06-29T00:00:00.000Z"
},
"contact": {
"en": "2026-06-29T00:00:00.000Z",
@@ -256,13 +256,22 @@
"fr": "2026-06-25T00:00:00.000Z"
},
"self-hosting": {
- "en": "2026-06-24T00:00:00.000Z",
- "zh-CN": "2026-06-24T00:00:00.000Z",
- "zh-TW": "2026-06-24T00:00:00.000Z",
- "ja": "2026-06-24T00:00:00.000Z",
- "ko": "2026-06-24T00:00:00.000Z",
- "de": "2026-06-24T00:00:00.000Z",
- "fr": "2026-06-24T00:00:00.000Z"
+ "en": "2026-06-29T00:00:00.000Z",
+ "zh-CN": "2026-06-29T00:00:00.000Z",
+ "zh-TW": "2026-06-29T00:00:00.000Z",
+ "ja": "2026-06-29T00:00:00.000Z",
+ "ko": "2026-06-29T00:00:00.000Z",
+ "de": "2026-06-29T00:00:00.000Z",
+ "fr": "2026-06-29T00:00:00.000Z"
+ },
+ "support": {
+ "en": "2026-06-29T00:00:00.000Z",
+ "zh-CN": "2026-06-29T00:00:00.000Z",
+ "zh-TW": "2026-06-29T00:00:00.000Z",
+ "ja": "2026-06-29T00:00:00.000Z",
+ "ko": "2026-06-29T00:00:00.000Z",
+ "de": "2026-06-29T00:00:00.000Z",
+ "fr": "2026-06-29T00:00:00.000Z"
},
"distribution-research": {
"en": "2026-06-25T00:00:00.000Z",
diff --git a/src/lib/sitemap-route-groups.json b/src/lib/sitemap-route-groups.json
index 19b1ee5b..cec89a1a 100644
--- a/src/lib/sitemap-route-groups.json
+++ b/src/lib/sitemap-route-groups.json
@@ -29,6 +29,7 @@
"roadmap",
"changelog",
"self-hosting",
+ "support",
"distribution-research",
"terms",
"install-app",
diff --git a/tests/guards/pricing-positioning.test.ts b/tests/guards/pricing-positioning.test.ts
index 95f9e336..1e478ff6 100644
--- a/tests/guards/pricing-positioning.test.ts
+++ b/tests/guards/pricing-positioning.test.ts
@@ -32,7 +32,7 @@ describe("pricing positioning", () => {
it("routes pricing CTAs to free tools, support, self-hosting, and internal deployment guidance only", () => {
expect(PRICING_SOURCE).toContain("/all-tools")
- expect(PRICING_SOURCE).toContain("/contact")
+ expect(PRICING_SOURCE).toContain("/support")
expect(PRICING_SOURCE).toContain("https://github.com/baixiangcpp/byteflow.tools")
expect(PRICING_SOURCE).toContain("pricing_support_title")
expect(PRICING_SOURCE).toContain("self_hosting_title")
diff --git a/tests/guards/public-planning-docs.test.ts b/tests/guards/public-planning-docs.test.ts
index 67b8ba0f..44228e2c 100644
--- a/tests/guards/public-planning-docs.test.ts
+++ b/tests/guards/public-planning-docs.test.ts
@@ -11,10 +11,11 @@ import { buildCanonicalUrl } from "@/core/seo/urls"
import RoadmapPage from "@/app/[lang]/roadmap/page"
import ChangelogPage from "@/app/[lang]/changelog/page"
import SelfHostingPage from "@/app/[lang]/self-hosting/page"
+import SupportPage from "@/app/[lang]/support/page"
import DistributionResearchPage from "@/app/[lang]/distribution-research/page"
import ContactPage from "@/app/[lang]/contact/page"
-const PUBLIC_PLANNING_SLUGS = ["roadmap", "changelog", "self-hosting", "distribution-research"]
+const PUBLIC_PLANNING_SLUGS = ["roadmap", "changelog", "self-hosting", "support", "distribution-research"]
describe("public roadmap, changelog, self-hosting, and distribution docs", () => {
it("adds public planning pages to sitemap for every locale", () => {
@@ -33,6 +34,7 @@ describe("public roadmap, changelog, self-hosting, and distribution docs", () =>
renderToStaticMarkup(await RoadmapPage({ params })),
renderToStaticMarkup(await ChangelogPage({ params })),
renderToStaticMarkup(await SelfHostingPage({ params })),
+ renderToStaticMarkup(await SupportPage({ params })),
renderToStaticMarkup(await DistributionResearchPage({ params })),
renderToStaticMarkup(createElement(
LangProvider,
@@ -49,10 +51,17 @@ describe("public roadmap, changelog, self-hosting, and distribution docs", () =>
expect(markup).toContain("Request launcher access")
expect(markup).toContain("no server-side tool payload processing")
expect(markup).toContain("no payload sync")
+ expect(markup).toContain("no tracking pixels")
+ expect(markup).toContain("no personalized ads")
+ expect(markup).toContain("no ad scripts")
+ expect(markup).toContain("payload access")
+ expect(markup).toContain("No cloud account or hosted payload history")
expect(markup).toContain("Self-host byteflow.tools")
+ expect(markup).toContain("Privacy-safe support")
expect(markup).toContain("/en/roadmap")
expect(markup).toContain("/en/distribution-research")
expect(markup).toContain("/en/self-hosting")
+ expect(markup).toContain("/en/support")
expect(markup).toContain("feat%3A%20extension%20or%20desktop%20distribution")
expect(markup).toContain("issues/new?template=feature_request.yml")
expect(markup).toContain("label%3Aenhancement")
@@ -76,6 +85,49 @@ describe("public roadmap, changelog, self-hosting, and distribution docs", () =>
expect(markup).not.toContain("Use public requests only with sanitized examples")
})
+ it("ships a localized privacy-safe sponsor and support conversion path", async () => {
+ const urls = new Set(sitemap().map((entry) => entry.url))
+ const sources = {
+ contact: fs.readFileSync(path.join(process.cwd(), "src/app/[lang]/contact/page.tsx"), "utf8"),
+ footer: fs.readFileSync(path.join(process.cwd(), "src/components/layout/server-footer.tsx"), "utf8"),
+ pricing: fs.readFileSync(path.join(process.cwd(), "src/app/[lang]/pricing/page.tsx"), "utf8"),
+ selfHosting: fs.readFileSync(path.join(process.cwd(), "src/app/[lang]/self-hosting/page.tsx"), "utf8"),
+ support: fs.readFileSync(path.join(process.cwd(), "src/app/[lang]/support/page.tsx"), "utf8"),
+ }
+
+ for (const locale of LOCALES) {
+ const copy = getTranslation(locale).pages
+ expect(copy.support_title.trim(), locale).not.toBe("")
+ expect(copy.support_intro.trim(), locale).not.toBe("")
+ expect(copy.support_boundary_no_tracking.trim(), locale).not.toBe("")
+ expect(copy.support_boundary_no_payload.trim(), locale).not.toBe("")
+ expect(copy.contact_support_desc.trim(), locale).not.toBe("")
+ expect(urls.has(buildCanonicalUrl(locale, "support")), `${locale}/support`).toBe(true)
+ }
+
+ const markup = renderToStaticMarkup(await SupportPage({ params: Promise.resolve({ lang: "en" }) }))
+ expect(markup).toContain("Core tools remain free and open source")
+ expect(markup).toContain("no tracking pixels")
+ expect(markup).toContain("no personalized ads")
+ expect(markup).toContain("no ad scripts")
+ expect(markup).toContain("payload access")
+ expect(markup).toContain("query text")
+ expect(markup).toContain("user identifiers")
+ expect(markup).toContain("behavioral profiles")
+ expect(markup).toContain("static hosting")
+ expect(markup).toContain("internal deployment")
+ expect(markup).toContain("security review")
+ expect(markup).toContain("packaging")
+ expect(markup).toContain("maintenance")
+ expect(markup).toContain("No cloud account or hosted payload history")
+
+ expect(sources.contact).toContain("/support")
+ expect(sources.footer).toContain("support")
+ expect(sources.pricing).toContain("/support")
+ expect(sources.selfHosting).toContain("/support")
+ expect(sources.support).not.toMatch(/googletag|adsbygoogle|doubleclick|googlesyndication|facebook\.net|connect\.facebook|gtag\(|trackingPixel|tracking-pixel/i)
+ })
+
it("keeps the All Tools empty state wired to privacy-safe request and voting flows", () => {
const allToolsPage = fs.readFileSync(path.join(process.cwd(), "src/app/[lang]/all-tools/page.tsx"), "utf8")
const allToolsDiscovery = fs.readFileSync(path.join(process.cwd(), "src/features/tool-discovery/all-tools-discovery.tsx"), "utf8")