---
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: <MainPage /> },
  // ...
];
```

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.
