Skip to Content
Living documentation — last reviewed 2026-05-28
RunbooksRebrand runbook: FitKit → Taikan

Rebrand runbook: FitKit → Taikan

Status: code rename done on chore/rebrand-taikan (main repo + mobile repo). Everything below is what the code now assumes exists, and the order in which to make it true.

Already applied 2026-08-22 (agent, via API/MCP): Vercel projects renamed to taikan-web / taikan-marketing / taikan-admin / taikan-minisites; PostHog project → “Taikan”, dashboard → “Taikan Coach Observability”, authorized URLs now include usetaikan.com + app.taikan.fit.

Also applied 2026-08-22 after approval: GitHub repos renamed to desmotech/taikan + desmotech/taikan-mobile (homepage/description set; local remotes in the main checkouts updated); Railway project → Taikan, services → @taikan/api / @taikan/api-scheduler; Sentry projects → taikan-backend / taikan-frontend / taikan-mobile (DSNs unchanged — ids 4510894678540368 / 4510895035449424 / 4511416743362640 verified identical, so no DSN edits anywhere); SENTRY_API_PROJECT=taikan-backend set on Railway prod+preview (API + scheduler). The Sentry org slug is still fitkit1 (dashboard-only) — sentry-release.yml and a new Vercel SENTRY_ORG=fitkit1 env pin it until you rename the org, then flip both to taikan.

Target map:

ConcernOldNew
Marketing / companyfitkit.fitusetaikan.com
Web appapp.fitkit.fitapp.taikan.fit
APIapi.fitkit.fitapi.taikan.fit
Adminadmin.fitkit.fitadmin.taikan.fit
Clerk frontend APIclerk.fitkit.fit (+ accounts.)clerk.taikan.fit (+ accounts.)
Per-org minisites<slug>.fitkit.fit<slug>.taikan.fit (legacy suffix still resolves)
Docsdocs.fitkit.fit / fitkit-docs.pages.devdocs.usetaikan.com / taikan-docs.pages.dev
Outbound email* <…@fitkit.fit>Taikan <support@usetaikan.com>, noreply@usetaikan.com
Inbound (conversation replies)contact+<id>@inbound.fitkit.fitcontact+<id>@inbound.usetaikan.com
Media / CDN / formscdn. media. forms.fitkit.fitsame hosts on taikan.fit
npm package (mobile)@desmotech/fitkit-shared@desmotech/taikan-shared
Workspace scope@fitkit/*@taikan/*
GitHub reposdesmotech/FitKit, desmotech/FitKit-mobiledesmotech/taikan, desmotech/taikan-mobile
Sentryorg fitkit1, projects fitkit-{backend,frontend,mobile}org taikan, projects taikan-{backend,frontend,mobile}
Mobile appfit.fitkit.app, slug fitkit, scheme fitkit://new app fit.taikan.app, slug taikan, scheme taikan:// (+ fitkit:// kept)
Local DBsfitkit_dev, fitkit_testtaikan_dev, taikan_test
CI seed secretfitkit-e2e-secrettaikan-e2e-secret

Deliberately not renamed (vendor-issued or identity-bearing — renaming breaks things for no gain): FITKITPAYMENT* Cardcom module ids · Sentry short-ids FITKIT-BACKEND-nn in docs · Firebase project fitkit-7b46b (replaced by a new project, see §6) · the legacy iOS app id in apple-app-site-association (listed next to the new one) · ICS UID:…@fitkit.fit in apps/web/src/components/course-player/ics.ts (calendar identity) · Railway host fitkitapi-preview.up.railway.app (re-provisioned in §4) · Linear FIT- issue prefix.


0. Domains — DONE 2026-08-22

Registered on Namecheap, delegated to Cloudflare (joan/osmar.ns.cloudflare.com), zones taikan.fit (610d48c6…) and usetaikan.com (d18f3ef7…) created, SSL mode Full. Records written (§1 table is now the live state), Email Routing enabled on usetaikan.com with contact@ → leads-worker + catch-all, HTTP→HTTPS and www→root redirect rules copied. Vercel: app./admin./*.taikan.fit, taikan.fit (308 → app), usetaikan.com + www attached and verified. Railway: api.taikan.fit custom domain created (CNAME target u0cel7ja.up.railway.app). Cloudflare Pages taikan-docs created with docs.usetaikan.com attached.

Production cutover executed 2026-08-22 15:00 IDT: Clerk on clerk.taikan.fit (pk pk_live_Y2xlcmsudGFpa2FuLmZpdCQ=), Railway prod vars + Vercel web/admin env flipped via scripts/rebrand-cutover-prod.sh, api.taikan.fit validated on Railway via _railway-verify.api TXT and re-proxied (SSL Full). app.taikan.fit, admin.taikan.fit, api.taikan.fit, usetaikan.com all live (still FitKit-branded code until merge).

Still open from this block: (a) Cloudflare Access app “docs” must also cover docs.usetaikan.com + taikan-docs.pages.dev (Zero Trust → Applications → docs → add the hostnames; the API update was refused — max 5 destinations, drop *.fitkit-docs.pages.dev); (b) first docs deploy to taikan-docs happens on the next deploy-docs.yml run after merge; (c) _vercel TXT not needed — Vercel verified by team ownership.

0b. (historical) Before anything: buy + park the domains

  • Register usetaikan.com and taikan.fit.
  • Add both as zones in the existing Cloudflare account (FitKit, id 74e1f4e4…) and move NS at the registrar.
  • Rename the Cloudflare account display name to Taikan (dashboard → Manage Account).

Nothing in §1–§8 can be completed before this. Code can ship behind it: every new host is only referenced as a default/fallback or via env.

1. Cloudflare DNS (mirror of today’s fitkit.fit zone, split across two zones)

taikan.fit zone:

NameTypeTargetProxy
@CNAMEcname.vercel-dns.comoff — only if you want bare taikan.fit to redirect to app; otherwise point at marketing
*CNAMEcname.vercel-dns.comoff (minisites wildcard)
appCNAMEvalue Vercel gives for taikan-weboff
adminCNAMEvalue Vercel gives for taikan-adminoff
apiCNAME7u2r2buw.up.railway.appon, SSL mode Full (same as today — never grey-cloud it)
_railway-verify.apiTXTfrom Railway custom-domain dialog
clerk, accounts, clkmail, clk._domainkey, clk2._domainkeyCNAMEvalues from Clerk (§5)off
_vercelTXTfrom Vercel domain verification

usetaikan.com zone:

NameTypeTargetProxy
@CNAMEcname.vercel-dns.com (marketing, taikan-marketing)off
wwwCNAMEusetaikan.comon (WWW→root redirect rule, copy from fitkit.fit)
docsCNAMEtaikan-docs.pages.devon
@MX ×3route1/2/3.mx.cloudflare.net (Email Routing)
@TXTv=spf1 include:_spf.mx.cloudflare.net include:amazonses.com ~all
_dmarcTXTv=DMARC1; p=quarantine; rua=mailto:support@usetaikan.com
resend._domainkey, send MX + TXTfrom Resend after adding the domain (§7)
inboundMXResend inbound MX (§7)
google-site-verificationTXTnew value from Search Console
  • Email Routing on usetaikan.com: enable, re-create rule contact@usetaikan.com → Worker leads-worker, catch-all → saarku@gmail.com.
  • Keep the fitkit.fit zone alive for ≥ 12 months: HTTPS redirect rule *fitkit.fit/*https://usetaikan.com/$1 for apex/www, app.fitkit.fit/*https://app.taikan.fit/$1, api.fitkit.fit not redirected until the mobile install base is gone (old binaries hardcode it). Keep *.fitkit.fit wildcard → Vercel so legacy minisite hosts keep working (the API accepts both suffixes).
  • Keep MX + inbound on fitkit.fit until no open conversation threads carry @inbound.fitkit.fit reply-to headers (check conversations table, ~90 days).
  • Cloudflare Pages: projects can’t be renamed. Create taikan-docs, attach docs.usetaikan.com; .github/workflows/deploy-docs.yml already targets taikan-docs.
  • R2: buckets can’t be renamed. Prod today: R2_BUCKET_NAME=vibrafit-exports, R2_COMPLIANCE_BUCKET_NAME=fitkit-compliance, backups AWS_S3_BUCKET=fitkit-db-backups + BACKUP_FILE_PREFIX=fitkit-prod. Either keep them and set R2_BUCKET_NAME, R2_COMPLIANCE_BUCKET_NAME, R2_BUCKET (Railway, GH secrets, pg-s3-backups) to the old names — recommended, zero data movement — or create taikan-*, rclone sync, swap the env, and keep the old buckets read-only until stored object URLs are re-signed. .env.example now says taikan-dev; the real value is whatever you choose.
  • Worker leads-worker: no rename needed (name is internal).

2. Vercel (team pandawi's projects)

  • Projects renamed to taikan-web / taikan-marketing / taikan-admin / taikan-minisites (done via API; *.vercel.app preview hosts changed accordingly).
  • Add domains: app.taikan.fit → web, usetaikan.com + www → marketing, admin.taikan.fit → admin, *.taikan.fit → minisites. Keep the old domains attached until redirects are live.
  • Env vars to update on each project (names unchanged): NEXT_PUBLIC_API_URL, NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY (new key from §5), RESEND_FROM_ADDRESS. Note: the web project has no SENTRY_ORG/SENTRY_WEB_PROJECT vars, so next.config.js defaults apply — after this branch merges they are taikan/taikan-frontend, which only work once the Sentry org slug is renamed (§5). Add SENTRY_ORG=fitkit1 explicitly if you merge before that. VITE_API_URL, VITE_CLERK_PUBLISHABLE_KEY, PUBLIC_API_URL (marketing/minisites), RESEND_FROM_ADDRESS (web feedback), VERCEL_MINISITES_PROJECT_ID unchanged.
  • Minisite backfill: for every row in minisite_content with subdomain, call the Vercel domains API once for <subdomain>.taikan.fit (the API only registers the new suffix on the next publish). One-off script: SELECT subdomain FROM minisite_content WHERE subdomain IS NOT NULL AND published=truePOST /v9/projects/$VERCEL_MINISITES_PROJECT_ID/domains {"name": "<slug>.taikan.fit"}. Then re-save each org’s website URL (minisite-website-sync rewrites *.fitkit.fit*.taikan.fit on publish).
  • Re-link Git after the GitHub rename (§8) — Vercel follows redirects but the project settings show the old slug.

3. Railway (project FitKit)

  • Project and services renamed (Taikan, @taikan/api, @taikan/api-scheduler). Railway’s auto var is now RAILWAY_SERVICE__TAIKAN_API_URL — nothing in code referenced the old name.
  • Custom domain: add api.taikan.fit to the prod API service, put the verify TXT in DNS (§1), keep api.fitkit.fit attached.
  • Preview service: generate a new public domain (taikanapi-preview.up.railway.app) and update fitkit-mobile/eas.json EXPO_PUBLIC_API_URL/WS_URL in the development + preview profiles (still hardcoded to fitkitapi-preview…).
  • Env vars (prod + preview): APP_URL/WEB_URL/CORS_ORIGINS → new hosts, RESEND_FROM_ADDRESS="Taikan <support@usetaikan.com>", INBOUND_EMAIL_DOMAIN=usetaikan.com (prod currently uses the bare fitkit.fit, not inbound.), CLERK_SECRET_KEY + CLERK_PUBLISHABLE_KEY (§5), SENTRY_ORG=taikan, SENTRY_PROJECT=taikan-backend, TEST_SEED_SECRET=taikan-e2e-secret (preview only), R2 names per §1, PUBLIC_MINISITE_SUFFIX if you externalise it.
  • pg-s3-backups: bucket name per §1 decision; Better Stack heartbeat URL unchanged.

4. Clerk (gates everything else — do in a maintenance window)

Production instance domain change = new frontend API host = new publishable keys everywhere and every signed-in session is dropped.

  • Dashboard → Domains → change production domain to taikan.fit. Clerk issues new CNAMEs for clerk, accounts, clkmail, clk._domainkey, clk2._domainkey → add to DNS (§1), wait for verification.
  • Copy the new pk_live_… / sk_live_… into: Vercel web/admin, Railway API (prod + preview), EAS secrets (EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY), GitHub Actions secrets CLERK_PUBLISHABLE_KEY / CLERK_SECRET_KEY.
  • Allowed origins / redirect URLs: add https://app.taikan.fit, https://admin.taikan.fit, https://usetaikan.com, taikan://, keep old for the transition.
  • OAuth providers (Google etc.): register the new Clerk callback URL (https://clerk.taikan.fit/v1/oauth_callback) in each provider’s console.
  • Email templates / branding inside Clerk: app name “Taikan”, logo, sender noreply@usetaikan.com (Clerk’s own DKIM records above).
  • Invite flow: tickets redirect to https://app.taikan.fit/sign-up?__clerk_ticket=… — the mobile intent filters and AASA already list that host.

5. Sentry (org fitkit1, DE region)

  • Org settings → rename org to Taikan, slug taikan (dashboard only), then set SENTRY_ORG=taikan on Railway (prod+preview) + Vercel web + sentry-release.yml. DSNs are id-based and survive; fitkit1.sentry.io links in old docs die.
  • Project slugs renamed. Future short-ids become TAIKAN-BACKEND-nn; old ones still resolve by id.
  • Set SENTRY_ORG=taikan + project envs on Vercel/Railway/EAS in the same changenext.config.js, sentry-release.yml and app.config.ts defaults already say taikan / taikan-* (this also fixes the stale fitnx-* slugs the release workflow was silently failing on).
  • Allowed domains for the JS SDK: add app.taikan.fit, usetaikan.com.
  • GitHub integration: re-add the repo after the rename (§8) so commit association works.

6. Mobile: new app fit.taikan.app

This is a brand-new store listing; the FitKit app stays published until you sunset it.

  • Expo: create project taikan under the same account → eas init in fitkit-mobile → replace projectId and the updates.url in app.config.ts (both currently carry the FitKit id with a REBRAND: comment). Set EAS secrets (EXPO_PUBLIC_*, SENTRY_AUTH_TOKEN, SENTRY_ORG=taikan, SENTRY_PROJECT=taikan-mobile).
  • Apple: App Store Connect → new app, bundle id fit.taikan.app, team P25F278UF8; enable Associated Domains + Push; new APNs key or reuse the team key; update eas.json submit.ios.ascAppId.
  • Google: new Play app, package fit.taikan.app; new upload key (or Play App Signing) → new SHA-256 fingerprints → update apps/web/public/.well-known/assetlinks.json (currently still lists the FitKit fingerprints under the new package name).
  • Firebase: new project (fitkit-7b46b is bound to the old package) → download google-services.json for fit.taikan.app, replace the file (untouched by the rename), upload the FCM server key to Expo push credentials.
  • Universal links: AASA already lists P25F278UF8.fit.taikan.app; app.taikan.fit must serve it over HTTPS before the first TestFlight build.
  • Store listings: new name “Taikan”, screenshots, privacy labels; store-assets/play/* copy is already renamed.
  • Publish @desmotech/taikan-shared first (§8) then bump fitkit-mobile/package.json — right now @taikan/shared is aliased to npm:@desmotech/fitkit-shared@^0.1.55 so the repo installs.
  • Sunset plan for fit.fitkit.app: ship one last FitKit OTA/build whose home screen says “we’re now Taikan — install the new app”, keep api.fitkit.fit answering for as long as that install base exists, then remove from sale.

7. Resend

  • Add usetaikan.com → DKIM/SPF/MX records into DNS (§1), verify.
  • Add inbound.usetaikan.com as a receiving domain (MX) and point the inbound webhook at https://api.taikan.fit/<existing path>.
  • Flip RESEND_FROM_ADDRESS on Railway + Vercel; keep fitkit.fit verified until the inbound threads drain.

8. GitHub + npm

gh repo rename taikan --repo desmotech/FitKit --yes gh repo rename taikan-mobile --repo desmotech/FitKit-mobile --yes gh repo edit desmotech/taikan --homepage https://usetaikan.com --description "Taikan — fitness business OS" gh secret set TEST_SEED_SECRET --body taikan-e2e-secret # if it is ever promoted to a secret
  • Repos renamed; main checkouts’ remotes updated. Other worktrees still work via GitHub redirect, but to be tidy: git remote set-url origin git@github.com:desmotech/taikan.git in /Users/saar/dev/fitkit and every worktree; same for the mobile checkout.
  • GitHub Packages cannot rename a package: the next run of publish-shared.yml publishes @desmotech/taikan-shared as a new package (0.1.56). Then in the mobile repo: "@taikan/shared": "npm:@desmotech/taikan-shared@^0.1.56" + manual lockfile bump (memory: lockfile bump is manual — the GH registry 404s transitive deps).
  • Environments FitKit / preview, FitKit / production → rename to Taikan / … (dashboard) and update the environment: keys in the workflows that reference them.
  • Branch names/PR titles are fine; FIT- Linear keys stay.

9. PostHog (org “VibraFit”, slug fitnx, project now “Taikan”)

Done via MCP: project renamed to Taikan, dashboard “FitKit Coach Observability” → “Taikan Coach Observability”.

  • Org name → Taikan (dashboard; MCP has no org-update).
  • Feature flag fitkit-managed-payments / taikan-managed-payments: moot — the flag was merged permanently ON and deleted from the codebase on 2026-08-22. Archive whichever key still exists in the PostHog UI; nothing reads it.
  • Authorized URLs: https://usetaikan.com, https://app.taikan.fit added (old kept).
  • Flag descriptions still say “FitKit prod org” — cosmetic.

10. Better Stack

  • Monitors: add https://usetaikan.com, https://app.taikan.fit/he/sign-in, https://api.taikan.fit/health (keyword) and rename the three existing ones to “(legacy fitkit.fit)” until the redirects are removed. Heartbeat names FitKit scheduler alive etc. → rename (URLs/tokens unchanged, no code change). fitkit-db-backup heartbeat is currently down — unrelated, worth a look.

11. Linear

  • Workspace name + URL key (linear.app/fitkitlinear.app/taikan) and team name — dashboard. Keep the team key FIT (hundreds of FIT-nnn references in commits/docs would break).

12. Local dev after merge

# main checkout: the Makefile/docker-compose/.env.example now say taikan_dev / taikan_test psql postgresql://postgres:postgres@localhost:5432/postgres -c 'ALTER DATABASE fitkit_dev RENAME TO taikan_dev' -c 'ALTER DATABASE fitkit_test RENAME TO taikan_test' # then edit apps/api/.env + libs/db/.env DATABASE_URL (untracked, not touched by the rename) pnpm db:doctor

Per-worktree clones from db-clone.sh will now be named taikan_dev_<branch>.

13. Blind spots / verification checklist

  • Logo: every taikan-logo*.svg/png is the old FitKit artwork under a new filename (path-only SVGs, no text node). A real Taikan mark is needed before the marketing site, emails (https://usetaikan.com/logo/taikan-logo-64.png is in the letterhead), app icons, Clerk branding and store listings go live.
  • Client state resets: moving the web app to a new origin drops every cookie/localStorage key (active-org cookie, cookie-consent record, drafts, tour flags) — no shim is possible across origins; expect everyone to re-consent and re-pick an org. Same for mobile: new bundle id = fresh AsyncStorage/SecureStore. That is why no storage-key migration shims were added.
  • Cardcom: TypeOfPlannedService KYC text now says “מערכת Taikan” — confirm with Cardcom that the merchant-of-record name on the dealer agreement doesn’t need to match; module ids FITKITPAYMENT* stay.
  • Morning / invoices: check whether issued documents carry a platform name anywhere (templates, footers).
  • Legal: Terms/Privacy/DPA pages on usetaikan.com must name the legal entity; a rename clause + notice to customers (Israeli Privacy Protection Law requires notifying data subjects of the controller’s identity change if the entity changes, not just the brand). Vendor DPAs (Clerk, PostHog, Sentry, Resend, Railway, Vercel, Cloudflare) are per-account and survive.
  • Email deliverability: brand-new sending domain = cold reputation. Warm usetaikan.com (send from it for low-volume transactional first; keep DMARC at p=none for two weeks, then quarantine).
  • Search / SEO: 301 every fitkit.fit URL to its usetaikan.com twin (marketing slugs are unchanged), new Search Console property + change-of-address, update robots.ts sitemap host (already points at usetaikan.com), OG images.
  • Existing members’ bookmarks, QR codes, printed material: QR codes encode fitkit:// / app.fitkit.fit/checkin — both keep working (scheme kept, host redirected). Tell gym owners anyway.
  • Advisory locks: fitkit:recurring-charge-cron / fitkit:audit-retention-cron lock ids changed. During the rolling deploy old and new pods hold different locks → one overlapping window where both could run the recurring-charge tick. Deploy the API with a brief scheduler pause (AUTOMATIONS_ENABLED/scheduler scale-to-zero for 1 min) or accept the idempotency guards.
  • TEST_SEED_SECRET: the value moved to taikan-e2e-secret in CI + fixtures; the Railway preview env must match or the full-test gate fails on seed calls.
  • Test-auth headers fitkit.test.*taikan.test.*: web and API renamed together; e2e storage state caches from before the rename are stale — delete apps/web/e2e/.auth.
  • Apple Pay / Google Pay merchant ids, Meta Business Verification (WhatsApp work) and Facebook app name: all carry the brand; update when those go live.
  • Docs archive (docs/_archive/**) was renamed too, per “everywhere” — it now reads as if the product was always Taikan. Revert that folder if you want the history intact.
  • Third-party listings: app store search, G2/Product Hunt if any, LinkedIn company page, email signatures, invoice templates, bank descriptor (“FITKIT” on members’ credit-card statements comes from the Cardcom terminal name — ask Cardcom to change the DBA).