TypeScript Migration Scope
This document fixes the TypeScript migration boundary for the Barbelic React app. The current step is intentionally mechanical: rename code files into the TypeScript extension space without changing runtime behavior.
Goals
- Move every
src/reactcode file from JS/JSX to TS/TSX. - Keep existing runtime validation at RPC, import, admin, and sync boundaries.
- Keep existing
.mjstests, but let the test runner import TS source throughnode --import tsx --test. - Make the migration easy to continue in smaller follow-up PRs.
Tooling Baseline
typescript,tsx,@types/node,@types/react, and@types/react-domare dev dependencies.npm run check:typesrunstsc --noEmit.npm run check:ts-boundary-gateforbids source-level TypeScript suppression comments across the checked source tree and locks explicitanyto a reviewed any-boundary inventory.npm run check:ts-strict-gateremains as a compatibility alias.npm run check:tsconfigguards the TypeScript config shape.npm run check:unusedenablesnoUnusedLocalsandnoUnusedParametersonly inside a dedicated GitHub Actions ratchet step; the shared tsconfig files and the default localnpm run checkremain unchanged.npm run testusesnode --import tsx --test.tsconfig.base.jsonis the final strict target:allowJs: false,checkJs: false,strict: true,noImplicitAny: true,noUncheckedIndexedAccess: true, andexactOptionalPropertyTypes: false.tsconfig.jsonextends the base config for the current staged migration.src/react/types/contains the shared type skeleton forcommon,supabase,screenRpc,workout,admin,import,sync,reactComponents,controllers,mobileUi, anddesktopUidomains. These cover common values, Supabase rows/RPCs, screen RPC payloads, workout drafts, admin payloads, import batches, sync tasks, and checked React component prop contracts, plus intentionally broad mobile screen/fixture and desktop screen/fixture presentation props.- Supabase DB types use a manual minimal first-pass type in
src/react/types/supabase.ts; the long-term target is generated Supabase types from the remote project:supabase gen types typescript --project-id kobxeylancdimqhfkbnl. - Browser/native bridge globals are declared in
src/react/global.d.ts, including the iOSwindow.webkit.messageHandlersbridge, native social auth events, and Barbelic debug globals.
In Scope
Current scope snapshot:
| Area | Current files | Target |
|---|---|---|
src/react/**/*.js | 0 | renamed to .ts |
src/react/**/*.jsx | 0 | renamed to .tsx |
supabase/functions/_shared/*.js | 0 | renamed to .ts |
supabase/functions/*/index.ts | 3 | keep .ts |
tests/**/*.mjs | live inventory | keep .mjs; adding tests must not require a gate update |
Converted areas:
- React entry/root files:
src/react/vite/*.tsx,src/react/app.tsx,src/react/mobileApp.tsx,src/react/desktopApp.tsx - React shell/components/screens/fixtures/previews under
src/react/ui/** - services/controllers/domain modules under
src/react/servicesandsrc/react/controllers - write/import/auth modules such as
directWorkoutWrite,workoutDraftCache,wodupJsonlUpload, andsupabaseAuth - design contract code under
src/react/contracts - Supabase Edge Function shared workers under
supabase/functions/_shared
Import Specifier Policy
Source import specifiers intentionally keep their existing .js and .jsx suffixes for now, for example:
import { foo } from "./foo.js";With moduleResolution: "Bundler" and the Vite/tsx toolchain, these specifiers resolve to the migrated .ts or .tsx source files. This keeps the rename PR mechanical and avoids a noisy second-order import rewrite.
Only true filesystem entry points were updated, such as index.html, preview HTML files, and Deno Edge Function _shared imports.
TypeScript Boundary Gate Policy
The policy is documented in docs/gates/typescript-boundary-gate.md.
Source implementation files must not carry // @ts-nocheck, // @ts-ignore, or // @ts-expect-error. The default npm run check command runs check:ts-boundary-gate, so reintroducing these suppressions anywhere in the checked source tree fails locally and in CI.
There are no current @ts-nocheck exceptions. The Claude desktop dashboard design-intake preview harness is type-checked and remains guarded by import boundary and design marker tests. App containers, controllers, repositories, domain services, RPC adapters, import/sync/auth code, mobile UI, admin operations, workout flow, the desktop journal, training report and PR screen, shared desktop widgets, and shared shell code all follow the same zero-suppression policy.
Explicit any is still present at known migration and external data boundaries, especially Supabase RPC/raw row mapping, Wodup JSON normalization, browser/native bridges, controller state, and broad first-pass presentation props. Every file that contains explicit any must appear in scripts/check-typescript-boundary-gate.mjs with a reviewed any-boundary reason. New unreviewed any locations fail the same gate.
The first checked React component pass covers the shared app shell, Vite roots, and the desktop admin operations console. Their reusable prop contracts live in src/react/types/reactComponents.ts.
The checked controller pass covers appController and every file under src/react/controllers. Reusable state setter, toast, and external row boundary types live in src/react/types/controllers.ts.
The checked platform container pass covers mobileApp, desktopApp, tweaks-panel, contracts/designContract, and the mobile/desktop Vite roots.
The checked mobile UI pass covers every src/react/ui/mobile/screens/*.tsx screen component. The first-pass screen props live in src/react/types/mobileUi.ts and stay intentionally broad at presentation boundaries while still keeping the files under real TypeScript checking.
The checked desktop UI pass covers app-owned desktop surfaces, including admin, the favorite-group editor, Home, journal, log table, PR, import, mapping, onboarding, profile, search, plan editor, workout-flow, and shell-adjacent screens. Preview harnesses and fixtures are Claude Design local-only material and no longer exist in this repository (docs/process/design-codex-transfer-contract.md).
Verification Baseline
Every TypeScript migration step should run the same local baseline:
npm.cmd run check:unused
npm.cmd run check:types
npm.cmd run check
npm.cmd run buildThe Node test runner imports TypeScript source through node --import tsx --test. The screen RPC contract tests prove that validator and payload contracts fail closed when they diverge, and the frontend import boundary tests keep raw repository loaders out of app-facing UI/controller paths.
Out Of Scope
- SQL files and Supabase migrations
- CSS, HTML, PNG, SVG, Markdown, TOML, and other non-code assets
- Rewriting existing
.mjstests to TypeScript - Generating full Supabase DB types from the remote project in this first pass
- Feature behavior changes, UI redesign, import pipeline behavior changes, or DB schema changes
Order
- Add TypeScript tooling and
check:types. - Add shared app/domain/RPC payload types.
- Add the first-pass Supabase type strategy.
- Rename JS/JSX source files to TS/TSX.
- Adjust filesystem entry points and tests to the renamed files.
- Keep source import specifiers stable until a later dedicated rewrite.
- Remove all temporary
// @ts-nocheckheaders, including the desktop design-intake preview harness. - Keep the boundary gate green so TypeScript suppressions cannot return to core/app/data paths and new explicit
anyusage is reviewed.
Completion Criteria
- No
.jsor.jsxfiles remain undersrc/react. - No
.jsfiles remain undersupabase/functions/_shared. - Existing
.mjstests remain.mjsand pass against TS source. npm run check:types,npm run check, andnpm run buildpass.- Runtime validation remains active for RPC/import/admin payload boundaries.