Crawlers received an empty client-rendered shell (107 characters of text);
most AI crawlers do not run JavaScript, so the product was invisible to them.
- Build renders each locale to static HTML (/ for Korean, /en/ … /vi/) with
src/entry-server.tsx + scripts/prerender.mjs; the browser hydrates the same
locale. The language menu links to those pages instead of switching in place.
- Per-locale head: title, description, canonical, hreflang (+ x-default /en/),
Open Graph and X cards with a per-locale 1200x630 image.
- JSON-LD graph: Organization, WebSite, WebPage, SoftwareApplication (KRW
offers, version, release date, download URL from the canonical sources),
HowTo and FAQPage. No invented ratings.
- robots.txt (search, ai-input and ai-train allowed; /app, /api, invites
excluded), sitemap.xml with language alternates, llms.txt and llms-full.txt
generated from the same translations and canonical values.
- IndexNow key and a post-deploy ping (Bing, Naver, Yandex).
- A factual "at a glance" section and two FAQ answers (recognised languages,
where data is stored) in all 10 languages.
- Icons, apple-touch-icon and web manifest; asset base is now absolute so
sub-path pages load the same bundle.
Verified: 3.6k-7.7k characters of text per page, no hydration warnings,
no overflow at 320/1440 in six locales, axe 0, Lighthouse mobile SEO,
accessibility and best practices 100.
The first real Forgejo CI run failed because the linux-builder runner ships
Node 18.19: scripts using import.meta.dirname threw, and its older npm
reported the mobile lock as out of sync with the file: dependency on
packages/core (the lock is in sync under Node 24's npm).
bootstrap-linux-toolchain.sh gains a checksum-verified `node` mode
(24.19.0, the .nvmrc version); ci.yml (quality, build-validation,
mobile-quality) and deploy-site.yml add it to GITHUB_PATH before npm runs.
The repository has Forgejo and GitLab remotes but no GitHub remote, so
nothing under .github/workflows ever ran - including the daily Payple
renewal job, which means Payple subscriptions were not being renewed.
- Port payple-renew (daily cron + manual dispatch) to Forgejo. Requires the
Forgejo secrets SUPABASE_URL and CRON_SECRET.
- Port the CI checks (quality incl. version:check and contract:check, build,
mobile quality, edge functions, API tests) to .forgejo/workflows/ci.yml.
macOS and Android emulator jobs are dropped: no macOS runner here, and the
signed Android release stays on GitLab mobile-production-release.
- Keep one site deploy workflow (Linux, Cloudflare Pages); remove the
manual Windows duplicate. The mobile release boundary self-test runs there.
- Release verifiers read the Forgejo/GitLab workflows, fail if .github
workflows come back, and check the rewritten site offers no mobile package.
Policy: docs/REFACTOR_POLICY.md Wave 3, W3-7 and W3-8.