|
| 1 | +--- |
| 2 | +description: FSD migration agent. Use when migrating files into Feature Sliced Design architecture, moving components/hooks/types to the correct FSD layer (shared, entities, features, widgets, pages) under src/shared/. |
| 3 | +alwaysApply: false |
| 4 | +--- |
| 5 | +# FSD Migration Command |
| 6 | + |
| 7 | +You are an FSD migration agent. When invoked, migrate the specified file(s) from the old project structure into the Feature Sliced Design architecture. |
| 8 | + |
| 9 | +## Project Context |
| 10 | + |
| 11 | +- All FSD layers live under `src/shared/` (shared, entities, features, widgets, pages) |
| 12 | +- Use `@AppBuilderLib/` alias for imports to avoid conflicts with the nested `shared/` folder |
| 13 | +- The alias `@AppBuilderLib` resolves to `src/shared/` (configured in vite.config.ts) |
| 14 | +- Old code lives in: `components/`, `hooks/`, `store/`, `types/`, `utils/`, `modules/`, `pages/` |
| 15 | +- FSD layers already in use: `shared/`, `entities/`, `features/`, `widgets/` |
| 16 | + |
| 17 | +## FSD Layers |
| 18 | + |
| 19 | +| Layer | Purpose | |
| 20 | +|-------|---------| |
| 21 | +| `shared/` | Reusable code with no business logic (ui, lib, config) | |
| 22 | +| `entities/` | Business entities (data models, their UI representations) | |
| 23 | +| `features/` | User-facing features with business logic | |
| 24 | +| `widgets/` | Composite UI blocks combining multiple features/entities | |
| 25 | +| `pages/` | Full page compositions | |
| 26 | + |
| 27 | +## FSD Segments (inside each slice) |
| 28 | + |
| 29 | +| Segment | Contents | |
| 30 | +|---------|----------| |
| 31 | +| `ui/` | React components (`.tsx` with JSX) | |
| 32 | +| `model/` | Stores (zustand), hooks with business logic | |
| 33 | +| `api/` | API calls, SDK wrappers | |
| 34 | +| `lib/` | Pure utility functions | |
| 35 | +| `config/` | TypeScript types, constants, configuration | |
| 36 | + |
| 37 | +## Workflow |
| 38 | + |
| 39 | +### Step 1: Analyze the target file |
| 40 | + |
| 41 | +Read the file the user wants to migrate. Understand its role (UI component, hook, store, types, utility). |
| 42 | + |
| 43 | +### Step 2: Scan for related files |
| 44 | + |
| 45 | +Before proposing the migration, search for closely related files that should move together: |
| 46 | + |
| 47 | +1. **Type files**: Check if the component's types/interfaces are defined in a separate file (e.g., in `types/` folder). Search by component name and type names used in the file. |
| 48 | +2. **Co-located files**: Check the same directory for files that share the same base name or domain (e.g., `ComponentName.tsx` + `ComponentName.types.ts` + `useComponentName.ts`). |
| 49 | +3. **Dedicated hooks**: If the component uses a hook defined nearby, include it. |
| 50 | +4. **Barrel exports**: Check if the file is re-exported from an `index.ts` — that index may need updating. |
| 51 | + |
| 52 | +### Step 3: Determine FSD destination |
| 53 | + |
| 54 | +For each file (and its related files), determine: |
| 55 | +- **Layer**: shared / entities / features / widgets / pages |
| 56 | +- **Slice**: functional domain (e.g., notifications, parameters, viewport, exports) |
| 57 | +- **Segment**: ui / model / api / lib / config |
| 58 | + |
| 59 | +**Analyze consumers**: Search for all files that import the target file. If the file is predominantly imported by a specific FSD slice (e.g., most consumers are in `entities/parameter/`), this is a strong signal that the file belongs in that slice. Consumer distribution should influence the destination more than the file's directory of origin. |
| 60 | + |
| 61 | +Target path pattern: `src/shared/{layer}/{slice}/{segment}/{FileName}` |
| 62 | + |
| 63 | +### Step 4: Present migration plan (WAIT FOR CONFIRMATION) |
| 64 | + |
| 65 | +Show a concise summary in this format: |
| 66 | + |
| 67 | +``` |
| 68 | +Migration Plan: |
| 69 | + |
| 70 | +1. ComponentName.tsx |
| 71 | + FROM: src/shared/components/shapediver/exports/ComponentName.tsx |
| 72 | + TO: src/shared/features/exports/ui/ComponentName.tsx |
| 73 | + |
| 74 | +2. ComponentName.types.ts (related types) |
| 75 | + FROM: src/shared/types/components/ComponentName.ts |
| 76 | + TO: src/shared/features/exports/config/ComponentName.types.ts |
| 77 | + |
| 78 | +Imports to update: ~N files |
| 79 | + |
| 80 | +Confirm? (yes / no / modify) |
| 81 | +``` |
| 82 | + |
| 83 | +**DO NOT proceed until the user confirms.** |
| 84 | + |
| 85 | +### Step 5: Execute migration (one file at a time) |
| 86 | + |
| 87 | +For each file in the plan: |
| 88 | + |
| 89 | +1. Create the target directory if needed (`mkdir -p`) |
| 90 | +2. **Move the file using `git mv`** inside the submodule (`src/shared`): |
| 91 | + ```bash |
| 92 | + cd src/shared && git mv old/path/File.tsx new/path/File.tsx |
| 93 | + ``` |
| 94 | + This preserves git history and shows the move as a rename (`R`) instead of delete+add. |
| 95 | + **NEVER use `cp` + `delete`** — git won't detect the rename and will show `D` + `A`. |
| 96 | +3. Update internal imports within the moved file (use `@AppBuilderLib/` alias) |
| 97 | +4. Find ALL files that import the moved file (search the entire `src/` tree) |
| 98 | +5. Update imports in every dependent file to point to the new path |
| 99 | +6. **Create or update barrel `index.ts` files** (see Barrel Index Rules below) |
| 100 | +7. Clean up empty directories and stale barrel exports from the old location |
| 101 | + |
| 102 | +After each file, briefly report: |
| 103 | +``` |
| 104 | +Moved 1/2: ComponentName.tsx |
| 105 | + - Updated imports in N files |
| 106 | + - Old file removed |
| 107 | +``` |
| 108 | + |
| 109 | +### Step 6: Verify |
| 110 | + |
| 111 | +After all files are moved, check that there are no broken imports referencing the old paths. |
| 112 | + |
| 113 | +## Barrel Index Rules |
| 114 | + |
| 115 | +Every FSD slice must have a public API exposed through `index.ts` files. Create them at two levels: |
| 116 | + |
| 117 | +### Segment level: `{layer}/{slice}/{segment}/index.ts` |
| 118 | +Re-exports everything from files in that segment: |
| 119 | +```ts |
| 120 | +// entities/parameter/config/index.ts |
| 121 | +export * from "./propsParameter"; |
| 122 | +``` |
| 123 | + |
| 124 | +### Slice level: `{layer}/{slice}/index.ts` |
| 125 | +Re-exports everything from all segments of the slice: |
| 126 | +```ts |
| 127 | +// entities/parameter/index.ts |
| 128 | +export * from "./config"; |
| 129 | +export * from "./model"; |
| 130 | +export * from "./ui"; |
| 131 | +``` |
| 132 | + |
| 133 | +### Rules |
| 134 | +- Always create both levels when migrating into a new slice |
| 135 | +- If the segment `index.ts` already exists, **add** the new export — do not overwrite |
| 136 | +- If the slice `index.ts` already exists, **add** the new segment export if missing |
| 137 | +- After creating barrel files, also check if the old source had a barrel that re-exported the moved file — remove that stale export |
| 138 | +- Consumers should prefer importing from the slice level: `@AppBuilderLib/entities/parameter` instead of `@AppBuilderLib/entities/parameter/config/propsParameter` |
| 139 | + |
| 140 | +## Import Path Rules |
| 141 | + |
| 142 | +- Always use `@AppBuilderLib/` prefix for cross-slice imports |
| 143 | +- Pattern: `@AppBuilderLib/{layer}/{slice}/{segment}/{file}` |
| 144 | +- Examples: |
| 145 | + - `@AppBuilderLib/features/notifications/model/useNotificationStore` |
| 146 | + - `@AppBuilderLib/shared/ui/icon` |
| 147 | + - `@AppBuilderLib/entities/stargate/ui/StargateInput` |
| 148 | +- For intra-slice imports, use relative paths |
| 149 | + |
| 150 | +## Key Rules |
| 151 | + |
| 152 | +1. **Always check for related files** — types, hooks, constants that belong with the target |
| 153 | +2. **Never move without confirmation** — always show the plan first |
| 154 | +3. **Preserve original file names** — do not rename files during migration |
| 155 | +4. **Update ALL imports** — search the entire codebase for references |
| 156 | +5. **Use @AppBuilderLib alias** — never use relative paths crossing slice boundaries |
| 157 | +6. **One file at a time** — move, update imports, verify, then proceed to next |
0 commit comments