--- name: migrate-module description: Migrates a dashboard module to the self-contained modular architecture. Usage: /migrate-module Goals --- # /migrate-module $ARGUMENTS Migrates an existing module to the architecture defined in `module-architecture.mdc`. Execute the steps in strict order. Commit after each numbered step. If `$ARGUMENTS` is empty, ask: "Which module do you want to migrate? (folder name under `src/pages/dashboard/`, in PascalCase — e.g. `Goals`, `TimeOff`, `Learning/Sessions`)" ## Pre-requisite Read `rules/file-types/module-architecture-conventions.mdc` (invariants), `rules/file-types/module-architecture.mdc` (structure), `rules/file-types/module-architecture-files.mdc`, and `rules/file-types/module-architecture-hooks.mdc` before starting. ## Input `{ModuleName}` = `$ARGUMENTS`, in **PascalCase**. Examples: `Goals`, `Profile`, `TimeOff`, `Surveys`, `Learning/Sessions`. --- ## Step 1: Inventory Find all module-related files scattered outside its folder. Names may vary (camelCase, PascalCase, singular/plural, `Service` suffix): ```bash find src/services -iname "*{moduleName}*" find src/types -iname "*{moduleName}*" find src/constants -iname "*{moduleName}*" find src/hooks -iname "*{moduleName}*" find src/utils -iname "*{moduleName}*" ``` For each file found, count how many files import it: ```bash grep -rn "from '.*{filename}'" src/ --include="*.ts" --include="*.tsx" | wc -l ``` Show the user: - Table with the path of each found file and number of references - Current state of `src/pages/dashboard/{ModuleName}/` (what already exists inside) **Ask for user confirmation before continuing.** --- ## Step 2: Move services If `src/services/{moduleName}.ts` exists (or a variant): 1. If `src/pages/dashboard/{ModuleName}/services.ts` already exists, merge the content without overwriting. If it doesn't exist, move the file. 2. Update the HTTP client import: ```typescript // Before import axios from 'src/utils/axios' // After import api from 'src/config/api' ``` Replace all references: `axios.get` → `api.get`, `axios.post` → `api.post`, etc. 3. Find and update all imports from the old path: ```bash grep -rn "from 'src/services/{moduleName}'" src/ grep -rn "from \"src/services/{moduleName}\"" src/ ``` 4. `bun tsc --noEmit` 5. Commit: `feat({ModuleName}): move services to module` --- ## Step 3: Move types If `src/types/{moduleName}.ts` exists (or a variant): 1. Read the file. If it has clearly separable domains, create a `types/` folder without a barrel: ``` types/entities.ts # domain types types/api.ts # request/response shapes types/forms.ts # form types ``` If it's cohesive, move it directly as `types.ts`. **Do not create a `types/index.ts` barrel.** 2. Find and update all imports: ```bash grep -rn "from 'src/types/{moduleName}'" src/ ``` 3. `bun tsc --noEmit` 4. Commit: `feat({ModuleName}): move types to module` --- ## Step 4: Move constants If `src/constants/{moduleName}.ts` exists (or a variant): 1. If the module already has `constants.ts`, merge the content. 2. Find and update imports: ```bash grep -rn "from 'src/constants/{moduleName}'" src/ ``` 3. `bun tsc --noEmit` 4. Commit: `feat({ModuleName}): move constants to module` --- ## Step 5: Move and refactor hooks If `src/hooks/queryHooks/{moduleName}.ts` exists (or a variant): 1. Read the full file and identify each hook: - Query hooks (GET): `useGet{Entity}.ts` - Mutation hooks: `use{Action}{Entity}Mutation.ts` - Custom logic hooks: `use{CustomLogic}.ts` 2. Create an individual file per hook in `src/pages/dashboard/{ModuleName}/hooks/`. **Do not create a `hooks/index.ts` barrel.** 3. In each new file, update internal imports to relative paths: ```typescript // Before: import { goalsKeys } from 'src/pages/dashboard/Goals/queries' // After: import { goalsKeys } from '../queries' import { getGoals } from '../services' ``` 4. Find and update references to the old file: ```bash grep -rn "from 'src/hooks/queryHooks/{moduleName}'" src/ ``` 5. `bun tsc --noEmit` 6. Commit: `feat({ModuleName}): split and move hooks to module` --- ## Step 6: Move utils If `src/utils/{moduleName}.ts` exists (or a variant): 1. Review each function: those used by 2+ modules must NOT be moved. 2. Move the exclusive ones to `src/pages/dashboard/{ModuleName}/utils.ts`. 3. Update imports. 4. `bun tsc --noEmit` 5. Commit: `feat({ModuleName}): move utils to module` --- ## Step 7: Verify queries.ts If `src/pages/dashboard/{ModuleName}/queries.ts` doesn't exist, create it: ```typescript export const {moduleName}Keys = { all: () => ['{ModuleName}'] as const, lists: () => [...{moduleName}Keys.all(), 'list'] as const, list: (params?: unknown) => [...{moduleName}Keys.lists(), params] as const, details: () => [...{moduleName}Keys.all(), 'detail'] as const, detail: (id: number | string) => [...{moduleName}Keys.details(), id] as const, }; ``` If it already exists, verify that the migrated hooks reference it with the relative path `'../queries'`. --- ## Step 8: Reorganize pages to {PageName}/index.tsx 1. List `.tsx` files in the module root that are pages/views. 2. Each loose page becomes a folder with `index.tsx`: ``` Goals.tsx → Goals/index.tsx MyGoals.tsx → MyGoals/index.tsx ``` 3. Verify that each `index.tsx` has `export default ComponentName`. 4. `bun tsc --noEmit` --- ## Step 9: Create/update routes.ts ```typescript import { lazy } from 'react'; export const {moduleName}Routes = { root: () => '/{module-path}', // ... actual module routes }; const MainPage = lazy(() => import('./{MainPage}')); // ... one lazy import per page export const {moduleName}RouteConfig = [ { path: {moduleName}Routes.root(), element: }, // ... ]; ``` Each `lazy()` points to the folder — the bundler resolves `index.tsx` automatically. `bun tsc --noEmit` Commit: `feat({ModuleName}): setup routes.ts with lazy loading` --- ## Step 10: Update src/routes.tsx 1. Read `src/routes.tsx` to see how the module is currently imported. 2. Replace with the new route config: ```typescript import { {moduleName}RouteConfig } from 'src/pages/dashboard/{ModuleName}/routes'; // ... ...{moduleName}RouteConfig, ``` 3. **humand-backoffice only**: remove the lazy import from `src/lazyLoad.tsx`. 4. `bun tsc --noEmit` 5. Commit: `feat({ModuleName}): wire route config in src/routes.tsx` --- ## Step 11: Create index.tsx entry component Create `src/pages/dashboard/{ModuleName}/index.tsx` as the **entry component** of the module — an actual React component, not a re-exporter: ```typescript // {ModuleName}/index.tsx const {ModuleName} = () => { // main module view }; export default {ModuleName}; ``` **Do NOT create an `index.ts` barrel** (a file that only re-exports from other files). Consumers should import directly from the specific file they need: ```typescript // ✅ Correct import { {moduleName}Routes } from 'src/pages/dashboard/{ModuleName}/routes'; // ❌ Avoid import { {moduleName}Routes } from 'src/pages/dashboard/{ModuleName}'; ``` --- ## Step 12: Create README.md Use the template in `templates/module-readme.md`. Fill in with: - Functional description of the module - Core features - Structure table with real files - Available routes - Relevant technical notes --- ## Step 13: Final verification 1. `bun tsc --noEmit` 2. `bun biome:fix` 3. Verify there are no old imports: ```bash grep -rn "from 'src/services/{moduleName}'" src/ grep -rn "from 'src/types/{moduleName}'" src/ grep -rn "from 'src/constants/{moduleName}'" src/ grep -rn "from 'src/hooks/queryHooks/{moduleName}'" src/ ``` 4. Verify there are no cross-module imports: ```bash grep -rn "dashboard/" src/pages/dashboard/{ModuleName}/ | grep -v "dashboard/{ModuleName}" ``` 5. Show summary: files moved, files modified, commits made. --- ## Important notes - **One PR per module.** - If a file doesn't exist at the expected location, continue with the next step. - If a type/util is shared with 2+ modules, do NOT move it. - If `bun tsc --noEmit` fails, fix it before continuing. - **humand-backoffice only**: once all modules are migrated, `src/lazyLoad.tsx` can be removed.